VirtualMailManager/Config.py
changeset 571 a4aead244f75
parent 465 c0e1fb1b0145
parent 570 28230a8230bf
child 572 3238c58d01ae
equal deleted inserted replaced
465:c0e1fb1b0145 571:a4aead244f75
     1 # -*- coding: UTF-8 -*-
       
     2 # Copyright (c) 2007 - 2010, Pascal Volk
       
     3 # See COPYING for distribution information.
       
     4 
       
     5 """Configuration class for read, modify and write the
       
     6 configuration from Virtual Mail Manager.
       
     7 
       
     8 """
       
     9 
       
    10 from shutil import copy2
       
    11 from ConfigParser import ConfigParser, MissingSectionHeaderError, ParsingError
       
    12 from cStringIO import StringIO
       
    13 
       
    14 from __main__ import ENCODING, ERR, w_std
       
    15 from Exceptions import VMMConfigException
       
    16 
       
    17 class Config(ConfigParser):
       
    18     """This class is for reading and modifying vmm's configuration file."""
       
    19 
       
    20     def __init__(self, filename):
       
    21         """Creates a new Config instance
       
    22 
       
    23         Arguments:
       
    24         filename -- path to the configuration file
       
    25         """
       
    26         ConfigParser.__init__(self)
       
    27         self.__cfgFileName = filename
       
    28         self.__cfgFile = None
       
    29         self.__VMMsections = ['database', 'maildir', 'services', 'domdir',
       
    30                 'bin', 'misc', 'config']
       
    31         self.__changes = False
       
    32         self.__missing = {}
       
    33         self.__dbopts = [
       
    34                 ['host', 'localhot'],
       
    35                 ['user', 'vmm'],
       
    36                 ['pass', 'your secret password'],
       
    37                 ['name', 'mailsys']
       
    38                 ]
       
    39         self.__mdopts = [
       
    40                 ['name', 'Maildir'],
       
    41                 ['folders', 'Drafts:Sent:Templates:Trash'],
       
    42                 ['mode', 448],
       
    43                 ['diskusage', 'false'],
       
    44                 ['delete', 'false']
       
    45                 ]
       
    46         self.__serviceopts = [
       
    47                 ['smtp', 'true'],
       
    48                 ['pop3', 'true'],
       
    49                 ['imap', 'true'],
       
    50                 ['sieve', 'true']
       
    51                 ]
       
    52         self.__domdopts = [
       
    53                 ['base', '/srv/mail'],
       
    54                 ['mode', 504],
       
    55                 ['delete', 'false']
       
    56                 ]
       
    57         self.__binopts = [
       
    58                 ['dovecotpw', '/usr/sbin/dovecotpw'],
       
    59                 ['du', '/usr/bin/du'],
       
    60                 ['postconf', '/usr/sbin/postconf']
       
    61                 ]
       
    62         self.__miscopts = [
       
    63                 ['passwdscheme', 'PLAIN'],
       
    64                 ['gid_mail', 8],
       
    65                 ['forcedel', 'false'],
       
    66                 ['transport', 'dovecot:'],
       
    67                 ['dovecotvers', '11']
       
    68                 ]
       
    69 
       
    70     def load(self):
       
    71         """Loads the configuration, read only.
       
    72 
       
    73         Raises a VMMConfigException if the configuration syntax is invalid.
       
    74         """
       
    75         try:
       
    76             self.__cfgFile = file(self.__cfgFileName, 'r')
       
    77             self.readfp(self.__cfgFile)
       
    78         except (MissingSectionHeaderError, ParsingError), e:
       
    79             self.__cfgFile.close()
       
    80             raise VMMConfigException(str(e), ERR.CONF_ERROR)
       
    81         self.__cfgFile.close()
       
    82 
       
    83     def check(self):
       
    84         """Performs a configuration check.
       
    85 
       
    86         Raises a VMMConfigException if the check fails.
       
    87         """
       
    88         if not self.__chkSections():
       
    89             errmsg = StringIO()
       
    90             errmsg.write(_("Using configuration file: %s\n") %\
       
    91                     self.__cfgFileName)
       
    92             for k,v in self.__missing.items():
       
    93                 if v[0] is True:
       
    94                     errmsg.write(_(u"missing section: %s\n") % k)
       
    95                 else:
       
    96                     errmsg.write(_(u"missing options in section %s:\n") % k)
       
    97                     for o in v:
       
    98                         errmsg.write(" * %s\n" % o)
       
    99             raise VMMConfigException(errmsg.getvalue(), ERR.CONF_ERROR)
       
   100 
       
   101     def getsections(self):
       
   102         """Return a list with all configurable sections."""
       
   103         return self.__VMMsections[:-1]
       
   104 
       
   105     def get(self, section, option, raw=False, vars=None):
       
   106         return unicode(ConfigParser.get(self, section, option, raw, vars),
       
   107                 ENCODING, 'replace')
       
   108 
       
   109     def configure(self, sections):
       
   110         """Interactive method for configuring all options in the given sections
       
   111 
       
   112         Arguments:
       
   113         sections -- list of strings with section names
       
   114         """
       
   115         if not isinstance(sections, list):
       
   116             raise TypeError("Argument 'sections' is not a list.")
       
   117         # if [config] done = false (default at 1st run),
       
   118         # then set changes true
       
   119         try:
       
   120             if not self.getboolean('config', 'done'):
       
   121                 self.__changes = True
       
   122         except ValueError:
       
   123             self.set('config', 'done', 'False')
       
   124             self.__changes = True
       
   125         w_std(_(u'Using configuration file: %s\n') % self.__cfgFileName)
       
   126         for s in sections:
       
   127             if s != 'config':
       
   128                 w_std(_(u'* Config section: ā€œ%sā€') % s )
       
   129             for opt, val in self.items(s):
       
   130                 newval = raw_input(
       
   131                 _('Enter new value for option %(opt)s [%(val)s]: ').encode(
       
   132                     ENCODING, 'replace') % {'opt': opt, 'val': val})
       
   133                 if newval and newval != val:
       
   134                     self.set(s, opt, newval)
       
   135                     self.__changes = True
       
   136             print
       
   137         if self.__changes:
       
   138             self.__saveChanges()
       
   139 
       
   140     def __saveChanges(self):
       
   141         """Writes changes to the configuration file."""
       
   142         self.set('config', 'done', 'true')
       
   143         copy2(self.__cfgFileName, self.__cfgFileName+'.bak')
       
   144         self.__cfgFile = file(self.__cfgFileName, 'w')
       
   145         self.write(self.__cfgFile)
       
   146         self.__cfgFile.close()
       
   147 
       
   148     def __chkSections(self):
       
   149         """Checks if all configuration sections are existing."""
       
   150         errors = False
       
   151         for s in self.__VMMsections:
       
   152             if not self.has_section(s):
       
   153                 self.__missing[s] = [True]
       
   154                 errors = True
       
   155             elif not self.__chkOptions(s):
       
   156                 errors = True
       
   157         return not errors
       
   158 
       
   159     def __chkOptions(self, section):
       
   160         """Checks if all configuration options in section are existing.
       
   161 
       
   162         Arguments:
       
   163         section -- the section to be checked
       
   164         """
       
   165         retval = True
       
   166         missing = []
       
   167         if section == 'database':
       
   168             opts = self.__dbopts
       
   169         elif section == 'maildir':
       
   170             opts = self.__mdopts
       
   171         elif section == 'services':
       
   172             opts = self.__serviceopts
       
   173         elif section == 'domdir':
       
   174             opts = self.__domdopts
       
   175         elif section == 'bin':
       
   176             opts = self.__binopts
       
   177         elif section == 'misc':
       
   178             opts = self.__miscopts
       
   179         elif section == 'config':
       
   180             opts = [['done', 'false']]
       
   181         for o, v in opts:
       
   182             if not self.has_option(section, o):
       
   183                 missing.append(o)
       
   184                 retval = False
       
   185         if len(missing):
       
   186             self.__missing[section] = missing
       
   187         return retval