# -*- coding: UTF-8 -*-# Copyright (c) 2007 - 2010, Pascal Volk# See COPYING for distribution information."""Configuration class for read, modify and write theconfiguration from Virtual Mail Manager."""fromshutilimportcopy2fromConfigParserimportConfigParser,MissingSectionHeaderError,ParsingErrorfromcStringIOimportStringIOfrom__main__importENCODING,ERR,w_stdfromExceptionsimportVMMConfigExceptionclassConfig(ConfigParser):"""This class is for reading and modifying vmm's configuration file."""def__init__(self,filename):"""Creates a new Config instance Arguments: filename -- path to the configuration file """ConfigParser.__init__(self)self.__cfgFileName=filenameself.__cfgFile=Noneself.__VMMsections=('account','bin','database','domain','maildir','misc','config')self.__changes=Falseself.__missing={}self.__dbopts=[['host','localhot'],['user','vmm'],['pass','your secret password'],['name','mailsys']]self.__mdopts=[['name','Maildir'],['folders','Drafts:Sent:Templates:Trash'],]self.__accountopts=[['delete_directory','false'],['directory_mode',448],['disk_usage','false'],['password_len',8],['random_password','false'],['smtp','true'],['pop3','true'],['imap','true'],['sieve','true']]self.__domdopts=[['auto_postmaster','true'],['delete_directory','false'],['directory_mode',504],['force_del','false'],]self.__binopts=[['dovecotpw','/usr/sbin/dovecotpw'],['du','/usr/bin/du'],['postconf','/usr/sbin/postconf']]self.__miscopts=[['base_dir','/srv/mail'],['dovecot_vers','11'],['gid_mail',8],['password_scheme','PLAIN'],['transport','dovecot:'],]defload(self):"""Loads the configuration, read only. Raises a VMMConfigException if the configuration syntax is invalid. """try:self.__cfgFile=file(self.__cfgFileName,'r')self.readfp(self.__cfgFile)except(MissingSectionHeaderError,ParsingError),e:self.__cfgFile.close()raiseVMMConfigException(str(e),ERR.CONF_ERROR)self.__cfgFile.close()defcheck(self):"""Performs a configuration check. Raises a VMMConfigException if the check fails. """ifnotself.__chkSections():errmsg=StringIO()errmsg.write(_("Using configuration file: %s\n")%\self.__cfgFileName)fork,vinself.__missing.items():ifv[0]isTrue:errmsg.write(_(u"missing section: %s\n")%k)else:errmsg.write(_(u"missing options in section %s:\n")%k)foroinv:errmsg.write(" * %s\n"%o)raiseVMMConfigException(errmsg.getvalue(),ERR.CONF_ERROR)defgetsections(self):"""Return a list with all configurable sections."""returnself.__VMMsections[:-1]defget(self,section,option,raw=False,vars=None):returnunicode(ConfigParser.get(self,section,option,raw,vars),ENCODING,'replace')defconfigure(self,sections):"""Interactive method for configuring all options in the given sections Arguments: sections -- list of strings with section names """ifnotisinstance(sections,list):raiseTypeError("Argument 'sections' is not a list.")# if [config] done = false (default at 1st run),# then set changes truetry:ifnotself.getboolean('config','done'):self.__changes=TrueexceptValueError:self.set('config','done','False')self.__changes=Truew_std(_(u'Using configuration file: %s\n')%self.__cfgFileName)forsinsections:ifs!='config':w_std(_(u'* Config section: “%s”')%s)foropt,valinself.items(s):newval=raw_input(_('Enter new value for option %(opt)s [%(val)s]: ').encode(ENCODING,'replace')%{'opt':opt,'val':val})ifnewvalandnewval!=val:self.set(s,opt,newval)self.__changes=Trueprintifself.__changes:self.__saveChanges()def__saveChanges(self):"""Writes changes to the configuration file."""self.set('config','done','true')copy2(self.__cfgFileName,self.__cfgFileName+'.bak')self.__cfgFile=file(self.__cfgFileName,'w')self.write(self.__cfgFile)self.__cfgFile.close()def__chkSections(self):"""Checks if all configuration sections are existing."""errors=Falseforsinself.__VMMsections:ifnotself.has_section(s):self.__missing[s]=[True]elifnotself.__chkOptions(s):errors=Truereturnnoterrorsdef__chkOptions(self,section):"""Checks if all configuration options in section are existing. Arguments: section -- the section to be checked """retval=Truemissing=[]ifsection=='database':opts=self.__dboptselifsection=='maildir':opts=self.__mdoptselifsection=='account':opts=self.__accountoptselifsection=='domain':opts=self.__domdoptselifsection=='bin':opts=self.__binoptselifsection=='misc':opts=self.__miscoptselifsection=='config':opts=[['done','false']]foro,vinopts:ifnotself.has_option(section,o):missing.append(o)retval=Falseiflen(missing):self.__missing[section]=missingreturnretval