root / pykota / trunk / bin / edpykota @ 952

Revision 952, 23.3 kB (checked in by jalet, 21 years ago)

Preliminary support for LPRng added BUT STILL UNTESTED.

  • 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 Print Quota Editor
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.43  2003/04/23 22:13:56  jalet
26# Preliminary support for LPRng added BUT STILL UNTESTED.
27#
28# Revision 1.42  2003/04/17 13:38:47  jalet
29# Docstring corrected for better manual page
30#
31# Revision 1.41  2003/04/16 12:35:49  jalet
32# Groups quota work now !
33#
34# Revision 1.40  2003/04/16 08:22:09  jalet
35# More strict error detection.
36# Minor code rewrite to avoid some repetitive tests.
37#
38# Revision 1.39  2003/04/16 08:01:53  jalet
39# edpykota --charge command line option works now.
40#
41# Revision 1.38  2003/04/15 22:02:43  jalet
42# More complete docstring
43#
44# Revision 1.37  2003/04/15 21:58:33  jalet
45# edpykota now accepts a --delete option.
46# Preparation to allow edpykota to accept much more command line options
47# (WARNING : docstring is OK, but code isn't !)
48#
49# Revision 1.36  2003/04/15 13:55:28  jalet
50# Options --limitby and --balance added to edpykota
51#
52# Revision 1.35  2003/04/15 13:06:39  jalet
53# Allow to add a printer without any user
54#
55# Revision 1.34  2003/04/11 16:51:11  jalet
56# Bug fix for edpykota --add with users who already had a quota on the printer.
57#
58# Revision 1.33  2003/04/10 21:47:20  jalet
59# Job history added. Upgrade script neutralized for now !
60#
61# Revision 1.32  2003/04/08 21:31:39  jalet
62# (anything or 0) = anything !!! Go back to school Jerome !
63#
64# Revision 1.31  2003/04/08 21:13:44  jalet
65# Prepare --groups option to work.
66#
67# Revision 1.30  2003/04/08 21:10:18  jalet
68# Checks --groups option presence instead of --users because --users is the default.
69#
70# Revision 1.29  2003/04/05 09:28:56  jalet
71# Unnecessary message was logged
72#
73# Revision 1.28  2003/03/29 13:45:26  jalet
74# GPL paragraphs were incorrectly (from memory) copied into the sources.
75# Two README files were added.
76# Upgrade script for PostgreSQL pre 1.01 schema was added.
77#
78# Revision 1.27  2003/03/10 00:23:04  jalet
79# Bad english
80#
81# Revision 1.26  2003/03/10 00:11:27  jalet
82# Cleaner example.
83#
84# Revision 1.25  2003/03/09 23:56:21  jalet
85# Option noquota added to do accounting only.
86#
87# Revision 1.24  2003/02/27 23:48:41  jalet
88# Correctly maps PyKota's log levels to syslog log levels
89#
90# Revision 1.23  2003/02/27 22:55:20  jalet
91# WARN log priority doesn't exist.
92#
93# Revision 1.22  2003/02/27 09:37:02  jalet
94# Wildcards seem to work now
95#
96# Revision 1.21  2003/02/27 09:04:46  jalet
97# user and group names can be passed as wildcards if the --add option
98# is not set. The default is to act on all users or groups.
99#
100# Revision 1.20  2003/02/10 12:07:30  jalet
101# Now repykota should output the recorded total page number for each printer too.
102#
103# Revision 1.19  2003/02/09 13:40:29  jalet
104# typo
105#
106# Revision 1.18  2003/02/09 12:56:53  jalet
107# Internationalization begins...
108#
109# Revision 1.17  2003/02/08 22:47:23  jalet
110# Option --reset can now be used without having to use soft and hard limits
111# on the command line.
112#
113# Revision 1.16  2003/02/08 22:39:46  jalet
114# --reset command line option added
115#
116# Revision 1.15  2003/02/08 22:20:01  jalet
117# Clarification on why we don't check with /etc/passwd to see if the user
118# name is valid or not.
119#
120# Revision 1.14  2003/02/08 22:18:15  jalet
121# Now checks user and group names for validity before adding them
122#
123# Revision 1.13  2003/02/08 22:09:02  jalet
124# Only printer was added the first time.
125#
126# Revision 1.12  2003/02/08 21:44:49  jalet
127# Python 2.1 string module doesn't define ascii_letters
128#
129# Revision 1.11  2003/02/08 09:42:44  jalet
130# Better handle wrong or bad command line arguments
131#
132# Revision 1.10  2003/02/08 09:39:20  jalet
133# typos
134#
135# Revision 1.9  2003/02/08 09:38:06  jalet
136# Badly placed test
137#
138# Revision 1.8  2003/02/07 22:53:57  jalet
139# Checks if printer name is valid before adding it
140#
141# Revision 1.7  2003/02/07 22:17:58  jalet
142# Incomplete test
143#
144# Revision 1.6  2003/02/07 22:13:13  jalet
145# Perhaps edpykota is now able to add printers !!! Oh, stupid me !
146#
147# Revision 1.5  2003/02/06 14:49:04  jalet
148# edpykota should be ok now
149#
150# Revision 1.4  2003/02/06 14:28:59  jalet
151# edpykota should be ok, minus some typos
152#
153# Revision 1.3  2003/02/06 10:47:21  jalet
154# Documentation string and command line options didn't match.
155#
156# Revision 1.2  2003/02/06 10:39:23  jalet
157# Preliminary edpykota work.
158#
159# Revision 1.1  2003/02/05 21:41:09  jalet
160# Skeletons added for all command line tools
161#
162#
163#
164
165import sys
166
167from pykota import version
168from pykota.tool import PyKotaTool, PyKotaToolError
169
170__doc__ = """edpykota v%s (C) 2003 C@LL - Conseil Internet & Logiciels Libres
171A Print Quota editor for PyKota.
172
173command line usage :
174
175  edpykota [options] user1 user2 ... userN
176 
177  edpykota [options] group1 group2 ... groupN
178
179options :
180
181  -v | --version       Prints edpykota's version number then exits.
182  -h | --help          Prints this message then exits.
183 
184  -a | --add           Adds users and/or printers if they don't
185                       exist on the Quota Storage Server.
186                       
187  -d | --delete        Deletes users/groups from the quota storage.
188                       Printers are never deleted.
189                       
190  -c | --charge p[,j]  Sets the price per page and per job to charge
191                       for a particular printer. Job price is optional.
192                       If both are to be set, separate them with a comma.
193                       Floating point values are allowed.
194 
195  -i | --ingroups g1[,g2...]  Puts the users into each of the groups
196                              listed, separated by commas. The groups
197                              must already exist in the Quota Storage.
198 
199  -u | --users         Edit users print quotas, this is the default.
200 
201  -P | --printer p     Edit quotas on printer p only. Actually p can
202                       use wildcards characters to select only
203                       some printers. The default value is *, meaning
204                       all printers.
205 
206  -g | --groups        Edit groups print quotas instead of users.
207                         
208  -p | --prototype u|g Uses user u or group g as a prototype to set
209                       print quotas
210                       
211  -n | --noquota       Doesn't set a quota but only does accounting.
212 
213  -r | --reset         Resets the printed page counter for the user
214                       or group to zero. The life time page counter
215                       is kept unchanged.
216                       
217  -l | --limitby l     Choose if the user/group is limited in printing                     
218                       by its account balance or by its page quota.
219                       The default value is 'quota'. Allowed values
220                       are 'quota' and 'balance'.
221                       
222  -b | --balance b     Sets the user's account balance to b.                     
223                       Account balance may be increase or decreased
224                       if b is prefixed with + or -.
225                       WARNING : when decreasing account balance,
226                       the total paid so far by the user is decreased
227                       too.
228                       Groups don't have a real balance, but the
229                       sum of their users' account balance.
230                       
231  -S | --softlimit sl  Sets the quota soft limit to sl pages.                       
232 
233  -H | --hardlimit hl  Sets the quota hard limit to hl pages.
234 
235  user1 through userN and group1 through groupN can use wildcards
236  if the --add option is not set.
237 
238examples :                             
239
240  $ edpykota -p jerome john paul george ringo
241 
242  This will set print quotas for the users john, paul, george and ringo
243  to the same values than user jerome. User jerome must exist.
244 
245  $ edpykota --printer lp -S 50 -H 60 jerome
246 
247  This will set jerome's print quota on the lp printer to a soft limit
248  of 50 pages, and a hard limit of 60 pages. If either user jerome or
249  printer lp doesn't exist on the Quota Storage Server then nothing is done.
250
251  $ edpykota --add --printer lp --ingroups coders,it -S 50 -H 60 jerome
252 
253  Same as above, but if either user jerome or printer lp doesn't exist
254  on the Quota Storage Server they are automatically added. Also
255  user jerome is put into the groups "coders" and "it" which must
256  already exist in the Quota Storage.
257  WARNING : the CUPS PPD file for this printer or the /etc/printcap
258            file (depending on your printing backend)  must still be
259            modified manually, as well as pykota's configuration file
260            for a new printer to be managed successfully.
261           
262  $ edpykota -g -S 500 -H 550 financial support           
263 
264  This will set print quota soft limit to 500 pages and hard limit
265  to 550 pages for groups financial and support on all printers.
266 
267  $ edpykota --reset jerome "jo*"
268 
269  This will reset jerome's page counter to zero on all printers, as
270  well as every user whose name begins with 'jo'.
271  Their life time page counter on each printer will be kept unchanged.
272 
273  $ edpykota --printer hpcolor --noquota jerome
274 
275  This will tell PyKota to not limit jerome when printing on the
276  hpcolor printer. All his jobs will be allowed on this printer, but
277  accounting of the pages he prints will still be kept.
278  Print Quotas for jerome on other printers are unchanged.
279 
280  $ edpykota --limitby balance jerome
281 
282  This will tell PyKota to limit jerome by his account's balance
283  when printing.
284 
285  $ edpykota --balance +10.0 jerome
286 
287  This will increase jerome's account balance by 10.0 (in your
288  own currency). You can decrease the account balance with a
289  dash prefix, and set it to a fixed amount with no prefix.
290 
291  $ edpykota --delete jerome rachel
292 
293  This will completely delete jerome and rachel from the Quota Storage
294  database. All their quotas and jobs will be deleted too.
295 
296  $ edpykota --printer lp --charge 0.1
297 
298  This will set the page price for printer lp to 0.1. Job price
299  will not be changed.
300
301This program is free software; you can redistribute it and/or modify
302it under the terms of the GNU General Public License as published by
303the Free Software Foundation; either version 2 of the License, or
304(at your option) any later version.
305
306This program is distributed in the hope that it will be useful,
307but WITHOUT ANY WARRANTY; without even the implied warranty of
308MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
309GNU General Public License for more details.
310
311You should have received a copy of the GNU General Public License
312along with this program; if not, write to the Free Software
313Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
314
315Please e-mail bugs to: %s""" % (version.__version__, version.__author__)
316       
317class EdPyKota(PyKotaTool) :       
318    """A class for edpykota."""
319    def main(self, names, options) :
320        """Edit user or group quotas."""
321        printeradded = 0
322        printers = self.storage.getMatchingPrinters(options["printer"])
323        if not printers :
324            pname = options["printer"]
325            if options["add"] and pname :
326                if self.isValidName(pname) :
327                    printerid = self.storage.addPrinter(pname)
328                    printers = [ (printerid, pname) ]
329                    printeradded = 1
330                else :   
331                    raise PyKotaToolError, _("Invalid printer name %s") % pname
332            else :
333                raise PyKotaToolError, _("There's no printer matching %s") % pname
334               
335        softlimit = hardlimit = None   
336        if options["softlimit"] :
337            try :
338                softlimit = int(options["softlimit"].strip())
339            except ValueError :   
340                raise PyKotaToolError, _("Invalid softlimit value %s.") % options["softlimit"]
341        if options["hardlimit"] :
342            try :
343                hardlimit = int(options["hardlimit"].strip())
344            except ValueError :   
345                raise PyKotaToolError, _("Invalid hardlimit value %s.") % options["hardlimit"]
346        if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :       
347            # error, exchange them
348            self.logger.log_message(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit))
349            (softlimit, hardlimit) = (hardlimit, softlimit)
350           
351        if not names :   
352            if options["add"] and not printeradded :
353                raise PyKotaToolError, _("You have to pass user or group names on the command line")
354            else :   
355                names = [ "*" ] # all users
356               
357        balance = options["balance"]
358        if balance :
359            balance = balance.strip()
360            try :
361                balancevalue = float(balance)
362            except ValueError :   
363                raise PyKotaToolError, _("Invalid balance value %s" % options["balance"])
364           
365        if options["charge"] :
366            try :
367                charges = [float(part) for part in options["charge"].split(',', 1)]
368            except ValueError :   
369                raise PyKotaToolError, _("Invalid charge amount value %s" % options["charge"])
370            else :   
371                if len(charges) < 2 :
372                    charges.append(None)
373                   
374        limitby = options["limitby"]
375        if limitby :
376            limitby = limitby.strip().lower()
377        if limitby and (limitby not in ('quota', 'balance')) :   
378            raise PyKotaToolError, _("Invalid limitby value %s" % options["limitby"])
379           
380        if options["ingroups"] :   
381            groupnames = [gname.strip() for gname in options["ingroups"].split(',')]
382        else :   
383            groupnames = []
384           
385        for (printerid, printer) in printers :
386            if options["charge"] :
387                (perpage, perjob) = charges
388                if perjob is None :
389                    # we don't want to change this one, get the old value
390                    (dummy, perjob) = self.storage.getPrinterPrices(printerid)
391                self.storage.setPrinterPrices(printerid, perpage, perjob)   
392            if options["prototype"] :
393                if options["groups"] :
394                    prototype = self.storage.getGroupPQuota(self.storage.getGroupId(options["prototype"]), printerid)
395                else :     
396                    # default is user quota edition
397                    prototype = self.storage.getUserPQuota(self.storage.getUserId(options["prototype"]), printerid)
398                if prototype is None :
399                    self.logger.log_message(_("Prototype %s not found in Quota Storage for printer %s.") % (options["prototype"], printer))
400                    continue    # skip this printer
401                else :   
402                    (softlimit, hardlimit) = (prototype["softlimit"], prototype["hardlimit"])
403            if hardlimit is None :   
404                hardlimit = softlimit
405                if hardlimit is not None :
406                    self.logger.log_message(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer))
407            if softlimit is None :   
408                softlimit = hardlimit
409                if softlimit is not None :
410                    self.logger.log_message(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer))
411            if (not options["ingroups"] and not options["reset"] and not options["noquota"] and not options["prototype"] and not options["limitby"] and not options["balance"] and not options["delete"] and not options["charge"]) and ((hardlimit is None) or (softlimit is None)) :
412                raise PyKotaToolError, _("Both hard and soft limits must be set ! Aborting.")
413            if options["add"] :   
414                if options["groups"] :   
415                    allidnames = [(self.storage.getGroupId(n), n) for n in names]
416                else :
417                    allidnames = [(self.storage.getUserId(n), n) for n in names]
418            else :   
419                if options["groups"] :   
420                    allidnames = self.storage.getPrinterGroups(printerid)
421                else :   
422                    allidnames = self.storage.getPrinterUsers(printerid)
423            for (ident, name) in [(i, n) for (i, n) in allidnames if self.matchString(n, names)]:
424                if options["groups"] :
425                    quota = self.storage.getGroupPQuota(ident, printerid)
426                else :
427                    quota = self.storage.getUserPQuota(ident, printerid)
428                if quota is None :
429                    # not found
430                    if options["add"] :
431                        # In case we want to add something, it is crucial
432                        # that we DON'T check with the system accounts files
433                        # like /etc/passwd because users may be defined
434                        # only remotely
435                        if options["groups"] :
436                            if self.isValidName(name) :
437                                (ident, printerid) = self.storage.addGroupPQuota(name, printerid)
438                                quota = self.storage.getGroupPQuota(ident, printerid)
439                            else :   
440                                self.logger.log_message(_("Invalid group name %s") % name)
441                        else :
442                            if self.isValidName(name) :
443                                (ident, printerid) = self.storage.addUserPQuota(name, printerid)
444                                quota = self.storage.getUserPQuota(ident, printerid)
445                            else :   
446                                self.logger.log_message(_("Invalid user name %s") % name)
447                if quota is None :     
448                    self.logger.log_message(_("Quota not found for object %s on printer %s.") % (name, printer))
449                else :   
450                    if options["delete"] :
451                        if options["groups"] :
452                            self.storage.deleteGroup(ident)
453                        else :
454                            self.storage.deleteUser(ident)
455                    else :
456                        if options["groups"] :
457                            if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) :
458                                self.storage.setGroupPQuota(ident, printerid, softlimit, hardlimit)
459                            if options["reset"] :
460                                self.storage.resetGroupPQuota(ident, printerid)
461                            if limitby :
462                                self.storage.limitGroupBy(ident, limitby)
463                            self.warnGroupPQuota(name, printer)   
464                        else :
465                            if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) :
466                                self.storage.setUserPQuota(ident, printerid, softlimit, hardlimit)
467                            if options["reset"] :
468                                self.storage.resetUserPQuota(ident, printerid)
469                            if limitby :
470                                self.storage.limitUserBy(ident, limitby)
471                            if balance :
472                                if balance.startswith("+") or balance.startswith("-") :
473                                    self.storage.increaseUserBalance(ident, balancevalue)
474                                else :
475                                    self.storage.setUserBalance(ident, balancevalue)
476                            for groupname in groupnames :       
477                                groupid = self.storage.getGroupId(groupname)
478                                if groupid is not None :
479                                    self.storage.addUserToGroup(ident, groupid)
480                                else :
481                                    self.logger.log_message(_("Group %s not found in the PyKota Storage.") % groupname)
482                            self.warnUserPQuota(name, printer)   
483                     
484if __name__ == "__main__" : 
485    try :
486        defaults = { \
487                     "printer" : "*", \
488                   }
489        short_options = "vhdc:l:b:i:naugrp:P:S:H:"
490        long_options = ["help", "version", "charge=", "delete", "limitby=", "balance=", "ingroups=", "noquota", "add", "users", "groups", "reset", "prototype=", "printer=", "softlimit=", "hardlimit="]
491       
492        # Initializes the command line tool
493        editor = EdPyKota(doc=__doc__)
494       
495        # parse and checks the command line
496        (options, args) = editor.parseCommandline(sys.argv[1:], short_options, long_options)
497       
498        # sets long options
499        options["help"] = options["h"] or options["help"]
500        options["version"] = options["v"] or options["version"]
501        options["add"] = options["a"] or options["add"]
502        options["users"] = options["u"] or options["users"]
503        options["groups"] = options["g"] or options["groups"]
504        options["prototype"] = options["p"] or options["prototype"]
505        options["printer"] = options["P"] or options["printer"] or defaults["printer"]
506        options["softlimit"] = options["S"] or options["softlimit"]
507        options["hardlimit"] = options["H"] or options["hardlimit"] 
508        options["reset"] = options["r"] or options["reset"] 
509        options["noquota"] = options["n"] or options["noquota"]
510        options["limitby"] = options["l"] or options["limitby"]
511        options["balance"] = options["b"] or options["balance"] 
512        options["delete"] = options["d"] or options["delete"] 
513        options["ingroups"] = options["i"] or options["ingroups"]
514        options["charge"] = options["c"] or options["charge"]
515       
516        if options["help"] :
517            editor.display_usage_and_quit()
518        elif options["version"] :
519            editor.display_version_and_quit()
520        elif options["users"] and options["groups"] :   
521            raise PyKotaToolError, _("incompatible options, see help.")
522        elif (options["add"] or options["prototype"]) and options["delete"] :   
523            raise PyKotaToolError, _("incompatible options, see help.")
524        elif (options["softlimit"] or options["hardlimit"]) and options["prototype"] :   
525            raise PyKotaToolError, _("incompatible options, see help.")
526        elif options["noquota"] and (options["prototype"] or options["hardlimit"] or options["softlimit"]) :
527            raise PyKotaToolError, _("incompatible options, see help.")
528        elif options["groups"] and (options["balance"] or options["ingroups"]) :
529            raise PyKotaToolError, _("incompatible options, see help.")
530        else :
531            sys.exit(editor.main(args, options))
532    except PyKotaToolError, msg :           
533        sys.stderr.write("%s\n" % msg)
534        sys.stderr.flush()
535        sys.exit(-1)
Note: See TracBrowser for help on using the browser.