diff options
Diffstat (limited to 'mailman/config/config.py')
| -rw-r--r-- | mailman/config/config.py | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/mailman/config/config.py b/mailman/config/config.py new file mode 100644 index 000000000..031324eff --- /dev/null +++ b/mailman/config/config.py @@ -0,0 +1,202 @@ +# Copyright (C) 2006-2008 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""Configuration file loading and management.""" + +__metaclass__ = type +__all__ = [ + 'Configuration', + ] + + +import os +import sys +import errno +import logging + +from StringIO import StringIO +from lazr.config import ConfigSchema +from lazr.config.interfaces import NoCategoryError +from pkg_resources import resource_filename + +from mailman import Defaults +from mailman import version +from mailman.config.helpers import as_boolean +from mailman.core import errors +from mailman.domain import Domain +from mailman.languages import LanguageManager + + +SPACE = ' ' + + + +class Configuration(object): + """The core global configuration object.""" + + def __init__(self): + self.domains = {} # email host -> IDomain + self.qrunners = {} + self.qrunner_shortcuts = {} + self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION + self._config = None + + def __getattr__(self, name): + """Delegate to the configuration object.""" + return getattr(self._config, name) + + def load(self, filename=None): + """Load the configuration from the schema and config files.""" + schema_file = resource_filename('mailman.config', 'schema.cfg') + schema = ConfigSchema(schema_file) + # If a configuration file was given, load it now too. + if filename is None: + self._config = schema.loadFile(StringIO(''), '<default>') + else: + self._config = schema.load(filename) + self.post_process() + + def post_process(self): + """Perform post-processing after loading the configuration files.""" + # Set up the domains. + try: + domains = self._config.getByCategory('domain') + except NoCategoryError: + domains = [] + for section in domains: + domain = Domain(section.email_host, section.base_url, + section.description, section.contact_address) + if domain.email_host in self.domains: + raise errors.BadDomainSpecificationError( + 'Duplicate email host: %s' % domain.email_host) + # Make sure there's only one mapping for the url_host + if domain.url_host in self.domains.values(): + raise errors.BadDomainSpecificationError( + 'Duplicate url host: %s' % domain.url_host) + # We'll do the reverse mappings on-demand. There shouldn't be too + # many virtual hosts that it will really matter that much. + self.domains[domain.email_host] = domain + # Set up the queue runners. + try: + qrunners = self._config.getByCategory('qrunner') + except NoCategoryError: + qrunners = [] + for section in qrunners: + if not as_boolean(section.start): + continue + name = section['class'] + self.qrunners[name] = section.count + # Calculate the queue runner shortcut name. + classname = name.rsplit('.', 1)[1] + if classname.endswith('Runner'): + shortname = classname[:-6].lower() + else: + shortname = classname + self.qrunner_shortcuts[shortname] = section['class'] + # Set up directories. + self.BIN_DIR = os.path.abspath(os.path.dirname(sys.argv[0])) + VAR_DIR = self._config.mailman.var_dir + # Now that we've loaded all the configuration files we're going to + # load, set up some useful directories. + join = os.path.join + self.LIST_DATA_DIR = join(VAR_DIR, 'lists') + self.LOG_DIR = join(VAR_DIR, 'logs') + self.LOCK_DIR = lockdir = join(VAR_DIR, 'locks') + self.DATA_DIR = datadir = join(VAR_DIR, 'data') + self.ETC_DIR = etcdir = join(VAR_DIR, 'etc') + self.SPAM_DIR = join(VAR_DIR, 'spam') + self.EXT_DIR = join(VAR_DIR, 'ext') + self.PUBLIC_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'public') + self.PRIVATE_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'private') + # Directories used by the qrunner subsystem + self.QUEUE_DIR = qdir = join(VAR_DIR, 'qfiles') + self.ARCHQUEUE_DIR = join(qdir, 'archive') + self.BADQUEUE_DIR = join(qdir, 'bad') + self.BOUNCEQUEUE_DIR = join(qdir, 'bounces') + self.CMDQUEUE_DIR = join(qdir, 'commands') + self.INQUEUE_DIR = join(qdir, 'in') + self.MAILDIR_DIR = join(qdir, 'maildir') + self.NEWSQUEUE_DIR = join(qdir, 'news') + self.OUTQUEUE_DIR = join(qdir, 'out') + self.PIPELINEQUEUE_DIR = join(qdir, 'pipeline') + self.RETRYQUEUE_DIR = join(qdir, 'retry') + self.SHUNTQUEUE_DIR = join(qdir, 'shunt') + self.VIRGINQUEUE_DIR = join(qdir, 'virgin') + self.MESSAGES_DIR = join(VAR_DIR, 'messages') + # Other useful files + self.PIDFILE = join(datadir, 'master-qrunner.pid') + self.SITE_PW_FILE = join(datadir, 'adm.pw') + self.LISTCREATOR_PW_FILE = join(datadir, 'creator.pw') + self.CONFIG_FILE = join(etcdir, 'mailman.cfg') + self.LOCK_FILE = join(lockdir, 'master-qrunner') + # Set up all the languages. + self.languages = LanguageManager() + try: + languages = self._config.getByCategory('language') + except NoCategoryError: + languages = [] + for section in languages: + code = section.name.split('.')[1] + self.languages.add_language(code, section.description, + section.charset, section.enable) + # Always enable the server default language, which must be defined. + self.languages.enable_language(self._config.mailman.default_language) + # Create various registries. + self.archivers = {} + self.chains = {} + self.rules = {} + self.handlers = {} + self.pipelines = {} + self.commands = {} + + @property + def logger_configs(self): + """Return all log config sections.""" + try: + loggers = self._config.getByCategory('logging') + except NoCategoryError: + loggers = [] + return loggers + + @property + def paths(self): + """Return a substitution dictionary of all path variables.""" + return dict((k, self.__dict__[k]) + for k in self.__dict__ + if k.endswith('_DIR')) + + def ensure_directories_exist(self): + """Create all path directories if they do not exist.""" + for variable, directory in self.paths.items(): + try: + os.makedirs(directory, 02775) + except OSError, e: + if e.errno <> errno.EEXIST: + raise + + @property + def header_matches(self): + """Iterate over all spam matching headers. + + Values are 3-tuples of (header, pattern, chain) + """ + try: + matches = self._config.getByCategory('spam.headers') + except NoCategoryError: + matches = [] + for match in matches: + yield (matches.header, matches.pattern, matches.chain) |
