VirtualMailManager/Config.py
branchv0.6.x
changeset 264 04fea4d8b900
parent 262 6eea85d8b91d
child 270 d3389645a91d
equal deleted inserted replaced
263:07fdc93dde9f 264:04fea4d8b900
     6     VirtualMailManager.Config
     6     VirtualMailManager.Config
     7 
     7 
     8     VMM's configuration module for simplified configuration access.
     8     VMM's configuration module for simplified configuration access.
     9 """
     9 """
    10 
    10 
       
    11 import re
    11 
    12 
    12 from ConfigParser import \
    13 from ConfigParser import \
    13      Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \
    14      Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \
    14      ParsingError, RawConfigParser
    15      ParsingError, RawConfigParser
    15 from cStringIO import StringIO# TODO: move interactive stff to cli
    16 from cStringIO import StringIO# TODO: move interactive stff to cli
    16 
    17 
    17 from VirtualMailManager.common import exec_ok, get_unicode, is_dir
    18 from VirtualMailManager.common import exec_ok, get_unicode, is_dir, version_hex
    18 from VirtualMailManager.constants.ERROR import CONF_ERROR
    19 from VirtualMailManager.constants.ERROR import CONF_ERROR
    19 from VirtualMailManager.errors import ConfigError
    20 from VirtualMailManager.errors import ConfigError
    20 
    21 
    21 
    22 
    22 _ = lambda msg: msg
    23 _ = lambda msg: msg
   119           * `NoOptionError`
   120           * `NoOptionError`
   120 
   121 
   121         """
   122         """
   122         sect_opt = section_option.lower().split('.')
   123         sect_opt = section_option.lower().split('.')
   123         # TODO: cache it
   124         # TODO: cache it
   124         if len(sect_opt) != 2:# do we need a regexp to check the format?
   125         if len(sect_opt) != 2:  # do we need a regexp to check the format?
   125             raise BadOptionError(
   126             raise BadOptionError(
   126                         _(u"Bad format: '%s' - expected: section.option") %
   127                         _(u"Bad format: '%s' - expected: section.option") %
   127                                  get_unicode(section_option))
   128                                  get_unicode(section_option))
   128         if not sect_opt[0] in self._cfg:
   129         if not sect_opt[0] in self._cfg:
   129             raise NoSectionError(sect_opt[0])
   130             raise NoSectionError(sect_opt[0])
   134     def items(self, section):
   135     def items(self, section):
   135         """returns an iterable that returns key, value ``tuples`` from
   136         """returns an iterable that returns key, value ``tuples`` from
   136         the given ``section``.
   137         the given ``section``.
   137 
   138 
   138         """
   139         """
   139         if section in self._sections:# check if the section was parsed
   140         if section in self._sections:  # check if the section was parsed
   140             sect = self._sections[section]
   141             sect = self._sections[section]
   141         elif not section in self._cfg:
   142         elif not section in self._cfg:
   142             raise NoSectionError(section)
   143             raise NoSectionError(section)
   143         else:
   144         else:
   144             return ((k, self._cfg[section][k].default) \
   145             return ((k, self._cfg[section][k].default) \
   169         """
   170         """
   170         section, option = self._get_section_option(option)
   171         section, option = self._get_section_option(option)
   171         try:
   172         try:
   172             return self._cfg[section][option].getter(section, option)
   173             return self._cfg[section][option].getter(section, option)
   173         except (NoSectionError, NoOptionError):
   174         except (NoSectionError, NoOptionError):
   174             if not self._cfg[section][option].default is None:# may be False
   175             if not self._cfg[section][option].default is None:  # may be False
   175                 return self._cfg[section][option].default
   176                 return self._cfg[section][option].default
   176             else:
   177             else:
   177                 raise NoDefaultError(section, option)
   178                 raise NoDefaultError(section, option)
   178 
   179 
   179     def pget(self, option):
   180     def pget(self, option):
   248           None or any method, that takes one argument, in order to
   249           None or any method, that takes one argument, in order to
   249           check the value, when `LazyConfig.set()` is called.
   250           check the value, when `LazyConfig.set()` is called.
   250 
   251 
   251         """
   252         """
   252         self.__cls = cls
   253         self.__cls = cls
   253         if not default is None:# enforce the type of the default value
   254         if not default is None:  # enforce the type of the default value
   254             self.__default = self.__cls(default)
   255             self.__default = self.__cls(default)
   255         else:
   256         else:
   256             self.__default = default
   257             self.__default = default
   257         if not callable(getter):
   258         if not callable(getter):
   258             raise TypeError('getter has to be a callable, got a %r' %
   259             raise TypeError('getter has to be a callable, got a %r' %
   340                 'folders': LCO(str, 'Drafts:Sent:Templates:Trash', self.get),
   341                 'folders': LCO(str, 'Drafts:Sent:Templates:Trash', self.get),
   341                 'format': LCO(str, 'maildir', self.get),
   342                 'format': LCO(str, 'maildir', self.get),
   342             },
   343             },
   343             'misc': {
   344             'misc': {
   344                 'base_directory': LCO(str, '/srv/mail', self.get, is_dir),
   345                 'base_directory': LCO(str, '/srv/mail', self.get, is_dir),
   345                 'dovecot_version': LCO(int, 12, self.getint),
   346                 'dovecot_version': LCO(str, '1.2.11', self.hexversion,
       
   347                                        check_version_format),
   346                 'gid_mail': LCO(int, 8, self.getint),
   348                 'gid_mail': LCO(int, 8, self.getint),
   347                 'password_scheme': LCO(str, 'CRAM-MD5', self.get,
   349                 'password_scheme': LCO(str, 'CRAM-MD5', self.get,
   348                                        self.known_scheme),
   350                                        self.known_scheme),
   349                 'transport': LCO(str, 'dovecot:', self.get),
   351                 'transport': LCO(str, 'dovecot:', self.get),
   350             },
   352             },
   367                 self._cfg_file.close()
   369                 self._cfg_file.close()
   368 
   370 
   369     def check(self):
   371     def check(self):
   370         """Performs a configuration check.
   372         """Performs a configuration check.
   371 
   373 
   372         Raises a ConfigError if the check fails.
   374         Raises a ConfigError if settings w/o a default value are missed.
   373 
   375         Or a ConfigValueError if 'misc.dovecot_version' has the wrong
       
   376         format.
   374         """
   377         """
   375         # TODO: There are only two settings w/o defaults.
   378         # TODO: There are only two settings w/o defaults.
   376         #       So there is no need for cStringIO
   379         #       So there is no need for cStringIO
   377         if not self.__chk_cfg():
   380         if not self.__chk_cfg():
   378             errmsg = StringIO()
   381             errmsg = StringIO()
   382             for section, options in self.__missing.iteritems():
   385             for section, options in self.__missing.iteritems():
   383                 errmsg.write(_(u'* Section: %s\n') % section)
   386                 errmsg.write(_(u'* Section: %s\n') % section)
   384                 for option in options:
   387                 for option in options:
   385                     errmsg.write((u'    %s\n') % option)
   388                     errmsg.write((u'    %s\n') % option)
   386             raise ConfigError(errmsg.getvalue(), CONF_ERROR)
   389             raise ConfigError(errmsg.getvalue(), CONF_ERROR)
       
   390         check_version_format(self.get('misc', 'dovecot_version'))
       
   391 
       
   392     def hexversion(self, section, option):
       
   393         return version_hex(self.get(section, option))
   387 
   394 
   388     def known_scheme(self, scheme):
   395     def known_scheme(self, scheme):
   389         """Converts `scheme` to upper case and checks if is known by
   396         """Converts `scheme` to upper case and checks if is known by
   390         Dovecot (listed in VirtualMailManager.SCHEMES).
   397         Dovecot (listed in VirtualMailManager.SCHEMES).
   391 
   398 
   421             if missing:
   428             if missing:
   422                 self.__missing[section] = missing
   429                 self.__missing[section] = missing
   423         return not errors
   430         return not errors
   424 
   431 
   425 
   432 
       
   433 def check_version_format(version_string):
       
   434     """Check if the *version_string* has the proper format, e.g.: '1.2.3'.
       
   435     Returns the validated version string if it has the expected format.
       
   436     Otherwise a `ConfigValueError` will be raised.
       
   437     """
       
   438     version_re = r'^\d+\.\d+\.(?:\d+|(?:alpha|beta|rc)\d+)$'
       
   439     if not re.match(version_re, version_string):
       
   440         raise ConfigValueError(_(u"Not a valid Dovecot version: '%s'") %
       
   441                                get_unicode(version_string))
       
   442     return version_string
       
   443 
   426 del _
   444 del _