------------------------------------------------------------
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

Reply via email to