diff options
| author | Barry Warsaw | 2009-01-25 13:01:41 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2009-01-25 13:01:41 -0500 |
| commit | eefd06f1b88b8ecbb23a9013cd223b72ca85c20d (patch) | |
| tree | 72c947fe16fce0e07e996ee74020b26585d7e846 /mailman/core | |
| parent | 07871212f74498abd56bef3919bf3e029eb8b930 (diff) | |
| download | mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.gz mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.zst mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.zip | |
Diffstat (limited to 'mailman/core')
| -rw-r--r-- | mailman/core/__init__.py | 0 | ||||
| -rw-r--r-- | mailman/core/chains.py | 118 | ||||
| -rw-r--r-- | mailman/core/errors.py | 172 | ||||
| -rw-r--r-- | mailman/core/initialize.py | 125 | ||||
| -rw-r--r-- | mailman/core/logging.py | 163 | ||||
| -rw-r--r-- | mailman/core/pipelines.py | 125 | ||||
| -rw-r--r-- | mailman/core/plugins.py | 74 | ||||
| -rw-r--r-- | mailman/core/rules.py | 46 |
8 files changed, 0 insertions, 823 deletions
diff --git a/mailman/core/__init__.py b/mailman/core/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/mailman/core/__init__.py +++ /dev/null diff --git a/mailman/core/chains.py b/mailman/core/chains.py deleted file mode 100644 index 40b8c779f..000000000 --- a/mailman/core/chains.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) 2007-2009 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/>. - -"""Application support for chain processing.""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'initialize', - 'process', - ] - - -from mailman.chains.accept import AcceptChain -from mailman.chains.builtin import BuiltInChain -from mailman.chains.discard import DiscardChain -from mailman.chains.headers import HeaderMatchChain -from mailman.chains.hold import HoldChain -from mailman.chains.reject import RejectChain -from mailman.config import config -from mailman.interfaces.chain import LinkAction - - - -def process(mlist, msg, msgdata, start_chain='built-in'): - """Process the message through a chain. - - :param mlist: the IMailingList for this message. - :param msg: The Message object. - :param msgdata: The message metadata dictionary. - :param start_chain: The name of the chain to start the processing with. - """ - # Set up some bookkeeping. - chain_stack = [] - msgdata['rule_hits'] = hits = [] - msgdata['rule_misses'] = misses = [] - # Find the starting chain and begin iterating through its links. - chain = config.chains[start_chain] - chain_iter = chain.get_links(mlist, msg, msgdata) - # Loop until we've reached the end of all processing chains. - while chain: - # Iterate over all links in the chain. Do this outside a for-loop so - # we can capture a chain's link iterator in mid-flight. This supports - # the 'detour' link action - try: - link = next(chain_iter) - except StopIteration: - # This chain is exhausted. Pop the last chain on the stack and - # continue iterating through it. If there's nothing left on the - # chain stack then we're completely finished processing. - if len(chain_stack) == 0: - return - chain, chain_iter = chain_stack.pop() - continue - # Process this link. - if link.rule.check(mlist, msg, msgdata): - if link.rule.record: - hits.append(link.rule.name) - # The rule matched so run its action. - if link.action is LinkAction.jump: - chain = link.chain - chain_iter = chain.get_links(mlist, msg, msgdata) - continue - elif link.action is LinkAction.detour: - # Push the current chain so that we can return to it when - # the next chain is finished. - chain_stack.append((chain, chain_iter)) - chain = link.chain - chain_iter = chain.get_links(mlist, msg, msgdata) - continue - elif link.action is LinkAction.stop: - # Stop all processing. - return - elif link.action is LinkAction.defer: - # Just process the next link in the chain. - pass - elif link.action is LinkAction.run: - link.function(mlist, msg, msgdata) - else: - raise AssertionError( - 'Bad link action: {0}'.format(link.action)) - else: - # The rule did not match; keep going. - if link.rule.record: - misses.append(link.rule.name) - - - -def initialize(): - """Set up chains, both built-in and from the database.""" - for chain_class in (DiscardChain, HoldChain, RejectChain, AcceptChain): - chain = chain_class() - assert chain.name not in config.chains, ( - 'Duplicate chain name: {0}'.format(chain.name)) - config.chains[chain.name] = chain - # Set up a couple of other default chains. - chain = BuiltInChain() - config.chains[chain.name] = chain - # Create and initialize the header matching chain. - chain = HeaderMatchChain() - config.chains[chain.name] = chain - # XXX Read chains from the database and initialize them. - pass diff --git a/mailman/core/errors.py b/mailman/core/errors.py deleted file mode 100644 index 39401127e..000000000 --- a/mailman/core/errors.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright (C) 1998-2009 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/>. - -"""Mailman errors.""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'AlreadyReceivingDigests', - 'AlreadyReceivingRegularDeliveries', - 'BadDomainSpecificationError', - 'BadPasswordSchemeError', - 'CantDigestError', - 'DiscardMessage', - 'EmailAddressError', - 'HandlerError', - 'HoldMessage', - 'HostileSubscriptionError', - 'InvalidEmailAddress', - 'LostHeldMessage', - 'MailmanError', - 'MailmanException', - 'MemberError', - 'MembershipIsBanned', - 'MustDigestError', - 'NotAMemberError', - 'PasswordError', - 'RejectMessage', - 'SomeRecipientsFailed', - 'SubscriptionError', - ] - - - -# Base class for all exceptions raised in Mailman (XXX except legacy string -# exceptions). -class MailmanException(Exception): - pass - - - -# "New" style membership exceptions (new w/ MM2.1) -class MemberError(MailmanException): pass -class NotAMemberError(MemberError): pass -class AlreadyReceivingDigests(MemberError): pass -class AlreadyReceivingRegularDeliveries(MemberError): pass -class CantDigestError(MemberError): pass -class MustDigestError(MemberError): pass -class MembershipIsBanned(MemberError): pass - - - -# New style class based exceptions. All the above errors should eventually be -# converted. - -class MailmanError(MailmanException): - """Base class for all Mailman errors.""" - pass - -class BadDomainSpecificationError(MailmanError): - """The specification of a virtual domain is invalid or duplicated.""" - - - -# Exception hierarchy for bad email address errors that can be raised from -# Utils.ValidateEmail() -class EmailAddressError(MailmanError): - """Base class for email address validation errors.""" - - -class InvalidEmailAddress(EmailAddressError): - """Email address is invalid.""" - - - -# Exceptions for admin request database -class LostHeldMessage(MailmanError): - """Held message was lost.""" - pass - - - -def _(s): - return s - -# Exceptions for the Handler subsystem -class HandlerError(MailmanError): - """Base class for all handler errors.""" - -class HoldMessage(HandlerError): - """Base class for all message-being-held short circuits.""" - - # funky spelling is necessary to break import loops - reason = _('For some unknown reason') - - def reason_notice(self): - return self.reason - - # funky spelling is necessary to break import loops - rejection = _('Your message was rejected') - - def rejection_notice(self, mlist): - return self.rejection - -class DiscardMessage(HandlerError): - """The message can be discarded with no further action""" - -class SomeRecipientsFailed(HandlerError): - """Delivery to some or all recipients failed""" - def __init__(self, tempfailures, permfailures): - HandlerError.__init__(self) - self.tempfailures = tempfailures - self.permfailures = permfailures - -class RejectMessage(HandlerError): - """The message will be bounced back to the sender""" - def __init__(self, notice=None): - super(RejectMessage, self).__init__() - if notice is None: - notice = _('Your message was rejected') - if notice.endswith('\n\n'): - pass - elif notice.endswith('\n'): - notice += '\n' - else: - notice += '\n\n' - self.notice = notice - - - -# Subscription exceptions -class SubscriptionError(MailmanError): - """Subscription errors base class.""" - - -class HostileSubscriptionError(SubscriptionError): - """A cross-subscription attempt was made. - - This exception gets raised when an invitee attempts to use the - invitation to cross-subscribe to some other mailing list. - """ - - - -class PasswordError(MailmanError): - """A password related error.""" - - -class BadPasswordSchemeError(PasswordError): - """A bad password scheme was given.""" - - def __init__(self, scheme_name='unknown'): - super(BadPasswordSchemeError, self).__init__() - self.scheme_name = scheme_name - - def __str__(self): - return 'A bad password scheme was given: %s' % self.scheme_name diff --git a/mailman/core/initialize.py b/mailman/core/initialize.py deleted file mode 100644 index bb16f0036..000000000 --- a/mailman/core/initialize.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2006-2009 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/>. - -"""Initialize all global state. - -Every entrance into the Mailman system, be it by command line, mail program, -or cgi, must call the initialize function here in order for the system's -global state to be set up properly. Typically this is called after command -line argument parsing, since some of the initialization behavior is controlled -by the command line arguments. -""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'initialize', - 'initialize_1', - 'initialize_2', - 'initialize_3', - ] - - -import os - -from zope.interface.interface import adapter_hooks -from zope.interface.verify import verifyObject - -import mailman.config.config -import mailman.core.logging - -from mailman.core.plugins import get_plugin -from mailman.interfaces.database import IDatabase - - - -# These initialization calls are separated for the testing framework, which -# needs to do some internal calculations after config file loading and log -# initialization, but before database initialization. Generally all other -# code will just call initialize(). - -def initialize_1(config_path=None, propagate_logs=None): - """First initialization step. - - * The configuration system - * Run-time directories - * The logging subsystem - - :param config_path: The path to the configuration file. - :type config_path: string - :param propagate_logs: Should the log output propagate to stderr? - :type propagate_logs: boolean or None - """ - # By default, set the umask so that only owner and group can read and - # write our files. Specifically we must have g+rw and we probably want - # o-rwx although I think in most cases it doesn't hurt if other can read - # or write the files. Note that the Pipermail archive has more - # restrictive permissions in order to handle private archives, but it - # handles that correctly. - os.umask(007) - mailman.config.config.load(config_path) - # Create the queue and log directories if they don't already exist. - mailman.config.config.ensure_directories_exist() - mailman.core.logging.initialize(propagate_logs) - - -def initialize_2(debug=False): - """Second initialization step. - - * Rules - * Chains - * Pipelines - * Commands - - :param debug: Should the database layer be put in debug mode? - :type debug: boolean - """ - database_plugin = get_plugin('mailman.database') - # Instantiate the database plugin, ensure that it's of the right type, and - # initialize it. Then stash the object on our configuration object. - database = database_plugin() - verifyObject(IDatabase, database) - database.initialize(debug) - mailman.config.config.db = database - # Initialize the rules and chains. Do the imports here so as to avoid - # circular imports. - from mailman.app.commands import initialize as initialize_commands - from mailman.core.chains import initialize as initialize_chains - from mailman.core.pipelines import initialize as initialize_pipelines - from mailman.core.rules import initialize as initialize_rules - # Order here is somewhat important. - initialize_rules() - initialize_chains() - initialize_pipelines() - initialize_commands() - - -def initialize_3(): - """Third initialization step. - - * Adapters - """ - from mailman.app.registrar import adapt_domain_to_registrar - adapter_hooks.append(adapt_domain_to_registrar) - - - -def initialize(config_path=None, propagate_logs=None): - initialize_1(config_path, propagate_logs) - initialize_2() - initialize_3() diff --git a/mailman/core/logging.py b/mailman/core/logging.py deleted file mode 100644 index a18065965..000000000 --- a/mailman/core/logging.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (C) 2006-2009 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/>. - -"""Logging initialization, using Python's standard logging package.""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'initialize', - 'reopen', - ] - - -import os -import sys -import codecs -import logging - -from lazr.config import as_boolean, as_log_level - -from mailman.config import config - - -_handlers = {} - - - -# XXX I would love to simplify things and use Python 2.6's WatchedFileHandler, -# but there are two problems. First, it's more difficult to handle the test -# suite's need to reopen the file handler to a different path. Does -# zope.testing's logger support fix this? -# -# The other problem is that WatchedFileHandler doesn't really easily support -# HUPing the process to reopen the log file. Now, maybe that's not a big deal -# because the standard logging module would already handle things correctly if -# the file is moved, but still that's not an interface I'm ready to give up on -# yet. For now, keep our hack. - -class ReopenableFileHandler(logging.Handler): - """A file handler that supports reopening.""" - - def __init__(self, name, filename): - self.name = name - self._filename = filename - self._stream = self._open() - logging.Handler.__init__(self) - - def _open(self): - return codecs.open(self._filename, 'a', 'utf-8') - - def flush(self): - if self._stream: - self._stream.flush() - - def emit(self, record): - # It's possible for the stream to have been closed by the time we get - # here, due to the shut down semantics. This mostly happens in the - # test suite, but be defensive anyway. - stream = (self._stream if self._stream else sys.stderr) - try: - msg = self.format(record) - try: - stream.write('{0}'.format(msg)) - except UnicodeError: - stream.write('{0}'.format(msg.encode('string-escape'))) - self.flush() - except: - self.handleError(record) - - def close(self): - self.flush() - self._stream.close() - self._stream = None - logging.Handler.close(self) - - def reopen(self, filename=None): - """Reopen the output stream. - - :param filename: If given, this reopens the output stream to a new - file. This is used in the test suite. - :type filename: string - """ - if filename is not None: - self._filename = filename - self._stream.close() - self._stream = self._open() - - - -def initialize(propagate=None): - """Initialize all logs. - - :param propagate: Flag specifying whether logs should propagate their - messages to the root logger. If omitted, propagation is determined - from the configuration files. - :type propagate: bool or None - """ - # First, find the root logger and configure the logging subsystem. - # Initialize the root logger, then create a formatter for all the - # sublogs. The root logger should log to stderr. - logging.basicConfig(format=config.logging.root.format, - datefmt=config.logging.root.datefmt, - level=as_log_level(config.logging.root.level), - stream=sys.stderr) - # Create the subloggers. - for logger_config in config.logger_configs: - sub_name = logger_config.name.split('.')[-1] - if sub_name == 'root': - continue - logger_name = 'mailman.' + sub_name - log = logging.getLogger(logger_name) - # Get settings from log configuration file (or defaults). - log_format = logger_config.format - log_datefmt = logger_config.datefmt - # Propagation to the root logger is how we handle logging to stderr - # when the qrunners are not run as a subprocess of mailmanctl. - log.propagate = (as_boolean(logger_config.propagate) - if propagate is None else propagate) - # Set the logger's level. - log.setLevel(as_log_level(logger_config.level)) - # Create a formatter for this logger, then a handler, and link the - # formatter to the handler. - formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt) - path_str = logger_config.path - path_abs = os.path.normpath(os.path.join(config.LOG_DIR, path_str)) - handler = ReopenableFileHandler(sub_name, path_abs) - _handlers[sub_name] = handler - handler.setFormatter(formatter) - log.addHandler(handler) - - - -def reopen(): - """Re-open all log files.""" - for handler in _handlers.values(): - handler.reopen() - - - -def get_handler(sub_name): - """Return the handler associated with a named logger. - - :param sub_name: The logger name, sans the 'mailman.' prefix. - :type sub_name: string - :return: The file handler associated with the named logger. - :rtype: `ReopenableFileHandler` - """ - return _handlers[sub_name] diff --git a/mailman/core/pipelines.py b/mailman/core/pipelines.py deleted file mode 100644 index 8aae5cc25..000000000 --- a/mailman/core/pipelines.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2008-2009 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/>. - -"""Pipeline processor.""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'initialize', - 'process', - ] - - -from zope.interface import implements -from zope.interface.verify import verifyObject - -from mailman.config import config -from mailman.core.plugins import get_plugins -from mailman.i18n import _ -from mailman.interfaces.handler import IHandler -from mailman.interfaces.pipeline import IPipeline - - - -def process(mlist, msg, msgdata, pipeline_name='built-in'): - """Process the message through the given pipeline. - - :param mlist: the IMailingList for this message. - :param msg: The Message object. - :param msgdata: The message metadata dictionary. - :param pipeline_name: The name of the pipeline to process through. - """ - pipeline = config.pipelines[pipeline_name] - for handler in pipeline: - handler.process(mlist, msg, msgdata) - - - -class BasePipeline: - """Base pipeline implementation.""" - - implements(IPipeline) - - _default_handlers = () - - def __init__(self): - self._handlers = [] - for handler_name in self._default_handlers: - self._handlers.append(config.handlers[handler_name]) - - def __iter__(self): - """See `IPipeline`.""" - for handler in self._handlers: - yield handler - - -class BuiltInPipeline(BasePipeline): - """The built-in pipeline.""" - - name = 'built-in' - description = _('The built-in pipeline.') - - _default_handlers = ( - 'mime-delete', - 'scrubber', - 'tagger', - 'calculate-recipients', - 'avoid-duplicates', - 'cleanse', - 'cleanse-dkim', - 'cook-headers', - 'to-digest', - 'to-archive', - 'to-usenet', - 'after-delivery', - 'acknowledge', - 'to-outgoing', - ) - - -class VirginPipeline(BasePipeline): - """The processing pipeline for virgin messages. - - Virgin messages are those that are crafted internally by Mailman. - """ - name = 'virgin' - description = _('The virgin queue pipeline.') - - _default_handlers = ( - 'cook-headers', - 'to-outgoing', - ) - - - -def initialize(): - """Initialize the pipelines.""" - # Find all handlers in the registered plugins. - for handler_finder in get_plugins('mailman.handlers'): - for handler_class in handler_finder(): - handler = handler_class() - verifyObject(IHandler, handler) - assert handler.name not in config.handlers, ( - 'Duplicate handler "{0}" found in {1}'.format( - handler.name, handler_finder)) - config.handlers[handler.name] = handler - # Set up some pipelines. - for pipeline_class in (BuiltInPipeline, VirginPipeline): - pipeline = pipeline_class() - config.pipelines[pipeline.name] = pipeline diff --git a/mailman/core/plugins.py b/mailman/core/plugins.py deleted file mode 100644 index e9ba26571..000000000 --- a/mailman/core/plugins.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (C) 2007-2009 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/>. - -"""Get a requested plugin.""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - ] - - -import pkg_resources - - - -def get_plugin(group): - """Get the named plugin. - - In general, this returns exactly one plugin. If no plugins have been - added to the named group, the 'stock' plugin will be used. If more than - one plugin -- other than the stock one -- exists, an exception will be - raised. - - :param group: The plugin group name. - :return: The loaded plugin. - :raises RuntimeError: If more than one plugin overrides the stock plugin - for the named group. - """ - entry_points = list(pkg_resources.iter_entry_points(group)) - if len(entry_points) == 0: - raise RuntimeError( - 'No entry points found for group: {0}'.format(group)) - elif len(entry_points) == 1: - # Okay, this is the one to use. - return entry_points[0].load() - elif len(entry_points) == 2: - # Find the one /not/ named 'stock'. - entry_points = [ep for ep in entry_points if ep.name <> 'stock'] - if len(entry_points) == 0: - raise RuntimeError( - 'No stock plugin found for group: {0}'.format(group)) - elif len(entry_points) == 2: - raise RuntimeError('Too many stock plugins defined') - else: - raise AssertionError('Insanity') - return entry_points[0].load() - else: - raise RuntimeError('Too many plugins for group: {0}'.format(group)) - - - -def get_plugins(group): - """Get and return all plugins in the named group. - - :param group: Plugin group name. - :return: The loaded plugin. - """ - for entry_point in pkg_resources.iter_entry_points(group): - yield entry_point.load() diff --git a/mailman/core/rules.py b/mailman/core/rules.py deleted file mode 100644 index 83e24dfa2..000000000 --- a/mailman/core/rules.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2007-2009 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/>. - -"""Various rule helpers""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - 'initialize', - ] - - -from zope.interface.verify import verifyObject - -from mailman.config import config -from mailman.core.plugins import get_plugins -from mailman.interfaces.rules import IRule - - - -def initialize(): - """Find and register all rules in all plugins.""" - # Find rules in plugins. - for rule_finder in get_plugins('mailman.rules'): - for rule_class in rule_finder(): - rule = rule_class() - verifyObject(IRule, rule) - assert rule.name not in config.rules, ( - 'Duplicate rule "{0}" found in {1}'.format( - rule.name, rule_finder)) - config.rules[rule.name] = rule |
