root / pykota / trunk / bin / edpykota @ 2731

Revision 2731, 19.7 kB (checked in by jerome, 18 years ago)

Fixed deletion code.
Implemented creation code.

  • 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# -*- coding: ISO-8859-15 -*-
3
4# PyKota Print Quota Editor
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
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.
13#
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import sys
28import os
29import pwd
30import grp
31from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
32from pykota.config import PyKotaConfigError
33from pykota.storage import PyKotaStorageError
34
35__doc__ = N_("""edpykota v%(__version__)s (c) %(__years__)s %(__author__)s
36
37A Print Quota editor for PyKota.
38
39command line usage :
40
41  edpykota [options] user1 user2 ... userN
42 
43  edpykota [options] group1 group2 ... groupN
44
45options :
46
47  -v | --version       Prints edpykota's version number then exits.
48  -h | --help          Prints this message then exits.
49 
50  -a | --add           Adds users or groups print quota entries if
51                       they don't exist in database.
52                       
53  -d | --delete        Deletes users or groups print quota entries.
54                       Users or groups are never deleted, you have
55                       to use the pkusers command to delete them.
56                       The history will be purge from all matching
57                       jobs, unless -g | --groups is used.
58 
59  -P | --printer p     Edit quotas on printer p only. Actually p can
60                       use wildcards characters to select only
61                       some printers. The default value is *, meaning
62                       all printers.
63                       You can specify several names or wildcards,
64                       by separating them with commas.
65 
66  -g | --groups        Edit groups print quota entries instead of
67                       users print quota entries.
68                         
69  -L | --list          Lists users or groups print quota entries.
70 
71  -n | --noquota       Sets both soft and hard limits to None for users
72                       or groups print quota entries.
73 
74  -r | --reset         Resets the actual page counter for the user
75                       or group to zero on the specified printers.
76                       The life time page counter is kept unchanged.
77                       
78  -R | --hardreset     Resets the actual and life time page counters
79                       for the user or group to zero on the specified
80                       printers. This is a shortcut for '--used 0'.
81                       
82  -s | --skipexisting  In combination with the --add option above, tells
83                       edpykota to not modify existing print quota entries.
84                       
85  -S | --softlimit sl  Sets the quota soft limit to sl pages.                       
86 
87  -H | --hardlimit hl  Sets the quota hard limit to hl pages.
88 
89  -I | --increase v    Increase existing Soft and Hard limits by the value
90                       of v. You can prefix v with + or -, if no sign is
91                       used, + is assumed.
92
93  -U | --used u        Sets the page counters for the user u pages on
94                       the selected printers. Doesn't work for groups, since
95                       their page counters are the sum of all their members'
96                       page counters.
97                       Useful for migrating users from a different system
98                       where they have already used some pages. Actual
99                       and Life Time page counters may be increased or decreased
100                       if u is prefixed with + or -.
101                       WARNING : BOTH page counters are modified in all cases,
102                       so be careful.
103                       NB : if u equals '0', then the action taken is
104                       the same as if --hardreset was used.
105
106  user1 through userN and group1 through groupN can use wildcards
107  if the --add option is not set.
108 
109examples :                             
110
111  $ edpykota --add john paul george ringo
112 
113  This will create print quota entries for users john, paul, george
114  and ringo on all printers. These print quota entries will have no
115  limit set.
116 
117  $ edpykota --printer lp -S 50 -H 60 jerome
118 
119  This will set jerome's print quota on the lp printer to a soft limit
120  of 50 pages, and a hard limit of 60 pages. Both user jerome and
121  printer lp have been previously created with the pkusers and pkprinters
122  commands, respectively.
123
124  $ edpykota -g -S 500 -H 550 financial support           
125 
126  This will set print quota soft limit to 500 pages and hard limit
127  to 550 pages for groups financial and support on all printers.
128 
129  $ edpykota --reset jerome "jo*"
130 
131  This will reset jerome's page counter to zero on all printers, as
132  well as every user whose name begins with 'jo'.
133  Their life time page counter on each printer will be kept unchanged.
134  You can also reset the life time page counters by using the
135  --hardreset | -R command line option.
136 
137  $ edpykota --printer hpcolor --noquota jerome
138 
139  This will tell PyKota to not limit jerome when printing on the
140  hpcolor printer. All his jobs will be allowed on this printer, but
141  accounting of the pages he prints will still be kept.
142  Print Quotas for jerome on other printers are unchanged.
143 
144  $ edpykota --delete --printer "HP*,XER*" jerome rachel
145 
146  This will delete users jerome and rachel's print quota
147  entries on all printers which name begin with 'HP' or
148  'XER'. The jobs printed by these users on these printers
149  will be deleted from the history.
150""") 
151       
152class EdPyKota(PyKotaTool) :       
153    """A class for edpykota."""
154    def main(self, names, options) :
155        """Edit user or group quotas."""
156        if not self.config.isAdmin :
157            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
158       
159        suffix = (options["groups"] and "Group") or "User"       
160        printernames = options["printer"].split(",")
161        if not names :
162            names = ["*"]
163        (printers, entries, pqentries) = getattr(self.storage, "getPrinters%ssAndPQuotas" % suffix)(printernames, names)
164       
165        if options["delete"] :   
166            self.display("%s...\n" % _("Deletion"))
167            nbtotal = len(pqentries)
168            for i in range(nbtotal) :
169                (pqkey, pqentry) = pqentries.popitem()
170                if pqentry.Exists :
171                    pqentry.delete()
172                percent = 100.0 * float(i) / float(nbtotal)
173                self.display("\r%.02f%%" % percent)
174        else :
175            skipexisting = options["skipexisting"]
176            if options["add"] :
177                self.display("%s...\n" % _("Creation"))
178                mprinters = self.storage.getMatchingPrinters(options["printer"])
179                mentries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
180                nbtotal = len(mprinters) * len(mentries)
181                i = 0
182                for printer in mprinters :
183                    pname = printer.Name
184                    for entry in mentries :
185                        ename = entry.Name
186                        pqkey = "%s@%s" % (ename, pname)
187                        if pqentries.has_key(pqkey) and pqentries[pqkey].Exists :
188                            if skipexisting :
189                                self.printInfo(_("%s print quota entry %s@%s already exists, skipping.") % (suffix, ename, pname))
190                                del pqentries[pqkey]
191                            else :   
192                                self.printInfo(_("%s print quota entry %s@%s already exists, will be modified.") % (suffix, ename, pname))
193                        else :       
194                            newpqentry = getattr(self.storage, "add%sPQuota" % suffix)(entry, printer)
195                            if not newpqentry.Exists :
196                                self.printInfo(_("Impossible to create a print quota entry for %s@%s") % (ename, pname))
197                            else :
198                                pqentries[pqkey] = newpqentry
199                        percent = 100.0 * float(i) / float(nbtotal)
200                        self.display("\r%.02f%%" % percent)
201                        i += 1
202                self.display("\r100.00%%\r        \r%s\n" % _("Done."))
203               
204            if not pqentries :
205                raise PyKotaCommandLineError, _("There's no %s print quota entry matching %s") % (suffix.lower(), " ".join(names))
206                   
207            if options["list"] :
208                for (name, entry) in pqentries.items() :
209                    if entry.Exists :
210                        print name
211                        print "    %s" % (_("Page counter : %s") % entry.PageCounter)
212                        print "    %s" % (_("Lifetime page counter : %s") % entry.LifePageCounter)
213                        print "    %s" % (_("Soft limit : %s") % entry.SoftLimit)
214                        print "    %s" % (_("Hard limit : %s") % entry.HardLimit)
215                        print "    %s" % (_("Date limit : %s") % entry.DateLimit)
216                        # TODO : print "    %s" % (_("Maximum job size : %s") % ((entry.MaxJobSize and (_("%s pages") % entry.MaxJobSize)) or _("Unlimited")))
217                        if hasattr(entry, "WarnCount") :
218                            print "    %s" % (_("Warning banners printed : %s") % entry.WarnCount)
219                        print
220            else :
221                self.display("%s...\n" % _("Modification"))
222                raise PyKotaCommandLineError, "Not implemented yet."
223                softlimit = hardlimit = None
224               
225                used = options["used"]
226                if used :
227                    used = used.strip()
228                    try :
229                        int(used)
230                    except ValueError :
231                        raise PyKotaCommandLineError, _("Invalid used value %s.") % used
232                       
233                increase = options["increase"]
234                if increase :
235                    try :
236                        increase = int(increase.strip())
237                    except ValueError :
238                        raise PyKotaCommandLineError, _("Invalid increase value %s.") % increase
239               
240                if not options["noquota"] :
241                    if options["softlimit"] :
242                        try :
243                            softlimit = int(options["softlimit"].strip())
244                            if softlimit < 0 :
245                                raise ValueError
246                        except ValueError :   
247                            raise PyKotaCommandLineError, _("Invalid softlimit value %s.") % options["softlimit"]
248                    if options["hardlimit"] :
249                        try :
250                            hardlimit = int(options["hardlimit"].strip())
251                            if hardlimit < 0 :
252                                raise ValueError
253                        except ValueError :   
254                            raise PyKotaCommandLineError, _("Invalid hardlimit value %s.") % options["hardlimit"]
255                    if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :       
256                        # error, exchange them
257                        self.printInfo(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit))
258                        (softlimit, hardlimit) = (hardlimit, softlimit)
259                   
260                sys.stdout.write(_("Managing print quotas... (this may take a lot of time)"))
261                sys.stdout.flush()
262                missingusers = {}
263                missinggroups = {}   
264                changed = {} # tracks changes made at the user/group level
265                for printer in printers :
266                    if not options["noquota"] :   
267                        if hardlimit is None :   
268                            hardlimit = softlimit
269                            if hardlimit is not None :
270                                self.printInfo(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer.Name))
271                        if softlimit is None :   
272                            softlimit = hardlimit
273                            if softlimit is not None :
274                                self.printInfo(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer.Name))
275                               
276                    if options["add"] :   
277                        allentries = []   
278                        for name in names :
279                            email = ""
280                            if not options["groups"] :
281                                splitname = name.split('/', 1)     # username/email
282                                if len(splitname) == 1 :
283                                    splitname.append("")
284                                (name, email) = splitname
285                                if email and (email.count('@') != 1) :
286                                    self.printInfo(_("Invalid email address %s") % email)
287                                    email = ""
288                            entry = getattr(self.storage, "get%s" % suffix)(name)
289                            if email and not options["groups"] :
290                                entry.Email = email
291                            entrypquota = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
292                            allentries.append((entry, entrypquota))
293                    else :   
294                        allentries = getattr(self.storage, "getPrinter%ssAndQuotas" % suffix)(printer, names)
295                       
296                    for (entry, entrypquota) in allentries :
297                        if not changed.has_key(entry.Name) :
298                            changed[entry.Name] = {}
299                            if not options["groups"] :
300                                changed[entry.Name]["ingroups"] = []
301                               
302                        if entry.Exists and (not entrypquota.Exists) :
303                            # not found
304                            if options["add"] :
305                                entrypquota = getattr(self.storage, "add%sPQuota" % suffix)(entry, printer)
306                               
307                        if not entrypquota.Exists :     
308                            self.printInfo(_("Quota not found for object %s on printer %s.") % (entry.Name, printer.Name))
309                        else :   
310                            if options["noquota"] \
311                               or ((softlimit is not None) and (hardlimit is not None)) :
312                                entrypquota.setLimits(softlimit, hardlimit)
313                               
314                            if increase :
315                               if (entrypquota.SoftLimit is None) \
316                                   or (entrypquota.HardLimit is None) :
317                                   self.printInfo(_("You can't increase limits by %s when no limit is set.") % increase, "error")
318                               else :
319                                   newsoft = entrypquota.SoftLimit + increase         
320                                   newhard = entrypquota.HardLimit + increase         
321                                   if (newsoft >= 0) and (newhard >= 0) :
322                                       entrypquota.setLimits(newsoft, newhard)
323                                   else :   
324                                       self.printInfo(_("You can't set negative limits."), "error")
325                           
326                            if options["reset"] :
327                                entrypquota.reset()
328                               
329                            if options["hardreset"] :   
330                                entrypquota.hardreset()
331                               
332                            if not options["groups"] :
333                                if used :
334                                    entrypquota.setUsage(used)
335                               
336        if not options["list"] :               
337            self.display("\r100.00%%\r        \r%s\n" % _("Done."))
338                     
339if __name__ == "__main__" : 
340    retcode = 0
341    try :
342        defaults = { \
343                     "printer" : "*", \
344                   }
345        short_options = "vhdnagrLP:S:H:G:RU:I:s"
346        long_options = ["help", "version", \
347                        "delete", "list", \
348                        "noquota", "add", \
349                        "groups", "reset", "hardreset", \
350                        "printer=", "softlimit=", "hardlimit=", \
351                        "increase=", "used=", "skipexisting"]
352       
353        # Initializes the command line tool
354        manager = EdPyKota(doc=__doc__)
355        manager.deferredInit()
356       
357        # parse and checks the command line
358        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
359       
360        # sets long options
361        options["help"] = options["h"] or options["help"]
362        options["version"] = options["v"] or options["version"]
363        options["add"] = options["a"] or options["add"]
364        options["groups"] = options["g"] or options["groups"]
365        options["printer"] = options["P"] or options["printer"] or defaults["printer"]
366        options["softlimit"] = options["S"] or options["softlimit"]
367        options["hardlimit"] = options["H"] or options["hardlimit"] 
368        options["reset"] = options["r"] or options["reset"] 
369        options["noquota"] = options["n"] or options["noquota"]
370        options["delete"] = options["d"] or options["delete"] 
371        options["hardreset"] = options["R"] or options["hardreset"] 
372        options["used"] = options["U"] or options["used"]
373        options["increase"] = options["I"] or options["increase"]
374        options["list"] = options["L"] or options["list"]
375        options["skipexisting"] = options["s"] or options["skipexisting"]
376       
377        if options["help"] :
378            manager.display_usage_and_quit()
379        elif options["version"] :
380            manager.display_version_and_quit()
381        elif (options["add"] and options["delete"]) \
382             or (options["noquota"] and (options["hardlimit"] or options["softlimit"])) \
383             or (options["groups"] and options["used"]) \
384             or (options["skipexisting"] and not options["add"]) :
385            raise PyKotaCommandLineError, _("incompatible options, see help.")
386        elif options["delete"] and not args :
387            raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
388        else :
389            retcode = manager.main(args, options)
390    except KeyboardInterrupt :       
391        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
392        retcode = -3
393    except PyKotaCommandLineError, msg :     
394        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
395        retcode = -2
396    except SystemExit :       
397        pass
398    except :
399        try :
400            manager.crashed("edpykota failed")
401        except :   
402            crashed("edpykota failed")
403        retcode = -1
404
405    try :
406        manager.storage.close()
407    except (TypeError, NameError, AttributeError) :   
408        pass
409       
410    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.