# Copyright (C) 2008 by the Free Software Foundation, Inc. # # This program 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 2 # of the License, or (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. """Base class for terminal chains.""" __all__ = [ 'Chain', 'Link', 'TerminalChainBase', ] __metaclass__ = type from zope.interface import implements from Mailman.configuration import config from Mailman.interfaces import ( IChain, IChainIterator, IChainLink, IMutableChain, LinkAction) class Link: """A chain link.""" implements(IChainLink) def __init__(self, rule, action=None, chain=None, function=None): self.rule = rule self.action = (LinkAction.defer if action is None else action) self.chain = chain self.function = function class TerminalChainBase: """A base chain that always matches and executes a method. The method is called 'process' and must be provided by the subclass. """ implements(IChain, IChainIterator) def _process(self, mlist, msg, msgdata): """Process the message for the given mailing list. This must be overridden by subclasses. """ raise NotImplementedError def get_rule(self, name): """See `IChain`. This always returns the globally registered named rule. """ return config.rules[name] def get_links(self, mlist, msg, msgdata): """See `IChain`.""" return iter(self) def __iter__(self): """See `IChainIterator`.""" # First, yield a link that always runs the process method. yield Link('truth', LinkAction.run, function=self._process) # Now yield a rule that stops all processing. yield Link('truth', LinkAction.stop) class Chain: """Generic chain base class.""" implements(IMutableChain) def __init__(self, name, description): assert name not in config.chains, 'Duplicate chain name: %s' % name self.name = name self.description = description self._links = [] # Register the chain. config.chains[name] = self def append_link(self, link): """See `IMutableChain`.""" self._links.append(link) def flush(self): """See `IMutableChain`.""" self._links = [] def get_rule(self, name): """See `IChain`. This always returns the globally registered named rule. """ return config.rules[name] def get_links(self, mlist, msg, msgdata): """See `IChain`.""" return iter(ChainIterator(self)) def get_iterator(self): """Return an iterator over the links.""" # We do it this way in order to preserve a separation of interfaces, # and allows .get_links() to be overridden. for link in self._links: yield link class ChainIterator: """Generic chain iterator.""" implements(IChainIterator) def __init__(self, chain): self._chain = chain def __iter__(self): """See `IChainIterator`.""" return self._chain.get_iterator()