root / pykota / trunk / pykota / config.py @ 3568

Revision 3561, 34.3 kB (checked in by jerome, 11 years ago)

Changed copyright years.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# -*- coding: utf-8 -*-
2#
3# PyKota : Print Quotas for CUPS
4#
5# (c) 2003-2013 Jerome Alet <alet@librelogiciel.com>
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19# $Id$
20#
21#
22
23"""This module defines classes used to parse PyKota configuration files."""
24
25import sys
26import os
27import tempfile
28import ConfigParser
29
30from pykota.utils import unicodeToDatabase
31from pykota.errors import PyKotaConfigError
32
33class PyKotaConfig :
34    """A class to deal with PyKota's configuration."""
35    def __init__(self, directory) :
36        """Reads and checks the configuration file."""
37        self.isAdmin = 0
38        self.directory = directory
39        self.filename = os.path.join(directory, "pykota.conf")
40        self.adminfilename = os.path.join(directory, "pykotadmin.conf")
41        if not os.access(self.filename, os.R_OK) :
42            raise PyKotaConfigError, _("Configuration file %s can't be read. Please check that the file exists and that your permissions are sufficient.") % self.filename
43        if not os.path.isfile(self.adminfilename) :
44            raise PyKotaConfigError, _("Configuration file %s not found.") % self.adminfilename
45        if os.access(self.adminfilename, os.R_OK) :
46            self.isAdmin = 1
47        self.config = ConfigParser.ConfigParser()
48        self.config.read([self.filename])
49        try :
50            self.config_charset = self.config.get("global", \
51                                                  "config_charset", \
52                                                   raw=1)
53        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :
54            self.config_charset = "UTF-8"
55
56    def isTrue(self, option) :
57        """Returns True if option is set to true, else False."""
58        if (option is not None) and (option.strip().upper() in ['Y', 'YES', '1', 'ON', 'T', 'TRUE']) :
59            return True
60        else :
61            return False
62
63    def isFalse(self, option) :
64        """Returns True if option is set to false, else False."""
65        if (option is not None) and (option.strip().upper() in ['N', 'NO', '0', 'OFF', 'F', 'FALSE']) :
66            return True
67        else :
68            return False
69
70    def getPrinterNames(self) :
71        """Returns the list of configured printers, i.e. all sections names minus 'global'."""
72        return [pname for pname in self.config.sections() if pname != "global"]
73
74    def getGlobalOption(self, option, ignore=False) :
75        """Returns an option from the global section, or raises a PyKotaConfigError if ignore is not set, else returns None."""
76        try :
77            return self.config.get("global", option, raw=1).decode(self.config_charset)
78        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :
79            if ignore :
80                return None
81            else :
82                raise PyKotaConfigError, _("Option %s not found in section global of %s") % (option, self.filename)
83
84    def getPrinterOption(self, printername, option) :
85        """Returns an option from the printer section, or the global section, or raises a PyKotaConfigError."""
86        globaloption = self.getGlobalOption(option, ignore=True)
87        try :
88            return self.config.get(printername, option, raw=1).decode(self.config_charset)
89        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :
90            if globaloption is not None :
91                return globaloption
92            else :
93                raise PyKotaConfigError, _("Option %s not found in section %s of %s") % (option, printername, self.filename)
94
95    def getStorageBackend(self) :
96        """Returns the storage backend information as a Python mapping."""
97        backendinfo = {}
98        backend = self.getGlobalOption("storagebackend").lower()
99        backendinfo["storagebackend"] = backend
100        if backend == "sqlitestorage" :
101            issqlite = True
102            backendinfo["storagename"] = self.getGlobalOption("storagename")
103            for option in ["storageserver", "storageuser", "storageuserpw"] :
104                backendinfo[option] = None
105        else :
106            issqlite = False
107            for option in ["storageserver", "storagename", "storageuser"] :
108                backendinfo[option] = self.getGlobalOption(option)
109            backendinfo["storageuserpw"] = self.getGlobalOption("storageuserpw", ignore=True)  # password is optional
110
111        backendinfo["storageadmin"] = None
112        backendinfo["storageadminpw"] = None
113        if self.isAdmin :
114            adminconf = ConfigParser.ConfigParser()
115            adminconf.read([self.adminfilename])
116            if adminconf.sections() : # were we able to read the file ?
117                try :
118                    backendinfo["storageadmin"] = adminconf.get("global", "storageadmin", raw=1).decode(self.config_charset)
119                except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :
120                    if not issqlite :
121                        raise PyKotaConfigError, _("Option %s not found in section global of %s") % ("storageadmin", self.adminfilename)
122                try :
123                    backendinfo["storageadminpw"] = adminconf.get("global", "storageadminpw", raw=1).decode(self.config_charset)
124                except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :
125                    pass # Password is optional
126                # Now try to overwrite the storagebackend, storageserver
127                # and storagename. This allows admins to use the master LDAP
128                # server directly and users to use the replicas transparently.
129                try :
130                    backendinfo["storagebackend"] = adminconf.get("global", "storagebackend", raw=1).decode(self.config_charset)
131                except ConfigParser.NoOptionError :
132                    pass
133                try :
134                    backendinfo["storageserver"] = adminconf.get("global", "storageserver", raw=1).decode(self.config_charset)
135                except ConfigParser.NoOptionError :
136                    pass
137                try :
138                    backendinfo["storagename"] = adminconf.get("global", "storagename", raw=1).decode(self.config_charset)
139                except ConfigParser.NoOptionError :
140                    pass
141        return backendinfo
142
143    def getLDAPInfo(self) :
144        """Returns some hints for the LDAP backend."""
145        ldapinfo = {}
146        for option in [ "userbase", "userrdn", \
147                        "balancebase", "balancerdn", \
148                        "groupbase", "grouprdn", "groupmembers", \
149                        "printerbase", "printerrdn", \
150                        "userquotabase", "groupquotabase", \
151                        "jobbase", "lastjobbase", "billingcodebase", \
152                        "newuser", "newgroup", \
153                        "usermail", \
154                      ] :
155            ldapinfo[option] = unicodeToDatabase(self.getGlobalOption(option).strip())
156        for field in ["newuser", "newgroup"] :
157            if ldapinfo[field].lower().startswith('attach(') :
158                ldapinfo[field] = ldapinfo[field][7:-1]
159
160        # should we use TLS, by default (if unset) value is NO
161        ldapinfo["ldaptls"] = self.isTrue(self.getGlobalOption("ldaptls", ignore=True))
162        ldapinfo["cacert"] = self.getGlobalOption("cacert", ignore=True)
163        if ldapinfo["cacert"] :
164            ldapinfo["cacert"] = ldapinfo["cacert"].strip().encode(sys.getfilesystemencoding(), "replace")
165        if ldapinfo["ldaptls"] :
166            if not os.access(ldapinfo["cacert"] or "", os.R_OK) :
167                raise PyKotaConfigError, _("Option ldaptls is set, but certificate %s is not readable.") % repr(ldapinfo["cacert"])
168        return ldapinfo
169
170    def getLoggingBackend(self) :
171        """Returns the logging backend information."""
172        validloggers = [ "stderr", "system" ]
173        try :
174            logger = self.getGlobalOption("logger").lower()
175        except PyKotaConfigError :
176            logger = "system"
177        if logger not in validloggers :
178            raise PyKotaConfigError, _("Option logger only supports values in %s") % str(validloggers)
179        return logger
180
181    def getLogoURL(self) :
182        """Returns the URL to use for the logo in the CGI scripts."""
183        url = self.getGlobalOption("logourl", ignore=True) or \
184                   "http://www.pykota.com/pykota.png"
185        return url.strip()
186
187    def getLogoLink(self) :
188        """Returns the URL to go to when the user clicks on the logo in the CGI scripts."""
189        url = self.getGlobalOption("logolink", ignore=True) or \
190                   "http://www.pykota.com/"
191        return url.strip()
192
193    def getPreAccounterBackend(self, printername) :
194        """Returns the preaccounter backend to use for a given printer."""
195        validaccounters = [ "software", "ink" ]
196        try :
197            fullaccounter = self.getPrinterOption(printername, "preaccounter").strip()
198        except PyKotaConfigError :
199            return ("software", "")
200        else :
201            flower = fullaccounter.lower()
202            for vac in validaccounters :
203                if flower.startswith(vac) :
204                    try :
205                        (accounter, args) = [x.strip() for x in fullaccounter.split('(', 1)]
206                    except ValueError :
207                        raise PyKotaConfigError, _("Invalid preaccounter %s for printer %s") % (fullaccounter, printername)
208                    if args.endswith(')') :
209                        args = args[:-1].strip()
210                    if (vac == "ink") and not args :
211                        raise PyKotaConfigError, _("Invalid preaccounter %s for printer %s") % (fullaccounter, printername)
212                    return (vac, args)
213            raise PyKotaConfigError, _("Option preaccounter in section %s only supports values in %s") % (printername, str(validaccounters))
214
215    def getAccounterBackend(self, printername) :
216        """Returns the accounter backend to use for a given printer."""
217        validaccounters = [ "hardware", "software", "ink" ]
218        try :
219            fullaccounter = self.getPrinterOption(printername, "accounter").strip()
220        except PyKotaConfigError :
221            return ("software", "")
222        else :
223            flower = fullaccounter.lower()
224            for vac in validaccounters :
225                if flower.startswith(vac) :
226                    try :
227                        (accounter, args) = [x.strip() for x in fullaccounter.split('(', 1)]
228                    except ValueError :
229                        raise PyKotaConfigError, _("Invalid accounter %s for printer %s") % (fullaccounter, printername)
230                    if args.endswith(')') :
231                        args = args[:-1].strip()
232                    if (vac in ("hardware", "ink")) and not args :
233                        raise PyKotaConfigError, _("Invalid accounter %s for printer %s") % (fullaccounter, printername)
234                    return (vac, args)
235            raise PyKotaConfigError, _("Option accounter in section %s only supports values in %s") % (printername, str(validaccounters))
236
237    def getPreHook(self, printername) :
238        """Returns the prehook command line to launch, or None if unset."""
239        try :
240            return self.getPrinterOption(printername, "prehook").strip()
241        except PyKotaConfigError :
242            return      # No command to launch in the pre-hook
243
244    def getPostHook(self, printername) :
245        """Returns the posthook command line to launch, or None if unset."""
246        try :
247            return self.getPrinterOption(printername, "posthook").strip()
248        except PyKotaConfigError :
249            return      # No command to launch in the post-hook
250
251    def getStripTitle(self, printername) :
252        """Returns the striptitle directive's content, or None if unset."""
253        try :
254            return self.getPrinterOption(printername, "striptitle").strip()
255        except PyKotaConfigError :
256            return      # No prefix to strip off
257
258    def getAskConfirmation(self, printername) :
259        """Returns the askconfirmation directive's content, or None if unset."""
260        try :
261            return self.getPrinterOption(printername, "askconfirmation").strip()
262        except PyKotaConfigError :
263            return      # No overwriting will be done
264
265    def getOverwriteJobTicket(self, printername) :
266        """Returns the overwrite_jobticket directive's content, or None if unset."""
267        try :
268            return self.getPrinterOption(printername, "overwrite_jobticket").strip()
269        except PyKotaConfigError :
270            return      # No overwriting will be done
271
272    def getUnknownBillingCode(self, printername) :
273        """Returns the unknown_billingcode directive's content, or the default value if unset."""
274        validvalues = [ "CREATE", "DENY" ]
275        try :
276            fullvalue = self.getPrinterOption(printername, "unknown_billingcode")
277        except PyKotaConfigError :
278            return ("CREATE", None)
279        else :
280            try :
281                value = [x.strip() for x in fullvalue.split('(', 1)]
282            except ValueError :
283                raise PyKotaConfigError, _("Invalid unknown_billingcode directive %s for printer %s") % (fullvalue, printername)
284            if len(value) == 1 :
285                value.append("")
286            (value, args) = value
287            if args.endswith(')') :
288                args = args[:-1]
289            value = value.upper()
290            if (value == "DENY") and not args :
291                return ("DENY", None)
292            if value not in validvalues :
293                raise PyKotaConfigError, _("Directive unknown_billingcode in section %s only supports values in %s") % (printername, str(validvalues))
294            return (value, args)
295
296    def getPrinterEnforcement(self, printername) :
297        """Returns if quota enforcement should be strict or laxist for the current printer."""
298        validenforcements = [ "STRICT", "LAXIST" ]
299        try :
300            enforcement = self.getPrinterOption(printername, "enforcement")
301        except PyKotaConfigError :
302            return "LAXIST"
303        else :
304            enforcement = enforcement.upper()
305            if enforcement not in validenforcements :
306                raise PyKotaConfigError, _("Option enforcement in section %s only supports values in %s") % (printername, str(validenforcements))
307            return enforcement
308
309    def getPrinterOnBackendError(self, printername) :
310        """Returns what must be done whenever the real CUPS backend fails."""
311        validactions = [ "CHARGE", "NOCHARGE" ]
312        try :
313            action = self.getPrinterOption(printername, "onbackenderror")
314        except PyKotaConfigError :
315            return ["NOCHARGE"]
316        else :
317            action = action.upper().split(",")
318            error = False
319            for act in action :
320                if act not in validactions :
321                    if act.startswith("RETRY:") :
322                        try :
323                            (num, delay) = [int(p) for p in act[6:].split(":", 2)]
324                        except ValueError :
325                            error = True
326                    else :
327                        error = True
328            if error :
329                raise PyKotaConfigError, _("Option onbackenderror in section %s only supports values 'charge', 'nocharge', and 'retry:num:delay'") % printername
330            return action
331
332    def getPrinterOnAccounterError(self, printername) :
333        """Returns what must be done whenever the accounter fails."""
334        validactions = [ "CONTINUE", "STOP" ]
335        try :
336            action = self.getPrinterOption(printername, "onaccountererror")
337        except PyKotaConfigError :
338            return "STOP"
339        else :
340            action = action.upper()
341            if action not in validactions :
342                raise PyKotaConfigError, _("Option onaccountererror in section %s only supports values in %s") % (printername, str(validactions))
343            return action
344
345    def getPrinterPolicy(self, printername) :
346        """Returns the default policy for the current printer."""
347        validpolicies = [ "ALLOW", "DENY", "EXTERNAL" ]
348        try :
349            fullpolicy = self.getPrinterOption(printername, "policy")
350        except PyKotaConfigError :
351            return ("DENY", None)
352        else :
353            try :
354                policy = [x.strip() for x in fullpolicy.split('(', 1)]
355            except ValueError :
356                raise PyKotaConfigError, _("Invalid policy %s for printer %s") % (fullpolicy, printername)
357            if len(policy) == 1 :
358                policy.append("")
359            (policy, args) = policy
360            if args.endswith(')') :
361                args = args[:-1]
362            policy = policy.upper()
363            if (policy == "EXTERNAL") and not args :
364                raise PyKotaConfigError, _("Invalid policy %s for printer %s") % (fullpolicy, printername)
365            if policy not in validpolicies :
366                raise PyKotaConfigError, _("Option policy in section %s only supports values in %s") % (printername, str(validpolicies))
367            return (policy, args)
368
369    def getCrashRecipient(self) :
370        """Returns the email address of the software crash messages recipient."""
371        try :
372            return self.getGlobalOption("crashrecipient")
373        except :
374            return
375
376    def getSMTPServer(self) :
377        """Returns the SMTP server to use to send messages to users."""
378        try :
379            return self.getGlobalOption("smtpserver")
380        except PyKotaConfigError :
381            return "localhost"
382
383    def getMailDomain(self) :
384        """Returns the mail domain to use to send messages to users."""
385        try :
386            return self.getGlobalOption("maildomain")
387        except PyKotaConfigError :
388            return
389
390    def getAdminMail(self, printername) :
391        """Returns the Email address of the Print Quota Administrator."""
392        try :
393            return self.getPrinterOption(printername, "adminmail")
394        except PyKotaConfigError :
395            return "root@localhost"
396
397    def getAdmin(self, printername) :
398        """Returns the full name of the Print Quota Administrator."""
399        try :
400            return self.getPrinterOption(printername, "admin")
401        except PyKotaConfigError :
402            return "root"
403
404    def getMailTo(self, printername) :
405        """Returns the recipient of email messages."""
406        validmailtos = [ "EXTERNAL", "NOBODY", "NONE", "NOONE", "BITBUCKET", "DEVNULL", "BOTH", "USER", "ADMIN" ]
407        try :
408            fullmailto = self.getPrinterOption(printername, "mailto")
409        except PyKotaConfigError :
410            return ("BOTH", None)
411        else :
412            try :
413                mailto = [x.strip() for x in fullmailto.split('(', 1)]
414            except ValueError :
415                raise PyKotaConfigError, _("Invalid option mailto %s for printer %s") % (fullmailto, printername)
416            if len(mailto) == 1 :
417                mailto.append("")
418            (mailto, args) = mailto
419            if args.endswith(')') :
420                args = args[:-1]
421            mailto = mailto.upper()
422            if (mailto == "EXTERNAL") and not args :
423                raise PyKotaConfigError, _("Invalid option mailto %s for printer %s") % (fullmailto, printername)
424            if mailto not in validmailtos :
425                raise PyKotaConfigError, _("Option mailto in section %s only supports values in %s") % (printername, str(validmailtos))
426            return (mailto, args)
427
428    def getMaxDenyBanners(self, printername) :
429        """Returns the maximum number of deny banners to be printed for a particular user on a particular printer."""
430        try :
431            maxdb = self.getPrinterOption(printername, "maxdenybanners")
432        except PyKotaConfigError :
433            return 0 # default value is to forbid printing a deny banner.
434        try :
435            value = int(maxdb.strip())
436            if value < 0 :
437                raise ValueError
438        except (TypeError, ValueError) :
439            raise PyKotaConfigError, _("Invalid maximal deny banners counter %s") % maxdb
440        else :
441            return value
442
443    def getPrintCancelledBanners(self, printername) :
444        """Returns True if a banner should be printed when a job is cancelled, else False."""
445        try :
446            return self.isTrue(self.getPrinterOption(printername, "printcancelledbanners"))
447        except PyKotaConfigError :
448            return True
449
450    def getGraceDelay(self, printername) :
451        """Returns the grace delay in days."""
452        try :
453            gd = self.getPrinterOption(printername, "gracedelay")
454        except PyKotaConfigError :
455            gd = 7      # default value of 7 days
456        try :
457            return int(gd)
458        except (TypeError, ValueError) :
459            raise PyKotaConfigError, _("Invalid grace delay %s") % gd
460
461    def getPoorMan(self) :
462        """Returns the poor man's threshold."""
463        try :
464            pm = self.getGlobalOption("poorman")
465        except PyKotaConfigError :
466            pm = 1.0    # default value of 1 unit
467        try :
468            return float(pm)
469        except (TypeError, ValueError) :
470            raise PyKotaConfigError, _("Invalid poor man's threshold %s") % pm
471
472    def getBalanceZero(self) :
473        """Returns the value of the zero for balance limitation."""
474        try :
475            bz = self.getGlobalOption("balancezero")
476        except PyKotaConfigError :
477            bz = 0.0    # default value, zero is 0.0
478        try :
479            return float(bz)
480        except (TypeError, ValueError) :
481            raise PyKotaConfigError, _("Invalid balancezero value %s") % bz
482
483    def getPoorWarn(self) :
484        """Returns the poor man's warning message."""
485        try :
486            return self.getGlobalOption("poorwarn")
487        except PyKotaConfigError :
488            return _("Your Print Quota account balance is Low.\nSoon you'll not be allowed to print anymore.\nPlease contact the Print Quota Administrator to solve the problem.")
489
490    def getHardWarn(self, printername) :
491        """Returns the hard limit error message."""
492        try :
493            return self.getPrinterOption(printername, "hardwarn")
494        except PyKotaConfigError :
495            return _("You are not allowed to print anymore because\nyour Print Quota is exceeded on printer %s.") % printername
496
497    def getSoftWarn(self, printername) :
498        """Returns the soft limit error message."""
499        try :
500            return self.getPrinterOption(printername, "softwarn")
501        except PyKotaConfigError :
502            return _("You will soon be forbidden to print anymore because\nyour Print Quota is almost reached on printer %s.") % printername
503
504    def getPrivacy(self) :
505        """Returns True if privacy is activated, else False."""
506        return self.isTrue(self.getGlobalOption("privacy", ignore=True))
507
508    def getDebug(self) :
509        """Returns True if debugging is activated, else False."""
510        return self.isTrue(self.getGlobalOption("debug", ignore=True))
511
512    def getCaching(self) :
513        """Returns True if database caching is enabled, else False."""
514        return self.isTrue(self.getGlobalOption("storagecaching", ignore=True))
515
516    def getLDAPCache(self) :
517        """Returns True if low-level LDAP caching is enabled, else False."""
518        return self.isTrue(self.getGlobalOption("ldapcache", ignore=True))
519
520    def getDisableHistory(self) :
521        """Returns True if we want to disable history, else False."""
522        return self.isTrue(self.getGlobalOption("disablehistory", ignore=True))
523
524    def getUserNameToLower(self) :
525        """Deprecated."""
526        return self.getGlobalOption("utolower", ignore=True)
527
528    def getUserNameCase(self) :
529        """Returns value for user name case: upper, lower or native"""
530        validvalues = [ "upper", "lower", "native" ]
531        try :
532            value = self.getGlobalOption("usernamecase", ignore=True).strip().lower()
533        except AttributeError :
534            value = "native"
535        if value not in validvalues :
536            raise PyKotaConfigError, _("Option usernamecase only supports values in %s") % str(validvalues)
537        return value
538
539    def getRejectUnknown(self) :
540        """Returns True if we want to reject the creation of unknown users or groups, else False."""
541        return self.isTrue(self.getGlobalOption("reject_unknown", ignore=True))
542
543    def getPrinterKeepFiles(self, printername) :
544        """Returns True if files must be kept on disk, else False."""
545        try :
546            return self.isTrue(self.getPrinterOption(printername, "keepfiles"))
547        except PyKotaConfigError :
548            return False
549
550    def getPrinterDirectory(self, printername) :
551        """Returns the path to our working directory, else a directory suitable for temporary files."""
552        try :
553            return self.getPrinterOption(printername, "directory").strip()
554        except PyKotaConfigError :
555            return tempfile.gettempdir()
556
557    def getDenyDuplicates(self, printername) :
558        """Returns True or a command if we want to deny duplicate jobs, else False."""
559        try :
560            denyduplicates = self.getPrinterOption(printername, "denyduplicates")
561        except PyKotaConfigError :
562            return False
563        else :
564            if self.isTrue(denyduplicates) :
565                return True
566            elif self.isFalse(denyduplicates) :
567                return False
568            else :
569                # it's a command to run.
570                return denyduplicates
571
572    def getDuplicatesDelay(self, printername) :
573        """Returns the number of seconds after which two identical jobs are not considered a duplicate anymore."""
574        try :
575            duplicatesdelay = self.getPrinterOption(printername, "duplicatesdelay")
576        except PyKotaConfigError :
577            return 0
578        else :
579            try :
580                return int(duplicatesdelay)
581            except (TypeError, ValueError) :
582                raise PyKotaConfigError, _("Incorrect value %s for the duplicatesdelay directive in section %s") % (str(duplicatesdelay), printername)
583
584    def getNoPrintingMaxDelay(self, printername) :
585        """Returns the max number of seconds to wait for the printer to be in 'printing' mode."""
586        try :
587            maxdelay = self.getPrinterOption(printername, "noprintingmaxdelay")
588        except PyKotaConfigError :
589            return None         # tells to use hardcoded value
590        else :
591            try :
592                maxdelay = int(maxdelay)
593                if maxdelay < 0 :
594                    raise ValueError
595            except (TypeError, ValueError) :
596                raise PyKotaConfigError, _("Incorrect value %s for the noprintingmaxdelay directive in section %s") % (str(maxdelay), printername)
597            else :
598                return maxdelay
599
600    def getStatusStabilizationLoops(self, printername) :
601        """Returns the number of times the printer must return the 'idle' status to consider it stable."""
602        try :
603            stab = self.getPrinterOption(printername, "statusstabilizationloops")
604        except PyKotaConfigError :
605            return None         # tells to use hardcoded value
606        else :
607            try :
608                stab = int(stab)
609                if stab < 1 :
610                    raise ValueError
611            except (TypeError, ValueError) :
612                raise PyKotaConfigError, _("Incorrect value %s for the statusstabilizationloops directive in section %s") % (str(stab), printername)
613            else :
614                return stab
615
616    def getStatusStabilizationDelay(self, printername) :
617        """Returns the number of seconds to wait between two checks of the printer's status."""
618        try :
619            stab = self.getPrinterOption(printername, "statusstabilizationdelay")
620        except PyKotaConfigError :
621            return None         # tells to use hardcoded value
622        else :
623            try :
624                stab = float(stab)
625                if stab < 0.25 :
626                    raise ValueError
627            except (TypeError, ValueError) :
628                raise PyKotaConfigError, _("Incorrect value %s for the statusstabilizationdelay directive in section %s") % (str(stab), printername)
629            else :
630                return stab
631
632    def getPrinterSNMPErrorMask(self, printername) :
633        """Returns the SNMP error mask for a particular printer, or None if not defined."""
634        try :
635            errmask = self.getPrinterOption(printername, "snmperrormask").lower()
636        except PyKotaConfigError :
637            return None         # tells to use hardcoded value
638        else :
639            try :
640                if errmask.startswith("0x") :
641                    value = int(errmask, 16)
642                elif errmask.startswith("0") :
643                    value = int(errmask, 8)
644                else :
645                    value = int(errmask)
646                if 0 <= value < 65536 :
647                    return value
648                else :
649                    raise ValueError
650            except ValueError :
651                raise PyKotaConfigError, _("Incorrect value %s for the snmperrormask directive in section %s") % (errmask, printername)
652
653    def getWinbindSeparator(self) :
654        """Returns the winbind separator's value if it is set, else None."""
655        return self.getGlobalOption("winbind_separator", ignore=True)
656
657    def getAccountBanner(self, printername) :
658        """Returns which banner(s) to account for: NONE, BOTH, STARTING, ENDING."""
659        validvalues = [ "NONE", "BOTH", "STARTING", "ENDING" ]
660        try :
661            value = self.getPrinterOption(printername, "accountbanner")
662        except PyKotaConfigError :
663            return "BOTH"       # Default value of BOTH
664        else :
665            value = value.strip().upper()
666            if value not in validvalues :
667                raise PyKotaConfigError, _("Option accountbanner in section %s only supports values in %s") % (printername, str(validvalues))
668            return value
669
670    def getAvoidDuplicateBanners(self, printername) :
671        """Returns normalized value for avoiding extra banners. """
672        try :
673            avoidduplicatebanners = self.getPrinterOption(printername, "avoidduplicatebanners").upper()
674        except PyKotaConfigError :
675            return "NO"
676        else :
677            try :
678                value = int(avoidduplicatebanners)
679                if value < 0 :
680                    raise ValueError
681            except ValueError :
682                if avoidduplicatebanners not in ["YES", "NO"] :
683                    raise PyKotaConfigError, _("Option avoidduplicatebanners only accepts 'yes', 'no', or a positive integer.")
684                else :
685                    value = avoidduplicatebanners
686            return value
687
688    def getStartingBanner(self, printername) :
689        """Returns the startingbanner value if set, else None."""
690        try :
691            return self.getPrinterOption(printername, "startingbanner").strip()
692        except PyKotaConfigError :
693            return None
694
695    def getEndingBanner(self, printername) :
696        """Returns the endingbanner value if set, else None."""
697        try :
698            return self.getPrinterOption(printername, "endingbanner").strip()
699        except PyKotaConfigError :
700            return None
701
702    def getTrustJobSize(self, printername) :
703        """Returns the normalized value of the trustjobsize's directive."""
704        try :
705            value = self.getPrinterOption(printername, "trustjobsize").strip().upper()
706        except PyKotaConfigError :
707            return (None, "YES")
708        else :
709            if value == "YES" :
710                return (None, "YES")
711            try :
712                (limit, replacement) = [p.strip() for p in value.split(">")[1].split(":")]
713                limit = int(limit)
714                try :
715                    replacement = int(replacement)
716                except ValueError :
717                    if replacement != "PRECOMPUTED" :
718                        raise
719                if limit < 0 :
720                    raise ValueError
721                if (replacement != "PRECOMPUTED") and (replacement < 0) :
722                    raise ValueError
723            except (IndexError, ValueError, TypeError) :
724                raise PyKotaConfigError, _("Option trustjobsize for printer %s is incorrect") % printername
725            return (limit, replacement)
726
727    def getPrinterCoefficients(self, printername) :
728        """Returns a mapping of coefficients for a particular printer."""
729        branchbasename = "coefficient_"
730        try :
731            globalbranches = [ (k, self.config.get("global", k).decode(self.config_charset)) for k in self.config.options("global") if k.startswith(branchbasename) ]
732        except ConfigParser.NoSectionError, msg :
733            raise PyKotaConfigError, "Invalid configuration file : %s" % msg
734        try :
735            sectionbranches = [ (k, self.config.get(printername, k).decode(self.config_charset)) for k in self.config.options(printername) if k.startswith(branchbasename) ]
736        except ConfigParser.NoSectionError, msg :
737            sectionbranches = []
738        branches = {}
739        for (k, v) in globalbranches :
740            k = k.split('_', 1)[1]
741            value = v.strip()
742            if value :
743                try :
744                    branches[k] = float(value)
745                except ValueError :
746                    raise PyKotaConfigError, "Invalid coefficient %s (%s) for printer %s" % (k, value, printername)
747
748        for (k, v) in sectionbranches :
749            k = k.split('_', 1)[1]
750            value = v.strip()
751            if value :
752                try :
753                    branches[k] = float(value) # overwrite any global option or set a new value
754                except ValueError :
755                    raise PyKotaConfigError, "Invalid coefficient %s (%s) for printer %s" % (k, value, printername)
756            else :
757                del branches[k] # empty value disables a global option
758        return branches
759
760    def getPrinterSkipInitialWait(self, printername) :
761        """Returns True if we want to skip the initial waiting loop, else False."""
762        try :
763            return self.isTrue(self.getPrinterOption(printername, "skipinitialwait"))
764        except PyKotaConfigError :
765            return False
Note: See TracBrowser for help on using the browser.