------------------------------------------------------------
revno: 6699
committer: Barry Warsaw <[email protected]>
branch nick: hacking
timestamp: Tue 2009-03-03 00:31:03 -0500
message:
Convert content filter and acceptable aliases away from pickle types.
* Add an adapter from mailing lists to acceptable alias set. Use this instead
of the old acceptable alias interface, which is not removed.
* Add contentfilter table
* Add a bunch of missing docstrings
added:
src/mailman/database/mime.py
src/mailman/interfaces/mime.py
modified:
src/mailman/core/initialize.py
src/mailman/database/mailinglist.py
src/mailman/database/mailman.sql
src/mailman/interfaces/mailinglist.py
src/mailman/pipeline/docs/filtering.txt
src/mailman/pipeline/mime_delete.py
src/mailman/rules/docs/implicit-dest.txt
src/mailman/rules/implicit_dest.py
src/mailman/styles/default.py
=== modified file 'src/mailman/core/initialize.py'
--- src/mailman/core/initialize.py 2009-02-17 04:57:30 +0000
+++ src/mailman/core/initialize.py 2009-03-03 05:31:03 +0000
@@ -118,6 +118,9 @@
adapter_hooks.append(adapt_domain_to_registrar)
from mailman.database.autorespond import adapt_mailing_list_to_response_set
adapter_hooks.append(adapt_mailing_list_to_response_set)
+ from mailman.database.mailinglist import (
+ adapt_mailing_list_to_acceptable_alias_set)
+ adapter_hooks.append(adapt_mailing_list_to_acceptable_alias_set)
=== modified file 'src/mailman/database/mailinglist.py'
--- src/mailman/database/mailinglist.py 2009-02-23 19:13:32 +0000
+++ src/mailman/database/mailinglist.py 2009-03-03 05:31:03 +0000
@@ -22,6 +22,7 @@
__metaclass__ = type
__all__ = [
'MailingList',
+ 'adapt_mailing_list_to_acceptable_alias_set',
]
@@ -37,10 +38,12 @@
from mailman.config import config
from mailman.database import roster
from mailman.database.digests import OneLastDigest
+from mailman.database.mime import ContentFilter
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces.mailinglist import (
- IAcceptableAlias, IMailingList, Personalization)
+ IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization)
+from mailman.interfaces.mime import FilterType
from mailman.utilities.filesystem import makedirs
from mailman.utilities.string import expand
@@ -92,6 +95,10 @@
autoresponse_postings_text = Unicode()
autorespond_requests = Enum()
autoresponse_request_text = Unicode()
+ # Content filters.
+ filter_content = Bool()
+ collapse_alternatives = Bool()
+ convert_html_to_plaintext = Bool()
# Bounces and bans.
ban_list = Pickle()
bounce_info_stale_after = TimeDelta()
@@ -103,8 +110,6 @@
bounce_unrecognized_goes_to_list_owner = Bool()
bounce_you_are_disabled_warnings = Int()
bounce_you_are_disabled_warnings_interval = TimeDelta()
- collapse_alternatives = Bool()
- convert_html_to_plaintext = Bool()
default_member_moderation = Bool()
description = Unicode()
digest_footer = Unicode()
@@ -117,10 +122,6 @@
discard_these_nonmembers = Pickle()
emergency = Bool()
encode_ascii_prefixes = Bool()
- filter_action = Int()
- filter_content = Bool()
- filter_filename_extensions = Pickle()
- filter_mime_types = Pickle()
first_strip_reply_to = Bool()
forward_auto_discards = Bool()
gateway_to_mail = Bool()
@@ -149,8 +150,6 @@
nondigestable = Bool()
nonmember_rejection_notice = Unicode()
obscure_addresses = Bool()
- pass_filename_extensions = Pickle()
- pass_mime_types = Pickle()
personalize = Enum()
pipeline = Unicode()
post_id = Int()
@@ -230,41 +229,51 @@
@property
def posting_address(self):
+ """See `IMailingList`."""
return self.fqdn_listname
@property
def no_reply_address(self):
+ """See `IMailingList`."""
return '{...@{1}'.format(config.mailman.noreply_address,
self.host_name)
@property
def owner_address(self):
+ """See `IMailingList`."""
return '{0}-ow...@{1}'.format(self.list_name, self.host_name)
@property
def request_address(self):
+ """See `IMailingList`."""
return '{0}-requ...@{1}'.format(self.list_name, self.host_name)
@property
def bounces_address(self):
+ """See `IMailingList`."""
return '{0}-boun...@{1}'.format(self.list_name, self.host_name)
@property
def join_address(self):
+ """See `IMailingList`."""
return '{0}-j...@{1}'.format(self.list_name, self.host_name)
@property
def leave_address(self):
+ """See `IMailingList`."""
return '{0}-le...@{1}'.format(self.list_name, self.host_name)
@property
def subscribe_address(self):
+ """See `IMailingList`."""
return '{0}-subscr...@{1}'.format(self.list_name, self.host_name)
@property
def unsubscribe_address(self):
+ """See `IMailingList`."""
return '{0}-unsubscr...@{1}'.format(self.list_name, self.host_name)
def confirm_address(self, cookie):
+ """See `IMailingList`."""
local_part = expand(config.mta.verp_confirm_format, dict(
address = '{0}-confirm'.format(self.list_name),
cookie = cookie))
@@ -272,10 +281,12 @@
@property
def preferred_language(self):
+ """See `IMailingList`."""
return config.languages[self._preferred_language]
@preferred_language.setter
def preferred_language(self, language):
+ """See `IMailingList`."""
# Accept both a language code and a `Language` instance.
try:
self._preferred_language = language.code
@@ -298,31 +309,109 @@
results.remove()
return recipients
- def clear_acceptable_aliases(self):
- """See `IMailingList`."""
- Store.of(self).find(
- AcceptableAlias,
- AcceptableAlias.mailing_list == self).remove()
-
- def add_acceptable_alias(self, alias):
- if not (alias.startswith('^') or '@' in alias):
- raise ValueError(alias)
- alias = AcceptableAlias(self, alias.lower())
- Store.of(self).add(alias)
-
- def remove_acceptable_alias(self, alias):
- Store.of(self).find(
- AcceptableAlias,
- And(AcceptableAlias.mailing_list == self,
- AcceptableAlias.alias == alias.lower())).remove()
-
- @property
- def acceptable_aliases(self):
- aliases = Store.of(self).find(
- AcceptableAlias,
- AcceptableAlias.mailing_list == self)
- for alias in aliases:
- yield alias.alias
+ @property
+ def filter_types(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_mime))
+ for content_filter in results:
+ yield content_filter.filter_pattern
+
+ @filter_types.setter
+ def filter_types(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing MIME type filter patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_mime))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.filter_mime)
+ store.add(content_filter)
+
+ @property
+ def pass_types(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_mime))
+ for content_filter in results:
+ yield content_filter.filter_pattern
+
+ @pass_types.setter
+ def pass_types(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing MIME type pass patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_mime))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.pass_mime)
+ store.add(content_filter)
+
+ @property
+ def filter_extensions(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_extension))
+ for content_filter in results:
+ yield content_filter.filter_pattern
+
+ @filter_extensions.setter
+ def filter_extensions(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing file extensions filter patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_extension))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.filter_extension)
+ store.add(content_filter)
+
+ @property
+ def pass_extensions(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_extension))
+ for content_filter in results:
+ yield content_filter.pass_pattern
+
+ @pass_extensions.setter
+ def pass_extensions(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing file extensions pass patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_extension))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.pass_extension)
+ store.add(content_filter)
@@ -339,3 +428,52 @@
def __init__(self, mailing_list, alias):
self.mailing_list = mailing_list
self.alias = alias
+
+
+class AcceptableAliasSet:
+ implements(IAcceptableAliasSet)
+
+ def __init__(self, mailing_list):
+ self._mailing_list = mailing_list
+
+ def clear(self):
+ """See `IAcceptableAliasSet`."""
+ Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ AcceptableAlias.mailing_list == self._mailing_list).remove()
+
+ def add(self, alias):
+ if not (alias.startswith('^') or '@' in alias):
+ raise ValueError(alias)
+ alias = AcceptableAlias(self._mailing_list, alias.lower())
+ Store.of(self._mailing_list).add(alias)
+
+ def remove(self, alias):
+ Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ And(AcceptableAlias.mailing_list == self._mailing_list,
+ AcceptableAlias.alias == alias.lower())).remove()
+
+ @property
+ def aliases(self):
+ aliases = Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ AcceptableAlias.mailing_list == self._mailing_list)
+ for alias in aliases:
+ yield alias.alias
+
+
+
+def adapt_mailing_list_to_acceptable_alias_set(iface, obj):
+ """Adapt an `IMailingList` to an `IAcceptableAliasSet`.
+
+ :param iface: The interface to adapt to.
+ :type iface: `zope.interface.Interface`
+ :param obj: The object being adapted.
+ :type obj: `IMailingList`
+ :return: An `IAcceptableAliasSet` instance if adaptation succeeded or None
+ if it didn't.
+ """
+ return (AcceptableAliasSet(obj)
+ if IMailingList.providedBy(obj) and iface is IAcceptableAliasSet
+ else None)
=== modified file 'src/mailman/database/mailman.sql'
--- src/mailman/database/mailman.sql 2009-02-23 19:13:32 +0000
+++ src/mailman/database/mailman.sql 2009-03-03 05:31:03 +0000
@@ -54,6 +54,19 @@
CREATE INDEX ix_autoresponserecord_mailing_list_id
ON autoresponserecord (mailing_list_id);
+CREATE TABLE contentfilter (
+ id INTEGER NOT NULL,
+ mailing_list_id INTEGER,
+ filter_pattern TEXT,
+ filter_type INTEGER,
+ PRIMARY KEY (id),
+ CONSTRAINT contentfilter_mailing_list_id
+ FOREIGN KEY (mailing_list_id)
+ REFERENCES mailinglist (id)
+ );
+CREATE INDEX ix_contentfilter_mailing_list_id
+ ON contentfilter (mailing_list_id);
+
CREATE TABLE language (
id INTEGER NOT NULL,
code TEXT,
@@ -99,6 +112,8 @@
bounce_unrecognized_goes_to_list_owner BOOLEAN,
bounce_you_are_disabled_warnings INTEGER,
bounce_you_are_disabled_warnings_interval TEXT,
+ -- Content filtering.
+ filter_content BOOLEAN,
collapse_alternatives BOOLEAN,
convert_html_to_plaintext BOOLEAN,
default_member_moderation BOOLEAN,
@@ -113,10 +128,6 @@
discard_these_nonmembers BLOB,
emergency BOOLEAN,
encode_ascii_prefixes BOOLEAN,
- filter_action INTEGER,
- filter_content BOOLEAN,
- filter_filename_extensions BLOB,
- filter_mime_types BLOB,
first_strip_reply_to BOOLEAN,
forward_auto_discards BOOLEAN,
gateway_to_mail BOOLEAN,
@@ -145,8 +156,6 @@
nondigestable BOOLEAN,
nonmember_rejection_notice TEXT,
obscure_addresses BOOLEAN,
- pass_filename_extensions BLOB,
- pass_mime_types BLOB,
personalize TEXT,
pipeline TEXT,
post_id INTEGER,
=== added file 'src/mailman/database/mime.py'
--- src/mailman/database/mime.py 1970-01-01 00:00:00 +0000
+++ src/mailman/database/mime.py 2009-03-03 05:31:03 +0000
@@ -0,0 +1,52 @@
+# Copyright (C) 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/>.
+
+"""Module stuff."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'ContentFilter'
+ ]
+
+
+from storm.locals import Bool, Int, Reference, Unicode
+from zope.interface import implements
+
+from mailman.database.model import Model
+from mailman.database.types import Enum
+from mailman.interfaces.mime import IContentFilter
+
+
+
+class ContentFilter(Model):
+ """A single filter criteria."""
+ implements(IContentFilter)
+
+ id = Int(primary=True)
+
+ mailing_list_id = Int()
+ mailing_list = Reference(mailing_list_id, 'MailingList.id')
+
+ filter_type = Enum()
+ filter_pattern = Unicode()
+
+ def __init__(self, mailing_list, filter_pattern, filter_type):
+ self.mailing_list = mailing_list
+ self.filter_pattern = filter_pattern
+ self.filter_type = filter_type
=== modified file 'src/mailman/interfaces/mailinglist.py'
--- src/mailman/interfaces/mailinglist.py 2009-02-23 19:13:32 +0000
+++ src/mailman/interfaces/mailinglist.py 2009-03-03 05:31:03 +0000
@@ -22,6 +22,8 @@
__metaclass__ = type
__all__ = [
'DigestFrequency',
+ 'IAcceptableAlias',
+ 'IAcceptableAliasSet',
'IMailingList',
'Personalization',
'ReplyToMunging',
@@ -281,10 +283,74 @@
that gets created to accumlate messages for the digest.
""")
- def clear_acceptable_aliases():
+ filter_content = Attribute(
+ """Flag specifying whether to filter a message's content.
+
+ Filtering is performed on MIME type and file name extension.
+ """)
+
+ convert_html_to_plaintext = Attribute(
+ """Flag specifying whether text/html parts should be converted.
+
+ When True, after filtering, if there are any text/html parts left in
+ the original message, they are converted to text/plain.
+ """)
+
+ collapse_alternatives = Attribute(
+ """Flag specifying whether multipart/alternatives should be collapsed.
+
+ After all MIME content filtering is complete, collapsing alternatives
+ replaces the outer multipart/alternative parts with the first
+ subpart.
+ """)
+
+ filter_types = Attribute(
+ """Sequence of MIME types that should be filtered out.
+
+ These can be either main types or main/sub types. Set this attribute
+ to a sequence to change it, or to None to empty it.
+ """)
+
+ pass_types = Attribute(
+ """Sequence of MIME types to explicitly pass.
+
+ These can be either main types or main/sub types. Set this attribute
+ to a sequence to change it, or to None to empty it. Pass types are
+ consulted after filter types, and only if `pass_types` is non-empty.
+ """)
+
+ filter_extensions = Attribute(
+ """Sequence of file extensions that should be filtered out.
+
+ Set this attribute to a sequence to change it, or to None to empty it.
+ """)
+
+ pass_extensions = Attribute(
+ """Sequence of file extensions to explicitly pass.
+
+ Set this attribute to a sequence to change it, or to None to empty it.
+ Pass extensions are consulted after filter extensions, and only if
+ `pass_extensions` is non-empty.
+ """)
+
+
+
+
+class IAcceptableAlias(Interface):
+ """An acceptable alias for implicit destinations."""
+
+ mailing_list = Attribute('The associated mailing list.')
+
+ address = Attribute('The address or pattern to match against recipients.')
+
+
+class IAcceptableAliasSet(Interface):
+ """The set of acceptable aliases for a mailing list."""
+
+ def clear():
"""Clear the set of acceptable posting aliases."""
- def add_acceptable_alias(alias):
+ def add(alias):
"""Add the given address as an acceptable aliases for posting.
:param alias: The email address to accept as a recipient for implicit
@@ -296,7 +362,7 @@
'@' sign in it.
"""
- def remove_acceptable_alias(alias):
+ def remove(alias):
"""Remove the given address as an acceptable aliases for posting.
:param alias: The email address to no longer accept as a recipient for
@@ -304,14 +370,5 @@
:type alias: string
"""
- acceptable_aliases = Attribute(
+ aliases = Attribute(
"""An iterator over all the acceptable aliases.""")
-
-
-
-class IAcceptableAlias(Interface):
- """An acceptable alias for implicit destinations."""
-
- mailing_list = Attribute('The associated mailing list.')
-
- address = Attribute('The address or pattern to match against recipients.')
=== added file 'src/mailman/interfaces/mime.py'
--- src/mailman/interfaces/mime.py 1970-01-01 00:00:00 +0000
+++ src/mailman/interfaces/mime.py 2009-03-03 05:31:03 +0000
@@ -0,0 +1,68 @@
+# Copyright (C) 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/>.
+
+"""MIME content filtering."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'FilterAction',
+ 'FilterType',
+ 'IContentFilter',
+ ]
+
+
+from munepy import Enum
+from zope.interface import Interface, Attribute
+
+
+
+class FilterAction(Enum):
+ # Discard a message that matches the content type filter.
+ discard = 0
+ # Bounce the message back to the original author.
+ bounce = 1
+ # Discard and forward the message on to the list owner.
+ forward = 2
+ # Discard, but preserve it.
+ preserve = 3
+
+
+class FilterType(Enum):
+ # Filter MIME type.
+ filter_mime = 0
+ # Pass MIME type.
+ pass_mime = 1
+ # Filter file extension.
+ filter_extension = 2
+ # Pass file extension.
+ pass_extension = 3
+
+
+
+class IContentFilter(Interface):
+ """A single content filter settings for a mailing list."""
+
+ mailing_list = Attribute(
+ """The mailing list for this content filter.""")
+
+ filter_pattern = Attribute(
+ """The filter/pass content pattern.""")
+
+ filter_type = Attribute(
+ """Type of filter.""")
=== modified file 'src/mailman/pipeline/docs/filtering.txt'
--- src/mailman/pipeline/docs/filtering.txt 2008-12-23 04:26:58 +0000
+++ src/mailman/pipeline/docs/filtering.txt 2009-03-03 05:31:03 +0000
@@ -3,12 +3,9 @@
Mailman can filter the content of messages posted to a mailing list by
stripping MIME subparts, and possibly reorganizing the MIME structure of a
-message. It does this with the MimeDel handler module, although other
-handlers can potentially do other kinds of finer level content filtering.
+message.
- >>> from mailman.pipeline.mime_delete import process
- >>> mlist = config.db.list_manager.create(u'[email protected]')
- >>> mlist.preferred_language = u'en'
+ >>> mlist = create_list(u'[email protected]')
Several mailing list options control content filtering. First, the feature
must be enabled, then there are two options that control which MIME types get
@@ -17,8 +14,8 @@
for these variables, then we'll explain them in more detail below.
>>> mlist.filter_content = True
- >>> mlist.filter_mime_types = []
- >>> mlist.pass_mime_types = []
+ >>> mlist.filter_types = []
+ >>> mlist.pass_types = []
>>> mlist.convert_html_to_plaintext = False
@@ -29,9 +26,11 @@
parts, discarding all parts with a matching MIME type. If the message's outer
content type matches the filter, the entire message will be discarded.
- >>> mlist.filter_mime_types = ['image/jpeg']
- >>> # XXX Change this to an enum
- >>> mlist.filter_action = 0 # Discard
+ >>> from mailman.interfaces.mime import FilterAction
+
+ >>> mlist.filter_types = [u'image/jpeg']
+ >>> mlist.filter_action = FilterAction.discard
+
>>> msg = message_from_string("""\
... From: [email protected]
... Content-Type: image/jpeg
@@ -39,6 +38,8 @@
...
... xxxxx
... """)
+
+ >>> process = config.handlers['mime-delete'].process
>>> process(mlist, msg, {})
Traceback (most recent call last):
...
@@ -85,20 +86,21 @@
... From: [email protected]
... Content-Type: multipart/mixed; boundary=BOUNDARY
... MIME-Version: 1.0
- ...
+ ...
... --BOUNDARY
... Content-Type: image/jpeg
... MIME-Version: 1.0
- ...
+ ...
... xxx
- ...
+ ...
... --BOUNDARY
... Content-Type: image/gif
... MIME-Version: 1.0
- ...
+ ...
... yyy
... --BOUNDARY--
... """)
+
>>> process(mlist, msg, {})
>>> print msg.as_string()
From: [email protected]
@@ -136,24 +138,24 @@
... From: [email protected]
... Content-Type: multipart/mixed; boundary=BOUNDARY
... MIME-Version: 1.0
- ...
+ ...
... --BOUNDARY
... Content-Type: multipart/alternative; boundary=BOUND2
... MIME-Version: 1.0
- ...
+ ...
... --BOUND2
... Content-Type: image/jpeg
... MIME-Version: 1.0
- ...
+ ...
... xxx
- ...
+ ...
... --BOUND2
... Content-Type: image/gif
... MIME-Version: 1.0
- ...
+ ...
... yyy
... --BOUND2--
- ...
+ ...
... --BOUNDARY--
... """)
>>> process(mlist, msg, {})
@@ -176,21 +178,22 @@
part's content type. In other words, the left over inner part is promoted to
being the outer part.
- >>> mlist.filter_mime_types.append('text/html')
+ >>> mlist.filter_types = [u'image/jpeg', u'text/html']
>>> msg = message_from_string("""\
... From: [email protected]
... Content-Type: multipart/alternative; boundary=AAA
- ...
+ ...
... --AAA
... Content-Type: text/html
- ...
+ ...
... <b>This is some html</b>
... --AAA
... Content-Type: text/plain
- ...
+ ...
... This is plain text
... --AAA--
... """)
+
>>> process(mlist, msg, {})
>>> print msg.as_string()
From: [email protected]
@@ -201,7 +204,7 @@
Clean up.
- >>> ignore = mlist.filter_mime_types.pop()
+ >>> mlist.filter_types = [u'image/jpeg']
Conversion to plain text
@@ -245,7 +248,7 @@
... From: [email protected]
... Content-Type: text/html
... MIME-Version: 1.0
- ...
+ ...
... <html><head></head>
... <body></body></html>
... """)
@@ -272,39 +275,39 @@
>>> msg = message_from_string("""\
... From: [email protected]
... Content-Type: multipart/mixed; boundary=AAA
- ...
+ ...
... --AAA
... Content-Type: multipart/mixed; boundary=BBB
- ...
+ ...
... --BBB
... Content-Type: image/jpeg
- ...
+ ...
... xxx
... --BBB
... Content-Type: image/jpeg
- ...
+ ...
... yyy
... --BBB---
... --AAA
... Content-Type: multipart/alternative; boundary=CCC
- ...
+ ...
... --CCC
... Content-Type: text/html
- ...
+ ...
... <h2>This is a header</h2>
- ...
+ ...
... --CCC
... Content-Type: text/plain
- ...
+ ...
... A different message
... --CCC--
... --AAA
... Content-Type: image/gif
- ...
+ ...
... zzz
... --AAA
... Content-Type: image/gif
- ...
+ ...
... aaa
... --AAA--
... """)
=== modified file 'src/mailman/pipeline/mime_delete.py'
--- src/mailman/pipeline/mime_delete.py 2009-01-17 02:04:21 +0000
+++ src/mailman/pipeline/mime_delete.py 2009-03-03 05:31:03 +0000
@@ -54,17 +54,12 @@
def process(mlist, msg, msgdata):
- # Short-circuits
- if not mlist.filter_content:
- return
- if msgdata.get('isdigest'):
- return
# We also don't care about our own digests or plaintext
ctype = msg.get_content_type()
mtype = msg.get_content_maintype()
# Check to see if the outer type matches one of the filter types
- filtertypes = mlist.filter_mime_types
- passtypes = mlist.pass_mime_types
+ filtertypes = set(mlist.filter_types)
+ passtypes = set(mlist.pass_types)
if ctype in filtertypes or mtype in filtertypes:
dispose(mlist, msg, msgdata,
_("The message's content type was explicitly disallowed"))
@@ -74,8 +69,8 @@
dispose(mlist, msg, msgdata,
_("The message's content type was not explicitly allowed"))
# Filter by file extensions
- filterexts = mlist.filter_filename_extensions
- passexts = mlist.pass_filename_extensions
+ filterexts = set(mlist.filter_extensions)
+ passexts = set(mlist.pass_extensions)
fext = get_file_ext(msg)
if fext:
if fext in filterexts:
@@ -282,4 +277,9 @@
description = _('Filter the MIME content of messages.')
def process(self, mlist, msg, msgdata):
+ # Short-circuits
+ if not mlist.filter_content:
+ return
+ if msgdata.get('isdigest'):
+ return
process(mlist, msg, msgdata)
=== modified file 'src/mailman/rules/docs/implicit-dest.txt'
--- src/mailman/rules/docs/implicit-dest.txt 2009-02-23 19:13:32 +0000
+++ src/mailman/rules/docs/implicit-dest.txt 2009-03-03 05:31:03 +0000
@@ -9,11 +9,17 @@
>>> print rule.name
implicit-dest
+In order to check for implicit destinations, we need to adapt the mailing list
+to the appropriate interface.
+
+ >>> from mailman.interfaces.mailinglist import IAcceptableAliasSet
+ >>> alias_set = IAcceptableAliasSet(mlist)
+
This rule matches messages that have an implicit destination, meaning that the
mailing list's posting address isn't included in the explicit recipients.
>>> mlist.require_explicit_destination = True
- >>> mlist.clear_acceptable_aliases()
+ >>> alias_set.clear()
>>> msg = message_from_string("""\
... From: [email protected]
@@ -50,7 +56,7 @@
>>> rule.check(mlist, msg, {})
True
- >>> mlist.add_acceptable_alias(u'[email protected]')
+ >>> alias_set.add(u'[email protected]')
>>> rule.check(mlist, msg, {})
False
@@ -63,7 +69,7 @@
Additional aliases can be added.
- >>> mlist.add_acceptable_alias(u'[email protected]')
+ >>> alias_set.add(u'[email protected]')
>>> del msg['to']
>>> rule.check(mlist, msg, {})
True
@@ -74,7 +80,7 @@
Aliases can be removed.
- >>> mlist.remove_acceptable_alias(u'[email protected]')
+ >>> alias_set.remove(u'[email protected]')
>>> rule.check(mlist, msg, {})
True
@@ -84,7 +90,7 @@
>>> rule.check(mlist, msg, {})
False
- >>> mlist.clear_acceptable_aliases()
+ >>> alias_set.clear()
>>> rule.check(mlist, msg, {})
True
@@ -96,7 +102,7 @@
match against the recipients. For example, we can say that if there is a
recipient in the example.net domain, then the rule does not match.
- >>> mlist.add_acceptable_alias(u'^[email protected]')
+ >>> alias_set.add(u'^[email protected]')
>>> rule.check(mlist, msg, {})
True
@@ -111,7 +117,7 @@
You cannot add an alias that looks like neither a pattern nor an email
address.
- >>> mlist.add_acceptable_alias('foobar')
+ >>> alias_set.add('foobar')
Traceback (most recent call last):
...
ValueError: foobar
=== modified file 'src/mailman/rules/implicit_dest.py'
--- src/mailman/rules/implicit_dest.py 2009-02-23 19:13:32 +0000
+++ src/mailman/rules/implicit_dest.py 2009-03-03 05:31:03 +0000
@@ -30,6 +30,7 @@
from zope.interface import implements
from mailman.i18n import _
+from mailman.interfaces.mailinglist import IAcceptableAliasSet
from mailman.interfaces.rules import IRule
@@ -55,7 +56,9 @@
# a caret (i.e. ^), then it's a regular expression to match against.
aliases = set()
alias_patterns = set()
- for alias in mlist.acceptable_aliases:
+ # Adapt the mailing list to the appropriate interface.
+ alias_set = IAcceptableAliasSet(mlist)
+ for alias in alias_set.aliases:
if alias.startswith('^'):
alias_patterns.add(alias)
else:
=== modified file 'src/mailman/styles/default.py'
--- src/mailman/styles/default.py 2009-02-23 19:13:32 +0000
+++ src/mailman/styles/default.py 2009-03-03 05:31:03 +0000
@@ -94,20 +94,7 @@
mlist.preferred_language = 'en'
mlist.include_rfc2369_headers = True
mlist.include_list_post_header = True
- mlist.filter_mime_types = []
- mlist.pass_mime_types = [
- 'multipart/mixed',
- 'multipart/alternative',
- 'text/plain',
- ]
- mlist.filter_filename_extensions = [
- 'exe', 'bat', 'cmd', 'com', 'pif', 'scr', 'vbs', 'cpl',
- ]
- mlist.pass_filename_extensions = []
- mlist.filter_content = False
mlist.collapse_alternatives = True
- mlist.convert_html_to_plaintext = True
- mlist.filter_action = 0
# Digest related variables
mlist.digestable = True
mlist.digest_is_default = False
--
Primary development focus
https://code.launchpad.net/~mailman-coders/mailman/3.0
Your team Mailman Checkins is subscribed to branch lp:mailman.
To unsubscribe from this branch go to
https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org