summaryrefslogtreecommitdiff
path: root/Mailman/rules/implicit_dest.py
diff options
context:
space:
mode:
authorBarry Warsaw2007-12-29 17:02:46 -0500
committerBarry Warsaw2007-12-29 17:02:46 -0500
commit68cce110887cc9fc46fd4c7798f3b8d893f1038f (patch)
tree8bd390bd78a2b22c5be19540eb7d7bee503c478b /Mailman/rules/implicit_dest.py
parent9124e1a17f439314b17206f2ad80f17d7b7971e8 (diff)
downloadmailman-68cce110887cc9fc46fd4c7798f3b8d893f1038f.tar.gz
mailman-68cce110887cc9fc46fd4c7798f3b8d893f1038f.tar.zst
mailman-68cce110887cc9fc46fd4c7798f3b8d893f1038f.zip
Port the implicit destination checking to the rules infrastructure and add a
bunch of doctests. Note that the old Hold Notification tests are temporarily disabled as these will have to be rewritten when the rule matching logic gets added.
Diffstat (limited to 'Mailman/rules/implicit_dest.py')
-rw-r--r--Mailman/rules/implicit_dest.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/Mailman/rules/implicit_dest.py b/Mailman/rules/implicit_dest.py
new file mode 100644
index 000000000..8c9ba8899
--- /dev/null
+++ b/Mailman/rules/implicit_dest.py
@@ -0,0 +1,99 @@
+# Copyright (C) 2007 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.
+
+"""The implicit destination rule."""
+
+__all__ = ['implicit_dest']
+__metaclass__ = type
+
+
+import re
+from email.utils import getaddresses
+from itertools import chain
+from zope.interface import implements
+
+from Mailman.i18n import _
+from Mailman.interfaces import IRule
+
+
+
+class ImplicitDestination:
+ """The implicit destination rule."""
+ implements(IRule)
+
+ name = 'implicit-dest'
+ description = _('Catch messages with implicit destination.')
+
+ def check(self, mlist, msg, msgdata):
+ """See `IRule`."""
+ # Implicit destination checking must be enabled in the mailing list.
+ if not mlist.require_explicit_destination:
+ return False
+ # Messages gated from NNTP will always have an implicit destination so
+ # are never checked.
+ if msgdata.get('fromusenet'):
+ return False
+ # Calculate the list of acceptable aliases. If the alias starts with
+ # a caret (i.e. ^), then it's a regular expression to match against.
+ aliases = set()
+ alias_patterns = set()
+ for alias in mlist.acceptable_aliases.splitlines():
+ alias = alias.strip().lower()
+ if alias.startswith('^'):
+ alias_patterns.add(alias)
+ elif '@' in alias:
+ aliases.add(alias)
+ else:
+ # This is not a regular expression, nor a fully-qualified
+ # email address, so skip it.
+ pass
+ # Add the list's posting address, i.e. the explicit address, to the
+ # set of acceptable aliases.
+ aliases.add(mlist.posting_address)
+ # Look at all the recipients. If the recipient is any acceptable
+ # alias (or the explicit posting address), then this rule does not
+ # match. If not, then add it to the set of recipients we'll check
+ # against the alias patterns later.
+ recipients = set()
+ for header in ('to', 'cc', 'resent-to', 'resent-cc'):
+ for fullname, address in getaddresses(msg.get_all(header, [])):
+ address = address.lower()
+ if address in aliases:
+ return False
+ recipients.add(address)
+ # Now for all alias patterns, see if any of the recipients matches a
+ # pattern. If so, then this rule does not match.
+ for pattern in alias_patterns:
+ escaped = re.escape(pattern)
+ for recipient in recipients:
+ try:
+ if re.match(pattern, recipient, re.IGNORECASE):
+ return False
+ except re.error:
+ # The pattern is a malformed regular expression. Try
+ # matching again with the pattern escaped.
+ try:
+ if re.match(escaped, recipient, re.IGNORECASE):
+ return False
+ except re.error:
+ pass
+ # Nothing matched.
+ return True
+
+
+
+implicit_dest = ImplicitDestination()