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

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