#! /usr/bin/env python # -*- coding: utf-8 -*- # # PyKota : Print Quotas for CUPS # # (c) 2003-2013 Jerome Alet # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # $Id$ # # """A print quota entries manager for PyKota.""" import sys import pykota.appinit from pykota.utils import run from pykota.commandline import PyKotaOptionParser from pykota.errors import PyKotaCommandLineError from pykota.tool import PyKotaTool from pykota.storage import StorageUserPQuota, StorageGroupPQuota from pykota.progressbar import Percent class EdPyKota(PyKotaTool) : """A class for edpykota.""" def modifyPQEntry(self, pqkey, pqentry, noquota, softlimit, hardlimit, increase, reset, hardreset, suffix, used, maxjobsize) : """Modifies a print quota entry.""" if noquota or ((softlimit is not None) and (hardlimit is not None)) : pqentry.setLimits(softlimit, hardlimit) if increase : newsoft = (pqentry.SoftLimit or 0) + increase newhard = (pqentry.HardLimit or 0) + increase if (newsoft >= 0) and (newhard >= 0) : pqentry.setLimits(newsoft, newhard) else : self.printInfo(_("You can't set negative limits for %s") % pqkey, "error") if reset : pqentry.reset() if hardreset : pqentry.hardreset() if suffix == "User" : if used : pqentry.setUsage(used) if maxjobsize is not None : if maxjobsize == "unlimited" : pqentry.setMaxJobSize(None) else : pqentry.setMaxJobSize(maxjobsize) def main(self, names, options) : """Edit user or group quotas.""" islist = (options.action == "list") isadd = (options.action == "add") isdelete = (options.action == "delete") if not islist : self.adminOnly() names = self.sanitizeNames(names, options.groups) if not names : if isdelete : raise PyKotaCommandLineError, _("You must specify users or groups names on the command line.") names = [u"*"] if (((islist or isdelete) and (options.used \ or options.softlimit \ or options.hardlimit \ or options.reset \ or options.hardreset \ or options.noquota \ or options.increase \ or options.maxjobsize \ or options.skipexisting))) \ or (options.groups and (options.used \ or options.maxjobsize \ or options.increase \ or options.reset \ or options.hardreset)) : raise PyKotaCommandLineError, _("Incompatible command line options. Please look at the online help or manual page.") suffix = (options.groups and "Group") or "User" printernames = options.printer.split(",") if not islist : percent = Percent(self) percent.display("%s..." % _("Extracting datas")) printers = self.storage.getMatchingPrinters(options.printer) entries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names)) if not islist : percent.setSize(len(printers) * len(entries)) if islist : for printer in printers : for entry in entries : pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer) if pqentry.Exists : self.display("%s@%s\n" % (entry.Name, printer.Name)) self.display(" %s\n" % (_("Page counter : %s") % pqentry.PageCounter)) self.display(" %s\n" % (_("Lifetime page counter : %s") % pqentry.LifePageCounter)) self.display(" %s\n" % (_("Soft limit : %s") % pqentry.SoftLimit)) self.display(" %s\n" % (_("Hard limit : %s") % pqentry.HardLimit)) self.display(" %s\n" % (_("Date limit : %s") % pqentry.DateLimit)) if suffix == "User" : self.display(" %s\n" % (_("Maximum job size : %s") % (((pqentry.MaxJobSize is not None) and (_("%s pages") % pqentry.MaxJobSize)) or _("Unlimited")))) if hasattr(pqentry, "WarnCount") : self.display(" %s\n" % (_("Warning banners printed : %s") % pqentry.WarnCount)) self.display("\n") elif isdelete : percent.display("\n%s..." % _("Deletion")) getattr(self.storage, "deleteMany%sPQuotas" % suffix)(printers, entries) percent.display("\n") else : used = options.used if used : used = used.strip() try : int(used) except ValueError : raise PyKotaCommandLineError, _("Invalid used value %s.") % used increase = options.increase if increase : try : increase = int(increase.strip()) except ValueError : raise PyKotaCommandLineError, _("Invalid increase value %s.") % increase softlimit = hardlimit = None if not options.noquota : if options.softlimit : try : softlimit = int(options.softlimit.strip()) if softlimit < 0 : raise ValueError except ValueError : raise PyKotaCommandLineError, _("Invalid softlimit value %s.") % options.softlimit if options.hardlimit : try : hardlimit = int(options.hardlimit.strip()) if hardlimit < 0 : raise ValueError except ValueError : raise PyKotaCommandLineError, _("Invalid hardlimit value %s.") % options.hardlimit if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) : self.printInfo(_("Hard limit %(hardlimit)i is less than soft limit %(softlimit)i, values will be exchanged.") \ % locals()) (softlimit, hardlimit) = (hardlimit, softlimit) if hardlimit is None : hardlimit = softlimit if hardlimit is not None : self.printInfo(_("Undefined hard limit set to soft limit (%s).") % str(hardlimit)) if softlimit is None : softlimit = hardlimit if softlimit is not None : self.printInfo(_("Undefined soft limit set to hard limit (%s).") % str(softlimit)) if options.maxjobsize : if options.maxjobsize.lower() == "unlimited" : maxjobsize = "unlimited" else : try : maxjobsize = int(options.maxjobsize) if maxjobsize < 0 : raise ValueError except ValueError : raise PyKotaCommandLineError, _("Invalid maximum job size value %s") % options.maxjobsize else : maxjobsize = None self.storage.beginTransaction() try : if isadd : percent.display("\n%s...\n" % _("Creation")) if not entries : self.printInfo(_("No entry matches %s. Please use pkusers to create them first.") \ % (" ".join(names)), "warn") factory = globals()["Storage%sPQuota" % suffix] for printer in printers : pname = printer.Name for entry in entries : ename = entry.Name pqkey = "%s@%s" % (ename, pname) pqentry = factory(self.storage, entry, printer) self.modifyPQEntry(pqkey, pqentry, options.noquota, softlimit, hardlimit, increase, options.reset, options.hardreset, suffix, used, maxjobsize) oldpqentry = getattr(self.storage, "add%sPQuota" % suffix)(pqentry) if oldpqentry is not None : if options.skipexisting : self.logdebug("%s print quota entry %s@%s already exists, skipping." \ % (suffix, ename, pname)) else : self.logdebug("%s print quota entry %s@%s already exists, will be modified." \ % (suffix, ename, pname)) self.modifyPQEntry(pqkey, oldpqentry, options.noquota, softlimit, hardlimit, increase, options.reset, options.hardreset, suffix, used, maxjobsize) oldpqentry.save() percent.oneMore() else : percent.display("\n%s...\n" % _("Modification")) for printer in printers : for entry in entries : pqkey = "%s@%s" % (entry.Name, printer.Name) pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer) if pqentry.Exists : self.modifyPQEntry(pqkey, pqentry, options.noquota, softlimit, hardlimit, increase, options.reset, options.hardreset, suffix, used, maxjobsize) pqentry.save() percent.oneMore() except : self.storage.rollbackTransaction() raise else : self.storage.commitTransaction() if not islist : percent.done() if __name__ == "__main__" : parser = PyKotaOptionParser(description=_("Manages PyKota print quota entries for users or users groups. A print quota entry is related to both an user and a printer, or to both a group and a printer, meaning that for example different users can have different page count limits on the same printer. If an user doesn't have a print quota entry on a particular printer, he won't be allowed to print to it."), usage="edpykota [options] [usernames|groupnames]") parser.add_option("-a", "--add", action="store_const", const="add", dest="action", help=_("Add new, or modify existing, users or groups print quota entries.")) parser.add_option("-d", "--delete", action="store_const", const="delete", dest="action", help=_("Delete the specified users or groups print quota entries. When deleting users print quota entries, the matching jobs are also deleted from the printing history.")) parser.add_option("-S", "--softlimit", dest="softlimit", help=_("Set the soft page count limit for the specified print quota entries. Users can print over this limit for a number of days specified in the 'gracedelay' directive in pykota.conf")) parser.add_option("-H", "--hardlimit", dest="hardlimit", help=_("Set the hard page count limit for the specified print quota entries. Users are never allowed to print over this limit.")) parser.add_option("-g", "--groups", action="store_true", dest="groups", help=_("Manage groups print quota entries instead of users print quota entries.")) parser.add_option("-I", "--increase", dest="increase", help=_("Increase the existing soft and hard page count limits for the specified print quota entries. You can decrease the values instead by prefixing this parameter with a negative sign.")) parser.add_option("-L", "--list", action="store_const", const="list", dest="action", help=_("Display detailed informations about the specified users or groups print quota entries.")) parser.add_option("-m", "--maxjobsize", dest="maxjobsize", help=_("Set the maximum job size in pages the specified users are allowed to print to the specified printers in a single job. Accepted values are '0' to forbid printing, 'unlimited' to allow unrestricted printing, or any positive integer value. This option is not supported for users groups.")) parser.add_option("-n", "--noquota", dest="noquota", action="store_true", help=_("Set no limit for both soft and hard page counts for the specified users or groups print quota entries.")) parser.add_option("-P", "--printer", dest="printer", default="*", help=_("Specify a comma separated list of printers you want to manage print quota entries on. The default is '*', meaning all printers.")) parser.add_option("-r", "--reset", dest="reset", action="store_true", help=_("Reset the actual page counter for the specified users print quota entries (doesn't work for groups print quota entries). The life time page counter is left unchanged.")) parser.add_option("-R", "--hardreset", dest="hardreset", action="store_true", help=_("Reset the actual and life time page counters for the specified users print quota entries (doesn't work for groups print quota entries). This is a shortcut for --used 0.")) parser.add_option("-s", "--skipexisting", action="store_true", dest="skipexisting", help=_("If --add is used, ensure that existing users or groups print quota entries won't be modified.")) parser.add_option("-U", "--used", dest="used", help=_("Set the values of both the actual and life time page counters for the specified users print quota entries (doesn't work for groups print quota entries). This can be useful when migrating from a different print quota software. The values can also be increased or decreased by prefixing this parameter with either a positive or negative sign.")) parser.add_example("--add john paul george ringo", _("Would create print quota entries with no page count limits for these four users on all existing printers.")) parser.add_example("--printer HP --softlimit 50 --hardlimit 60 jerome", _("Would allow user 'jerome' to print up to 60 pages on printer 'HP'. This user would be warned when he would have reached 50 pages on this printer. Both the user and printer must have been created previously using the pkusers and pkprinters commands, respectively.")) parser.add_example("--groups --softlimit 500 --hardlimit 600 support financial", _("Would set soft and hard page count limits on any printer for groups 'support' and 'financial'.")) parser.add_example('--reset --printer HP jerome "jo*"', _("Would reset the actual page counter for users 'jerome' and all users whose name begins with 'jo' on printer 'HP'.")) parser.add_example("--printer HPCOLOR --noquota jerome", _("Would allow this user to print without any page limit on printer 'HPCOLOR'. Depending on how this user is limited, he may still be subject to being limited by the number of available credits in his account.")) parser.add_example("--add --skipexisting", _("Would create a print quota entry for each user on each printer for which none already existed. You'll most likely want to use this command at least once after initial setup.")) run(parser, EdPyKota)