summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildout.cfg2
-rw-r--r--mailman/Mailbox.py3
-rw-r--r--mailman/Message.py48
-rw-r--r--mailman/Utils.py6
-rw-r--r--mailman/app/lifecycle.py3
-rw-r--r--mailman/app/notifications.py6
-rw-r--r--mailman/app/replybot.py6
-rw-r--r--mailman/attic/Defaults.py (renamed from mailman/Defaults.py)0
-rw-r--r--mailman/bin/master.py8
-rw-r--r--mailman/config/__init__.py6
-rw-r--r--mailman/config/config.py9
-rw-r--r--mailman/config/mailman.cfg2
-rw-r--r--mailman/config/schema.cfg218
-rw-r--r--mailman/database/mailinglist.py6
-rw-r--r--mailman/database/pending.py4
-rw-r--r--mailman/pipeline/cleanse_dkim.py8
-rw-r--r--mailman/pipeline/scrubber.py13
-rw-r--r--mailman/pipeline/smtp_direct.py16
-rw-r--r--mailman/pipeline/to_digest.py14
-rw-r--r--mailman/pipeline/to_outgoing.py10
-rw-r--r--mailman/queue/__init__.py2
-rw-r--r--mailman/styles/__init__.py0
-rw-r--r--mailman/styles/default.py (renamed from mailman/core/styles.py)220
-rw-r--r--mailman/testing/layers.py7
-rw-r--r--setup.py1
25 files changed, 391 insertions, 227 deletions
diff --git a/buildout.cfg b/buildout.cfg
index d345bf142..f502d24e9 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -5,7 +5,7 @@ parts =
test
unzip = true
# bzr branch lp:~barry/lazr.config/megamerge
-develop = . /home/barry/projects/lazr/megamerge
+develop = . /Users/barry/projects/lazr/megamerge
[interpreter]
recipe = zc.recipe.egg
diff --git a/mailman/Mailbox.py b/mailman/Mailbox.py
index a56aeab05..d5902023a 100644
--- a/mailman/Mailbox.py
+++ b/mailman/Mailbox.py
@@ -25,7 +25,6 @@ import mailbox
from email.Errors import MessageParseError
from email.Generator import Generator
-from mailman import Defaults
from mailman.Message import Message
@@ -90,7 +89,7 @@ class ArchiverMailbox(Mailbox):
# scrub() method, giving the scrubber module a chance to do its thing
# before the message is archived.
def __init__(self, fp, mlist):
- scrubber_module = Defaults.ARCHIVE_SCRUBBER
+ scrubber_module = config.scrubber.archive_scrubber
if scrubber_module:
__import__(scrubber_module)
self._scrubber = sys.modules[scrubber_module].process
diff --git a/mailman/Message.py b/mailman/Message.py
index 5ca763b30..ac41a758c 100644
--- a/mailman/Message.py
+++ b/mailman/Message.py
@@ -17,8 +17,8 @@
"""Standard Mailman message object.
-This is a subclass of mimeo.Message but provides a slightly extended interface
-which is more convenient for use inside Mailman.
+This is a subclass of email.message.Message but provides a slightly extended
+interface which is more convenient for use inside Mailman.
"""
import re
@@ -28,15 +28,15 @@ import email.utils
from email.charset import Charset
from email.header import Header
+from lazr.config import as_boolean
-from mailman import Defaults
from mailman import Utils
from mailman.config import config
COMMASPACE = ', '
mo = re.match(r'([\d.]+)', email.__version__)
-VERSION = tuple([int(s) for s in mo.group().split('.')])
+VERSION = tuple(int(s) for s in mo.group().split('.'))
@@ -111,7 +111,7 @@ class Message(email.message.Message):
self._headers = headers
# I think this method ought to eventually be deprecated
- def get_sender(self, use_envelope=None, preserve_case=0):
+ def get_sender(self):
"""Return the address considered to be the author of the email.
This can return either the From: header, the Sender: header or the
@@ -124,20 +124,13 @@ class Message(email.message.Message):
- Otherwise, the search order is From:, Sender:, unixfrom
- The optional argument use_envelope, if given overrides the
- config.mailman.use_envelope_sender setting. It should be set to
- either True or False (don't use None since that indicates
- no-override).
-
unixfrom should never be empty. The return address is always
- lowercased, unless preserve_case is true.
+ lower cased.
This method differs from get_senders() in that it returns one and only
one address, and uses a different search order.
"""
- senderfirst = config.mailman.use_envelope_sender
- if use_envelope is not None:
- senderfirst = use_envelope
+ senderfirst = as_boolean(config.mailman.use_envelope_sender)
if senderfirst:
headers = ('sender', 'from')
else:
@@ -166,46 +159,41 @@ class Message(email.message.Message):
else:
# TBD: now what?!
address = ''
- if not preserve_case:
- return address.lower()
- return address
+ return address.lower()
- def get_senders(self, preserve_case=0, headers=None):
+ def get_senders(self):
"""Return a list of addresses representing the author of the email.
The list will contain the following addresses (in order)
depending on availability:
1. From:
- 2. unixfrom
+ 2. unixfrom (From_)
3. Reply-To:
4. Sender:
- The return addresses are always lower cased, unless `preserve_case' is
- true. Optional `headers' gives an alternative search order, with None
- meaning, search the unixfrom header. Items in `headers' are field
- names without the trailing colon.
+ The return addresses are always lower cased.
"""
- if headers is None:
- headers = Defaults.SENDER_HEADERS
pairs = []
- for h in headers:
- if h is None:
+ for header in config.mailman.sender_headers.split():
+ header = header.lower()
+ if header == 'from_':
# get_unixfrom() returns None if there's no envelope
- fieldval = self.get_unixfrom() or ''
+ unix_from = self.get_unixfrom()
+ fieldval = (unix_from if unix_from is not None else '')
try:
pairs.append(('', fieldval.split()[1]))
except IndexError:
# Ignore badly formatted unixfroms
pass
else:
- fieldvals = self.get_all(h)
+ fieldvals = self.get_all(header)
if fieldvals:
pairs.extend(email.utils.getaddresses(fieldvals))
authors = []
for pair in pairs:
address = pair[1]
- if address is not None and not preserve_case:
+ if address is not None:
address = address.lower()
authors.append(address)
return authors
diff --git a/mailman/Utils.py b/mailman/Utils.py
index 56f186a17..31848d5c8 100644
--- a/mailman/Utils.py
+++ b/mailman/Utils.py
@@ -35,11 +35,11 @@ import email.Header
import email.Iterators
from email.Errors import HeaderParseError
+from lazr.config import as_boolean
from string import ascii_letters, digits, whitespace, Template
import mailman.templates
-from mailman import Defaults
from mailman import passwords
from mailman.config import config
from mailman.core import errors
@@ -318,8 +318,8 @@ def Secure_MakeRandomPassword(length):
def MakeRandomPassword(length=None):
if length is None:
- length = Defaults.MEMBER_PASSWORD_LENGTH
- if Defaults.USER_FRIENDLY_PASSWORDS:
+ length = int(config.member_password_length)
+ if as_boolean(config.user_friendly_passwords):
password = UserFriendly_MakeRandomPassword(length)
else:
password = Secure_MakeRandomPassword(length)
diff --git a/mailman/app/lifecycle.py b/mailman/app/lifecycle.py
index e0d895650..7ea50a055 100644
--- a/mailman/app/lifecycle.py
+++ b/mailman/app/lifecycle.py
@@ -33,7 +33,6 @@ from mailman import Utils
from mailman.Utils import ValidateEmail
from mailman.config import config
from mailman.core import errors
-from mailman.core.styles import style_manager
from mailman.interfaces.member import MemberRole
@@ -50,7 +49,7 @@ def create_list(fqdn_listname, owners=None):
if domain not in config.domains:
raise errors.BadDomainSpecificationError(domain)
mlist = config.db.list_manager.create(fqdn_listname)
- for style in style_manager.lookup(mlist):
+ for style in config.style_manager.lookup(mlist):
style.apply(mlist)
# Coordinate with the MTA, as defined in the configuration file.
module_name, class_name = config.mta.incoming.rsplit('.', 1)
diff --git a/mailman/app/notifications.py b/mailman/app/notifications.py
index 62c9964c0..5d4b4572d 100644
--- a/mailman/app/notifications.py
+++ b/mailman/app/notifications.py
@@ -26,8 +26,8 @@ __all__ = [
from email.utils import formataddr
+from lazr.config import as_boolean
-from mailman import Defaults
from mailman import Message
from mailman import Utils
from mailman import i18n
@@ -79,7 +79,7 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
_('Welcome to the "$mlist.real_name" mailing list${digmode}'),
text, language)
msg['X-No-Archive'] = 'yes'
- msg.send(mlist, verp=Defaults.VERP_PERSONALIZED_DELIVERIES)
+ msg.send(mlist, verp=as_boolean(config.mta.verp_personalized_deliveries))
@@ -104,7 +104,7 @@ def send_goodbye_message(mlist, address, language):
address, mlist.bounces_address,
_('You have been unsubscribed from the $mlist.real_name mailing list'),
goodbye, language)
- msg.send(mlist, verp=Defaults.VERP_PERSONALIZED_DELIVERIES)
+ msg.send(mlist, verp=as_boolean(config.mta.verp_personalized_deliveries))
diff --git a/mailman/app/replybot.py b/mailman/app/replybot.py
index 0a8cdd5b7..ba357e18b 100644
--- a/mailman/app/replybot.py
+++ b/mailman/app/replybot.py
@@ -29,7 +29,6 @@ __all__ = [
import logging
import datetime
-from mailman import Defaults
from mailman import Utils
from mailman import i18n
@@ -48,7 +47,8 @@ def autorespond_to_sender(mlist, sender, lang=None):
"""
if lang is None:
lang = mlist.preferred_language
- if Defaults.MAX_AUTORESPONSES_PER_DAY == 0:
+ max_autoresponses_per_day = int(config.mta.max_autoresponses_per_day)
+ if max_autoresponses_per_day == 0:
# Unlimited.
return True
today = datetime.date.today()
@@ -64,7 +64,7 @@ def autorespond_to_sender(mlist, sender, lang=None):
# them of this fact, so there's nothing more to do.
log.info('-request/hold autoresponse discarded for: %s', sender)
return False
- if count >= Defaults.MAX_AUTORESPONSES_PER_DAY:
+ if count >= max_autoresponses_per_day:
log.info('-request/hold autoresponse limit hit for: %s', sender)
mlist.hold_and_cmd_autoresponses[sender] = (today, -1)
# Send this notification message instead.
diff --git a/mailman/Defaults.py b/mailman/attic/Defaults.py
index 6f72ed535..6f72ed535 100644
--- a/mailman/Defaults.py
+++ b/mailman/attic/Defaults.py
diff --git a/mailman/bin/master.py b/mailman/bin/master.py
index d3676629d..d954bc865 100644
--- a/mailman/bin/master.py
+++ b/mailman/bin/master.py
@@ -36,7 +36,6 @@ from lazr.config import as_boolean
from locknix import lockfile
from munepy import Enum
-from mailman import Defaults
from mailman.config import config
from mailman.core.logging import reopen
from mailman.i18n import _
@@ -44,7 +43,8 @@ from mailman.options import Options
DOT = '.'
-LOCK_LIFETIME = Defaults.days(1) + Defaults.hours(6)
+LOCK_LIFETIME = timedelta(days=1, hours=6)
+SECONDS_IN_A_DAY = 86400
@@ -233,9 +233,9 @@ class Loop:
# so this should be plenty.
def sigalrm_handler(signum, frame):
self._lock.refresh()
- signal.alarm(int(Defaults.days(1)))
+ signal.alarm(SECONDS_IN_A_DAY)
signal.signal(signal.SIGALRM, sigalrm_handler)
- signal.alarm(int(Defaults.days(1)))
+ signal.alarm(SECONDS_IN_A_DAY)
# SIGHUP tells the qrunners to close and reopen their log files.
def sighup_handler(signum, frame):
reopen()
diff --git a/mailman/config/__init__.py b/mailman/config/__init__.py
index 6ac060cb2..0611fc154 100644
--- a/mailman/config/__init__.py
+++ b/mailman/config/__init__.py
@@ -15,6 +15,12 @@
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+__metaclass__ = type
+__all__ = [
+ 'config',
+ ]
+
+
from mailman.config.config import Configuration
config = Configuration()
diff --git a/mailman/config/config.py b/mailman/config/config.py
index cbdea2aea..349202338 100644
--- a/mailman/config/config.py
+++ b/mailman/config/config.py
@@ -32,11 +32,11 @@ from StringIO import StringIO
from lazr.config import ConfigSchema, as_boolean
from pkg_resources import resource_string
-from mailman import Defaults
from mailman import version
from mailman.core import errors
from mailman.domain import Domain
from mailman.languages import LanguageManager
+from mailman.styles.manager import StyleManager
SPACE = ' '
@@ -149,6 +149,7 @@ class Configuration(object):
# Always enable the server default language, which must be defined.
self.languages.enable_language(self._config.mailman.default_language)
self.ensure_directories_exist()
+ self.style_manager = StyleManager()
@property
def logger_configs(self):
@@ -189,6 +190,12 @@ class Configuration(object):
yield getattr(sys.modules[module_name], class_name)()
@property
+ def style_configs(self):
+ """Iterate over all the style configuration sections."""
+ for section in self._config.getByCategory('style', []):
+ yield section
+
+ @property
def header_matches(self):
"""Iterate over all spam matching headers.
diff --git a/mailman/config/mailman.cfg b/mailman/config/mailman.cfg
index d88947975..2bf528bea 100644
--- a/mailman/config/mailman.cfg
+++ b/mailman/config/mailman.cfg
@@ -65,3 +65,5 @@ start: no
[qrunner.virgin]
class: mailman.queue.virgin.VirginRunner
+
+[style.default]
diff --git a/mailman/config/schema.cfg b/mailman/config/schema.cfg
index 47cf03eeb..654bbaabc 100644
--- a/mailman/config/schema.cfg
+++ b/mailman/config/schema.cfg
@@ -54,9 +54,37 @@ default_language: en
# spoofed messages may get through.
use_envelope_sender: no
+# Membership tests for posting purposes are usually performed by looking at a
+# set of headers, passing the test if any of their values match a member of
+# the list. Headers are checked in the order given in this variable. The
+# value From_ means to use the envelope sender. Field names are case
+# insensitive. This is a space separate list of headers.
+sender_headers: from from_ reply-to sender
+
# Mail command processor will ignore mail command lines after designated max.
email_commands_max_lines: 10
+# Default length of time a pending request is live before it is evicted from
+# the pending database.
+pending_request_life: 3d
+
+
+[passwords]
+# When Mailman generates them, this is the default length of member passwords.
+member_password_length: 8
+
+# Specify the type of passwords to use, when Mailman generates the passwords
+# itself, as would be the case for membership requests where the user did not
+# fill in a password, or during list creation, when auto-generation of admin
+# passwords was selected.
+#
+# Set this value to 'yes' for classic Mailman user-friendly(er) passwords.
+# These generate semi-pronounceable passwords which are easier to remember.
+# Set this value to 'no' to use more cryptographically secure, but harder to
+# remember, passwords -- if your operating system and Python version support
+# the necessary feature (specifically that /dev/urandom be available).
+user_friendly_passwords: yes
+
[qrunner.master]
# Define which process queue runners, and how many of them, to start.
@@ -248,6 +276,118 @@ smtp_port: 25
lmtp_host: localhost
lmtp_port: 8025
+# Ceiling on the number of recipients that can be specified in a single SMTP
+# transaction. Set to 0 to submit the entire recipient list in one
+# transaction.
+max_recipients: 500
+
+# Ceiling on the number of SMTP sessions to perform on a single socket
+# connection. Some MTAs have limits. Set this to 0 to do as many as we like
+# (i.e. your MTA has no limits). Set this to some number great than 0 and
+# Mailman will close the SMTP connection and re-open it after this number of
+# consecutive sessions.
+max_sessions_per_connection: 0
+
+# Maximum number of simultaneous subthreads that will be used for SMTP
+# delivery. After the recipients list is chunked according to max_recipients,
+# each chunk is handed off to the SMTP server by a separate such thread. If
+# your Python interpreter was not built for threads, this feature is disabled.
+# You can explicitly disable it in all cases by setting max_delivery_threads
+# to 0.
+max_delivery_threads: 0
+
+# These variables control the format and frequency of VERP-like delivery for
+# better bounce detection. VERP is Variable Envelope Return Path, defined
+# here:
+#
+# http://cr.yp.to/proto/verp.txt
+#
+# This involves encoding the address of the recipient as we (Mailman) know it
+# into the envelope sender address (i.e. the SMTP `MAIL FROM:' address).
+# Thus, no matter what kind of forwarding the recipient has in place, should
+# it eventually bounce, we will receive an unambiguous notice of the bouncing
+# address.
+#
+# However, we're technically only "VERP-like" because we're doing the envelope
+# sender encoding in Mailman, not in the MTA. We do require cooperation from
+# the MTA, so you must be sure your MTA can be configured for extended address
+# semantics.
+#
+# The first variable describes how to encode VERP envelopes. It must contain
+# these three string interpolations:
+#
+# $bounces -- the list-bounces mailbox will be set here
+# $mailbox -- the recipient's mailbox will be set here
+# $host -- the recipient's host name will be set here
+#
+# This example uses the default below.
+#
+# FQDN list address is: mylist@dom.ain
+# Recipient is: aperson@a.nother.dom
+#
+# The envelope sender will be mylist-bounces+aperson=a.nother.dom@dom.ain
+#
+# Note that your MTA /must/ be configured to deliver such an addressed message
+# to mylist-bounces!
+verp_delimiter: +
+verp_format: ${bounces}+${mailbox}=${host}
+
+# For nicer confirmation emails, use a VERP-like format which encodes the
+# confirmation cookie in the reply address. This lets us put a more user
+# friendly Subject: on the message, but requires cooperation from the MTA.
+# Format is like verp_format, but with the following substitutions:
+#
+# $address -- the list-confirm address
+# $cookie -- the confirmation cookie
+verp_confirm_format: $address+$cookie
+
+# This is analogous to verp_regexp, but for splitting apart the
+# verp_confirm_format. MUAs have been observed that mung
+#
+# From: local_part@host
+#
+# into
+#
+# To: "local_part" <local_part@host>
+#
+# when replying, so we skip everything up to '<' if any.
+verp_confirm_regexp: ^(.*<)?(?P<addr>[^+]+?)\+(?P<cookie>[^@]+)@.*$
+
+# Set this to 'yes' to enable VERP-like (more user friendly) confirmations.
+verp_confirmations: no
+
+# Another good opportunity is when regular delivery is personalized. Here
+# again, we're already incurring the performance hit for addressing each
+# individual recipient. Set this to 'yes' to enable VERPs on all personalized
+# regular deliveries (personalized digests aren't supported yet).
+verp_personalized_deliveries: no
+
+# And finally, we can VERP normal, non-personalized deliveries. However,
+# because it can be a significant performance hit, we allow you to decide how
+# often to VERP regular deliveries. This is the interval, in number of
+# messages, to do a VERP recipient address. The same variable controls both
+# regular and digest deliveries. Set to 0 to disable occasional VERPs, set to
+# 1 to VERP every delivery, or to some number > 1 for only occasional VERPs.
+verp_delivery_interval: 0
+
+# This is the maximum number of automatic responses sent to an address because
+# of -request messages or posting hold messages. This limit prevents response
+# loops between Mailman and misconfigured remote email robots. Mailman
+# already inhibits automatic replies to any message labeled with a header
+# "Precendence: bulk|list|junk". This is a fallback safety valve so it should
+# be set fairly high. Set to 0 for no limit (probably useful only for
+# debugging).
+max_autoresponses_per_day: 10
+
+# Some list posts and mail to the -owner address may contain DomainKey or
+# DomainKeys Identified Mail (DKIM) signature headers <http://www.dkim.org/>.
+# Various list transformations to the message such as adding a list header or
+# footer or scrubbing attachments or even reply-to munging can break these
+# signatures. It is generally felt that these signatures have value, even if
+# broken and even if the outgoing message is resigned. However, some sites
+# may wish to remove these headers by setting this to 'yes'.
+remove_dkim_headers: no
+
[archiver.master]
# To add new archivers, define a new section based on this one, overriding the
@@ -287,3 +427,81 @@ class: mailman.archiving.pipermail.Pipermail
[archiver.prototype]
# This is a prototypical sample archiver.
class: mailman.archiving.prototype.Prototype
+
+
+[style.master]
+# The style's priority, with 0 being the lowest priority.
+priority: 0
+
+# The class implementing the IStyle interface, which applies the style.
+class: mailman.styles.default.DefaultStyle
+
+
+[scrubber]
+# A filter module that converts from multipart messages to "flat" messages
+# (i.e. containing a single payload). This is required for Pipermail, and you
+# may want to set it to 0 for external archivers. You can also replace it
+# with your own module as long as it contains a process() function that takes
+# a MailList object and a Message object. It should raise
+# Errors.DiscardMessage if it wants to throw the message away. Otherwise it
+# should modify the Message object as necessary.
+archive_scrubber: mailman.pipeline.scrubber
+
+# This variable defines what happens to text/html subparts. They can be
+# stripped completely, escaped, or filtered through an external program. The
+# legal values are:
+# 0 - Strip out text/html parts completely, leaving a notice of the removal in
+# the message. If the outer part is text/html, the entire message is
+# discarded.
+# 1 - Remove any embedded text/html parts, leaving them as HTML-escaped
+# attachments which can be separately viewed. Outer text/html parts are
+# simply HTML-escaped.
+# 2 - Leave it inline, but HTML-escape it
+# 3 - Remove text/html as attachments but don't HTML-escape them. Note: this
+# is very dangerous because it essentially means anybody can send an HTML
+# email to your site containing evil JavaScript or web bugs, or other
+# nasty things, and folks viewing your archives will be susceptible. You
+# should only consider this option if you do heavy moderation of your list
+# postings.
+#
+# Note: given the current archiving code, it is not possible to leave
+# text/html parts inline and un-escaped. I wouldn't think it'd be a good idea
+# to do anyway.
+#
+# The value can also be a string, in which case it is the name of a command to
+# filter the HTML page through. The resulting output is left in an attachment
+# or as the entirety of the message when the outer part is text/html. The
+# format of the string must include a $filename substitution variable which
+# will contain the name of the temporary file that the program should operate
+# on. It should write the processed message to stdout. Set this to
+# HTML_TO_PLAIN_TEXT_COMMAND to specify an HTML to plain text conversion
+# program.
+archive_html_sanitizer: 1
+
+# Control parameter whether the scrubber should use the message attachment's
+# filename as is indicated by the filename parameter or use 'attachement-xxx'
+# instead. The default is set 'no' because the applications on PC and Mac
+# begin to use longer non-ascii filenames.
+use_attachment_filename: no
+
+# Use of attachment filename extension per se is may be dangerous because
+# viruses fakes it. You can set this 'yes' if you filter the attachment by
+# filename extension.
+use_attachment_filename_extension: no
+
+
+[digests]
+# Headers which should be kept in both RFC 1153 (plain) and MIME digests. RFC
+# 1153 also specifies these headers in this exact order, so order matters.
+# These are space separated and case insensitive.
+mime_digest_keep_headers:
+ Date From To Cc Subject Message-ID Keywords
+ In-Reply-To References Content-Type MIME-Version
+ Content-Transfer-Encoding Precedence Reply-To
+ Message
+
+plain_digest_keep_headers:
+ Message Date From
+ Subject To Cc
+ Message-ID Keywords
+ Content-Type
diff --git a/mailman/database/mailinglist.py b/mailman/database/mailinglist.py
index eac8ad05d..56caea296 100644
--- a/mailman/database/mailinglist.py
+++ b/mailman/database/mailinglist.py
@@ -22,7 +22,6 @@ from storm.locals import *
from urlparse import urljoin
from zope.interface import implements
-from mailman import Defaults
from mailman.Utils import fqdn_listname, makedirs, split_listname
from mailman.config import config
from mailman.database import roster
@@ -206,8 +205,7 @@ class MailingList(Model):
domain = config.domains[self.host_name]
# XXX Handle the case for when context is not None; those would be
# relative URLs.
- return urljoin(domain.base_url,
- target + Defaults.CGIEXT + '/' + self.fqdn_listname)
+ return urljoin(domain.base_url, target + '/' + self.fqdn_listname)
@property
def data_path(self):
@@ -253,7 +251,7 @@ class MailingList(Model):
return '%s-unsubscribe@%s' % (self.list_name, self.host_name)
def confirm_address(self, cookie):
- template = string.Template(Defaults.VERP_CONFIRM_FORMAT)
+ template = string.Template(config.mta.verp_confirm_format)
local_part = template.safe_substitute(
address = '%s-confirm' % self.list_name,
cookie = cookie)
diff --git a/mailman/database/pending.py b/mailman/database/pending.py
index 07e594253..6fe66f5fd 100644
--- a/mailman/database/pending.py
+++ b/mailman/database/pending.py
@@ -29,11 +29,11 @@ import random
import hashlib
import datetime
+from lazr.config import as_timedelta
from storm.locals import *
from zope.interface import implements
from zope.interface.verify import verifyObject
-from mailman import Defaults
from mailman.config import config
from mailman.database.model import Model
from mailman.interfaces.pending import (
@@ -87,7 +87,7 @@ class Pendings:
verifyObject(IPendable, pendable)
# Calculate the token and the lifetime.
if lifetime is None:
- lifetime = Defaults.PENDING_REQUEST_LIFE
+ lifetime = as_timedelta(config.pending_request_life)
# Calculate a unique token. Algorithm vetted by the Timbot. time()
# has high resolution on Linux, clock() on Windows. random gives us
# about 45 bits in Python 2.2, 53 bits on Python 2.3. The time and
diff --git a/mailman/pipeline/cleanse_dkim.py b/mailman/pipeline/cleanse_dkim.py
index bd7de83dc..d4d8f38ae 100644
--- a/mailman/pipeline/cleanse_dkim.py
+++ b/mailman/pipeline/cleanse_dkim.py
@@ -26,12 +26,14 @@ originating at the Mailman server for the outgoing message.
"""
__metaclass__ = type
-__all__ = ['CleanseDKIM']
+__all__ = [
+ 'CleanseDKIM',
+ ]
+from lazr.config import as_boolean
from zope.interface import implements
-from mailman import Defaults
from mailman.i18n import _
from mailman.interfaces.handler import IHandler
@@ -47,7 +49,7 @@ class CleanseDKIM:
def process(self, mlist, msg, msgdata):
"""See `IHandler`."""
- if Defaults.REMOVE_DKIM_HEADERS:
+ if as_boolean(config.mta.remove_dkim_headers):
del msg['domainkey-signature']
del msg['dkim-signature']
del msg['authentication-results']
diff --git a/mailman/pipeline/scrubber.py b/mailman/pipeline/scrubber.py
index 7431cec27..f7ffd51e1 100644
--- a/mailman/pipeline/scrubber.py
+++ b/mailman/pipeline/scrubber.py
@@ -34,11 +34,12 @@ import binascii
from email.charset import Charset
from email.generator import Generator
from email.utils import make_msgid, parsedate
+from lazr.config import as_boolean
from locknix.lockfile import Lock
from mimetypes import guess_all_extensions
+from string import Template
from zope.interface import implements
-from mailman import Defaults
from mailman import Utils
from mailman.config import config
from mailman.core.errors import DiscardMessage
@@ -159,7 +160,7 @@ def replace_payload_by_text(msg, text, charset):
def process(mlist, msg, msgdata=None):
- sanitize = Defaults.ARCHIVE_HTML_SANITIZER
+ sanitize = int(config.scrubber.archive_html_sanitizer)
outer = True
if msgdata is None:
msgdata = {}
@@ -410,7 +411,7 @@ def save_attachment(mlist, msg, dir, filter_html=True):
filename, fnext = os.path.splitext(filename)
# For safety, we should confirm this is valid ext for content-type
# but we can use fnext if we introduce fnext filtering
- if Defaults.SCRUBBER_USE_ATTACHMENT_FILENAME_EXTENSION:
+ if as_boolean(config.scrubber.use_attachment_filename_extension):
# HTML message doesn't have filename :-(
ext = fnext or guess_extension(ctype, fnext)
else:
@@ -431,7 +432,8 @@ def save_attachment(mlist, msg, dir, filter_html=True):
with Lock(os.path.join(fsdir, 'attachments.lock')):
# Now base the filename on what's in the attachment, uniquifying it if
# necessary.
- if not filename or Defaults.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME:
+ if (not filename or
+ not as_boolean(config.scrubber.use_attachment_filename)):
filebase = 'attachment'
else:
# Sanitize the filename given in the message headers
@@ -476,7 +478,8 @@ def save_attachment(mlist, msg, dir, filter_html=True):
try:
fp.write(decodedpayload)
fp.close()
- cmd = Defaults.ARCHIVE_HTML_SANITIZER % {'filename' : tmppath}
+ cmd = Template(config.mta.archive_html_sanitizer).safe_substitue(
+ filename=tmppath)
progfp = os.popen(cmd, 'r')
decodedpayload = progfp.read()
status = progfp.close()
diff --git a/mailman/pipeline/smtp_direct.py b/mailman/pipeline/smtp_direct.py
index 09b2223d6..b82fb9227 100644
--- a/mailman/pipeline/smtp_direct.py
+++ b/mailman/pipeline/smtp_direct.py
@@ -44,7 +44,6 @@ from email.Utils import formataddr
from string import Template
from zope.interface import implements
-from mailman import Defaults
from mailman import Utils
from mailman.config import config
from mailman.core import errors
@@ -70,7 +69,7 @@ class Connection:
port = int(config.mta.smtp_port)
log.debug('Connecting to %s:%s', host, port)
self.__conn.connect(host, port)
- self.__numsessions = Defaults.SMTP_MAX_SESSIONS_PER_CONNECTION
+ self.__numsessions = int(config.mta.max_sessions_per_connection)
def sendmail(self, envsender, recips, msgtext):
if self.__conn is None:
@@ -126,10 +125,10 @@ def process(mlist, msg, msgdata):
chunks = [[recip] for recip in recips]
msgdata['personalize'] = 1
deliveryfunc = verpdeliver
- elif Defaults.SMTP_MAX_RCPTS <= 0:
+ elif int(config.mta.max_recipients) <= 0:
chunks = [recips]
else:
- chunks = chunkify(recips, Defaults.SMTP_MAX_RCPTS)
+ chunks = chunkify(recips, int(config.mta.max_recipients))
# See if this is an unshunted message for which some were undelivered
if msgdata.has_key('undelivered'):
chunks = msgdata['undelivered']
@@ -316,12 +315,9 @@ def verpdeliver(mlist, msg, msgdata, envsender, failures, conn):
# this recipient.
log.info('Skipping VERP delivery to unqual recip: %s', recip)
continue
- d = {'bounces': bmailbox,
- 'mailbox': rmailbox,
- 'host' : DOT.join(rdomain),
- }
- envsender = '%s@%s' % ((Defaults.VERP_FORMAT % d),
- DOT.join(bdomain))
+ envsender = Template(config.mta.verp_format).safe_substitute(
+ bounces=bmailbox, mailbox=rmailbox,
+ host=DOT.join(rdomain)) + '@' + DOT.join(bdomain)
if mlist.personalize == Personalization.full:
# When fully personalizing, we want the To address to point to the
# recipient, not to the mailing list
diff --git a/mailman/pipeline/to_digest.py b/mailman/pipeline/to_digest.py
index d71bc71b0..e56c4a109 100644
--- a/mailman/pipeline/to_digest.py
+++ b/mailman/pipeline/to_digest.py
@@ -48,7 +48,6 @@ from email.parser import Parser
from email.utils import formatdate, getaddresses, make_msgid
from zope.interface import implements
-from mailman import Defaults
from mailman import Message
from mailman import Utils
from mailman import i18n
@@ -268,11 +267,10 @@ def send_i18n_digests(mlist, mboxfp):
# headers according to RFC 1153. Later, we'll strip out headers for
# for the specific MIME or plain digests.
keeper = {}
- all_keepers = {}
- for header in (Defaults.MIME_DIGEST_KEEP_HEADERS +
- Defaults.PLAIN_DIGEST_KEEP_HEADERS):
- all_keepers[header] = True
- all_keepers = all_keepers.keys()
+ all_keepers = set(
+ header for header in
+ config.digests.mime_digest_keep_headers.split() +
+ config.digests.plain_digest_keep_headers.split())
for keep in all_keepers:
keeper[keep] = msg.get_all(keep, [])
# Now remove all unkempt headers :)
@@ -283,7 +281,7 @@ def send_i18n_digests(mlist, mboxfp):
for field in keeper[keep]:
msg[keep] = field
# And a bit of extra stuff
- msg['Message'] = `msgcount`
+ msg['Message'] = repr(msgcount)
# Get the next message in the digest mailbox
msg = mbox.next()
# Now we're finished with all the messages in the digest. First do some
@@ -326,7 +324,7 @@ def send_i18n_digests(mlist, mboxfp):
print >> plainmsg, _('[Message discarded by content filter]')
continue
# Honor the default setting
- for h in Defaults.PLAIN_DIGEST_KEEP_HEADERS:
+ for h in config.digests.plain_digest_keep_headers.split():
if msg[h]:
uh = Utils.wrap('%s: %s' % (h, Utils.oneline(msg[h],
in_unicode=True)))
diff --git a/mailman/pipeline/to_outgoing.py b/mailman/pipeline/to_outgoing.py
index 7d56686b7..9ff7ab88a 100644
--- a/mailman/pipeline/to_outgoing.py
+++ b/mailman/pipeline/to_outgoing.py
@@ -23,12 +23,14 @@ recipient should just be placed in the out queue directly.
"""
__metaclass__ = type
-__all__ = ['ToOutgoing']
+__all__ = [
+ 'ToOutgoing',
+ ]
+from lazr.config import as_boolean
from zope.interface import implements
-from mailman import Defaults
from mailman.config import config
from mailman.i18n import _
from mailman.interfaces.handler import IHandler
@@ -46,7 +48,7 @@ class ToOutgoing:
def process(self, mlist, msg, msgdata):
"""See `IHandler`."""
- interval = Defaults.VERP_DELIVERY_INTERVAL
+ interval = int(config.mta.verp_delivery_interval)
# Should we VERP this message? If personalization is enabled for this
# list and VERP_PERSONALIZED_DELIVERIES is true, then yes we VERP it.
# Also, if personalization is /not/ enabled, but
@@ -58,7 +60,7 @@ class ToOutgoing:
if 'verp' in msgdata:
pass
elif mlist.personalize <> Personalization.none:
- if Defaults.VERP_PERSONALIZED_DELIVERIES:
+ if as_boolean(config.mta.verp_personalized_deliveries):
msgdata['verp'] = True
elif interval == 0:
# Never VERP
diff --git a/mailman/queue/__init__.py b/mailman/queue/__init__.py
index 65e31f6f3..e6d39ee1b 100644
--- a/mailman/queue/__init__.py
+++ b/mailman/queue/__init__.py
@@ -298,7 +298,7 @@ class Runner:
# sleep_time is a timedelta; turn it into a float for time.sleep().
self.sleep_float = (86400 * self.sleep_time.days +
self.sleep_time.seconds +
- self.sleep_time.microseconds / 1000000.0)
+ self.sleep_time.microseconds / 1.0e6)
self.max_restarts = int(section.max_restarts)
self.start = as_boolean(section.start)
self._stop = False
diff --git a/mailman/styles/__init__.py b/mailman/styles/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/mailman/styles/__init__.py
diff --git a/mailman/core/styles.py b/mailman/styles/default.py
index b375a743c..76b697296 100644
--- a/mailman/core/styles.py
+++ b/mailman/styles/default.py
@@ -20,25 +20,19 @@
__metaclass__ = type
__all__ = [
'DefaultStyle',
- 'style_manager',
]
# XXX Styles need to be reconciled with lazr.config.
import datetime
-from operator import attrgetter
from zope.interface import implements
-from zope.interface.verify import verifyObject
-from mailman import Defaults
from mailman import Utils
-from mailman.core.plugins import get_plugins
from mailman.i18n import _
from mailman.interfaces import Action, NewsModeration
-from mailman.interfaces.mailinglist import Personalization
-from mailman.interfaces.styles import (
- DuplicateStyleError, IStyle, IStyleManager)
+from mailman.interfaces.mailinglist import Personalization, ReplyToMunging
+from mailman.interfaces.styles import IStyle
@@ -57,77 +51,84 @@ class DefaultStyle:
# Most of these were ripped from the old MailList.InitVars() method.
mlist.volume = 1
mlist.post_id = 1
- mlist.new_member_options = Defaults.DEFAULT_NEW_MEMBER_OPTIONS
+ mlist.new_member_options = 256
# This stuff is configurable
mlist.real_name = mlist.list_name.capitalize()
mlist.respond_to_post_requests = True
- mlist.advertised = Defaults.DEFAULT_LIST_ADVERTISED
- mlist.max_num_recipients = Defaults.DEFAULT_MAX_NUM_RECIPIENTS
- mlist.max_message_size = Defaults.DEFAULT_MAX_MESSAGE_SIZE
- mlist.reply_goes_to_list = Defaults.DEFAULT_REPLY_GOES_TO_LIST
+ mlist.advertised = True
+ mlist.max_num_recipients = 10
+ mlist.max_message_size = 40 # KB
+ mlist.reply_goes_to_list = ReplyToMunging.no_munging
mlist.reply_to_address = u''
- mlist.first_strip_reply_to = Defaults.DEFAULT_FIRST_STRIP_REPLY_TO
- mlist.admin_immed_notify = Defaults.DEFAULT_ADMIN_IMMED_NOTIFY
- mlist.admin_notify_mchanges = (
- Defaults.DEFAULT_ADMIN_NOTIFY_MCHANGES)
- mlist.require_explicit_destination = (
- Defaults.DEFAULT_REQUIRE_EXPLICIT_DESTINATION)
- mlist.acceptable_aliases = Defaults.DEFAULT_ACCEPTABLE_ALIASES
- mlist.send_reminders = Defaults.DEFAULT_SEND_REMINDERS
- mlist.send_welcome_msg = Defaults.DEFAULT_SEND_WELCOME_MSG
- mlist.send_goodbye_msg = Defaults.DEFAULT_SEND_GOODBYE_MSG
- mlist.bounce_matching_headers = (
- Defaults.DEFAULT_BOUNCE_MATCHING_HEADERS)
+ mlist.first_strip_reply_to = False
+ mlist.admin_immed_notify = True
+ mlist.admin_notify_mchanges = False
+ mlist.require_explicit_destination = True
+ mlist.acceptable_aliases = u''
+ mlist.send_reminders = True
+ mlist.send_welcome_msg = True
+ mlist.send_goodbye_msg = True
+ mlist.bounce_matching_headers = u"""
+# Lines that *start* with a '#' are comments.
+to: friend@public.com
+message-id: relay.comanche.denmark.eu
+from: list@listme.com
+from: .*@uplinkpro.com
+"""
mlist.header_matches = []
- mlist.anonymous_list = Defaults.DEFAULT_ANONYMOUS_LIST
+ mlist.anonymous_list = False
mlist.description = u''
mlist.info = u''
mlist.welcome_msg = u''
mlist.goodbye_msg = u''
- mlist.subscribe_policy = Defaults.DEFAULT_SUBSCRIBE_POLICY
- mlist.subscribe_auto_approval = (
- Defaults.DEFAULT_SUBSCRIBE_AUTO_APPROVAL)
- mlist.unsubscribe_policy = Defaults.DEFAULT_UNSUBSCRIBE_POLICY
- mlist.private_roster = Defaults.DEFAULT_PRIVATE_ROSTER
- mlist.obscure_addresses = Defaults.DEFAULT_OBSCURE_ADDRESSES
- mlist.admin_member_chunksize = Defaults.DEFAULT_ADMIN_MEMBER_CHUNKSIZE
- mlist.administrivia = Defaults.DEFAULT_ADMINISTRIVIA
- mlist.preferred_language = Defaults.DEFAULT_SERVER_LANGUAGE
+ mlist.subscribe_policy = 1
+ mlist.subscribe_auto_approval = []
+ mlist.unsubscribe_policy = 0
+ mlist.private_roster = 1
+ mlist.obscure_addresses = True
+ mlist.admin_member_chunksize = 30
+ mlist.administrivia = True
+ mlist.preferred_language = u'en'
mlist.include_rfc2369_headers = True
mlist.include_list_post_header = True
- mlist.filter_mime_types = Defaults.DEFAULT_FILTER_MIME_TYPES
- mlist.pass_mime_types = Defaults.DEFAULT_PASS_MIME_TYPES
- mlist.filter_filename_extensions = (
- Defaults.DEFAULT_FILTER_FILENAME_EXTENSIONS)
- mlist.pass_filename_extensions = (
- Defaults.DEFAULT_PASS_FILENAME_EXTENSIONS)
- mlist.filter_content = Defaults.DEFAULT_FILTER_CONTENT
- mlist.collapse_alternatives = Defaults.DEFAULT_COLLAPSE_ALTERNATIVES
- mlist.convert_html_to_plaintext = (
- Defaults.DEFAULT_CONVERT_HTML_TO_PLAINTEXT)
- mlist.filter_action = Defaults.DEFAULT_FILTER_ACTION
+ 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 = Defaults.DEFAULT_DIGESTABLE
- mlist.digest_is_default = Defaults.DEFAULT_DIGEST_IS_DEFAULT
- mlist.mime_is_default_digest = Defaults.DEFAULT_MIME_IS_DEFAULT_DIGEST
- mlist.digest_size_threshold = Defaults.DEFAULT_DIGEST_SIZE_THRESHOLD
- mlist.digest_send_periodic = Defaults.DEFAULT_DIGEST_SEND_PERIODIC
- mlist.digest_header = Defaults.DEFAULT_DIGEST_HEADER
- mlist.digest_footer = Defaults.DEFAULT_DIGEST_FOOTER
- mlist.digest_volume_frequency = (
- Defaults.DEFAULT_DIGEST_VOLUME_FREQUENCY)
+ mlist.digestable = True
+ mlist.digest_is_default = False
+ mlist.mime_is_default_digest = False
+ mlist.digest_size_threshold = 30 # KB
+ mlist.digest_send_periodic = True
+ mlist.digest_header = u''
+ mlist.digest_footer = u"""\
+_______________________________________________
+$real_name mailing list
+$fqdn_listname
+${listinfo_page}
+"""
+ mlist.digest_volume_frequency = 1
mlist.one_last_digest = {}
mlist.next_digest_number = 1
- mlist.nondigestable = Defaults.DEFAULT_NONDIGESTABLE
+ mlist.nondigestable = True
mlist.personalize = Personalization.none
# New sender-centric moderation (privacy) options
- mlist.default_member_moderation = (
- Defaults.DEFAULT_DEFAULT_MEMBER_MODERATION)
+ mlist.default_member_moderation = False
# Archiver
- mlist.archive = Defaults.DEFAULT_ARCHIVE
- mlist.archive_private = Defaults.DEFAULT_ARCHIVE_PRIVATE
- mlist.archive_volume_frequency = (
- Defaults.DEFAULT_ARCHIVE_VOLUME_FREQUENCY)
+ mlist.archive = True
+ mlist.archive_private = 0
+ mlist.archive_volume_frequency = 1
mlist.emergency = False
mlist.member_moderation_action = Action.hold
mlist.member_moderation_notice = u''
@@ -135,9 +136,8 @@ class DefaultStyle:
mlist.hold_these_nonmembers = []
mlist.reject_these_nonmembers = []
mlist.discard_these_nonmembers = []
- mlist.forward_auto_discards = Defaults.DEFAULT_FORWARD_AUTO_DISCARDS
- mlist.generic_nonmember_action = (
- Defaults.DEFAULT_GENERIC_NONMEMBER_ACTION)
+ mlist.forward_auto_discards = True
+ mlist.generic_nonmember_action = 1
mlist.nonmember_rejection_notice = u''
# Ban lists
mlist.ban_list = []
@@ -145,9 +145,14 @@ class DefaultStyle:
# 2-tuple of the date of the last autoresponse and the number of
# autoresponses sent on that date.
mlist.hold_and_cmd_autoresponses = {}
- mlist.subject_prefix = _(Defaults.DEFAULT_SUBJECT_PREFIX)
- mlist.msg_header = Defaults.DEFAULT_MSG_HEADER
- mlist.msg_footer = Defaults.DEFAULT_MSG_FOOTER
+ mlist.subject_prefix = _(u'[$mlist.real_name] ')
+ mlist.msg_header = u''
+ mlist.msg_footer = u"""\
+_______________________________________________
+$real_name mailing list
+$fqdn_listname
+${listinfo_page}
+"""
# Set this to Never if the list's preferred language uses us-ascii,
# otherwise set it to As Needed
if Utils.GetCharSet(mlist.preferred_language) == 'us-ascii':
@@ -155,9 +160,9 @@ class DefaultStyle:
else:
mlist.encode_ascii_prefixes = 2
# scrub regular delivery
- mlist.scrub_nondigest = Defaults.DEFAULT_SCRUB_NONDIGEST
+ mlist.scrub_nondigest = False
# automatic discarding
- mlist.max_days_to_hold = Defaults.DEFAULT_MAX_DAYS_TO_HOLD
+ mlist.max_days_to_hold = 0
# Autoresponder
mlist.autorespond_postings = False
mlist.autorespond_admin = False
@@ -174,20 +179,15 @@ class DefaultStyle:
mlist.admin_responses = {}
mlist.request_responses = {}
# Bounces
- mlist.bounce_processing = Defaults.DEFAULT_BOUNCE_PROCESSING
- mlist.bounce_score_threshold = Defaults.DEFAULT_BOUNCE_SCORE_THRESHOLD
- mlist.bounce_info_stale_after = (
- Defaults.DEFAULT_BOUNCE_INFO_STALE_AFTER)
- mlist.bounce_you_are_disabled_warnings = (
- Defaults.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS)
+ mlist.bounce_processing = True
+ mlist.bounce_score_threshold = 5.0
+ mlist.bounce_info_stale_after = datetime.timedelta(days=7)
+ mlist.bounce_you_are_disabled_warnings = 3
mlist.bounce_you_are_disabled_warnings_interval = (
- Defaults.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS_INTERVAL)
- mlist.bounce_unrecognized_goes_to_list_owner = (
- Defaults.DEFAULT_BOUNCE_UNRECOGNIZED_GOES_TO_LIST_OWNER)
- mlist.bounce_notify_owner_on_disable = (
- Defaults.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_DISABLE)
- mlist.bounce_notify_owner_on_removal = (
- Defaults.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_REMOVAL)
+ datetime.timedelta(days=7))
+ mlist.bounce_unrecognized_goes_to_list_owner = True
+ mlist.bounce_notify_owner_on_disable = True
+ mlist.bounce_notify_owner_on_removal = True
# This holds legacy member related information. It's keyed by the
# member address, and the value is an object containing the bounce
# score, the date of the last received bounce, and a count of the
@@ -196,7 +196,7 @@ class DefaultStyle:
# New style delivery status
mlist.delivery_status = {}
# NNTP gateway
- mlist.nntp_host = Defaults.DEFAULT_NNTP_HOST
+ mlist.nntp_host = u''
mlist.linked_newsgroup = u''
mlist.gateway_to_news = False
mlist.gateway_to_mail = False
@@ -246,55 +246,3 @@ class DefaultStyle:
# If no other styles have matched, then the default style matches.
if len(styles) == 0:
styles.append(self)
-
-
-
-class StyleManager:
- """The built-in style manager."""
-
- implements(IStyleManager)
-
- def __init__(self):
- """Install all styles from registered plugins, and install them."""
- self._styles = {}
- # Install all the styles provided by plugins.
- for style_factory in get_plugins('mailman.styles'):
- style = style_factory()
- # Let DuplicateStyleErrors percolate up.
- self.register(style)
-
- def get(self, name):
- """See `IStyleManager`."""
- return self._styles.get(name)
-
- def lookup(self, mailing_list):
- """See `IStyleManager`."""
- matched_styles = []
- for style in self.styles:
- style.match(mailing_list, matched_styles)
- for style in matched_styles:
- yield style
-
- @property
- def styles(self):
- """See `IStyleManager`."""
- for style in sorted(self._styles.values(),
- key=attrgetter('priority'),
- reverse=True):
- yield style
-
- def register(self, style):
- """See `IStyleManager`."""
- verifyObject(IStyle, style)
- if style.name in self._styles:
- raise DuplicateStyleError(style.name)
- self._styles[style.name] = style
-
- def unregister(self, style):
- """See `IStyleManager`."""
- # Let KeyErrors percolate up.
- del self._styles[style.name]
-
-
-
-style_manager = StyleManager()
diff --git a/mailman/testing/layers.py b/mailman/testing/layers.py
index ef4535038..c9b99cab9 100644
--- a/mailman/testing/layers.py
+++ b/mailman/testing/layers.py
@@ -37,7 +37,6 @@ from textwrap import dedent
from mailman.config import config
from mailman.core import initialize
from mailman.core.logging import get_handler
-from mailman.core.styles import style_manager
from mailman.i18n import _
from mailman.testing.helpers import SMTPServer
@@ -139,7 +138,7 @@ class ConfigLayer:
def testSetUp(cls):
# Record the current (default) set of styles so that we can reset them
# easily in the tear down.
- cls.styles = set(style_manager.styles)
+ cls.styles = set(config.style_manager.styles)
@classmethod
def testTearDown(cls):
@@ -154,9 +153,9 @@ class ConfigLayer:
config.db.message_store.delete_message(message['message-id'])
config.db.commit()
# Reset the global style manager.
- new_styles = set(style_manager.styles) - cls.styles
+ new_styles = set(config.style_manager.styles) - cls.styles
for style in new_styles:
- style_manager.unregister(style)
+ config.style_manager.unregister(style)
cls.styles = None
# Flag to indicate that loggers should propagate to the console.
diff --git a/setup.py b/setup.py
index adefd459c..117528b7e 100644
--- a/setup.py
+++ b/setup.py
@@ -95,7 +95,6 @@ case second `m'. Any other spelling is incorrect.""",
'mailman.handlers' : 'default = mailman.pipeline:initialize',
'mailman.rules' : 'default = mailman.rules:initialize',
'mailman.scrubber' : 'stock = mailman.archiving.pipermail:Pipermail',
- 'mailman.styles' : 'default = mailman.core.styles:DefaultStyle',
},
install_requires = [
'lazr.config',