summaryrefslogtreecommitdiff
path: root/mailman/chains
diff options
context:
space:
mode:
authorBarry Warsaw2009-01-25 13:01:41 -0500
committerBarry Warsaw2009-01-25 13:01:41 -0500
commiteefd06f1b88b8ecbb23a9013cd223b72ca85c20d (patch)
tree72c947fe16fce0e07e996ee74020b26585d7e846 /mailman/chains
parent07871212f74498abd56bef3919bf3e029eb8b930 (diff)
downloadmailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.gz
mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.zst
mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.zip
Diffstat (limited to 'mailman/chains')
-rw-r--r--mailman/chains/__init__.py0
-rw-r--r--mailman/chains/accept.py58
-rw-r--r--mailman/chains/base.py122
-rw-r--r--mailman/chains/builtin.py86
-rw-r--r--mailman/chains/discard.py47
-rw-r--r--mailman/chains/headers.py156
-rw-r--r--mailman/chains/hold.py178
-rw-r--r--mailman/chains/reject.py59
8 files changed, 0 insertions, 706 deletions
diff --git a/mailman/chains/__init__.py b/mailman/chains/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/mailman/chains/__init__.py
+++ /dev/null
diff --git a/mailman/chains/accept.py b/mailman/chains/accept.py
deleted file mode 100644
index bd47f42c8..000000000
--- a/mailman/chains/accept.py
+++ /dev/null
@@ -1,58 +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/>.
-
-"""The terminal 'accept' chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'AcceptChain',
- ]
-
-import logging
-
-from mailman.chains.base import TerminalChainBase
-from mailman.config import config
-from mailman.i18n import _
-
-
-log = logging.getLogger('mailman.vette')
-SEMISPACE = '; '
-
-
-
-class AcceptChain(TerminalChainBase):
- """Accept the message for posting."""
-
- name = 'accept'
- description = _('Accept a message.')
-
- def _process(self, mlist, msg, msgdata):
- """See `TerminalChainBase`."""
- # Start by decorating the message with a header that contains a list
- # of all the rules that matched. These metadata could be None or an
- # empty list.
- rule_hits = msgdata.get('rule_hits')
- if rule_hits:
- msg['X-Mailman-Rule-Hits'] = SEMISPACE.join(rule_hits)
- rule_misses = msgdata.get('rule_misses')
- if rule_misses:
- msg['X-Mailman-Rule-Misses'] = SEMISPACE.join(rule_misses)
- accept_queue = config.switchboards['pipeline']
- accept_queue.enqueue(msg, msgdata)
- log.info('ACCEPT: %s', msg.get('message-id', 'n/a'))
diff --git a/mailman/chains/base.py b/mailman/chains/base.py
deleted file mode 100644
index bcd946b40..000000000
--- a/mailman/chains/base.py
+++ /dev/null
@@ -1,122 +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/>.
-
-"""Base class for terminal chains."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'Chain',
- 'Link',
- 'TerminalChainBase',
- ]
-
-
-from zope.interface import implements
-
-from mailman.config import config
-from mailman.interfaces.chain 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_links(self, mlist, msg, msgdata):
- """See `IChain`."""
- return iter(self)
-
- def __iter__(self):
- """See `IChainIterator`."""
- truth = config.rules['truth']
- # 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: {0}'.format(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_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()
diff --git a/mailman/chains/builtin.py b/mailman/chains/builtin.py
deleted file mode 100644
index 05912a2f2..000000000
--- a/mailman/chains/builtin.py
+++ /dev/null
@@ -1,86 +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/>.
-
-"""The default built-in starting chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'BuiltInChain',
- ]
-
-
-import logging
-
-from zope.interface import implements
-
-from mailman.chains.base import Link
-from mailman.config import config
-from mailman.i18n import _
-from mailman.interfaces.chain import IChain, LinkAction
-
-
-log = logging.getLogger('mailman.vette')
-
-
-
-class BuiltInChain:
- """Default built-in chain."""
-
- implements(IChain)
-
- name = 'built-in'
- description = _('The built-in moderation chain.')
-
- _link_descriptions = (
- ('approved', LinkAction.jump, 'accept'),
- ('emergency', LinkAction.jump, 'hold'),
- ('loop', LinkAction.jump, 'discard'),
- # Do all of the following before deciding whether to hold the message
- # for moderation.
- ('administrivia', LinkAction.defer, None),
- ('implicit-dest', LinkAction.defer, None),
- ('max-recipients', LinkAction.defer, None),
- ('max-size', LinkAction.defer, None),
- ('news-moderation', LinkAction.defer, None),
- ('no-subject', LinkAction.defer, None),
- ('suspicious-header', LinkAction.defer, None),
- # Now if any of the above hit, jump to the hold chain.
- ('any', LinkAction.jump, 'hold'),
- # Take a detour through the self header matching chain, which we'll
- # create later.
- ('truth', LinkAction.detour, 'header-match'),
- # Finally, the builtin chain selfs to acceptance.
- ('truth', LinkAction.jump, 'accept'),
- )
-
- def __init__(self):
- self._cached_links = None
-
- def get_links(self, mlist, msg, msgdata):
- """See `IChain`."""
- if self._cached_links is None:
- self._cached_links = links = []
- for rule_name, action, chain_name in self._link_descriptions:
- # Get the named rule.
- rule = config.rules[rule_name]
- # Get the chain, if one is defined.
- chain = (None if chain_name is None
- else config.chains[chain_name])
- links.append(Link(rule, action, chain))
- return iter(self._cached_links)
diff --git a/mailman/chains/discard.py b/mailman/chains/discard.py
deleted file mode 100644
index 1899e0340..000000000
--- a/mailman/chains/discard.py
+++ /dev/null
@@ -1,47 +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/>.
-
-"""The terminal 'discard' chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'DiscardChain',
- ]
-
-
-import logging
-
-from mailman.chains.base import TerminalChainBase
-from mailman.i18n import _
-
-
-log = logging.getLogger('mailman.vette')
-
-
-
-class DiscardChain(TerminalChainBase):
- """Discard a message."""
-
- name = 'discard'
- description = _('Discard a message and stop processing.')
-
- def _process(self, mlist, msg, msgdata):
- """See `TerminalChainBase`."""
- log.info('DISCARD: %s', msg.get('message-id', 'n/a'))
- # Nothing more needs to happen.
diff --git a/mailman/chains/headers.py b/mailman/chains/headers.py
deleted file mode 100644
index 2f85d78d0..000000000
--- a/mailman/chains/headers.py
+++ /dev/null
@@ -1,156 +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/>.
-
-"""The header-matching chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'HeaderMatchChain',
- ]
-
-
-import re
-import logging
-import itertools
-
-from zope.interface import implements
-
-from mailman.chains.base import Chain, Link
-from mailman.config import config
-from mailman.i18n import _
-from mailman.interfaces.chain import IChainIterator, LinkAction
-from mailman.interfaces.rules import IRule
-
-
-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: {0}'.format(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)
-
- # Sequential rule counter.
- _count = 1
-
- def __init__(self, header, pattern):
- self._header = header
- self._pattern = pattern
- self.name = 'header-match-{0:02}'.format(HeaderMatchRule._count)
- HeaderMatchRule._count += 1
- self.description = '{0}: {1}'.format(header, pattern)
- # XXX I think we should do better here, somehow recording that a
- # particular header matched a particular pattern, but that gets ugly
- # with RFC 2822 headers. It also doesn't match well with the rule
- # name concept. For now, we just record the rather useless numeric
- # rule name. I suppose we could do the better hit recording in the
- # check() method, and set self.record = False.
- self.record = True
-
- def check(self, mlist, msg, msgdata):
- """See `IRule`."""
- for value in msg.get_all(self._header, []):
- if re.search(self._pattern, value, re.IGNORECASE):
- return True
- return False
-
-
-
-class HeaderMatchChain(Chain):
- """Default header matching chain.
-
- This could be extended by header match rules in the database.
- """
-
- def __init__(self):
- super(HeaderMatchChain, self).__init__(
- 'header-match', _('The built-in header matching 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 = []
- # Initialize header check rules with those from the global
- # HEADER_MATCHES variable.
- for entry in config.header_matches:
- 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_name='hold'):
- """Extend the existing header matches.
-
- :param header: The case-insensitive header field name.
- :param pattern: The pattern to match the header's value again. The
- match is not anchored and is done case-insensitively.
- :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.
- """
- self._links.append(make_link((header, pattern, chain_name)))
-
- def flush(self):
- """See `IMutableChain`."""
- del self._links[self._permanent_link_count:]
-
- 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)
diff --git a/mailman/chains/hold.py b/mailman/chains/hold.py
deleted file mode 100644
index 16238a541..000000000
--- a/mailman/chains/hold.py
+++ /dev/null
@@ -1,178 +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/>.
-
-"""The terminal 'hold' chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'HoldChain',
- ]
-
-
-import logging
-
-from email.mime.message import MIMEMessage
-from email.mime.text import MIMEText
-from email.utils import formatdate, make_msgid
-from zope.interface import implements
-
-from mailman import i18n
-from mailman.Message import UserNotification
-from mailman.Utils import maketext, oneline, wrap, GetCharSet
-from mailman.app.moderator import hold_message
-from mailman.app.replybot import autorespond_to_sender, can_acknowledge
-from mailman.chains.base import TerminalChainBase
-from mailman.config import config
-from mailman.interfaces.pending import IPendable
-
-
-log = logging.getLogger('mailman.vette')
-SEMISPACE = '; '
-_ = i18n._
-
-
-
-class HeldMessagePendable(dict):
- implements(IPendable)
- PEND_KEY = 'held message'
-
-
-
-class HoldChain(TerminalChainBase):
- """Hold a message."""
-
- name = 'hold'
- description = _('Hold a message and stop processing.')
-
- def _process(self, mlist, msg, msgdata):
- """See `TerminalChainBase`."""
- # Start by decorating the message with a header that contains a list
- # of all the rules that matched. These metadata could be None or an
- # empty list.
- rule_hits = msgdata.get('rule_hits')
- if rule_hits:
- msg['X-Mailman-Rule-Hits'] = SEMISPACE.join(rule_hits)
- rule_misses = msgdata.get('rule_misses')
- if rule_misses:
- msg['X-Mailman-Rule-Misses'] = SEMISPACE.join(rule_misses)
- # Hold the message by adding it to the list's request database.
- # XXX How to calculate the reason?
- request_id = hold_message(mlist, msg, msgdata, None)
- # Calculate a confirmation token to send to the author of the
- # message.
- pendable = HeldMessagePendable(type=HeldMessagePendable.PEND_KEY,
- id=request_id)
- token = config.db.pendings.add(pendable)
- # Get the language to send the response in. If the sender is a
- # member, then send it in the member's language, otherwise send it in
- # the mailing list's preferred language.
- sender = msg.get_sender()
- member = mlist.members.get_member(sender)
- language = (member.preferred_language
- if member else mlist.preferred_language)
- # A substitution dictionary for the email templates.
- charset = GetCharSet(mlist.preferred_language)
- original_subject = msg.get('subject')
- if original_subject is None:
- original_subject = _('(no subject)')
- else:
- original_subject = oneline(original_subject, charset)
- substitutions = dict(
- listname = mlist.fqdn_listname,
- subject = original_subject,
- sender = sender,
- reason = 'XXX', #reason,
- confirmurl = '{0}/{1}'.format(mlist.script_url('confirm'), token),
- admindb_url = mlist.script_url('admindb'),
- )
- # At this point the message is held, but now we have to craft at least
- # two responses. The first will go to the original author of the
- # message and it will contain the token allowing them to approve or
- # discard the message. The second one will go to the moderators of
- # the mailing list, if the list is so configured.
- #
- # Start by possibly sending a response to the message author. There
- # are several reasons why we might not go through with this. If the
- # message was gated from NNTP, the author may not even know about this
- # list, so don't spam them. If the author specifically requested that
- # acknowledgments not be sent, or if the message was bulk email, then
- # we do not send the response. It's also possible that either the
- # mailing list, or the author (if they are a member) have been
- # configured to not send such responses.
- if (not msgdata.get('fromusenet') and
- can_acknowledge(msg) and
- mlist.respond_to_post_requests and
- autorespond_to_sender(mlist, sender, language)):
- # We can respond to the sender with a message indicating their
- # posting was held.
- subject = _(
- 'Your message to $mlist.fqdn_listname awaits moderator approval')
- send_language = msgdata.get('lang', language)
- text = maketext('postheld.txt', substitutions,
- lang=send_language, mlist=mlist)
- adminaddr = mlist.bounces_address
- nmsg = UserNotification(sender, adminaddr, subject, text,
- send_language)
- nmsg.send(mlist)
- # Now the message for the list moderators. This one should appear to
- # come from <list>-owner since we really don't need to do bounce
- # processing on it.
- if mlist.admin_immed_notify:
- # Now let's temporarily set the language context to that which the
- # administrators are expecting.
- with i18n.using_language(mlist.preferred_language):
- language = mlist.preferred_language
- charset = GetCharSet(language)
- # We need to regenerate or re-translate a few values in the
- # substitution dictionary.
- #d['reason'] = _(reason) # XXX reason
- substitutions['subject'] = original_subject
- # craft the admin notification message and deliver it
- subject = _(
- '$mlist.fqdn_listname post from $sender requires approval')
- nmsg = UserNotification(mlist.owner_address,
- mlist.owner_address,
- subject, lang=language)
- nmsg.set_type('multipart/mixed')
- text = MIMEText(
- maketext('postauth.txt', substitutions,
- raw=True, mlist=mlist),
- _charset=charset)
- dmsg = MIMEText(wrap(_("""\
-If you reply to this message, keeping the Subject: header intact, Mailman will
-discard the held message. Do this if the message is spam. If you reply to
-this message and include an Approved: header with the list password in it, the
-message will be approved for posting to the list. The Approved: header can
-also appear in the first line of the body of the reply.""")),
- _charset=GetCharSet(language))
- dmsg['Subject'] = 'confirm ' + token
- dmsg['Sender'] = mlist.request_address
- dmsg['From'] = mlist.request_address
- dmsg['Date'] = formatdate(localtime=True)
- dmsg['Message-ID'] = make_msgid()
- nmsg.attach(text)
- nmsg.attach(MIMEMessage(msg))
- nmsg.attach(MIMEMessage(dmsg))
- nmsg.send(mlist, **dict(tomoderators=True))
- # Log the held message
- # XXX reason
- reason = 'n/a'
- log.info('HOLD: %s post from %s held, message-id=%s: %s',
- mlist.fqdn_listname, sender,
- msg.get('message-id', 'n/a'), reason)
diff --git a/mailman/chains/reject.py b/mailman/chains/reject.py
deleted file mode 100644
index 3faf563da..000000000
--- a/mailman/chains/reject.py
+++ /dev/null
@@ -1,59 +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/>.
-
-"""The terminal 'reject' chain."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'RejectChain',
- ]
-
-
-import logging
-
-from mailman.app.bounces import bounce_message
-from mailman.chains.base import TerminalChainBase
-from mailman.i18n import _
-
-
-log = logging.getLogger('mailman.vette')
-SEMISPACE = '; '
-
-
-
-class RejectChain(TerminalChainBase):
- """Reject/bounce a message."""
-
- name = 'reject'
- description = _('Reject/bounce a message and stop processing.')
-
- def _process(self, mlist, msg, msgdata):
- """See `TerminalChainBase`."""
- # Start by decorating the message with a header that contains a list
- # of all the rules that matched. These metadata could be None or an
- # empty list.
- rule_hits = msgdata.get('rule_hits')
- if rule_hits:
- msg['X-Mailman-Rule-Hits'] = SEMISPACE.join(rule_hits)
- rule_misses = msgdata.get('rule_misses')
- if rule_misses:
- msg['X-Mailman-Rule-Misses'] = SEMISPACE.join(rule_misses)
- # XXX Exception/reason
- bounce_message(mlist, msg)
- log.info('REJECT: %s', msg.get('message-id', 'n/a'))