summaryrefslogtreecommitdiff
path: root/Mailman/chains/headers.py
diff options
context:
space:
mode:
authorBarry Warsaw2008-02-01 22:21:05 -0500
committerBarry Warsaw2008-02-01 22:21:05 -0500
commitb6f3ba4c9ebe821dd2c4676d7397fe5312b72a36 (patch)
tree5803f890642e5272b856e30869abd630b43271bc /Mailman/chains/headers.py
parentc1cc921b691eb60445cf28bc66a59b02b3cd09a4 (diff)
downloadmailman-b6f3ba4c9ebe821dd2c4676d7397fe5312b72a36.tar.gz
mailman-b6f3ba4c9ebe821dd2c4676d7397fe5312b72a36.tar.zst
mailman-b6f3ba4c9ebe821dd2c4676d7397fe5312b72a36.zip
Diffstat (limited to 'Mailman/chains/headers.py')
-rw-r--r--Mailman/chains/headers.py81
1 files changed, 58 insertions, 23 deletions
diff --git a/Mailman/chains/headers.py b/Mailman/chains/headers.py
index a802eaab4..06dfafeda 100644
--- a/Mailman/chains/headers.py
+++ b/Mailman/chains/headers.py
@@ -23,10 +23,11 @@ __metaclass__ = type
import re
import logging
+import itertools
from zope.interface import implements
-from Mailman.interfaces import IRule, LinkAction
+from Mailman.interfaces import IChainIterator, IRule, LinkAction
from Mailman.chains.base import Chain, Link
from Mailman.i18n import _
from Mailman.configuration import config
@@ -36,6 +37,29 @@ log = logging.getLogger('mailman.vette')
+def make_link(entry):
+ """Create a Link object.
+
+ :param entry: a 2- or 3-tuple describing a link. If a 2-tuple, it is a
+ header and a pattern, and a default chain of 'hold' will be used. If
+ a 3-tuple, the third item is the chain name to use.
+ :return: an ILink.
+ """
+ if len(entry) == 2:
+ header, pattern = entry
+ chain_name = 'hold'
+ elif len(entry) == 3:
+ header, pattern, chain_name = entry
+ # We don't assert that the chain exists here because the jump
+ # chain may not yet have been created.
+ else:
+ raise AssertionError('Bad link description: %s' % entry)
+ rule = HeaderMatchRule(header, pattern)
+ chain = config.chains[chain_name]
+ return Link(rule, LinkAction.jump, chain)
+
+
+
class HeaderMatchRule:
"""Header matching rule used by header-match chain."""
implements(IRule)
@@ -78,23 +102,16 @@ class HeaderMatchChain(Chain):
# The header match rules are not global, so don't register them.
# These are the only rules that the header match chain can execute.
self._links = []
- self._rules = {}
# Initialize header check rules with those from the global
# HEADER_MATCHES variable.
for entry in config.HEADER_MATCHES:
- if len(entry) == 2:
- header, pattern = entry
- chain = 'hold'
- elif len(entry) == 3:
- header, pattern, chain = entry
- # We don't assert that the chain exists here because the jump
- # chain may not yet have been created.
- else:
- raise AssertionError(
- 'Bad entry for HEADER_MATCHES: %s' % entry)
- self.extend(header, pattern, chain)
+ self._links.append(make_link(entry))
+ # Keep track of how many global header matching rules we've seen.
+ # This is so the flush() method will only delete those that were added
+ # via extend() or append_link().
+ self._permanent_link_count = len(self._links)
- def extend(self, header, pattern, chain='hold'):
+ def extend(self, header, pattern, chain_name='hold'):
"""Extend the existing header matches.
:param header: The case-insensitive header field name.
@@ -103,14 +120,32 @@ class HeaderMatchChain(Chain):
:param chain: Option chain to jump to if the pattern matches any of
the named header values. If not given, the 'hold' chain is used.
"""
- rule = HeaderMatchRule(header, pattern)
- self._rules[rule.name] = rule
- link = Link(rule.name, LinkAction.jump, chain)
- self._links.append(link)
+ self._links.append(make_link((header, pattern, chain_name)))
- def get_rule(self, name):
- """See `IChain`.
+ def flush(self):
+ """See `IMutableChain`."""
+ del self._links[self._permanent_link_count:]
- Only local rules are findable by this chain.
- """
- return self._rules[name]
+ def get_links(self, mlist, msg, msgdata):
+ """See `IChain`."""
+ list_iterator = HeaderMatchIterator(mlist)
+ return itertools.chain(iter(self._links), iter(list_iterator))
+
+ def __iter__(self):
+ for link in self._links:
+ yield link
+
+
+
+class HeaderMatchIterator:
+ """An iterator of both the global and list-specific chain links."""
+
+ implements(IChainIterator)
+
+ def __init__(self, mlist):
+ self._mlist = mlist
+
+ def __iter__(self):
+ """See `IChainIterator`."""
+ for entry in self._mlist.header_matches:
+ yield make_link(entry)