summaryrefslogtreecommitdiff
path: root/Mailman/chains/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'Mailman/chains/base.py')
-rw-r--r--Mailman/chains/base.py131
1 files changed, 131 insertions, 0 deletions
diff --git a/Mailman/chains/base.py b/Mailman/chains/base.py
new file mode 100644
index 000000000..30b66b1cf
--- /dev/null
+++ b/Mailman/chains/base.py
@@ -0,0 +1,131 @@
+# 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()