VirtualMailManager/ext/Postconf.py
author Pascal Volk <neverseen@users.sourceforge.net>
Fri, 26 Feb 2010 02:35:25 +0000
branchv0.6.x
changeset 216 0c8c053b451c
parent 185 6e1ef32fbd82
child 223 5c7b7cbb01cd
permissions -rw-r--r--
Moved VirtualMailManager/Exceptions to VirtualMailManager/errors. Renamed VMM*Exception classes to *Error. No longer add the attribute 'message' to VMMError if it doesn't exist, like in Python 2.4. It has been deprecated as of Python 2.6. Also removed the methods code() and msg(), the values are now accessible via the attributes 'code' and 'msg'.

# -*- coding: UTF-8 -*-
# Copyright (c) 2008 - 2010, Pascal Volk
# See COPYING for distribution information.

"""A small - r/o - wrapper class for Postfix' postconf."""

import re
from subprocess import Popen, PIPE

import VirtualMailManager.constants.ERROR as ERR
from VirtualMailManager.errors import VMMError

RE_PC_PARAMS = """^\w+$"""
RE_PC_VARIABLES = r"""\$\b\w+\b"""

class Postconf(object):
    __slots__ = ('__bin', '__val', '__varFinder')
    def __init__(self, postconf_bin):
        """Creates a new Postconf instance.

        Keyword arguments:
        postconf_bin -- absolute path to the Postfix postconf binary (str)
        """
        self.__bin = postconf_bin
        self.__val = ''
        self.__varFinder = re.compile(RE_PC_VARIABLES)

    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

        Keyword arguments:
        parameter -- the name of a Postfix configuration parameter (str)
        expand_vars -- default True (bool)
        """
        if not re.match(RE_PC_PARAMS, parameter):
            raise VMMError(_(u'The value “%s” doesn\'t look like a valid\
 postfix configuration parameter name.') % parameter, ERR.VMM_ERROR)
        self.__val = self.__read(parameter)
        if expand_vars:
            self.__expandVars()
        return self.__val

    def __expandVars(self):
        while True:
            pvars = set(self.__varFinder.findall(self.__val))
            pvars_len = len(pvars)
            if pvars_len < 1:
                break
            if pvars_len > 1:
                self.__expandMultiVars(self.__readMulti(pvars))
                continue
            pvars = pvars.pop()
            self.__val = self.__val.replace(pvars, self.__read(pvars[1:]))

    def __expandMultiVars(self, old_new):
        for old, new in old_new.items():
            self.__val = self.__val.replace('$'+old, new)

    def __read(self, parameter):
        out, err = Popen([self.__bin, '-h', parameter], stdout=PIPE,
                stderr=PIPE).communicate()
        if len(err):
            raise VMMError(err.strip(), ERR.VMM_ERROR)
        return out.strip()

    def __readMulti(self, parameters):
        cmd = [self.__bin]
        for parameter in parameters:
            cmd.append(parameter[1:])
        out, err = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
        if len(err):
            raise VMMError(err.strip(), ERR.VMM_ERROR)
        par_val = {}
        for line in out.splitlines():
            par, val = line.split(' = ')
            par_val[par] = val
        return par_val