[1595] | 1 | #! /usr/bin/env python |
---|
[3411] | 2 | # -*- coding: utf-8 -*-*- |
---|
[1595] | 3 | # |
---|
[3260] | 4 | # PyKota : Print Quotas for CUPS |
---|
[1595] | 5 | # |
---|
[3275] | 6 | # (c) 2003, 2004, 2005, 2006, 2007, 2008 Jerome Alet <alet@librelogiciel.com> |
---|
[3260] | 7 | # This program is free software: you can redistribute it and/or modify |
---|
[1595] | 8 | # it under the terms of the GNU General Public License as published by |
---|
[3260] | 9 | # the Free Software Foundation, either version 3 of the License, or |
---|
[1595] | 10 | # (at your option) any later version. |
---|
[3413] | 11 | # |
---|
[1595] | 12 | # This program is distributed in the hope that it will be useful, |
---|
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | # GNU General Public License for more details. |
---|
[3413] | 16 | # |
---|
[1595] | 17 | # You should have received a copy of the GNU General Public License |
---|
[3260] | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
[1595] | 19 | # |
---|
| 20 | # $Id$ |
---|
| 21 | # |
---|
[2028] | 22 | # |
---|
[1595] | 23 | |
---|
[3330] | 24 | """An On Screen Display (OSD) monitor for PyKota's end users.""" |
---|
| 25 | |
---|
[1595] | 26 | import sys |
---|
| 27 | import os |
---|
| 28 | import pwd |
---|
| 29 | import time |
---|
| 30 | |
---|
[1607] | 31 | try : |
---|
| 32 | import pyosd |
---|
[3413] | 33 | except ImportError : |
---|
[3330] | 34 | sys.stderr.write("Sorry ! You need both xosd and the Python OSD library (pyosd) for this software to work.\n") |
---|
[1607] | 35 | sys.exit(-1) |
---|
| 36 | |
---|
[3294] | 37 | import pykota.appinit |
---|
[3330] | 38 | from pykota.utils import run, loginvalidparam |
---|
[3328] | 39 | from pykota.commandline import PyKotaOptionParser |
---|
[3288] | 40 | from pykota.errors import PyKotaToolError, PyKotaCommandLineError |
---|
[3295] | 41 | from pykota.tool import PyKotaTool |
---|
[1595] | 42 | |
---|
[1605] | 43 | class PyKOSD(PyKotaTool) : |
---|
[2829] | 44 | """A class for an On Screen Display print quota monitor.""" |
---|
[1605] | 45 | def main(self, args, options) : |
---|
| 46 | """Main function starts here.""" |
---|
[3328] | 47 | savecolor = options.color |
---|
| 48 | loop = options.loop |
---|
| 49 | username = pwd.getpwuid(os.getuid())[0] |
---|
| 50 | while True : |
---|
[1608] | 51 | color = savecolor |
---|
[3328] | 52 | user = self.storage.getUserFromBackend(username) # don't use cache |
---|
[1595] | 53 | if not user.Exists : |
---|
[3328] | 54 | raise PyKotaCommandLineError, _("You %(username)s don't have a PyKota printing account. Please contact your administrator.") % locals() |
---|
[3413] | 55 | if user.LimitBy == "quota" : |
---|
[2692] | 56 | printers = self.storage.getMatchingPrinters("*") |
---|
| 57 | upquotas = [ self.storage.getUserPQuotaFromBackend(user, p) for p in printers ] # don't use cache |
---|
[1596] | 58 | nblines = len(upquotas) |
---|
[3413] | 59 | display = pyosd.osd(font=options.font, |
---|
| 60 | colour=color, |
---|
| 61 | timeout=options.duration, |
---|
| 62 | shadow=2, |
---|
[3328] | 63 | lines=nblines) |
---|
[1596] | 64 | for line in range(nblines) : |
---|
| 65 | upq = upquotas[line] |
---|
| 66 | if upq.HardLimit is None : |
---|
| 67 | if upq.SoftLimit is None : |
---|
[3328] | 68 | percent = "%i" % upq.PageCounter |
---|
[3413] | 69 | else : |
---|
[3328] | 70 | percent = "%i%%" % min((upq.PageCounter * 100) / upq.SoftLimit, 100) |
---|
[3413] | 71 | else : |
---|
[3328] | 72 | percent = "%i%%" % min((upq.PageCounter * 100) / upq.HardLimit, 100) |
---|
[3413] | 73 | printername = upq.Printer.Name |
---|
[3328] | 74 | msg = _("Pages used on %(printername)s : %(percent)s") % locals() |
---|
[3413] | 75 | display.display(msg.encode(self.charset, "replace"), |
---|
| 76 | type=pyosd.TYPE_STRING, |
---|
[3328] | 77 | line=line) |
---|
[2544] | 78 | elif user.LimitBy == "balance" : |
---|
[2692] | 79 | if user.AccountBalance <= self.config.getBalanceZero() : |
---|
[1597] | 80 | color = "#FF0000" |
---|
[3413] | 81 | display = pyosd.osd(font=options.font, |
---|
| 82 | colour=color, |
---|
| 83 | timeout=options.duration, |
---|
[3328] | 84 | shadow=2) |
---|
[3413] | 85 | balance = user.AccountBalance |
---|
[3328] | 86 | msg = _("PyKota Units left : %(balance).2f") % locals() |
---|
[3413] | 87 | display.display(msg.encode(self.charset, "replace"), |
---|
[3328] | 88 | type=pyosd.TYPE_STRING) |
---|
[3413] | 89 | elif user.LimitBy == "noprint" : |
---|
| 90 | display = pyosd.osd(font=options.font, |
---|
| 91 | colour="#FF0000", |
---|
| 92 | timeout=options.duration, |
---|
[3328] | 93 | shadow=2) |
---|
| 94 | msg = _("Printing denied.") |
---|
[3413] | 95 | display.display(msg.encode(self.charset, "replace"), |
---|
[3328] | 96 | type=pyosd.TYPE_STRING) |
---|
[3413] | 97 | elif user.LimitBy == "noquota" : |
---|
| 98 | display = pyosd.osd(font=options.font, |
---|
| 99 | colour=savecolor, |
---|
| 100 | timeout=options.duration, |
---|
[3328] | 101 | shadow=2) |
---|
| 102 | msg = _("Printing not limited.") |
---|
[3413] | 103 | display.display(msg.encode(self.charset, "replace"), |
---|
[3328] | 104 | type=pyosd.TYPE_STRING) |
---|
[3413] | 105 | elif user.LimitBy == "nochange" : |
---|
| 106 | display = pyosd.osd(font=options.font, |
---|
| 107 | colour=savecolor, |
---|
| 108 | timeout=options.duration, |
---|
[3328] | 109 | shadow=2) |
---|
| 110 | msg = _("Printing not limited, no accounting.") |
---|
[3413] | 111 | display.display(msg.encode(self.charset, "replace"), |
---|
[3328] | 112 | type=pyosd.TYPE_STRING) |
---|
[3413] | 113 | else : |
---|
[3328] | 114 | limitby = repr(user.LimitBy) |
---|
| 115 | raise PyKotaToolError, "Incorrect limitation factor %(limitby)s for user %(username)s" % locals() |
---|
[3413] | 116 | |
---|
[3328] | 117 | time.sleep(options.duration + 1) |
---|
[1605] | 118 | if loop : |
---|
| 119 | loop -= 1 |
---|
| 120 | if not loop : |
---|
| 121 | break |
---|
[3413] | 122 | time.sleep(options.sleep) |
---|
| 123 | |
---|
| 124 | return 0 |
---|
| 125 | |
---|
[1605] | 126 | if __name__ == "__main__" : |
---|
[3413] | 127 | def checkandset_positiveint(option, opt, value, optionparser) : |
---|
[3328] | 128 | """Checks and sets positive integer values.""" |
---|
| 129 | if value < 0 : |
---|
| 130 | loginvalidparam(opt, value, option.default) |
---|
[3330] | 131 | setattr(optionparser.values, option.dest, option.default) |
---|
[3413] | 132 | else : |
---|
[3330] | 133 | setattr(optionparser.values, option.dest, value) |
---|
[3413] | 134 | |
---|
| 135 | def checkandset_color(option, opt, value, optionparser) : |
---|
[3328] | 136 | """Checks and sets the color value.""" |
---|
| 137 | if not value.startswith("#") : |
---|
| 138 | value = "#%s" % value |
---|
[3413] | 139 | try : |
---|
[3328] | 140 | int(value[1:], 16) |
---|
[3413] | 141 | except (ValueError, TypeError) : |
---|
[3328] | 142 | error = True |
---|
[3413] | 143 | else : |
---|
[3328] | 144 | error = False |
---|
| 145 | if (len(value) != 7) or error : |
---|
| 146 | loginvalidparam(opt, value, option.default) |
---|
[3330] | 147 | setattr(optionparser.values, option.dest, option.default) |
---|
[3413] | 148 | else : |
---|
[3330] | 149 | setattr(optionparser.values, option.dest, value) |
---|
[3413] | 150 | |
---|
[3328] | 151 | parser = PyKotaOptionParser(description=_("An On Screen Display (OSD) monitor for PyKota's end users.")) |
---|
| 152 | parser.add_option("-c", "--color", "--colour", |
---|
[3330] | 153 | type="string", |
---|
[3328] | 154 | action="callback", |
---|
| 155 | callback=checkandset_color, |
---|
| 156 | dest="color", |
---|
| 157 | default="#00FF00", |
---|
| 158 | help=_("Set the color that will be used for display, as an hexadecimal triplet. For example #FF0000 is 100% red. The default is 100% green (%default).")) |
---|
| 159 | parser.add_option("-d", "--duration", |
---|
| 160 | type="int", |
---|
| 161 | action="callback", |
---|
| 162 | callback=checkandset_positiveint, |
---|
| 163 | dest="duration", |
---|
| 164 | default=3, |
---|
| 165 | help=_("Set the time in seconds during which the message will be displayed. Defaults to %default seconds.")) |
---|
| 166 | parser.add_option("-f", "--font", |
---|
| 167 | dest="font", |
---|
| 168 | default=pyosd.default_font, |
---|
[3360] | 169 | help=_("Set the font to use. Defaults to %default.")) |
---|
[3328] | 170 | parser.add_option("-l", "--loop", |
---|
| 171 | type="int", |
---|
| 172 | action="callback", |
---|
| 173 | callback=checkandset_positiveint, |
---|
| 174 | dest="loop", |
---|
| 175 | default=0, |
---|
| 176 | help=_("Set the number of times the info will be displayed. Defaults to %default, which means loop forever.")) |
---|
| 177 | parser.add_option("-s", "--sleep", |
---|
| 178 | type="int", |
---|
| 179 | action="callback", |
---|
| 180 | callback=checkandset_positiveint, |
---|
| 181 | dest="sleep", |
---|
| 182 | default=180, |
---|
| 183 | help=_("Set the sleeping time in seconds between two refreshes. Defaults to %default seconds.")) |
---|
[3413] | 184 | |
---|
[3328] | 185 | parser.add_example('-s 60 --loop 5', |
---|
| 186 | _("This would tell pykosd to display the current user's status for 3 seconds (the default) every 60 seconds, and exit after 5 iterations.")) |
---|
[3413] | 187 | |
---|
[3328] | 188 | run(parser, PyKOSD) |
---|