summaryrefslogtreecommitdiff
path: root/src/mailman/utilities/importer.py
diff options
context:
space:
mode:
authorBarry Warsaw2015-10-20 22:58:33 -0400
committerBarry Warsaw2015-10-20 22:58:33 -0400
commit724b7cee7ed92a8107733cdef2906ef9c0d69f56 (patch)
tree42e12a19ac1cb1915cbf801b223ce0c4a92a74d7 /src/mailman/utilities/importer.py
parent49d17bc04386293b3f659e24070f618f5f1b3b05 (diff)
parent5104e712380acca2faef5cfd7dc24a3ffc82bfbe (diff)
downloadmailman-724b7cee7ed92a8107733cdef2906ef9c0d69f56.tar.gz
mailman-724b7cee7ed92a8107733cdef2906ef9c0d69f56.tar.zst
mailman-724b7cee7ed92a8107733cdef2906ef9c0d69f56.zip
Mailing lists can now have their own header matching rules, although
site-defined rules still take precedence. Importing a Mailman 2.1 list with header matching rules defined will create them in Mailman 3, albeit with a few unsupported corner cases. Definition of new header matching rules is not yet exposed through the REST API. Given by Aurélien Bompard. Code cleaning pass by Barry Warsaw. Closes !42
Diffstat (limited to 'src/mailman/utilities/importer.py')
-rw-r--r--src/mailman/utilities/importer.py71
1 files changed, 70 insertions, 1 deletions
diff --git a/src/mailman/utilities/importer.py b/src/mailman/utilities/importer.py
index 293e9c39c..a15eac7f9 100644
--- a/src/mailman/utilities/importer.py
+++ b/src/mailman/utilities/importer.py
@@ -24,8 +24,10 @@ __all__ = [
import os
+import re
import sys
import codecs
+import logging
import datetime
from mailman.config import config
@@ -39,7 +41,7 @@ from mailman.interfaces.bans import IBanManager
from mailman.interfaces.bounce import UnrecognizedBounceDisposition
from mailman.interfaces.digests import DigestFrequency
from mailman.interfaces.languages import ILanguageManager
-from mailman.interfaces.mailinglist import IAcceptableAliasSet
+from mailman.interfaces.mailinglist import IAcceptableAliasSet, IHeaderMatchSet
from mailman.interfaces.mailinglist import Personalization, ReplyToMunging
from mailman.interfaces.mailinglist import SubscriptionPolicy
from mailman.interfaces.member import DeliveryMode, DeliveryStatus, MemberRole
@@ -51,6 +53,8 @@ from sqlalchemy import Boolean
from urllib.error import URLError
from zope.component import getUtility
+log = logging.getLogger('mailman.error')
+
class Import21Error(MailmanError):
@@ -124,6 +128,24 @@ def nonmember_action_mapping(value):
3: Action.discard,
}[value]
+
+def action_to_chain(value):
+ # Converts an action number in Mailman 2.1 to the name of the corresponding
+ # chain in 3.x. The actions 'approve', 'subscribe' and 'unsubscribe' are
+ # ignored. The defer action is converted to None, because it is not
+ # a jump to a terminal chain.
+ return {
+ 0: None,
+ #1: 'approve',
+ 2: 'reject',
+ 3: 'discard',
+ #4: 'subscribe',
+ #5: 'unsubscribe',
+ 6: 'accept',
+ 7: 'hold',
+ }[value]
+
+
def check_language_code(code):
if code is None:
@@ -310,6 +332,53 @@ def import_config_pck(mlist, config_dict):
# When .add() rejects this, the line probably contains a regular
# expression. Make that explicit for MM3.
alias_set.add('^' + address)
+ # Handle header_filter_rules conversion to header_matches.
+ header_match_set = IHeaderMatchSet(mlist)
+ header_filter_rules = config_dict.get('header_filter_rules', [])
+ for line_patterns, action, _unused in header_filter_rules:
+ try:
+ chain = action_to_chain(action)
+ except KeyError:
+ log.warning('Unsupported header_filter_rules action: %r',
+ action)
+ continue
+ # Now split the line into a header and a pattern.
+ for line_pattern in line_patterns.splitlines():
+ if len(line_pattern.strip()) == 0:
+ continue
+ for sep in (': ', ':.', ':'):
+ header, sep, pattern = line_pattern.partition(sep)
+ if sep:
+ # We found it.
+ break
+ else:
+ # Matches any header, which is not supported. XXX
+ log.warning('Unsupported header_filter_rules pattern: %r',
+ line_pattern)
+ continue
+ header = header.strip().lstrip('^').lower()
+ header = header.replace('\\', '')
+ if not header:
+ log.warning(
+ 'Cannot parse the header in header_filter_rule: %r',
+ line_pattern)
+ continue
+ if len(pattern) == 0:
+ # The line matched only the header, therefore the header can
+ # be anything.
+ pattern = '.*'
+ try:
+ re.compile(pattern)
+ except re.error:
+ log.warning('Skipping header_filter rule because of an '
+ 'invalid regular expression: %r', line_pattern)
+ continue
+ try:
+ header_match_set.add(header, pattern, chain)
+ except ValueError:
+ log.warning('Skipping duplicate header_filter rule: %r',
+ line_pattern)
+ continue
# Handle conversion to URIs. In MM2.1, the decorations are strings
# containing placeholders, and there's no provision for language-specific
# templates. In MM3, template locations are specified by URLs with the