summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildout.cfg3
-rw-r--r--mailman/Archiver/Archiver.py2
-rw-r--r--mailman/Archiver/HyperArch.py12
-rw-r--r--mailman/Mailbox.py2
-rw-r--r--mailman/Message.py2
-rw-r--r--mailman/Utils.py2
-rw-r--r--mailman/app/commands.py2
-rw-r--r--mailman/app/lifecycle.py2
-rw-r--r--mailman/app/membership.py2
-rw-r--r--mailman/app/moderator.py2
-rw-r--r--mailman/app/notifications.py2
-rw-r--r--mailman/app/registrar.py2
-rw-r--r--mailman/app/replybot.py2
-rw-r--r--mailman/archiving/__init__.py2
-rw-r--r--mailman/archiving/mailarchive.py2
-rw-r--r--mailman/archiving/mhonarc.py2
-rw-r--r--mailman/archiving/pipermail.py2
-rw-r--r--mailman/archiving/prototype.py2
-rw-r--r--mailman/bin/master.py6
-rw-r--r--mailman/bin/withlist.py4
-rw-r--r--mailman/chains/accept.py2
-rw-r--r--mailman/chains/base.py2
-rw-r--r--mailman/chains/builtin.py2
-rw-r--r--mailman/chains/headers.py4
-rw-r--r--mailman/chains/hold.py2
-rw-r--r--mailman/commands/cmd_confirm.py2
-rw-r--r--mailman/commands/cmd_help.py2
-rw-r--r--mailman/commands/cmd_lists.py2
-rw-r--r--mailman/commands/cmd_password.py2
-rw-r--r--mailman/commands/cmd_set.py2
-rw-r--r--mailman/commands/cmd_who.py2
-rw-r--r--mailman/commands/join.py2
-rw-r--r--mailman/config/__init__.py20
-rw-r--r--mailman/config/config.py202
-rw-r--r--mailman/config/helpers.py61
-rw-r--r--mailman/config/schema.cfg235
-rw-r--r--mailman/configuration.py248
-rw-r--r--mailman/core/chains.py4
-rw-r--r--mailman/core/initialize.py (renamed from mailman/initialize.py)12
-rw-r--r--mailman/core/logging.py109
-rw-r--r--mailman/core/pipelines.py2
-rw-r--r--mailman/core/rules.py2
-rw-r--r--mailman/core/styles.py2
-rw-r--r--mailman/database/__init__.py10
-rw-r--r--mailman/database/address.py2
-rw-r--r--mailman/database/listmanager.py2
-rw-r--r--mailman/database/mailinglist.py2
-rw-r--r--mailman/database/member.py2
-rw-r--r--mailman/database/message.py2
-rw-r--r--mailman/database/messagestore.py2
-rw-r--r--mailman/database/pending.py2
-rw-r--r--mailman/database/requests.py2
-rw-r--r--mailman/database/roster.py2
-rw-r--r--mailman/database/user.py2
-rw-r--r--mailman/database/usermanager.py2
-rw-r--r--mailman/i18n.py2
-rw-r--r--mailman/loginit.py183
-rw-r--r--mailman/options.py6
-rw-r--r--mailman/pipeline/acknowledge.py2
-rw-r--r--mailman/pipeline/avoid_duplicates.py2
-rw-r--r--mailman/pipeline/calculate_recipients.py2
-rw-r--r--mailman/pipeline/cleanse_dkim.py2
-rw-r--r--mailman/pipeline/cook_headers.py2
-rw-r--r--mailman/pipeline/decorate.py2
-rw-r--r--mailman/pipeline/mime_delete.py2
-rw-r--r--mailman/pipeline/moderate.py2
-rw-r--r--mailman/pipeline/scrubber.py2
-rw-r--r--mailman/pipeline/smtp_direct.py109
-rw-r--r--mailman/pipeline/to_archive.py2
-rw-r--r--mailman/pipeline/to_digest.py2
-rw-r--r--mailman/pipeline/to_outgoing.py2
-rw-r--r--mailman/pipeline/to_usenet.py2
-rw-r--r--mailman/queue/__init__.py2
-rw-r--r--mailman/rules/administrivia.py6
-rw-r--r--mailman/testing/helpers.py2
-rw-r--r--mailman/tests/test_documentation.py2
-rw-r--r--mailman/tests/test_membership.py2
-rw-r--r--mailman/tests/test_security_mgr.py2
-rw-r--r--setup.py1
79 files changed, 767 insertions, 588 deletions
diff --git a/buildout.cfg b/buildout.cfg
index eec2173e5..8c03f89d3 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -24,5 +24,6 @@ eggs = mailman
[test]
recipe = zc.recipe.testrunner
-eggs = mailman
+eggs =
+ mailman
defaults = '--tests-pattern ^tests --exit-with-status'.split()
diff --git a/mailman/Archiver/Archiver.py b/mailman/Archiver/Archiver.py
index 313bd9a0a..261dfe206 100644
--- a/mailman/Archiver/Archiver.py
+++ b/mailman/Archiver/Archiver.py
@@ -34,7 +34,7 @@ from string import Template
from mailman import Mailbox
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
log = logging.getLogger('mailman.error')
diff --git a/mailman/Archiver/HyperArch.py b/mailman/Archiver/HyperArch.py
index 11fd32cf1..0395f6482 100644
--- a/mailman/Archiver/HyperArch.py
+++ b/mailman/Archiver/HyperArch.py
@@ -29,6 +29,7 @@
import os
import re
import sys
+import gzip
import time
import errno
import urllib
@@ -47,20 +48,13 @@ from mailman import i18n
from mailman.Archiver import HyperDatabase
from mailman.Archiver import pipermail
from mailman.Mailbox import ArchiverMailbox
-from mailman.configuration import config
+from mailman.config import config
log = logging.getLogger('mailman.error')
# Set up i18n. Assume the current language has already been set in the caller.
_ = i18n._
-gzip = None
-if config.GZIP_ARCHIVE_TXT_FILES:
- try:
- import gzip
- except ImportError:
- pass
-
EMPTYSTRING = ''
NL = '\n'
@@ -239,7 +233,7 @@ class Article(pipermail.Article):
_last_article_time = time.time()
def __init__(self, message=None, sequence=0, keepHeaders=[],
- lang=config.DEFAULT_SERVER_LANGUAGE, mlist=None):
+ lang=config.mailman.default_language, mlist=None):
self.__super_init(message, sequence, keepHeaders)
self.prev = None
self.next = None
diff --git a/mailman/Mailbox.py b/mailman/Mailbox.py
index afbfb8166..cbc38585a 100644
--- a/mailman/Mailbox.py
+++ b/mailman/Mailbox.py
@@ -27,7 +27,7 @@ from email.Generator import Generator
from email.Parser import Parser
from mailman.Message import Message
-from mailman.configuration import config
+from mailman.config import config
diff --git a/mailman/Message.py b/mailman/Message.py
index f4f939568..e78678dc4 100644
--- a/mailman/Message.py
+++ b/mailman/Message.py
@@ -30,7 +30,7 @@ from email.charset import Charset
from email.header import Header
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
COMMASPACE = ', '
diff --git a/mailman/Utils.py b/mailman/Utils.py
index 607c457d9..d7c193799 100644
--- a/mailman/Utils.py
+++ b/mailman/Utils.py
@@ -41,7 +41,7 @@ from string import ascii_letters, digits, whitespace, Template
import mailman.templates
from mailman import passwords
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
AT = '@'
diff --git a/mailman/app/commands.py b/mailman/app/commands.py
index 6ff6fdf0a..1782e46fe 100644
--- a/mailman/app/commands.py
+++ b/mailman/app/commands.py
@@ -23,7 +23,7 @@ __all__ = [
]
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.interfaces import IEmailCommand
diff --git a/mailman/app/lifecycle.py b/mailman/app/lifecycle.py
index b707fdbbd..6cd3219d0 100644
--- a/mailman/app/lifecycle.py
+++ b/mailman/app/lifecycle.py
@@ -31,7 +31,7 @@ import logging
from mailman import Utils
from mailman.Utils import ValidateEmail
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.core.plugins import get_plugin
from mailman.core.styles import style_manager
diff --git a/mailman/app/membership.py b/mailman/app/membership.py
index ae14b3f25..150c2c999 100644
--- a/mailman/app/membership.py
+++ b/mailman/app/membership.py
@@ -30,7 +30,7 @@ from mailman import Message
from mailman import Utils
from mailman import i18n
from mailman.app.notifications import send_goodbye_message
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.interfaces import AlreadySubscribedError, DeliveryMode, MemberRole
diff --git a/mailman/app/moderator.py b/mailman/app/moderator.py
index 9cce5aa8a..a678f3734 100644
--- a/mailman/app/moderator.py
+++ b/mailman/app/moderator.py
@@ -37,7 +37,7 @@ from mailman import i18n
from mailman.app.membership import add_member, delete_member
from mailman.app.notifications import (
send_admin_subscription_notice, send_welcome_message)
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.interfaces import Action, DeliveryMode, RequestType
from mailman.interfaces.member import AlreadySubscribedError
diff --git a/mailman/app/notifications.py b/mailman/app/notifications.py
index 41180de7d..d3546ee83 100644
--- a/mailman/app/notifications.py
+++ b/mailman/app/notifications.py
@@ -30,7 +30,7 @@ from email.utils import formataddr
from mailman import Message
from mailman import Utils
from mailman import i18n
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces.member import DeliveryMode
_ = i18n._
diff --git a/mailman/app/registrar.py b/mailman/app/registrar.py
index 320086ec7..491eb43af 100644
--- a/mailman/app/registrar.py
+++ b/mailman/app/registrar.py
@@ -31,7 +31,7 @@ from zope.interface import implements
from mailman.Message import UserNotification
from mailman.Utils import ValidateEmail
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IDomain, IPendable, IRegistrar
from mailman.interfaces.member import MemberRole
diff --git a/mailman/app/replybot.py b/mailman/app/replybot.py
index 483f3f3cf..394a93aaa 100644
--- a/mailman/app/replybot.py
+++ b/mailman/app/replybot.py
@@ -31,7 +31,7 @@ import datetime
from mailman import Utils
from mailman import i18n
-from mailman.configuration import config
+from mailman.config import config
log = logging.getLogger('mailman.vette')
diff --git a/mailman/archiving/__init__.py b/mailman/archiving/__init__.py
index 41dff720c..290eb3631 100644
--- a/mailman/archiving/__init__.py
+++ b/mailman/archiving/__init__.py
@@ -21,7 +21,7 @@ __all__ = [
]
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
diff --git a/mailman/archiving/mailarchive.py b/mailman/archiving/mailarchive.py
index 30e721fc6..3edeb8c39 100644
--- a/mailman/archiving/mailarchive.py
+++ b/mailman/archiving/mailarchive.py
@@ -30,7 +30,7 @@ from urllib import quote
from urlparse import urljoin
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver
from mailman.queue import Switchboard
diff --git a/mailman/archiving/mhonarc.py b/mailman/archiving/mhonarc.py
index 7f31a6fb1..3d17ffd13 100644
--- a/mailman/archiving/mhonarc.py
+++ b/mailman/archiving/mhonarc.py
@@ -32,7 +32,7 @@ from string import Template
from urlparse import urljoin
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver
diff --git a/mailman/archiving/pipermail.py b/mailman/archiving/pipermail.py
index df16e6e98..f42f064ed 100644
--- a/mailman/archiving/pipermail.py
+++ b/mailman/archiving/pipermail.py
@@ -30,7 +30,7 @@ from string import Template
from zope.interface import implements
from zope.interface.interface import adapter_hooks
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver, IPipermailMailingList
from mailman.interfaces.mailinglist import IMailingList
diff --git a/mailman/archiving/prototype.py b/mailman/archiving/prototype.py
index 5e86a606f..7691c1c13 100644
--- a/mailman/archiving/prototype.py
+++ b/mailman/archiving/prototype.py
@@ -29,7 +29,7 @@ from base64 import b32encode
from urlparse import urljoin
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver
diff --git a/mailman/bin/master.py b/mailman/bin/master.py
index 1c45e04f8..39f119725 100644
--- a/mailman/bin/master.py
+++ b/mailman/bin/master.py
@@ -36,8 +36,8 @@ from locknix import lockfile
from munepy import Enum
from mailman import Defaults
-from mailman import loginit
-from mailman.configuration import config
+from mailman.config import config
+from mailman.core.logging import reopen
from mailman.i18n import _
from mailman.options import Options
@@ -237,7 +237,7 @@ class Loop:
signal.alarm(int(Defaults.days(1)))
# SIGHUP tells the qrunners to close and reopen their log files.
def sighup_handler(signum, frame):
- loginit.reopen()
+ reopen()
for pid in self._kids:
os.kill(pid, signal.SIGHUP)
log.info('Master watcher caught SIGHUP. Re-opening log files.')
diff --git a/mailman/bin/withlist.py b/mailman/bin/withlist.py
index 32bfb1206..51c3ba9d5 100644
--- a/mailman/bin/withlist.py
+++ b/mailman/bin/withlist.py
@@ -20,9 +20,9 @@ import sys
import optparse
from mailman import interact
-from mailman.configuration import config
+from mailman.config import config
+from mailman.core.initialize import initialize
from mailman.i18n import _
-from mailman.initialize import initialize
from mailman.version import MAILMAN_VERSION
diff --git a/mailman/chains/accept.py b/mailman/chains/accept.py
index a4f02b217..0ced02d44 100644
--- a/mailman/chains/accept.py
+++ b/mailman/chains/accept.py
@@ -23,7 +23,7 @@ __metaclass__ = type
import logging
from mailman.chains.base import TerminalChainBase
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.queue import Switchboard
diff --git a/mailman/chains/base.py b/mailman/chains/base.py
index 39968a1fe..17c129f19 100644
--- a/mailman/chains/base.py
+++ b/mailman/chains/base.py
@@ -27,7 +27,7 @@ __all__ = [
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces import (
IChain, IChainIterator, IChainLink, IMutableChain, LinkAction)
diff --git a/mailman/chains/builtin.py b/mailman/chains/builtin.py
index 238cf4099..0528bf769 100644
--- a/mailman/chains/builtin.py
+++ b/mailman/chains/builtin.py
@@ -26,7 +26,7 @@ import logging
from zope.interface import implements
from mailman.chains.base import Link
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IChain, LinkAction
diff --git a/mailman/chains/headers.py b/mailman/chains/headers.py
index d53f67e06..062c42438 100644
--- a/mailman/chains/headers.py
+++ b/mailman/chains/headers.py
@@ -30,7 +30,7 @@ from zope.interface import implements
from mailman.interfaces import IChainIterator, IRule, LinkAction
from mailman.chains.base import Chain, Link
from mailman.i18n import _
-from mailman.configuration import config
+from mailman.config import config
log = logging.getLogger('mailman.vette')
@@ -104,7 +104,7 @@ class HeaderMatchChain(Chain):
self._links = []
# Initialize header check rules with those from the global
# HEADER_MATCHES variable.
- for entry in config.HEADER_MATCHES:
+ for entry in config.header_matches:
self._links.append(make_link(entry))
# Keep track of how many global header matching rules we've seen.
# This is so the flush() method will only delete those that were added
diff --git a/mailman/chains/hold.py b/mailman/chains/hold.py
index 85e8c3fec..1b44cee1b 100644
--- a/mailman/chains/hold.py
+++ b/mailman/chains/hold.py
@@ -36,7 +36,7 @@ from mailman.Utils import maketext, oneline, wrap, GetCharSet
from mailman.app.moderator import hold_message
from mailman.app.replybot import autorespond_to_sender, can_acknowledge
from mailman.chains.base import TerminalChainBase
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces import IPendable
diff --git a/mailman/commands/cmd_confirm.py b/mailman/commands/cmd_confirm.py
index 20fa0169e..700b69022 100644
--- a/mailman/commands/cmd_confirm.py
+++ b/mailman/commands/cmd_confirm.py
@@ -23,7 +23,7 @@
from mailman import Errors
from mailman import Pending
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
STOP = 1
diff --git a/mailman/commands/cmd_help.py b/mailman/commands/cmd_help.py
index 4577c947e..9686bb307 100644
--- a/mailman/commands/cmd_help.py
+++ b/mailman/commands/cmd_help.py
@@ -24,7 +24,7 @@ import os
import sys
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
EMPTYSTRING = ''
diff --git a/mailman/commands/cmd_lists.py b/mailman/commands/cmd_lists.py
index b7b5a3b74..df0fdcece 100644
--- a/mailman/commands/cmd_lists.py
+++ b/mailman/commands/cmd_lists.py
@@ -21,7 +21,7 @@
"""
from mailman.MailList import MailList
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
diff --git a/mailman/commands/cmd_password.py b/mailman/commands/cmd_password.py
index 0c09aa99d..75985a8a5 100644
--- a/mailman/commands/cmd_password.py
+++ b/mailman/commands/cmd_password.py
@@ -29,7 +29,7 @@
from email.Utils import parseaddr
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
STOP = 1
diff --git a/mailman/commands/cmd_set.py b/mailman/commands/cmd_set.py
index 94ba9192f..5c89abf5c 100644
--- a/mailman/commands/cmd_set.py
+++ b/mailman/commands/cmd_set.py
@@ -20,7 +20,7 @@ from email.Utils import parseaddr, formatdate
from mailman import Errors
from mailman import MemberAdaptor
from mailman import i18n
-from mailman.configuration import config
+from mailman.config import config
def _(s): return s
diff --git a/mailman/commands/cmd_who.py b/mailman/commands/cmd_who.py
index 725040f4d..157b84773 100644
--- a/mailman/commands/cmd_who.py
+++ b/mailman/commands/cmd_who.py
@@ -18,7 +18,7 @@
from email.Utils import parseaddr
from mailman import i18n
-from mailman.configuration import config
+from mailman.config import config
STOP = 1
diff --git a/mailman/commands/join.py b/mailman/commands/join.py
index 17fb071a6..a803a1e4c 100644
--- a/mailman/commands/join.py
+++ b/mailman/commands/join.py
@@ -29,7 +29,7 @@ from email.utils import formataddr, parseaddr
from zope.interface import implements
from mailman.Utils import MakeRandomPassword
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import (
ContinueProcessing, DeliveryMode, IEmailCommand)
diff --git a/mailman/config/__init__.py b/mailman/config/__init__.py
new file mode 100644
index 000000000..375cafa51
--- /dev/null
+++ b/mailman/config/__init__.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2008 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/>.
+
+from mailman.config.config import Configuration
+
+config = Configuration()
diff --git a/mailman/config/config.py b/mailman/config/config.py
new file mode 100644
index 000000000..031324eff
--- /dev/null
+++ b/mailman/config/config.py
@@ -0,0 +1,202 @@
+# Copyright (C) 2006-2008 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/>.
+
+"""Configuration file loading and management."""
+
+__metaclass__ = type
+__all__ = [
+ 'Configuration',
+ ]
+
+
+import os
+import sys
+import errno
+import logging
+
+from StringIO import StringIO
+from lazr.config import ConfigSchema
+from lazr.config.interfaces import NoCategoryError
+from pkg_resources import resource_filename
+
+from mailman import Defaults
+from mailman import version
+from mailman.config.helpers import as_boolean
+from mailman.core import errors
+from mailman.domain import Domain
+from mailman.languages import LanguageManager
+
+
+SPACE = ' '
+
+
+
+class Configuration(object):
+ """The core global configuration object."""
+
+ def __init__(self):
+ self.domains = {} # email host -> IDomain
+ self.qrunners = {}
+ self.qrunner_shortcuts = {}
+ self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION
+ self._config = None
+
+ def __getattr__(self, name):
+ """Delegate to the configuration object."""
+ return getattr(self._config, name)
+
+ def load(self, filename=None):
+ """Load the configuration from the schema and config files."""
+ schema_file = resource_filename('mailman.config', 'schema.cfg')
+ schema = ConfigSchema(schema_file)
+ # If a configuration file was given, load it now too.
+ if filename is None:
+ self._config = schema.loadFile(StringIO(''), '<default>')
+ else:
+ self._config = schema.load(filename)
+ self.post_process()
+
+ def post_process(self):
+ """Perform post-processing after loading the configuration files."""
+ # Set up the domains.
+ try:
+ domains = self._config.getByCategory('domain')
+ except NoCategoryError:
+ domains = []
+ for section in domains:
+ domain = Domain(section.email_host, section.base_url,
+ section.description, section.contact_address)
+ if domain.email_host in self.domains:
+ raise errors.BadDomainSpecificationError(
+ 'Duplicate email host: %s' % domain.email_host)
+ # Make sure there's only one mapping for the url_host
+ if domain.url_host in self.domains.values():
+ raise errors.BadDomainSpecificationError(
+ 'Duplicate url host: %s' % domain.url_host)
+ # We'll do the reverse mappings on-demand. There shouldn't be too
+ # many virtual hosts that it will really matter that much.
+ self.domains[domain.email_host] = domain
+ # Set up the queue runners.
+ try:
+ qrunners = self._config.getByCategory('qrunner')
+ except NoCategoryError:
+ qrunners = []
+ for section in qrunners:
+ if not as_boolean(section.start):
+ continue
+ name = section['class']
+ self.qrunners[name] = section.count
+ # Calculate the queue runner shortcut name.
+ classname = name.rsplit('.', 1)[1]
+ if classname.endswith('Runner'):
+ shortname = classname[:-6].lower()
+ else:
+ shortname = classname
+ self.qrunner_shortcuts[shortname] = section['class']
+ # Set up directories.
+ self.BIN_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
+ VAR_DIR = self._config.mailman.var_dir
+ # Now that we've loaded all the configuration files we're going to
+ # load, set up some useful directories.
+ join = os.path.join
+ self.LIST_DATA_DIR = join(VAR_DIR, 'lists')
+ self.LOG_DIR = join(VAR_DIR, 'logs')
+ self.LOCK_DIR = lockdir = join(VAR_DIR, 'locks')
+ self.DATA_DIR = datadir = join(VAR_DIR, 'data')
+ self.ETC_DIR = etcdir = join(VAR_DIR, 'etc')
+ self.SPAM_DIR = join(VAR_DIR, 'spam')
+ self.EXT_DIR = join(VAR_DIR, 'ext')
+ self.PUBLIC_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'public')
+ self.PRIVATE_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'private')
+ # Directories used by the qrunner subsystem
+ self.QUEUE_DIR = qdir = join(VAR_DIR, 'qfiles')
+ self.ARCHQUEUE_DIR = join(qdir, 'archive')
+ self.BADQUEUE_DIR = join(qdir, 'bad')
+ self.BOUNCEQUEUE_DIR = join(qdir, 'bounces')
+ self.CMDQUEUE_DIR = join(qdir, 'commands')
+ self.INQUEUE_DIR = join(qdir, 'in')
+ self.MAILDIR_DIR = join(qdir, 'maildir')
+ self.NEWSQUEUE_DIR = join(qdir, 'news')
+ self.OUTQUEUE_DIR = join(qdir, 'out')
+ self.PIPELINEQUEUE_DIR = join(qdir, 'pipeline')
+ self.RETRYQUEUE_DIR = join(qdir, 'retry')
+ self.SHUNTQUEUE_DIR = join(qdir, 'shunt')
+ self.VIRGINQUEUE_DIR = join(qdir, 'virgin')
+ self.MESSAGES_DIR = join(VAR_DIR, 'messages')
+ # Other useful files
+ self.PIDFILE = join(datadir, 'master-qrunner.pid')
+ self.SITE_PW_FILE = join(datadir, 'adm.pw')
+ self.LISTCREATOR_PW_FILE = join(datadir, 'creator.pw')
+ self.CONFIG_FILE = join(etcdir, 'mailman.cfg')
+ self.LOCK_FILE = join(lockdir, 'master-qrunner')
+ # Set up all the languages.
+ self.languages = LanguageManager()
+ try:
+ languages = self._config.getByCategory('language')
+ except NoCategoryError:
+ languages = []
+ for section in languages:
+ code = section.name.split('.')[1]
+ self.languages.add_language(code, section.description,
+ section.charset, section.enable)
+ # Always enable the server default language, which must be defined.
+ self.languages.enable_language(self._config.mailman.default_language)
+ # Create various registries.
+ self.archivers = {}
+ self.chains = {}
+ self.rules = {}
+ self.handlers = {}
+ self.pipelines = {}
+ self.commands = {}
+
+ @property
+ def logger_configs(self):
+ """Return all log config sections."""
+ try:
+ loggers = self._config.getByCategory('logging')
+ except NoCategoryError:
+ loggers = []
+ return loggers
+
+ @property
+ def paths(self):
+ """Return a substitution dictionary of all path variables."""
+ return dict((k, self.__dict__[k])
+ for k in self.__dict__
+ if k.endswith('_DIR'))
+
+ def ensure_directories_exist(self):
+ """Create all path directories if they do not exist."""
+ for variable, directory in self.paths.items():
+ try:
+ os.makedirs(directory, 02775)
+ except OSError, e:
+ if e.errno <> errno.EEXIST:
+ raise
+
+ @property
+ def header_matches(self):
+ """Iterate over all spam matching headers.
+
+ Values are 3-tuples of (header, pattern, chain)
+ """
+ try:
+ matches = self._config.getByCategory('spam.headers')
+ except NoCategoryError:
+ matches = []
+ for match in matches:
+ yield (matches.header, matches.pattern, matches.chain)
diff --git a/mailman/config/helpers.py b/mailman/config/helpers.py
new file mode 100644
index 000000000..306ef21b4
--- /dev/null
+++ b/mailman/config/helpers.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2008 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/>.
+
+"""Configuration helpers."""
+
+__metaclass__ = type
+__all__ = [
+ 'as_boolean',
+ 'as_log_level',
+ ]
+
+
+import logging
+
+
+
+def as_boolean(value):
+ """Turn a string into a boolean.
+
+ :param value: A string with one of the following values
+ (case-insensitive): true, yes, 1, on, enable, enabled (for True), or
+ false, no, 0, off, disable, disabled (for False). Everything else is
+ an error.
+ :type value: string
+ :return: True or False.
+ :rtype: boolean
+ """
+ value = value.lower()
+ if value in ('true', 'yes', '1', 'on', 'enabled', 'enable'):
+ return True
+ if value in ('false', 'no', '0', 'off', 'disabled', 'disable'):
+ return False
+ raise ValueError('Invalid boolean value: %s' % value)
+
+
+
+def as_log_level(value):
+ """Turn a string into a log level.
+
+ :param value: A string with a value (case-insensitive) equal to one of the
+ symbolic logging levels.
+ :type value: string
+ :return: A logging level constant.
+ :rtype: int
+ """
+ value = value.upper()
+ return getattr(logging, value)
diff --git a/mailman/config/schema.cfg b/mailman/config/schema.cfg
new file mode 100644
index 000000000..181116e74
--- /dev/null
+++ b/mailman/config/schema.cfg
@@ -0,0 +1,235 @@
+# Copyright (C) 2008 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/>.
+
+# This is the GNU Mailman configuration schema. It defines the default
+# configuration options for the core system and plugins. It uses ini-style
+# formats under the lazr.config regime to define all system configuration
+# options. See <https://launchpad.net/lazr.config> for details. You can
+# override the defaults by creating a mailman.cfg file in your etc directory.
+# See mailman.cfg.sample as an example.
+
+[mailman]
+# This address is the "site owner" address. Certain messages which must be
+# delivered to a human, but which can't be delivered to a list owner (e.g. a
+# bounce from a list owner), will be sent to this address. It should point to
+# a human.
+site-owner: changeme@example.com
+
+# This address is used as the from address whenever a message comes from some
+# entity to which there is no natural reply recipient. Set this to a real
+# human or to /dev/null. It will be appended with the host name of the list
+# involved. This address must not bounce and it must not point to a Mailman
+# process.
+noreply-address: noreply
+
+# Where all the runtime data will be kept. This directory must exist.
+var_dir: /tmp/mailman
+
+# The default language for this server.
+default_language: en
+
+
+[qrunner.template]
+# Define which process queue runners, and how many of them, to start.
+class: mailman.queue.runner.Runner
+count: 1
+start: yes
+
+[qrunner.archive]
+class: mailman.queue.archive.ArchiveRunner
+
+[qrunner.bounce]
+class: mailman.queue.bounce.BounceRunner
+
+[qrunner.command]
+class: mailman.queue.command.CommandRunner
+
+[qrunner.incoming]
+class: mailman.queue.incoming.IncomingRunner
+
+[qrunner.news]
+class: mailman.queue.news.NewsRunner
+
+[qrunner.outgoing]
+class: mailman.queue.outgoing.OutgoingRunner
+
+[qrunner.pipeline]
+class: mailman.queue.pipeline.PipelineRunner
+
+[qrunner.retry]
+class: mailman.queue.retry.RetryRunner
+
+[qrunner.virgin]
+class: mailman.queue.virgin.VirginRunner
+
+[qrunner.lmtp]
+class: mailman.queue.lmtp.LMTPRunner
+
+
+[database]
+# Use this to set the Storm database engine URL. You generally have one
+# primary database connection for all of Mailman. List data and most rosters
+# will store their data in this database, although external rosters may access
+# other databases in their own way. This string supports standard
+# 'configuration' substitutions.
+url: sqlite:///$DATA_DIR/mailman.db
+debug: no
+
+[logging.template]
+# This defines various log settings. The options available are:
+#
+# - level -- Overrides the default level; this may be any of the
+# standard Python logging levels, case insensitive.
+# - format -- Overrides the default format string
+# - datefmt -- Overrides the default date format string
+# - path -- Overrides the default logger path. This may be a relative
+# path name, in which case it is relative to Mailman's LOG_DIR,
+# or it may be an absolute path name. You cannot change the
+# handler class that will be used.
+# - propagate -- Boolean specifying whether to propagate log message from this
+# logger to the root "mailman" logger. You cannot override
+# settings for the root logger.
+#
+# In this section, you can define defaults for all loggers, which will be
+# prefixed by 'mailman.'. Use subsections to override settings for specific
+# loggers. The names of the available loggers are:
+#
+# - archiver -- All archiver output
+# - bounce -- All bounce processing logs go here
+# - config -- Configuration issues
+# - debug -- Only used for development
+# - error -- All exceptions go to this log
+# - fromusenet -- Information related to the Usenet to Mailman gateway
+# - http -- Internal wsgi-based web interface
+# - locks -- Lock state changes
+# - mischief -- Various types of hostile activity
+# - post -- Information about messages posted to mailing lists
+# - qrunner -- qrunner start/stops
+# - smtp -- Successful SMTP activity
+# - smtp-failure -- Unsuccessful SMTP activity
+# - subscribe -- Information about leaves/joins
+# - vette -- Information related to admindb activity
+format: %(asctime)s (%(process)d) %(message)s
+datefmt: %b %d %H:%M:%S %Y
+propagate: no
+level: info
+path: mailman
+
+[logging.root]
+
+[logging.archiver]
+
+[logging.bounce]
+path: bounce
+
+[logging.config]
+
+[logging.debug]
+path: debug
+level: debug
+
+[logging.error]
+
+[logging.fromusenet]
+
+[logging.http]
+
+[logging.locks]
+
+[logging.mischief]
+
+[logging.qrunner]
+
+[logging.smtp]
+path: smtp
+
+# The smtp logger defines additional options for handling the logging of each
+# attempted delivery. These format strings specify what information is logged
+# for every message, every successful delivery, every refused delivery and
+# every recipient failure. To disable a status message, set the value to 'no'
+# (without the quotes).
+#
+# These template strings accept the following set of substitution
+# placeholders, if available.
+#
+# msgid -- the Message-ID of the message in question
+# listname -- the fully-qualified list name
+# sender -- the sender if available
+# recip -- the recipient address if available, or the number of
+# recipients being delivered to
+# size -- the approximate size of the message in bytes
+# seconds -- the number of seconds the operation took
+# refused -- the number of refused recipients
+# smtpcode -- the SMTP success or failure code
+# smtpmsg -- the SMTP success or failure message
+
+every: [$msgid] smtp to $listname for $recip recips, completed in $time seconds
+success: [$msgid] post to $listname from $sender, $size bytes
+refused: [$msgid] post to $listname from $sender, $size bytes, $refused failures
+failure: [$msgid] delivery to $recip failed with code $smtpcode, $smtpmsg
+
+
+[logging.subscribe]
+
+[logging.vette]
+
+
+[domain.template]
+# Site-wide domain defaults. To configure an individual
+# domain, add a [domain.example_com] section with the overrides.
+
+# This is the host name for the email interface.
+email_host: example.com
+# This is the base url for the domain's web interface. It must include the
+# url scheme.
+base_url: http://example.com
+# The contact address for this domain. This is advertised as the human to
+# contact when users have problems with the lists in this domain.
+contact_address: postmaster@example.com
+# A short description of this domain.
+description: An example domain.
+
+
+[language.template]
+# Template for language definitions. The section name must be [language.xx]
+# where xx is the 2-character ISO code for the language.
+
+# The English name for the language.
+description: English (USA)
+# And the default character set for the language.
+charset: us-ascii
+# Whether the language is enabled or not.
+enable: yes
+
+[language.en]
+description: English (USA)
+charset: us-ascii
+
+
+[spam.headers.template]
+# This section defines basic header matching actions. Each spam.header
+# section names a header to match (case-insensitively), a pattern to match
+# against the header's value, and the chain to jump to when the match
+# succeeds.
+#
+# The header value should not include the trailing colon.
+header: X-Spam
+# The pattern is always matched with re.IGNORECASE.
+pattern: xyz
+# The chain to jump to if the pattern matches. Maybe be any existing chain
+# such as 'discard', 'reject', 'hold', or 'accept'.
+chain: hold
diff --git a/mailman/configuration.py b/mailman/configuration.py
deleted file mode 100644
index 070f82085..000000000
--- a/mailman/configuration.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# Copyright (C) 2006-2008 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/>.
-
-"""Configuration file loading and management."""
-
-import os
-import sys
-import errno
-
-from mailman import Defaults
-from mailman import version
-from mailman.core import errors
-from mailman.domain import Domain
-from mailman.languages import LanguageManager
-
-SPACE = ' '
-_missing = object()
-
-DEFAULT_QRUNNERS = (
- '.archive.ArchiveRunner',
- '.bounce.BounceRunner',
- '.command.CommandRunner',
- '.incoming.IncomingRunner',
- '.news.NewsRunner',
- '.outgoing.OutgoingRunner',
- '.pipeline.PipelineRunner',
- '.retry.RetryRunner',
- '.virgin.VirginRunner',
- )
-
-
-
-class Configuration(object):
- def __init__(self):
- self.domains = {} # email host -> IDomain
- self.qrunners = {}
- self.qrunner_shortcuts = {}
- self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION
-
- def load(self, filename=None):
- join = os.path.join
- # Set up the execfile namespace
- ns = Defaults.__dict__.copy()
- # Prune a few things, add a few things
- del ns['__file__']
- del ns['__name__']
- del ns['__doc__']
- ns['add_domain'] = self.add_domain
- ns['add_qrunner'] = self.add_qrunner
- ns['del_qrunner'] = self.del_qrunner
- self._languages = LanguageManager()
- ns['add_language'] = self._languages.add_language
- ns['enable_language'] = self._languages.enable_language
- # Add all known languages, but don't enable them.
- for code, (desc, charset) in Defaults._DEFAULT_LANGUAGE_DATA.items():
- self._languages.add_language(code, desc, charset, False)
- # Set up the default list of qrunners so that the mailman.cfg file may
- # add or delete them.
- for name in DEFAULT_QRUNNERS:
- self.add_qrunner(name)
- # Load the configuration from the named file, or if not given, search
- # around for a mailman.cfg file. Whatever you find, create a
- # namespace and execfile that file in it. The values in that
- # namespace are exposed as attributes on this Configuration instance.
- self.filename = None
- self.BIN_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
- dev_dir = os.path.dirname(self.BIN_DIR)
- paths = [
- # Development directories.
- join(dev_dir, 'var', 'etc', 'mailman.cfg'),
- join(os.getcwd(), 'var', 'etc', 'mailman.cfg'),
- join(os.getcwd(), 'etc', 'mailman.cfg'),
- # Standard installation directories.
- join('/etc', 'mailman.cfg'),
- join(Defaults.DEFAULT_VAR_DIRECTORY, 'etc', 'mailman.cfg'),
- ]
- if filename is not None:
- paths.insert(0, filename)
- for cfg_path in paths:
- path = os.path.abspath(os.path.expanduser(cfg_path))
- try:
- execfile(path, ns, ns)
- except EnvironmentError, e:
- if e.errno <> errno.ENOENT:
- # It's okay if the mailman.cfg file does not exist. This
- # can happen for example in the test suite.
- raise
- else:
- self.filename = cfg_path
- break
- if self.filename is None:
- # The logging subsystem isn't running yet, so use stderr.
- print >> sys.stderr, 'No runtime configuration file file. Use -C'
- sys.exit(-1)
- # Based on values possibly set in mailman.cfg, add additional qrunners.
- if ns['USE_MAILDIR']:
- self.add_qrunner('.maildir.MaildirRunner')
- if ns['USE_LMTP']:
- self.add_qrunner('.lmtp.LMTPRunner')
- # Pull out the defaults.
- VAR_DIR = os.path.abspath(ns['VAR_DIR'])
- # Now that we've loaded all the configuration files we're going to
- # load, set up some useful directories.
- self.LIST_DATA_DIR = join(VAR_DIR, 'lists')
- self.LOG_DIR = join(VAR_DIR, 'logs')
- self.LOCK_DIR = lockdir = join(VAR_DIR, 'locks')
- self.DATA_DIR = datadir = join(VAR_DIR, 'data')
- self.ETC_DIR = etcdir = join(VAR_DIR, 'etc')
- self.SPAM_DIR = join(VAR_DIR, 'spam')
- self.EXT_DIR = join(VAR_DIR, 'ext')
- self.PUBLIC_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'public')
- self.PRIVATE_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'private')
- # Directories used by the qrunner subsystem
- self.QUEUE_DIR = qdir = join(VAR_DIR, 'qfiles')
- self.ARCHQUEUE_DIR = join(qdir, 'archive')
- self.BADQUEUE_DIR = join(qdir, 'bad')
- self.BOUNCEQUEUE_DIR = join(qdir, 'bounces')
- self.CMDQUEUE_DIR = join(qdir, 'commands')
- self.INQUEUE_DIR = join(qdir, 'in')
- self.MAILDIR_DIR = join(qdir, 'maildir')
- self.NEWSQUEUE_DIR = join(qdir, 'news')
- self.OUTQUEUE_DIR = join(qdir, 'out')
- self.PIPELINEQUEUE_DIR = join(qdir, 'pipeline')
- self.RETRYQUEUE_DIR = join(qdir, 'retry')
- self.SHUNTQUEUE_DIR = join(qdir, 'shunt')
- self.VIRGINQUEUE_DIR = join(qdir, 'virgin')
- self.MESSAGES_DIR = join(VAR_DIR, 'messages')
- # Other useful files
- self.PIDFILE = join(datadir, 'master-qrunner.pid')
- self.SITE_PW_FILE = join(datadir, 'adm.pw')
- self.LISTCREATOR_PW_FILE = join(datadir, 'creator.pw')
- self.CONFIG_FILE = join(etcdir, 'mailman.cfg')
- self.LOCK_FILE = join(lockdir, 'master-qrunner')
- # Now update our dict so attribute syntax just works
- del ns['add_domain']
- del ns['add_qrunner']
- del ns['del_qrunner']
- self.__dict__.update(ns)
- # Enable all specified languages, and promote the language manager to
- # a public attribute.
- self.languages = self._languages
- del self._languages
- available_languages = set(self._DEFAULT_LANGUAGE_DATA)
- enabled_languages = set(self.LANGUAGES.split())
- if 'all' in enabled_languages:
- languages = available_languages
- else:
- unknown_language = enabled_languages - available_languages
- if unknown_language:
- print >> sys.stderr, 'Ignoring unknown language codes:', \
- SPACE.join(unknown_language)
- languages = available_languages & enabled_languages
- for code in languages:
- self.languages.enable_language(code)
- # Always add and enable the default server language.
- code = self.DEFAULT_SERVER_LANGUAGE
- self.languages.enable_language(code)
- # Create various registries.
- self.archivers = {}
- self.chains = {}
- self.rules = {}
- self.handlers = {}
- self.pipelines = {}
- self.commands = {}
-
- def add_domain(self, *args, **kws):
- """Add a virtual domain.
-
- See `Domain`.
- """
- domain = Domain(*args, **kws)
- if domain.email_host in self.domains:
- raise errors.BadDomainSpecificationError(
- 'Duplicate email host: %s' % domain.email_host)
- # Make sure there's only one mapping for the url_host
- if domain.url_host in self.domains.values():
- raise errors.BadDomainSpecificationError(
- 'Duplicate url host: %s' % domain.url_host)
- # We'll do the reverse mappings on-demand. There shouldn't be too
- # many virtual hosts that it will really matter that much.
- self.domains[domain.email_host] = domain
-
- # Proxy the docstring for the above method.
- add_domain.__doc__ = Domain.__init__.__doc__
-
- def add_qrunner(self, name, count=1):
- """Convenient interface for adding additional qrunners.
-
- :param name: the qrunner name, which must not include the 'Runner'
- suffix. E.g. 'HTTP' or 'LMTP'.
- :param count: is the number of qrunner slices to create, default: 1.
- """
- if name.startswith('.'):
- name = 'mailman.queue' + name
- self.qrunners[name] = count
- # Calculate the queue runner shortcut name.
- classname = name.rsplit('.', 1)[1]
- if classname.endswith('Runner'):
- shortname = classname[:-6].lower()
- else:
- shortname = classname
- self.qrunner_shortcuts[shortname] = name
-
- def del_qrunner(self, name):
- """Remove the named qrunner so that it does not start.
-
- :param name: the qrunner name, which must not include the 'Runner'
- suffix.
- """
- if name.startswith('.'):
- name = 'mailman.queue' + name
- self.qrunners.pop(name)
- for shortname, classname in self.qrunner_shortcuts:
- if name == classname:
- del self.qrunner_shortcuts[shortname]
- break
-
- @property
- def paths(self):
- return dict([(k, self.__dict__[k])
- for k in self.__dict__
- if k.endswith('_DIR')])
-
- def ensure_directories_exist(self):
- for variable, directory in self.paths.items():
- try:
- os.makedirs(directory, 02775)
- except OSError, e:
- if e.errno <> errno.EEXIST:
- raise
-
-
-
-config = Configuration()
diff --git a/mailman/core/chains.py b/mailman/core/chains.py
index bebbf5bee..812302d3f 100644
--- a/mailman/core/chains.py
+++ b/mailman/core/chains.py
@@ -17,11 +17,11 @@
"""Application support for chain processing."""
+__metaclass__ = type
__all__ = [
'initialize',
'process',
]
-__metaclass__ = type
from mailman.chains.accept import AcceptChain
@@ -30,7 +30,7 @@ from mailman.chains.discard import DiscardChain
from mailman.chains.headers import HeaderMatchChain
from mailman.chains.hold import HoldChain
from mailman.chains.reject import RejectChain
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces import LinkAction
diff --git a/mailman/initialize.py b/mailman/core/initialize.py
index ea7c294c8..16dcecf94 100644
--- a/mailman/initialize.py
+++ b/mailman/core/initialize.py
@@ -29,8 +29,8 @@ import os
from zope.interface.interface import adapter_hooks
from zope.interface.verify import verifyObject
-import mailman.configuration
-import mailman.loginit
+import mailman.config.config
+import mailman.core.logging
from mailman.core.plugins import get_plugin
from mailman.interfaces import IDatabase
@@ -61,10 +61,10 @@ def initialize_1(config_path, propagate_logs):
# restrictive permissions in order to handle private archives, but it
# handles that correctly.
os.umask(007)
- mailman.configuration.config.load(config_path)
+ mailman.config.config.load(config_path)
# Create the queue and log directories if they don't already exist.
- mailman.configuration.config.ensure_directories_exist()
- mailman.loginit.initialize(propagate_logs)
+ mailman.config.config.ensure_directories_exist()
+ mailman.core.logging.initialize(propagate_logs)
def initialize_2(debug=False):
@@ -85,7 +85,7 @@ def initialize_2(debug=False):
database = database_plugin()
verifyObject(IDatabase, database)
database.initialize(debug)
- mailman.configuration.config.db = database
+ mailman.config.config.db = database
# Initialize the rules and chains. Do the imports here so as to avoid
# circular imports.
from mailman.app.commands import initialize as initialize_commands
diff --git a/mailman/core/logging.py b/mailman/core/logging.py
new file mode 100644
index 000000000..608b59c2c
--- /dev/null
+++ b/mailman/core/logging.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2006-2008 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/>.
+
+"""Logging initialization, using Python's standard logging package."""
+
+from __future__ import absolute_import
+
+import os
+import sys
+import codecs
+import logging
+import ConfigParser
+
+from mailman.config import config
+from mailman.config.helpers import as_boolean, as_log_level
+
+
+_handlers = []
+
+
+
+class ReopenableFileHandler(logging.Handler):
+ def __init__(self, filename):
+ self._filename = filename
+ self._stream = self._open()
+ logging.Handler.__init__(self)
+
+ def _open(self):
+ return codecs.open(self._filename, 'a', 'utf-8')
+
+ def flush(self):
+ if self._stream:
+ self._stream.flush()
+
+ def emit(self, record):
+ # It's possible for the stream to have been closed by the time we get
+ # here, due to the shut down semantics. This mostly happens in the
+ # test suite, but be defensive anyway.
+ stream = (self._stream if self._stream else sys.stderr)
+ try:
+ msg = self.format(record)
+ fs = '%s\n'
+ try:
+ stream.write(fs % msg)
+ except UnicodeError:
+ stream.write(fs % msg.encode('string-escape'))
+ self.flush()
+ except:
+ self.handleError(record)
+
+ def close(self):
+ self.flush()
+ self._stream.close()
+ self._stream = None
+ logging.Handler.close(self)
+
+ def reopen(self):
+ self._stream.close()
+ self._stream = self._open()
+
+
+
+def initialize(propagate=False):
+ # First, find the root logger and configure the logging subsystem.
+ # Initialize the root logger, then create a formatter for all the sublogs.
+ logging.basicConfig(format=config.logging.root.format,
+ datefmt=config.logging.root.datefmt,
+ level=as_log_level(config.logging.root.level))
+ # Create the subloggers
+ for logger_config in config.logger_configs:
+ logger_name = 'mailman.' + logger_config.name.split('.')[-1]
+ log = logging.getLogger(logger_name)
+ # Get settings from log configuration file (or defaults).
+ log_format = logger_config.format
+ log_datefmt = logger_config.datefmt
+ # Propagation to the root logger is how we handle logging to stderr
+ # when the qrunners are not run as a subprocess of mailmanctl.
+ log.propagate = as_boolean(logger_config.propagate)
+ # Set the logger's level.
+ log.setLevel(as_log_level(logger_config.level))
+ # Create a formatter for this logger, then a handler, and link the
+ # formatter to the handler.
+ formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt)
+ path_str = logger_config.path
+ path_abs = os.path.normpath(os.path.join(config.LOG_DIR, path_str))
+ handler = ReopenableFileHandler(path_abs)
+ _handlers.append(handler)
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+
+
+
+def reopen():
+ for handler in _handlers:
+ handler.reopen()
diff --git a/mailman/core/pipelines.py b/mailman/core/pipelines.py
index c790901b2..7c177b511 100644
--- a/mailman/core/pipelines.py
+++ b/mailman/core/pipelines.py
@@ -27,7 +27,7 @@ __all__ = [
from zope.interface import implements
from zope.interface.verify import verifyObject
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.i18n import _
from mailman.interfaces import IHandler, IPipeline
diff --git a/mailman/core/rules.py b/mailman/core/rules.py
index 2c1e4fb3b..28f58d76e 100644
--- a/mailman/core/rules.py
+++ b/mailman/core/rules.py
@@ -26,7 +26,7 @@ __all__ = [
from zope.interface import implements
from zope.interface.verify import verifyObject
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.interfaces import IRule
diff --git a/mailman/core/styles.py b/mailman/core/styles.py
index 96104c204..d264143f5 100644
--- a/mailman/core/styles.py
+++ b/mailman/core/styles.py
@@ -30,7 +30,7 @@ from zope.interface import implements
from zope.interface.verify import verifyObject
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.i18n import _
from mailman.interfaces import (
diff --git a/mailman/database/__init__.py b/mailman/database/__init__.py
index dfafe4473..429fea953 100644
--- a/mailman/database/__init__.py
+++ b/mailman/database/__init__.py
@@ -31,14 +31,15 @@ from zope.interface import implements
import mailman.version
-from mailman.configuration import config
+from mailman.config import config
+from mailman.config.helpers import as_boolean
from mailman.database.listmanager import ListManager
from mailman.database.messagestore import MessageStore
from mailman.database.pending import Pendings
from mailman.database.requests import Requests
from mailman.database.usermanager import UserManager
from mailman.database.version import Version
-from mailman.interfaces import IDatabase, SchemaVersionMismatchError
+from mailman.interfaces.database import IDatabase, SchemaVersionMismatchError
@@ -82,8 +83,7 @@ class StockDatabase:
def _create(self, debug):
# Calculate the engine url.
- url = Template(config.DEFAULT_DATABASE_URL).safe_substitute(
- config.paths)
+ url = Template(config.database.url).safe_substitute(config.paths)
# XXX By design of SQLite, database file creation does not honor
# umask. See their ticket #1193:
# http://www.sqlite.org/cvstrac/tktview?tn=1193,31
@@ -101,7 +101,7 @@ class StockDatabase:
touch(url)
database = create_database(url)
store = Store(database)
- database.DEBUG = (config.DEFAULT_DATABASE_ECHO
+ database.DEBUG = (as_boolean(config.database.debug)
if debug is None else debug)
# Check the sqlite master database to see if the version file exists.
# If so, then we assume the database schema is correctly initialized.
diff --git a/mailman/database/address.py b/mailman/database/address.py
index 95e3007ef..272ad8dc3 100644
--- a/mailman/database/address.py
+++ b/mailman/database/address.py
@@ -25,7 +25,7 @@ from email.utils import formataddr
from storm.locals import *
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.member import Member
from mailman.database.model import Model
from mailman.database.preferences import Preferences
diff --git a/mailman/database/listmanager.py b/mailman/database/listmanager.py
index c4cebce4c..45c939cd1 100644
--- a/mailman/database/listmanager.py
+++ b/mailman/database/listmanager.py
@@ -22,7 +22,7 @@ import datetime
from zope.interface import implements
from mailman.Utils import split_listname, fqdn_listname
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.mailinglist import MailingList
from mailman.interfaces import IListManager, ListAlreadyExistsError
diff --git a/mailman/database/mailinglist.py b/mailman/database/mailinglist.py
index d5e6fd7b8..e1c6414be 100644
--- a/mailman/database/mailinglist.py
+++ b/mailman/database/mailinglist.py
@@ -22,7 +22,7 @@ from storm.locals import *
from zope.interface import implements
from mailman.Utils import fqdn_listname, makedirs, split_listname
-from mailman.configuration import config
+from mailman.config import config
from mailman.database import roster
from mailman.database.model import Model
from mailman.database.types import Enum
diff --git a/mailman/database/member.py b/mailman/database/member.py
index a4011840a..a25f2b0f7 100644
--- a/mailman/database/member.py
+++ b/mailman/database/member.py
@@ -19,7 +19,7 @@ from storm.locals import *
from zope.interface import implements
from mailman.Utils import split_listname
-from mailman.configuration import config
+from mailman.config import config
from mailman.constants import SystemDefaultPreferences
from mailman.database.model import Model
from mailman.database.types import Enum
diff --git a/mailman/database/message.py b/mailman/database/message.py
index 578445acf..7a4ba87d5 100644
--- a/mailman/database/message.py
+++ b/mailman/database/message.py
@@ -18,7 +18,7 @@
from storm.locals import *
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.model import Model
from mailman.interfaces import IMessage
diff --git a/mailman/database/messagestore.py b/mailman/database/messagestore.py
index a784f89cc..3c6528105 100644
--- a/mailman/database/messagestore.py
+++ b/mailman/database/messagestore.py
@@ -29,7 +29,7 @@ import cPickle as pickle
from zope.interface import implements
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.message import Message
from mailman.interfaces import IMessageStore
diff --git a/mailman/database/pending.py b/mailman/database/pending.py
index 31cc4e285..bdfd9cc72 100644
--- a/mailman/database/pending.py
+++ b/mailman/database/pending.py
@@ -27,7 +27,7 @@ from storm.locals import *
from zope.interface import implements
from zope.interface.verify import verifyObject
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.model import Model
from mailman.interfaces import (
IPendable, IPended, IPendedKeyValue, IPendings)
diff --git a/mailman/database/requests.py b/mailman/database/requests.py
index 963d34cc4..0569de14d 100644
--- a/mailman/database/requests.py
+++ b/mailman/database/requests.py
@@ -21,7 +21,7 @@ from datetime import timedelta
from storm.locals import *
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces import IListRequests, IPendable, IRequests, RequestType
diff --git a/mailman/database/roster.py b/mailman/database/roster.py
index 60087c243..4a16ebc1b 100644
--- a/mailman/database/roster.py
+++ b/mailman/database/roster.py
@@ -38,7 +38,7 @@ __all__ = [
from storm.locals import *
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.constants import SystemDefaultPreferences
from mailman.database.address import Address
from mailman.database.member import Member
diff --git a/mailman/database/user.py b/mailman/database/user.py
index 9d8e87a9f..9bb134734 100644
--- a/mailman/database/user.py
+++ b/mailman/database/user.py
@@ -19,7 +19,7 @@ from email.utils import formataddr
from storm.locals import *
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.model import Model
from mailman.database.address import Address
from mailman.database.preferences import Preferences
diff --git a/mailman/database/usermanager.py b/mailman/database/usermanager.py
index fb97f0947..8507fa550 100644
--- a/mailman/database/usermanager.py
+++ b/mailman/database/usermanager.py
@@ -21,7 +21,7 @@ import os
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.address import Address
from mailman.database.preferences import Preferences
from mailman.database.user import User
diff --git a/mailman/i18n.py b/mailman/i18n.py
index 186965509..6abb8fa0e 100644
--- a/mailman/i18n.py
+++ b/mailman/i18n.py
@@ -22,7 +22,7 @@ import string
import gettext
import mailman.messages
-from mailman.configuration import config
+from mailman.config import config
_translation = None
_missing = object()
diff --git a/mailman/loginit.py b/mailman/loginit.py
deleted file mode 100644
index d3e64790d..000000000
--- a/mailman/loginit.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# Copyright (C) 2006-2008 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/>.
-
-"""Logging initialization, using Python's standard logging package.
-
-This module cannot be called 'logging' because that would interfere with the
-import below. Ah, for Python 2.5 and absolute imports.
-"""
-
-import os
-import sys
-import codecs
-import logging
-import ConfigParser
-
-from mailman.configuration import config
-
-
-
-FMT = '%(asctime)s (%(process)d) %(message)s'
-DATEFMT = '%b %d %H:%M:%S %Y'
-
-LOGGERS = (
- 'archiver', # All archiver output
- 'bounce', # All bounce processing logs go here
- 'config', # Configuration issues
- 'debug', # Only used for development
- 'error', # All exceptions go to this log
- 'fromusenet', # Information related to the Usenet to Mailman gateway
- 'http', # Internal wsgi-based web interface
- 'locks', # Lock state changes
- 'mischief', # Various types of hostile activity
- 'post', # Information about messages posted to mailing lists
- 'qrunner', # qrunner start/stops
- 'smtp', # Successful SMTP activity
- 'smtp-failure', # Unsuccessful SMTP activity
- 'subscribe', # Information about leaves/joins
- 'vette', # Information related to admindb activity
- )
-
-_handlers = []
-
-
-
-class ReallySafeConfigParser(ConfigParser.SafeConfigParser):
- """Like `SafeConfigParser` but catches `NoOptionError`."""
-
- def getstring(self, section, option, default=None):
- try:
- return ConfigParser.SafeConfigParser.get(self, section, option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- # Try again with the '*' section.
- try:
- return ConfigParser.SafeConfigParser.get(self, '*', option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- return default
-
- def getboolean(self, section, option, default=None):
- try:
- return ConfigParser.SafeConfigParser.getboolean(
- self, section, option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- # Try again with the '*' section.
- try:
- return ConfigParser.SafeConfigParser.getboolean(
- self, '*', option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- return default
-
- def getlevel(self, section, option, default=None):
- try:
- level_str = ConfigParser.SafeConfigParser.get(
- self, section, option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- # Try again with the '*' section.
- try:
- level_str = ConfigParser.SafeConfigParser.get(
- self, '*', option)
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- level_str = default
- # Convert the level string into an integer.
- level_str = level_str.upper()
- level_def = (logging.DEBUG if section == 'debug' else logging.INFO)
- return getattr(logging, level_str, level_def)
-
-
-
-class ReopenableFileHandler(logging.Handler):
- def __init__(self, filename):
- self._filename = filename
- self._stream = self._open()
- logging.Handler.__init__(self)
-
- def _open(self):
- return codecs.open(self._filename, 'a', 'utf-8')
-
- def flush(self):
- if self._stream:
- self._stream.flush()
-
- def emit(self, record):
- # It's possible for the stream to have been closed by the time we get
- # here, due to the shut down semantics. This mostly happens in the
- # test suite, but be defensive anyway.
- stream = self._stream or sys.stderr
- try:
- msg = self.format(record)
- fs = '%s\n'
- try:
- stream.write(fs % msg)
- except UnicodeError:
- stream.write(fs % msg.encode('string-escape'))
- self.flush()
- except:
- self.handleError(record)
-
- def close(self):
- self.flush()
- self._stream.close()
- self._stream = None
- logging.Handler.close(self)
-
- def reopen(self):
- self._stream.close()
- self._stream = self._open()
-
-
-
-def initialize(propagate=False):
- # Initialize the root logger, then create a formatter for all the sublogs.
- logging.basicConfig(format=FMT, datefmt=DATEFMT, level=logging.INFO)
- # If a custom log configuration file was specified, load it now. Note
- # that we don't use logging.config.fileConfig() because it requires that
- # all loggers, formatters, and handlers be defined. We want to support
- # minimal overloading of our logger configurations.
- cp = ReallySafeConfigParser()
- if config.LOG_CONFIG_FILE:
- path = os.path.join(config.ETC_DIR, config.LOG_CONFIG_FILE)
- cp.read(os.path.normpath(path))
- # Create the subloggers
- for logger in LOGGERS:
- log = logging.getLogger('mailman.' + logger)
- # Get settings from log configuration file (or defaults).
- log_format = cp.getstring(logger, 'format', FMT)
- log_datefmt = cp.getstring(logger, 'datefmt', DATEFMT)
- # Propagation to the root logger is how we handle logging to stderr
- # when the qrunners are not run as a subprocess of mailmanctl.
- log.propagate = cp.getboolean(logger, 'propagate', propagate)
- # Set the logger's level. Note that if the log configuration file
- # does not set an override, the default level will be INFO except for
- # the 'debug' logger. It doesn't make much sense for the debug logger
- # to ignore debug level messages!
- level_int = cp.getlevel(logger, 'level', 'INFO')
- log.setLevel(level_int)
- # Create a formatter for this logger, then a handler, and link the
- # formatter to the handler.
- formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt)
- path_str = cp.getstring(logger, 'path', logger)
- path_abs = os.path.normpath(os.path.join(config.LOG_DIR, path_str))
- handler = ReopenableFileHandler(path_abs)
- _handlers.append(handler)
- handler.setFormatter(formatter)
- log.addHandler(handler)
-
-
-
-def reopen():
- for handler in _handlers:
- handler.reopen()
diff --git a/mailman/options.py b/mailman/options.py
index 94d03f657..adfe26cd9 100644
--- a/mailman/options.py
+++ b/mailman/options.py
@@ -29,10 +29,10 @@ import sys
from copy import copy
from optparse import Option, OptionParser, OptionValueError
-from mailman.version import MAILMAN_VERSION
-from mailman.configuration import config
+from mailman.config import config
+from mailman.core.initialize import initialize
from mailman.i18n import _
-from mailman.initialize import initialize
+from mailman.version import MAILMAN_VERSION
diff --git a/mailman/pipeline/acknowledge.py b/mailman/pipeline/acknowledge.py
index 41fc931ae..7421fcdd6 100644
--- a/mailman/pipeline/acknowledge.py
+++ b/mailman/pipeline/acknowledge.py
@@ -28,7 +28,7 @@ from zope.interface import implements
from mailman import Message
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
diff --git a/mailman/pipeline/avoid_duplicates.py b/mailman/pipeline/avoid_duplicates.py
index d228c6ad9..604d8b162 100644
--- a/mailman/pipeline/avoid_duplicates.py
+++ b/mailman/pipeline/avoid_duplicates.py
@@ -30,7 +30,7 @@ __all__ = ['AvoidDuplicates']
from email.Utils import getaddresses, formataddr
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
diff --git a/mailman/pipeline/calculate_recipients.py b/mailman/pipeline/calculate_recipients.py
index f892435cd..3207a398e 100644
--- a/mailman/pipeline/calculate_recipients.py
+++ b/mailman/pipeline/calculate_recipients.py
@@ -30,7 +30,7 @@ from zope.interface import implements
from mailman import Message
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.i18n import _
from mailman.interfaces import DeliveryStatus, IHandler
diff --git a/mailman/pipeline/cleanse_dkim.py b/mailman/pipeline/cleanse_dkim.py
index ae51fc27c..bc76e2726 100644
--- a/mailman/pipeline/cleanse_dkim.py
+++ b/mailman/pipeline/cleanse_dkim.py
@@ -31,7 +31,7 @@ __all__ = ['CleanseDKIM']
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
diff --git a/mailman/pipeline/cook_headers.py b/mailman/pipeline/cook_headers.py
index 362c8ecf7..bd3ad8a84 100644
--- a/mailman/pipeline/cook_headers.py
+++ b/mailman/pipeline/cook_headers.py
@@ -32,7 +32,7 @@ from email.utils import parseaddr, formataddr, getaddresses
from zope.interface import implements
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.i18n import _
from mailman.interfaces import IHandler, Personalization, ReplyToMunging
diff --git a/mailman/pipeline/decorate.py b/mailman/pipeline/decorate.py
index 3e9c6360b..bc684a1b1 100644
--- a/mailman/pipeline/decorate.py
+++ b/mailman/pipeline/decorate.py
@@ -30,7 +30,7 @@ from zope.interface import implements
from mailman import Utils
from mailman.Message import Message
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
diff --git a/mailman/pipeline/mime_delete.py b/mailman/pipeline/mime_delete.py
index 9cb34297f..6de3d0a72 100644
--- a/mailman/pipeline/mime_delete.py
+++ b/mailman/pipeline/mime_delete.py
@@ -39,7 +39,7 @@ from zope.interface import implements
from mailman.Message import UserNotification
from mailman.Utils import oneline
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.i18n import _
from mailman.interfaces import IHandler
diff --git a/mailman/pipeline/moderate.py b/mailman/pipeline/moderate.py
index 11471dd3a..aa78eaa36 100644
--- a/mailman/pipeline/moderate.py
+++ b/mailman/pipeline/moderate.py
@@ -24,7 +24,7 @@ from email.MIMEText import MIMEText
from mailman import Message
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.i18n import _
diff --git a/mailman/pipeline/scrubber.py b/mailman/pipeline/scrubber.py
index 4b8d9f770..abc904613 100644
--- a/mailman/pipeline/scrubber.py
+++ b/mailman/pipeline/scrubber.py
@@ -39,7 +39,7 @@ from mimetypes import guess_all_extensions
from zope.interface import implements
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.errors import DiscardMessage
from mailman.core.plugins import get_plugin
from mailman.i18n import _
diff --git a/mailman/pipeline/smtp_direct.py b/mailman/pipeline/smtp_direct.py
index 7d9242417..ab5ca0096 100644
--- a/mailman/pipeline/smtp_direct.py
+++ b/mailman/pipeline/smtp_direct.py
@@ -27,7 +27,9 @@ for a threaded implementation.
"""
__metaclass__ = type
-__all__ = ['SMTPDirect']
+__all__ = [
+ 'SMTPDirect',
+ ]
import copy
@@ -44,20 +46,15 @@ from email.Utils import formataddr
from zope.interface import implements
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.i18n import _
from mailman.interfaces import IHandler, Personalization
DOT = '.'
-
-log = logging.getLogger('mailman.smtp')
-flog = logging.getLogger('mailman.smtp-failure')
-every_log = logging.getLogger('mailman.' + config.SMTP_LOG_EVERY_MESSAGE[0])
-success_log = logging.getLogger('mailman.' + config.SMTP_LOG_SUCCESS[0])
-refused_log = logging.getLogger('mailman.' + config.SMTP_LOG_REFUSED[0])
-failure_log = logging.getLogger('mailman.' + config.SMTP_LOG_EACH_FAILURE[0])
+COMMA = ','
+log = logging.getLogger('mailman.smtp')
@@ -101,20 +98,6 @@ class Connection:
-class MessageDict(dict):
- def __init__(self, message, extras):
- super(MessageDict, self).__init__()
- for key, value in message.items():
- self[key.lower()] = value
- self.update(extras)
-
-
-class Template(string.Template):
- # Allow dashes and # signs, in addition to the standard pattern.
- idpattern = '[_a-z#-][_a-z0-9#-]*'
-
-
-
def process(mlist, msg, msgdata):
recips = msgdata.get('recips')
if not recips:
@@ -192,38 +175,39 @@ def process(mlist, msg, msgdata):
msgdata['recips'] = origrecips
# Log the successful post
t1 = time.time()
- substitutions = MessageDict(msg, {
- 'time' : t1-t0,
- 'size' : msg.original_size,
- '#recips' : len(recips),
- '#refused' : len(refused),
- 'listname' : mlist.fqdn_listname,
- 'sender' : origsender,
- })
- if 'message-id' not in substitutions:
- substitutions['message-id'] = 'n/a'
- # We have to use the copy() method because extended call syntax requires a
- # concrete dictionary object; it does not allow a generic mapping (XXX is
- # this still true in Python 2.3?).
- if config.SMTP_LOG_EVERY_MESSAGE:
- template = Template(config.SMTP_LOG_EVERY_MESSAGE[1])
- every_log.info('%s', template.safe_substitute(substitutions))
-
+ substitutions = dict(
+ msgid = msg.get('message-id', 'n/a'),
+ listname = mlist.fqdn_listname,
+ sender = origsender,
+ recip = len(recips),
+ size = msg.original_size,
+ seconds = t1 - t0,
+ refused = len(refused),
+ smtpcode = 'n/a',
+ smtpmsg = 'n/a',
+ )
+ # Log this message.
+ template = config.logging.smtp.every
+ if template != 'no':
+ template = Template(template)
+ log.info('%s', template.safe_substitute(substitutions))
if refused:
- if config.SMTP_LOG_REFUSED:
- template = Template(config.SMTP_LOG_REFUSED[1])
- refused_log.info('%s', template.safe_substitute(substitutions))
-
- elif msgdata.get('tolist'):
- # Log the successful post, but only if it really was a post to the
- # mailing list. Don't log sends to the -owner, or -admin addrs.
- # -request addrs should never get here. BAW: it may be useful to log
- # the other messages, but in that case, we should probably have a
- # separate configuration variable to control that.
- if config.SMTP_LOG_SUCCESS:
- template = Template(config.SMTP_LOG_SUCCESS[1])
- success_log.info('%s', template.safe_substitute(substitutions))
-
+ template = config.logging.smtp.refused
+ if template != 'no':
+ template = Template(template)
+ log.info('%s', template.safe_substitute(substitutions))
+ else:
+ # Log the successful post, but if it was not destined to the mailing
+ # list (e.g. to the owner or admin), print the actual recipients
+ # instead of just the number.
+ if not msgdata.get('tolist'):
+ recips = msg.get_all('to', [])
+ recips.extend(msg.get_all('cc', []))
+ substitutions['recips'] = COMMA.join(recips)
+ template = config.logging.smtp.success
+ if template != 'no':
+ template = Template(template)
+ log.info('%s', template.safe_substitute(substitutions))
# Process any failed deliveries.
tempfailures = []
permfailures = []
@@ -244,14 +228,15 @@ def process(mlist, msg, msgdata):
# Deal with persistent transient failures by queuing them up for
# future delivery. TBD: this could generate lots of log entries!
tempfailures.append(recip)
- if config.SMTP_LOG_EACH_FAILURE:
- substitutions.update({
- 'recipient' : recip,
- 'failcode' : code,
- 'failmsg' : smtpmsg,
- })
- template = Template(config.SMTP_LOG_EACH_FAILURE[1])
- failure_log.info('%s', template.safe_substitute(substitutions))
+ template = config.logging.smtp.failure
+ if template != 'no':
+ substitutions.update(
+ recip = recip,
+ smtpcode = code,
+ smtpmsg = smtpmsg,
+ )
+ template = Template(template)
+ log.info('%s', template.safe_substitute(substitutions))
# Return the results
if tempfailures or permfailures:
raise errors.SomeRecipientsFailed(tempfailures, permfailures)
diff --git a/mailman/pipeline/to_archive.py b/mailman/pipeline/to_archive.py
index b693d8341..4d8c27cf1 100644
--- a/mailman/pipeline/to_archive.py
+++ b/mailman/pipeline/to_archive.py
@@ -23,7 +23,7 @@ __all__ = ['ToArchive']
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
from mailman.queue import Switchboard
diff --git a/mailman/pipeline/to_digest.py b/mailman/pipeline/to_digest.py
index cec2fa1fc..78984c92e 100644
--- a/mailman/pipeline/to_digest.py
+++ b/mailman/pipeline/to_digest.py
@@ -53,7 +53,7 @@ from mailman import Utils
from mailman import i18n
from mailman.Mailbox import Mailbox
from mailman.Mailbox import Mailbox
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.interfaces import DeliveryMode, DeliveryStatus, IHandler
from mailman.pipeline.decorate import decorate
diff --git a/mailman/pipeline/to_outgoing.py b/mailman/pipeline/to_outgoing.py
index 48633da96..d8d1ec935 100644
--- a/mailman/pipeline/to_outgoing.py
+++ b/mailman/pipeline/to_outgoing.py
@@ -28,7 +28,7 @@ __all__ = ['ToOutgoing']
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler, Personalization
from mailman.queue import Switchboard
diff --git a/mailman/pipeline/to_usenet.py b/mailman/pipeline/to_usenet.py
index 4ebd94bec..14e7811bb 100644
--- a/mailman/pipeline/to_usenet.py
+++ b/mailman/pipeline/to_usenet.py
@@ -25,7 +25,7 @@ import logging
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler
from mailman.queue import Switchboard
diff --git a/mailman/queue/__init__.py b/mailman/queue/__init__.py
index 961a46283..27ea83320 100644
--- a/mailman/queue/__init__.py
+++ b/mailman/queue/__init__.py
@@ -48,7 +48,7 @@ from zope.interface import implements
from mailman import i18n
from mailman import Message
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
from mailman.interfaces import IRunner, ISwitchboard
# 20 bytes of all bits set, maximum hashlib.sha.digest() value
diff --git a/mailman/rules/administrivia.py b/mailman/rules/administrivia.py
index 1c09d98e1..b4fa9b172 100644
--- a/mailman/rules/administrivia.py
+++ b/mailman/rules/administrivia.py
@@ -17,14 +17,16 @@
"""The administrivia rule."""
-__all__ = ['Administrivia']
__metaclass__ = type
+__all__ = [
+ 'Administrivia',
+ ]
from email.iterators import typed_subpart_iterator
from zope.interface import implements
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IRule
diff --git a/mailman/testing/helpers.py b/mailman/testing/helpers.py
index 47c20ca2f..0f9c3edae 100644
--- a/mailman/testing/helpers.py
+++ b/mailman/testing/helpers.py
@@ -42,7 +42,7 @@ from Queue import Empty, Queue
from datetime import datetime, timedelta
from mailman.bin.master import Loop as Master
-from mailman.configuration import config
+from mailman.config import config
from mailman.queue import Switchboard
from mailman.testing.smtplistener import Server
diff --git a/mailman/tests/test_documentation.py b/mailman/tests/test_documentation.py
index cf53be245..ffb955c58 100644
--- a/mailman/tests/test_documentation.py
+++ b/mailman/tests/test_documentation.py
@@ -27,7 +27,7 @@ from email import message_from_string
import mailman
from mailman.Message import Message
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.styles import style_manager
from mailman.testing.helpers import SMTPServer
diff --git a/mailman/tests/test_membership.py b/mailman/tests/test_membership.py
index 792681472..501b71ca3 100644
--- a/mailman/tests/test_membership.py
+++ b/mailman/tests/test_membership.py
@@ -23,7 +23,7 @@ import unittest
from mailman import Utils
from mailman import passwords
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.errors import NotAMemberError
diff --git a/mailman/tests/test_security_mgr.py b/mailman/tests/test_security_mgr.py
index 835530496..b02561902 100644
--- a/mailman/tests/test_security_mgr.py
+++ b/mailman/tests/test_security_mgr.py
@@ -27,7 +27,7 @@ from StringIO import StringIO
from mailman import Utils
from mailman import passwords
-from mailman.configuration import config
+from mailman.config import config
diff --git a/setup.py b/setup.py
index 250e6f9eb..4a5acb595 100644
--- a/setup.py
+++ b/setup.py
@@ -107,6 +107,7 @@ case second `m'. Any other spelling is incorrect.""",
'mailman.handlers' : 'default = mailman.pipeline:initialize',
},
install_requires = [
+ 'lazr.config',
'locknix',
'munepy',
'storm',