diff -r f4956b4ceba1 -r 011066435e6f VirtualMailManager/ext/postconf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualMailManager/ext/postconf.py Wed Jul 28 02:08:03 2010 +0000 @@ -0,0 +1,127 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2008 - 2010, Pascal Volk +# See COPYING for distribution information. +""" + VirtualMailManager.ext.postconf + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Wrapper class for Postfix's postconf. + Postconf instances can be used to read actual values of configuration + parameters or edit the value of a configuration parameter. + + postconf.read(parameter) -> value + postconf.edit(parameter, value) +""" + +import re +from subprocess import Popen, PIPE + +from VirtualMailManager.errors import VMMError +from VirtualMailManager.constants import VMM_ERROR + +_ = lambda msg: msg + + +class Postconf(object): + """Wrapper class for Postfix's postconf.""" + __slots__ = ('_bin', '_val') + _parameter_re = re.compile(r'^\w+$') + _variables_re = re.compile(r'\$\b\w+\b') + + def __init__(self, postconf_bin): + """Creates a new Postconf instance. + + Argument: + + `postconf_bin` : str + absolute path to the Postfix postconf binary. + """ + self._bin = postconf_bin + self._val = '' + + def edit(self, parameter, value): + """Set the `parameter`'s value to `value`. + + Arguments: + + `parameter` : str + the name of a Postfix configuration parameter + `value` : str + the parameter's new value. + """ + self._check_parameter(parameter) + stdout, stderr = Popen((self._bin, '-e', parameter + '=' + str(value)), + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) + + def read(self, parameter, expand_vars=True): + """Returns the parameters value. + + If expand_vars is True (default), all variables in the value will be + expanded: + e.g. mydestination: mail.example.com, localhost.example.com, localhost + Otherwise the value may contain one or more variables. + e.g. mydestination: $myhostname, localhost.$mydomain, localhost + + Arguments: + + `parameter` : str + the name of a Postfix configuration parameter. + `expand_vars` : bool + indicates if variables should be expanded or not, default True + """ + self._check_parameter(parameter) + self._val = self._read(parameter) + if expand_vars: + self._expand_vars() + return self._val + + def _check_parameter(self, parameter): + """Check that the `parameter` looks like a configuration parameter. + If not, a VMMError will be raised.""" + if not self.__class__._parameter_re.match(parameter): + raise VMMError(_(u"The value '%s' doesn't look like a valid " + u"postfix configuration parameter name.") % + parameter, VMM_ERROR) + + def _expand_vars(self): + """Expand the $variables in self._val to their values.""" + while True: + pvars = set(self.__class__._variables_re.findall(self._val)) + if not pvars: + break + if len(pvars) > 1: + self._expand_multi_vars(self._read_multi(pvars)) + continue + pvars = pvars.pop() + self._val = self._val.replace(pvars, self._read(pvars[1:])) + + def _expand_multi_vars(self, old_new): + """Replace all $vars in self._val with their values.""" + for old, new in old_new.iteritems(): + self._val = self._val.replace('$' + old, new) + + def _read(self, parameter): + """Ask postconf for the value of a single configuration parameter.""" + stdout, stderr = Popen([self._bin, '-h', parameter], stdout=PIPE, + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) + return stdout.strip() + + def _read_multi(self, parameters): + """Ask postconf for multiple configuration parameters. Returns a dict + parameter: value items.""" + cmd = [self._bin] + cmd.extend(parameter[1:] for parameter in parameters) + stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) + par_val = {} + for line in stdout.splitlines(): + par, val = line.split(' = ') + par_val[par] = val + return par_val + +del _