diff options
| author | Barry Warsaw | 2015-10-20 22:58:33 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2015-10-20 22:58:33 -0400 |
| commit | 724b7cee7ed92a8107733cdef2906ef9c0d69f56 (patch) | |
| tree | 42e12a19ac1cb1915cbf801b223ce0c4a92a74d7 /src/mailman/utilities/importer.py | |
| parent | 49d17bc04386293b3f659e24070f618f5f1b3b05 (diff) | |
| parent | 5104e712380acca2faef5cfd7dc24a3ffc82bfbe (diff) | |
| download | mailman-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.py | 71 |
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 |
