summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore6
-rw-r--r--README.txt7
-rw-r--r--bootstrap.py77
-rw-r--r--buildout.cfg32
-rw-r--r--docs/ALPHA.txt70
-rw-r--r--docs/NEWS.txt2
-rw-r--r--mailman/Archiver/Archiver.py4
-rw-r--r--mailman/Archiver/HyperArch.py36
-rw-r--r--mailman/Archiver/HyperDatabase.py2
-rw-r--r--mailman/Archiver/__init__.py2
-rw-r--r--mailman/Bouncers/BouncerAPI.py2
-rw-r--r--mailman/Bouncers/Caiwireless.py2
-rw-r--r--mailman/Bouncers/Compuserve.py2
-rw-r--r--mailman/Bouncers/DSN.py2
-rw-r--r--mailman/Bouncers/Exchange.py2
-rw-r--r--mailman/Bouncers/Exim.py2
-rw-r--r--mailman/Bouncers/GroupWise.py2
-rw-r--r--mailman/Bouncers/LLNL.py2
-rw-r--r--mailman/Bouncers/Microsoft.py2
-rw-r--r--mailman/Bouncers/Netscape.py2
-rw-r--r--mailman/Bouncers/Postfix.py2
-rw-r--r--mailman/Bouncers/Qmail.py2
-rw-r--r--mailman/Bouncers/SMTP32.py2
-rw-r--r--mailman/Bouncers/SimpleMatch.py2
-rw-r--r--mailman/Bouncers/SimpleWarning.py2
-rw-r--r--mailman/Bouncers/Sina.py2
-rw-r--r--mailman/Bouncers/Yahoo.py2
-rw-r--r--mailman/Bouncers/Yale.py2
-rw-r--r--mailman/Defaults.py9
-rw-r--r--mailman/MTA/Manual.py2
-rw-r--r--mailman/MTA/Postfix.py2
-rw-r--r--mailman/MTA/Utils.py2
-rw-r--r--mailman/Mailbox.py11
-rw-r--r--mailman/Message.py26
-rw-r--r--mailman/Utils.py6
-rw-r--r--mailman/app/bounces.py2
-rw-r--r--mailman/app/commands.py4
-rw-r--r--mailman/app/lifecycle.py4
-rw-r--r--mailman/app/membership.py4
-rw-r--r--mailman/app/moderator.py8
-rw-r--r--mailman/app/notifications.py8
-rw-r--r--mailman/app/registrar.py4
-rw-r--r--mailman/app/replybot.py8
-rw-r--r--mailman/archiving/__init__.py4
-rw-r--r--mailman/archiving/mailarchive.py21
-rw-r--r--mailman/archiving/mhonarc.py9
-rw-r--r--mailman/archiving/pipermail.py13
-rw-r--r--mailman/archiving/prototype.py4
-rw-r--r--mailman/attic/Bouncer.py2
-rw-r--r--mailman/attic/Deliverer.py2
-rw-r--r--mailman/attic/Digester.py2
-rw-r--r--mailman/attic/MailList.py2
-rw-r--r--mailman/attic/SecurityManager.py2
-rwxr-xr-xmailman/attic/bin/clone_member (renamed from bin/clone_member)0
-rw-r--r--mailman/attic/bin/discard (renamed from bin/discard)0
-rw-r--r--mailman/attic/bin/fix_url.py (renamed from bin/fix_url.py)2
-rw-r--r--mailman/attic/bin/list_admins (renamed from bin/list_admins)0
-rw-r--r--[-rwxr-xr-x]mailman/attic/bin/msgfmt.py (renamed from bin/msgfmt.py)0
-rw-r--r--[-rwxr-xr-x]mailman/attic/bin/po2templ.py (renamed from bin/po2templ.py)2
-rw-r--r--[-rwxr-xr-x]mailman/attic/bin/pygettext.py (renamed from bin/pygettext.py)0
-rwxr-xr-xmailman/attic/bin/remove_members (renamed from bin/remove_members)0
-rw-r--r--mailman/attic/bin/reset_pw.py (renamed from bin/reset_pw.py)2
-rwxr-xr-xmailman/attic/bin/sync_members (renamed from bin/sync_members)0
-rw-r--r--[-rwxr-xr-x]mailman/attic/bin/templ2pot.py (renamed from bin/templ2pot.py)0
-rwxr-xr-xmailman/attic/bin/transcheck (renamed from bin/transcheck)0
-rw-r--r--mailman/bin/__init__.py2
-rw-r--r--mailman/bin/add_members.py2
-rw-r--r--mailman/bin/arch.py2
-rw-r--r--mailman/bin/bounces.py2
-rw-r--r--mailman/bin/bumpdigests.py2
-rw-r--r--mailman/bin/check_perms.py2
-rw-r--r--mailman/bin/checkdbs.py2
-rw-r--r--mailman/bin/cleanarch.py2
-rw-r--r--mailman/bin/config_list.py2
-rw-r--r--mailman/bin/confirm.py2
-rw-r--r--mailman/bin/create_list.py2
-rw-r--r--mailman/bin/disabled.py2
-rw-r--r--mailman/bin/docs/master.txt9
-rw-r--r--mailman/bin/dumpdb.py2
-rw-r--r--mailman/bin/export.py2
-rw-r--r--mailman/bin/find_member.py2
-rw-r--r--mailman/bin/gate_news.py2
-rw-r--r--mailman/bin/genaliases.py2
-rw-r--r--mailman/bin/import.py2
-rw-r--r--mailman/bin/inject.py2
-rw-r--r--mailman/bin/join.py2
-rw-r--r--mailman/bin/leave.py2
-rw-r--r--mailman/bin/list_lists.py2
-rw-r--r--mailman/bin/list_members.py2
-rw-r--r--mailman/bin/list_owners.py2
-rw-r--r--mailman/bin/mailmanctl.py2
-rw-r--r--mailman/bin/make_instance.py2
-rw-r--r--mailman/bin/master.py62
-rw-r--r--mailman/bin/mmsitepass.py2
-rw-r--r--mailman/bin/nightly_gzip.py2
-rw-r--r--mailman/bin/owner.py2
-rw-r--r--mailman/bin/post.py2
-rw-r--r--mailman/bin/qrunner.py32
-rw-r--r--mailman/bin/remove_list.py2
-rw-r--r--mailman/bin/request.py2
-rw-r--r--mailman/bin/senddigests.py2
-rw-r--r--mailman/bin/set_members.py2
-rw-r--r--mailman/bin/show_config.py2
-rw-r--r--mailman/bin/show_qfiles.py2
-rw-r--r--mailman/bin/testall.py2
-rw-r--r--mailman/bin/unshunt.py2
-rw-r--r--mailman/bin/update.py2
-rw-r--r--mailman/bin/version.py2
-rw-r--r--mailman/bin/withlist.py6
-rw-r--r--mailman/chains/accept.py7
-rw-r--r--mailman/chains/base.py4
-rw-r--r--mailman/chains/builtin.py4
-rw-r--r--mailman/chains/discard.py2
-rw-r--r--mailman/chains/headers.py6
-rw-r--r--mailman/chains/hold.py4
-rw-r--r--mailman/chains/reject.py2
-rw-r--r--mailman/commands/__init__.py2
-rw-r--r--mailman/commands/cmd_confirm.py4
-rw-r--r--mailman/commands/cmd_help.py4
-rw-r--r--mailman/commands/cmd_info.py2
-rw-r--r--mailman/commands/cmd_leave.py2
-rw-r--r--mailman/commands/cmd_lists.py4
-rw-r--r--mailman/commands/cmd_password.py4
-rw-r--r--mailman/commands/cmd_remove.py2
-rw-r--r--mailman/commands/cmd_set.py4
-rw-r--r--mailman/commands/cmd_stop.py2
-rw-r--r--mailman/commands/cmd_unsubscribe.py2
-rw-r--r--mailman/commands/cmd_who.py4
-rw-r--r--mailman/commands/docs/echo.txt1
-rw-r--r--mailman/commands/docs/end.txt1
-rw-r--r--mailman/commands/docs/join.txt4
-rw-r--r--mailman/commands/echo.py2
-rw-r--r--mailman/commands/end.py2
-rw-r--r--mailman/commands/join.py4
-rw-r--r--mailman/config/__init__.py20
-rw-r--r--mailman/config/config.py188
-rw-r--r--mailman/config/mailman.cfg67
-rw-r--r--mailman/config/schema.cfg255
-rw-r--r--mailman/configuration.py248
-rw-r--r--mailman/constants.py2
-rw-r--r--mailman/core/chains.py6
-rw-r--r--mailman/core/errors.py2
-rw-r--r--mailman/core/initialize.py (renamed from mailman/initialize.py)21
-rw-r--r--mailman/core/logging.py154
-rw-r--r--mailman/core/pipelines.py4
-rw-r--r--mailman/core/plugins.py2
-rw-r--r--mailman/core/rules.py4
-rw-r--r--mailman/core/styles.py132
-rw-r--r--mailman/database/__init__.py16
-rw-r--r--mailman/database/address.py4
-rw-r--r--mailman/database/language.py2
-rw-r--r--mailman/database/listmanager.py4
-rw-r--r--mailman/database/mailinglist.py9
-rw-r--r--mailman/database/member.py4
-rw-r--r--mailman/database/message.py4
-rw-r--r--mailman/database/messagestore.py4
-rw-r--r--mailman/database/model.py2
-rw-r--r--mailman/database/pending.py7
-rw-r--r--mailman/database/preferences.py2
-rw-r--r--mailman/database/requests.py4
-rw-r--r--mailman/database/roster.py4
-rw-r--r--mailman/database/transaction.py4
-rw-r--r--mailman/database/types.py2
-rw-r--r--mailman/database/user.py4
-rw-r--r--mailman/database/usermanager.py4
-rw-r--r--mailman/database/version.py2
-rw-r--r--mailman/docs/addresses.txt1
-rw-r--r--mailman/docs/archivers.txt3
-rw-r--r--mailman/docs/bounces.txt4
-rw-r--r--mailman/docs/chains.txt6
-rw-r--r--mailman/docs/domains.txt63
-rw-r--r--mailman/docs/lifecycle.txt2
-rw-r--r--mailman/docs/listmanager.txt1
-rw-r--r--mailman/docs/membership.txt1
-rw-r--r--mailman/docs/message.txt4
-rw-r--r--mailman/docs/messagestore.txt1
-rw-r--r--mailman/docs/mlist-addresses.txt6
-rw-r--r--mailman/docs/pending.txt1
-rw-r--r--mailman/docs/pipelines.txt7
-rw-r--r--mailman/docs/registration.txt18
-rw-r--r--mailman/docs/requests.txt7
-rw-r--r--mailman/docs/styles.txt7
-rw-r--r--mailman/docs/usermanager.txt1
-rw-r--r--mailman/docs/users.txt1
-rw-r--r--mailman/domain.py2
-rw-r--r--mailman/i18n.py4
-rw-r--r--mailman/inject.py34
-rw-r--r--mailman/interact.py2
-rw-r--r--mailman/interfaces/__init__.py2
-rw-r--r--mailman/interfaces/address.py2
-rw-r--r--mailman/interfaces/archiver.py2
-rw-r--r--mailman/interfaces/chain.py2
-rw-r--r--mailman/interfaces/command.py2
-rw-r--r--mailman/interfaces/database.py2
-rw-r--r--mailman/interfaces/domain.py2
-rw-r--r--mailman/interfaces/errors.py2
-rw-r--r--mailman/interfaces/handler.py2
-rw-r--r--mailman/interfaces/languages.py2
-rw-r--r--mailman/interfaces/listmanager.py2
-rw-r--r--mailman/interfaces/mailinglist.py2
-rw-r--r--mailman/interfaces/member.py2
-rw-r--r--mailman/interfaces/messages.py2
-rw-r--r--mailman/interfaces/mlistrequest.py2
-rw-r--r--mailman/interfaces/pending.py2
-rw-r--r--mailman/interfaces/permissions.py2
-rw-r--r--mailman/interfaces/pipeline.py2
-rw-r--r--mailman/interfaces/preferences.py2
-rw-r--r--mailman/interfaces/registrar.py2
-rw-r--r--mailman/interfaces/requests.py2
-rw-r--r--mailman/interfaces/roster.py2
-rw-r--r--mailman/interfaces/rules.py2
-rw-r--r--mailman/interfaces/runner.py7
-rw-r--r--mailman/interfaces/styles.py2
-rw-r--r--mailman/interfaces/switchboard.py2
-rw-r--r--mailman/interfaces/user.py2
-rw-r--r--mailman/interfaces/usermanager.py2
-rw-r--r--mailman/languages.py2
-rw-r--r--mailman/loginit.py183
-rw-r--r--mailman/options.py18
-rw-r--r--mailman/passwords.py2
-rw-r--r--mailman/pipeline/__init__.py2
-rw-r--r--mailman/pipeline/acknowledge.py4
-rw-r--r--mailman/pipeline/after_delivery.py2
-rw-r--r--mailman/pipeline/avoid_duplicates.py4
-rw-r--r--mailman/pipeline/calculate_recipients.py4
-rw-r--r--mailman/pipeline/cleanse.py2
-rw-r--r--mailman/pipeline/cleanse_dkim.py6
-rw-r--r--mailman/pipeline/cook_headers.py4
-rw-r--r--mailman/pipeline/decorate.py7
-rw-r--r--mailman/pipeline/docs/ack-headers.txt1
-rw-r--r--mailman/pipeline/docs/acknowledge.txt4
-rw-r--r--mailman/pipeline/docs/after-delivery.txt1
-rw-r--r--mailman/pipeline/docs/archives.txt4
-rw-r--r--mailman/pipeline/docs/avoid-duplicates.txt1
-rw-r--r--mailman/pipeline/docs/calc-recips.txt1
-rw-r--r--mailman/pipeline/docs/cleanse.txt1
-rw-r--r--mailman/pipeline/docs/cook-headers.txt1
-rw-r--r--mailman/pipeline/docs/decorate.txt1
-rw-r--r--mailman/pipeline/docs/digests.txt17
-rw-r--r--mailman/pipeline/docs/file-recips.txt1
-rw-r--r--mailman/pipeline/docs/filtering.txt1
-rw-r--r--mailman/pipeline/docs/nntp.txt4
-rw-r--r--mailman/pipeline/docs/reply-to.txt1
-rw-r--r--mailman/pipeline/docs/replybot.txt4
-rw-r--r--mailman/pipeline/docs/scrubber.txt6
-rw-r--r--mailman/pipeline/docs/subject-munging.txt1
-rw-r--r--mailman/pipeline/docs/tagger.txt2
-rw-r--r--mailman/pipeline/docs/to-outgoing.txt23
-rw-r--r--mailman/pipeline/file_recipients.py2
-rw-r--r--mailman/pipeline/mime_delete.py4
-rw-r--r--mailman/pipeline/moderate.py4
-rw-r--r--mailman/pipeline/owner_recipients.py2
-rw-r--r--mailman/pipeline/replybot.py2
-rw-r--r--mailman/pipeline/scrubber.py13
-rw-r--r--mailman/pipeline/smtp_direct.py134
-rw-r--r--mailman/pipeline/tagger.py2
-rw-r--r--mailman/pipeline/to_archive.py11
-rw-r--r--mailman/pipeline/to_digest.py14
-rw-r--r--mailman/pipeline/to_outgoing.py14
-rw-r--r--mailman/pipeline/to_usenet.py9
-rw-r--r--mailman/queue/__init__.py124
-rw-r--r--mailman/queue/archive.py24
-rw-r--r--mailman/queue/bounce.py31
-rw-r--r--mailman/queue/command.py13
-rw-r--r--mailman/queue/docs/archiver.txt4
-rw-r--r--mailman/queue/docs/command.txt19
-rw-r--r--mailman/queue/docs/incoming.txt16
-rw-r--r--mailman/queue/docs/lmtp.txt2
-rw-r--r--mailman/queue/docs/news.txt1
-rw-r--r--mailman/queue/docs/outgoing.txt6
-rw-r--r--mailman/queue/docs/runner.txt24
-rw-r--r--mailman/queue/docs/switchboard.txt1
-rw-r--r--mailman/queue/http.py4
-rw-r--r--mailman/queue/incoming.py6
-rw-r--r--mailman/queue/lmtp.py36
-rw-r--r--mailman/queue/maildir.py4
-rw-r--r--mailman/queue/news.py14
-rw-r--r--mailman/queue/outgoing.py17
-rw-r--r--mailman/queue/pipeline.py8
-rw-r--r--mailman/queue/retry.py15
-rw-r--r--mailman/queue/virgin.py8
-rw-r--r--mailman/rules/__init__.py2
-rw-r--r--mailman/rules/administrivia.py10
-rw-r--r--mailman/rules/any.py2
-rw-r--r--mailman/rules/approved.py2
-rw-r--r--mailman/rules/docs/administrivia.txt1
-rw-r--r--mailman/rules/docs/approve.txt1
-rw-r--r--mailman/rules/docs/emergency.txt4
-rw-r--r--mailman/rules/docs/header-matching.txt1
-rw-r--r--mailman/rules/docs/implicit-dest.txt1
-rw-r--r--mailman/rules/docs/loop.txt1
-rw-r--r--mailman/rules/docs/max-size.txt1
-rw-r--r--mailman/rules/docs/moderation.txt1
-rw-r--r--mailman/rules/docs/news-moderation.txt1
-rw-r--r--mailman/rules/docs/no-subject.txt1
-rw-r--r--mailman/rules/docs/recipients.txt1
-rw-r--r--mailman/rules/docs/rules.txt1
-rw-r--r--mailman/rules/docs/suspicious.txt1
-rw-r--r--mailman/rules/docs/truth.txt1
-rw-r--r--mailman/rules/emergency.py2
-rw-r--r--mailman/rules/implicit_dest.py2
-rw-r--r--mailman/rules/loop.py2
-rw-r--r--mailman/rules/max_recipients.py2
-rw-r--r--mailman/rules/max_size.py2
-rw-r--r--mailman/rules/moderation.py2
-rw-r--r--mailman/rules/news_moderation.py2
-rw-r--r--mailman/rules/no_subject.py2
-rw-r--r--mailman/rules/suspicious.py2
-rw-r--r--mailman/rules/truth.py2
-rw-r--r--mailman/testing/helpers.py40
-rw-r--r--mailman/testing/layers.py208
-rw-r--r--mailman/testing/smtplistener.py2
-rw-r--r--mailman/testing/testing.cfg80
-rw-r--r--mailman/testing/testing.cfg.in17
-rw-r--r--mailman/tests/test_bounces.py2
-rw-r--r--mailman/tests/test_documentation.py102
-rw-r--r--mailman/tests/test_membership.py4
-rw-r--r--mailman/tests/test_passwords.py2
-rw-r--r--mailman/tests/test_security_mgr.py4
-rw-r--r--mailman/version.py4
-rw-r--r--mailman/web/Cgi/Auth.py2
-rw-r--r--mailman/web/Cgi/admin.py2
-rw-r--r--mailman/web/Cgi/admindb.py2
-rw-r--r--mailman/web/Cgi/confirm.py2
-rw-r--r--mailman/web/Cgi/create.py2
-rw-r--r--mailman/web/Cgi/edithtml.py2
-rw-r--r--mailman/web/Cgi/listinfo.py2
-rw-r--r--mailman/web/Cgi/options.py2
-rw-r--r--mailman/web/Cgi/private.py2
-rw-r--r--mailman/web/Cgi/rmlist.py2
-rw-r--r--mailman/web/Cgi/roster.py2
-rw-r--r--mailman/web/Cgi/subscribe.py2
-rw-r--r--mailman/web/Cgi/wsgi_app.py2
-rw-r--r--mailman/web/Gui/Archive.py2
-rw-r--r--mailman/web/Gui/Autoresponse.py2
-rw-r--r--mailman/web/Gui/Bounce.py2
-rw-r--r--mailman/web/Gui/ContentFilter.py2
-rw-r--r--mailman/web/Gui/Digest.py2
-rw-r--r--mailman/web/Gui/GUIBase.py2
-rw-r--r--mailman/web/Gui/General.py2
-rw-r--r--mailman/web/Gui/Language.py2
-rw-r--r--mailman/web/Gui/Membership.py2
-rw-r--r--mailman/web/Gui/NonDigest.py2
-rw-r--r--mailman/web/Gui/Passwords.py2
-rw-r--r--mailman/web/Gui/Privacy.py2
-rw-r--r--mailman/web/Gui/Topics.py2
-rw-r--r--mailman/web/Gui/Usenet.py2
-rw-r--r--mailman/web/Gui/__init__.py2
-rw-r--r--mailman/web/HTMLFormatter.py2
-rw-r--r--mailman/web/htmlformat.py2
-rw-r--r--setup.py4
351 files changed, 2126 insertions, 1492 deletions
diff --git a/.bzrignore b/.bzrignore
index f8601acd0..e63ce55b5 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -7,7 +7,11 @@ dist/
mailman.egg-info
misc/mailman
setuptools*
-staging
TAGS
var/
.shelf
+bin
+.installed.cfg
+develop-eggs
+parts
+./bin
diff --git a/README.txt b/README.txt
index 0f288b1f5..f174c43a5 100644
--- a/README.txt
+++ b/README.txt
@@ -1,5 +1,5 @@
Mailman - The GNU Mailing List Management System
-Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
INTRODUCTION
@@ -38,13 +38,10 @@ INTRODUCTION
http://wiki.list.org
- Mailman 3.0 requires Python 2.5 or greater, which can be downloaded from:
+ Mailman 3.0 requires Python 2.6 or greater, which can be downloaded from:
http://www.python.org
- It is recommended that you use at least Python 2.5.2, the latest release
- as of this writing (31-Mar-2008).
-
FEATURES
diff --git a/bootstrap.py b/bootstrap.py
new file mode 100644
index 000000000..7728587f2
--- /dev/null
+++ b/bootstrap.py
@@ -0,0 +1,77 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout'],
+ env=dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
diff --git a/buildout.cfg b/buildout.cfg
new file mode 100644
index 000000000..e4f46a0fc
--- /dev/null
+++ b/buildout.cfg
@@ -0,0 +1,32 @@
+[buildout]
+parts =
+ interpreter
+ tags
+ test
+unzip = true
+develop = . /Users/barry/projects/lazr/megamerge
+
+[interpreter]
+recipe = zc.recipe.egg
+interpreter = py
+eggs =
+ lazr.config
+ lazr.delegates
+ locknix
+ mailman
+ munepy
+ storm
+ zope.interface
+
+[tags]
+recipe = z3c.recipe.tag:tags
+eggs = mailman
+
+[test]
+recipe = zc.recipe.testrunner
+eggs =
+ mailman
+defaults = '--tests-pattern ^tests --exit-with-status'.split()
+# Hack in extra arguments to zope.testrunner.
+initialization = from mailman.testing.layers import ConfigLayer;
+ ConfigLayer.hack_options_parser()
diff --git a/docs/ALPHA.txt b/docs/ALPHA.txt
index 10e752011..427332e74 100644
--- a/docs/ALPHA.txt
+++ b/docs/ALPHA.txt
@@ -1,5 +1,5 @@
Mailman - The GNU Mailing List Management System
-Copyright (C) 2008 by the Free Software Foundation, Inc.
+Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
ALPHA RELEASE
@@ -7,22 +7,44 @@ ALPHA RELEASE
The Mailman 3 alpha releases are being provided to give developers and
other interested people early looks at the next major version. As such,
many things may not work yet. Your feedback and contributions are
- welcome. At this time, please do not submit bug reports, but please
- provide your comments on the mailman-developers mailing list.
+ welcome. Bug reports are welcome on the Mailman bug tracker at
+
+ https://bugs.launchpad.net/mailman
+
+ or on the mailman-developers mailing list.
USING THE ALPHA
- Start by using setuptools to build the code. Here's what I do, season to
- taste. Python 2.5 is required.
+ Python 2.6 is required. It can either be the default 'python' on your
+ $PATH or it can be accessible via the 'python2.6' binary. See
+ http://www.python.org for details on getting Python 2.6.
+
+ Mailman 3 is now based on the zc.buildout infrastructure, which greatly
+ simplifies building and testing Mailman.
+
+ This version of Mailman depends on an unofficial branch of the lazr.config
+ package. This branch adds a number of useful features and fixes some
+ bugs, but it is still under review and not yet part of the official
+ package. Start by checking out this unofficial branch:
+
+ % cd wherever
+ % bzr branch lp:~barry/lazr.config/megamerge
+
+ Now you need to edit Mailman's buildout.cfg file. Look for the 'develop'
+ line under the [buildout] section. Change the path to the megamerge
+ package to point to the location of your checked out branch above.
+
+ You do not need anything other than Python 2.6 and an internet connection
+ to get all the other Mailman 3 dependencies. Here are the commands to
+ build everything:
- % mkdir staging
- % export PYTHONPATH=`pwd`/staging
- % python2.5 setup.py develop -d staging
+ % python2.6 bootstrap.py
+ % bin/buildout
- Now you can run the test suite.
+ Now you can run the test suite via:
- % staging/bin/testall
+ % bin/test
You should see no failures.
@@ -31,23 +53,29 @@ USING THE ALPHA
first, so they should give you a pretty good idea how various components
of Mailman 3 works.
- What, you actually want to /run/ Mailman 3? Oh well, okay. First you
- have to create a Mailman instance (as with all commands you can use --help
- to get a list of options).
+ What, you actually want to /run/ Mailman 3? Oh well, if you insist. You
+ will need to set up a configuration file to override the defaults and set
+ things up for your environment. Currently Mailman 3 is configured with a
+ bastard mix of the old configuration system and lazr.config, which is an
+ ini-style configuration system. Eventually all configuration will be
+ converted to lazr.config.
- % staging/bin/make_instance -d var
+ For now though, start by looking through mailman/config/schema.cfg.
+ Create a file for your overrides; it can be called anything and can live
+ anywhere, but I like to call it 'mailman.cfg'. For any value in
+ schema.cfg you want to override, just add a section header (the
+ square-bracketed names) and then the 'key: value' pair you want to
+ override.
- Look at mailman/Defaults.py and and mailman/configuration.py, and edit
- var/etc/mailman.cfg as necessary. You will almost definitely want to add
- at least one add_domain() call. You may also want to set LOG_CONFIG_FILE
- if you want to get more detailed logging, and USE_LMTP to turn on the LMTP
- server.
+ You will need to pass the -C flag to any bin command you want to invoke,
+ pointing it at your mailman.cfg file. The next release will make this
+ simpler by searching some default locations.
You can use the create_list, remove_list, list_lists, add_members, and
- list_members to set up and populate some mailing lists. You of coruse
+ list_members to set up and populate some mailing lists. You of course
also need to use mailmanctl to start the queue runners, and then you can
use the inject command to put some messages into the queue. For the most
- part, they ought to get delivered <wink>
+ part, they ought to get delivered <wink>.
Please note that the web u/i does /not/ work yet.
diff --git a/docs/NEWS.txt b/docs/NEWS.txt
index 276d2e136..e9e29405a 100644
--- a/docs/NEWS.txt
+++ b/docs/NEWS.txt
@@ -1,5 +1,5 @@
Mailman - The GNU Mailing List Management System
-Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Here is a history of user visible changes to Mailman.
diff --git a/mailman/Archiver/Archiver.py b/mailman/Archiver/Archiver.py
index 313bd9a0a..74e80a742 100644
--- a/mailman/Archiver/Archiver.py
+++ b/mailman/Archiver/Archiver.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..bb57e398d 100644
--- a/mailman/Archiver/HyperArch.py
+++ b/mailman/Archiver/HyperArch.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -29,6 +29,7 @@
import os
import re
import sys
+import gzip
import time
import errno
import urllib
@@ -42,25 +43,20 @@ from email.Header import decode_header, make_header
from locknix.lockfile import Lock
from string import Template
+from mailman import Defaults
from mailman import Utils
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'
@@ -180,7 +176,7 @@ def quick_maketext(templatefile, dict=None, lang=None, mlist=None):
listname = mlist.fqdn_listname
if lang is None:
if mlist is None:
- lang = config.DEFAULT_SERVER_LANGUAGE
+ lang = Defaults.DEFAULT_SERVER_LANGUAGE
else:
lang = mlist.preferred_language
cachekey = (templatefile, lang, listname)
@@ -239,7 +235,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
@@ -256,7 +252,7 @@ class Article(pipermail.Article):
self._lang = lang
self._mlist = mlist
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
# Avoid i18n side-effects. Note that the language for this
# article (for this list) could be different from the site-wide
# preferred language, so we need to ensure no side-effects will
@@ -331,7 +327,7 @@ class Article(pipermail.Article):
if hasattr(self, '_mlist'):
self._lang = self._mlist.preferred_language
else:
- self._lang = config.DEFAULT_SERVER_LANGUAGE
+ self._lang = Defaults.DEFAULT_SERVER_LANGUAGE
if not d.has_key('cenc'):
self.cenc = None
if not d.has_key('decoded'):
@@ -363,7 +359,7 @@ class Article(pipermail.Article):
if email:
self.decoded['email'] = email
if subject:
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
with i18n.using_language(self._lang):
atmark = _(' at ')
subject = re.sub(r'([-+,.\w]+)@([-+.\w]+)',
@@ -411,7 +407,7 @@ class Article(pipermail.Article):
d["subject_html"] = self.quote(self.subject)
d["subject_url"] = url_quote(self.subject)
d["in_reply_to_url"] = url_quote(self.in_reply_to)
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
# Point the mailto url back to the list
author = re.sub('@', _(' at '), self.author)
emailurl = self._mlist.posting_address
@@ -515,7 +511,7 @@ class Article(pipermail.Article):
# Coerce the body to Unicode and replace any invalid characters.
if not isinstance(body, unicode):
body = unicode(body, cset, 'replace')
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
with i18n.using_language(self._lang):
atmark = _(' at ')
body = re.sub(r'([-+,.\w]+)@([-+.\w]+)',
@@ -711,7 +707,7 @@ class HyperArchive(pipermail.T):
# The TOC is always in the charset of the list's preferred language
d['meta'] += html_charset % Utils.GetCharSet(mlist.preferred_language)
# The site can disable public access to the mbox file.
- if config.PUBLIC_MBOX:
+ if Defaults.PUBLIC_MBOX:
template = 'archtoc.html'
else:
template = 'archtocnombox.html'
@@ -968,7 +964,7 @@ class HyperArchive(pipermail.T):
def write_index_entry(self, article):
subject = self.get_header("subject", article)
author = self.get_header("author", article)
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
try:
author = re.sub('@', _(' at '), author)
except UnicodeError:
@@ -1044,7 +1040,7 @@ class HyperArchive(pipermail.T):
def update_archive(self, archive):
self.__super_update_archive(archive)
# only do this if the gzip module was imported globally, and
- # gzip'ing was enabled via config.GZIP_ARCHIVE_TXT_FILES. See
+ # gzip'ing was enabled via Defaults.GZIP_ARCHIVE_TXT_FILES. See
# above.
if gzip:
archz = None
@@ -1141,7 +1137,7 @@ class HyperArchive(pipermail.T):
if j != -1 and (j < k or k == -1):
text = jr.group(1)
length = len(text)
- if config.ARCHIVER_OBSCURES_EMAILADDRS:
+ if Defaults.ARCHIVER_OBSCURES_EMAILADDRS:
text = re.sub('@', atmark, text)
URL = self.maillist.GetScriptURL(
'listinfo', absolute=1)
diff --git a/mailman/Archiver/HyperDatabase.py b/mailman/Archiver/HyperDatabase.py
index d3486d8fc..49928d7b3 100644
--- a/mailman/Archiver/HyperDatabase.py
+++ b/mailman/Archiver/HyperDatabase.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Archiver/__init__.py b/mailman/Archiver/__init__.py
index 5b3e49ef7..322010acb 100644
--- a/mailman/Archiver/__init__.py
+++ b/mailman/Archiver/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/BouncerAPI.py b/mailman/Bouncers/BouncerAPI.py
index 0467d86b7..f4712ec20 100644
--- a/mailman/Bouncers/BouncerAPI.py
+++ b/mailman/Bouncers/BouncerAPI.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Caiwireless.py b/mailman/Bouncers/Caiwireless.py
index 44b9c6a04..8c26c7b97 100644
--- a/mailman/Bouncers/Caiwireless.py
+++ b/mailman/Bouncers/Caiwireless.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Compuserve.py b/mailman/Bouncers/Compuserve.py
index 7804f1ba4..2297a72a9 100644
--- a/mailman/Bouncers/Compuserve.py
+++ b/mailman/Bouncers/Compuserve.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/DSN.py b/mailman/Bouncers/DSN.py
index 6345390a8..425eee6fb 100644
--- a/mailman/Bouncers/DSN.py
+++ b/mailman/Bouncers/DSN.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Exchange.py b/mailman/Bouncers/Exchange.py
index d524a8cf1..cf8beefce 100644
--- a/mailman/Bouncers/Exchange.py
+++ b/mailman/Bouncers/Exchange.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Exim.py b/mailman/Bouncers/Exim.py
index 62a0b7848..0f4e7f4cf 100644
--- a/mailman/Bouncers/Exim.py
+++ b/mailman/Bouncers/Exim.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/GroupWise.py b/mailman/Bouncers/GroupWise.py
index aeac3b10f..e74291217 100644
--- a/mailman/Bouncers/GroupWise.py
+++ b/mailman/Bouncers/GroupWise.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/LLNL.py b/mailman/Bouncers/LLNL.py
index b1419b69f..cc1a08542 100644
--- a/mailman/Bouncers/LLNL.py
+++ b/mailman/Bouncers/LLNL.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Microsoft.py b/mailman/Bouncers/Microsoft.py
index 43d24e19a..98d27d4ee 100644
--- a/mailman/Bouncers/Microsoft.py
+++ b/mailman/Bouncers/Microsoft.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Netscape.py b/mailman/Bouncers/Netscape.py
index 2754083c5..319329e84 100644
--- a/mailman/Bouncers/Netscape.py
+++ b/mailman/Bouncers/Netscape.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Postfix.py b/mailman/Bouncers/Postfix.py
index ada5ea5e8..cfc97a05e 100644
--- a/mailman/Bouncers/Postfix.py
+++ b/mailman/Bouncers/Postfix.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Qmail.py b/mailman/Bouncers/Qmail.py
index 7edb1951e..2431da653 100644
--- a/mailman/Bouncers/Qmail.py
+++ b/mailman/Bouncers/Qmail.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/SMTP32.py b/mailman/Bouncers/SMTP32.py
index 41b9c09e1..a7fff2ed3 100644
--- a/mailman/Bouncers/SMTP32.py
+++ b/mailman/Bouncers/SMTP32.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/SimpleMatch.py b/mailman/Bouncers/SimpleMatch.py
index 8eb170b84..338f52a19 100644
--- a/mailman/Bouncers/SimpleMatch.py
+++ b/mailman/Bouncers/SimpleMatch.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/SimpleWarning.py b/mailman/Bouncers/SimpleWarning.py
index bb69b22e3..ab18d2530 100644
--- a/mailman/Bouncers/SimpleWarning.py
+++ b/mailman/Bouncers/SimpleWarning.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Sina.py b/mailman/Bouncers/Sina.py
index 39e6192c4..a6b8e0911 100644
--- a/mailman/Bouncers/Sina.py
+++ b/mailman/Bouncers/Sina.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Yahoo.py b/mailman/Bouncers/Yahoo.py
index 61ec4f22a..b0480b818 100644
--- a/mailman/Bouncers/Yahoo.py
+++ b/mailman/Bouncers/Yahoo.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Bouncers/Yale.py b/mailman/Bouncers/Yale.py
index 3f5534d4f..956dfb838 100644
--- a/mailman/Bouncers/Yale.py
+++ b/mailman/Bouncers/Yale.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Defaults.py b/mailman/Defaults.py
index a0aad0b8e..2cbfe8241 100644
--- a/mailman/Defaults.py
+++ b/mailman/Defaults.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -693,11 +693,6 @@ USE_MAILDIR = No
# alias_maps = hash:/etc/aliases, hash:<prefix>/data/aliases
USE_LMTP = No
-# Change LMTP_HOST and LMTP_PORT for your convenience. You should be careful
-# enough to use a firewall if you open your port on global address interface.
-LMTP_HOST = 'localhost'
-LMTP_PORT = 8025
-
# Name of the domains which operate on LMTP Mailman only. Currently valid
# only for Postfix alias generation.
LMTP_ONLY_DOMAINS = []
@@ -1051,7 +1046,7 @@ DEFAULT_DIGEST_FOOTER = DEFAULT_MSG_FOOTER
DEFAULT_DIGEST_IS_DEFAULT = No
DEFAULT_MIME_IS_DEFAULT_DIGEST = No
-DEFAULT_DIGEST_SIZE_THRESHHOLD = 30 # KB
+DEFAULT_DIGEST_SIZE_THRESHOLD = 30 # KB
DEFAULT_DIGEST_SEND_PERIODIC = Yes
# Headers which should be kept in both RFC 1153 (plain) and MIME digests. RFC
diff --git a/mailman/MTA/Manual.py b/mailman/MTA/Manual.py
index 549079013..d0e7c359a 100644
--- a/mailman/MTA/Manual.py
+++ b/mailman/MTA/Manual.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/MTA/Postfix.py b/mailman/MTA/Postfix.py
index 7f4fa1050..901c21089 100644
--- a/mailman/MTA/Postfix.py
+++ b/mailman/MTA/Postfix.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/MTA/Utils.py b/mailman/MTA/Utils.py
index 5fba893bb..bebbc69b7 100644
--- a/mailman/MTA/Utils.py
+++ b/mailman/MTA/Utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/Mailbox.py b/mailman/Mailbox.py
index afbfb8166..14fed7402 100644
--- a/mailman/Mailbox.py
+++ b/mailman/Mailbox.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -26,8 +26,8 @@ from email.Errors import MessageParseError
from email.Generator import Generator
from email.Parser import Parser
+from mailman import Defaults
from mailman.Message import Message
-from mailman.configuration import config
@@ -91,9 +91,10 @@ 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):
- if config.ARCHIVE_SCRUBBER:
- __import__(config.ARCHIVE_SCRUBBER)
- self._scrubber = sys.modules[config.ARCHIVE_SCRUBBER].process
+ scrubber_module = Defaults.ARCHIVE_SCRUBBER
+ if scrubber_module:
+ __import__(scrubber_module)
+ self._scrubber = sys.modules[scrubber_module].process
else:
self._scrubber = None
self._mlist = mlist
diff --git a/mailman/Message.py b/mailman/Message.py
index f4f939568..5ca763b30 100644
--- a/mailman/Message.py
+++ b/mailman/Message.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -29,8 +29,9 @@ import email.utils
from email.charset import Charset
from email.header import Header
+from mailman import Defaults
from mailman import Utils
-from mailman.configuration import config
+from mailman.config import config
COMMASPACE = ', '
@@ -118,14 +119,15 @@ class Message(email.message.Message):
header value found is returned. However the search order is
determined by the following:
- - If config.USE_ENVELOPE_SENDER is true, then the search order is
- Sender:, From:, unixfrom
+ - If config.mailman.use_envelope_sender is true, then the search order
+ is Sender:, From:, unixfrom
- Otherwise, the search order is From:, Sender:, unixfrom
The optional argument use_envelope, if given overrides the
- config.USE_ENVELOPE_SENDER setting. It should be set to either 0 or 1
- (don't use None since that indicates no-override).
+ 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.
@@ -133,7 +135,7 @@ class Message(email.message.Message):
This method differs from get_senders() in that it returns one and only
one address, and uses a different search order.
"""
- senderfirst = config.USE_ENVELOPE_SENDER
+ senderfirst = config.mailman.use_envelope_sender
if use_envelope is not None:
senderfirst = use_envelope
if senderfirst:
@@ -185,7 +187,7 @@ class Message(email.message.Message):
names without the trailing colon.
"""
if headers is None:
- headers = config.SENDER_HEADERS
+ headers = Defaults.SENDER_HEADERS
pairs = []
for h in headers:
if h is None:
@@ -263,8 +265,7 @@ class UserNotification(Message):
def _enqueue(self, mlist, **_kws):
# Not imported at module scope to avoid import loop
- from mailman.queue import Switchboard
- virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ virginq = config.switchboards['virgin']
# The message metadata better have a 'recip' attribute.
enqueue_kws = dict(
recips=self.recips,
@@ -287,7 +288,7 @@ class OwnerNotification(UserNotification):
else:
roster = mlist.owners
recips = [address.address for address in roster.addresses]
- sender = config.SITE_OWNER_ADDRESS
+ sender = config.mailman.site_owner
lang = mlist.preferred_language
UserNotification.__init__(self, recips, sender, subject, text, lang)
# Hack the To header to look like it's going to the -owner address
@@ -297,8 +298,7 @@ class OwnerNotification(UserNotification):
def _enqueue(self, mlist, **_kws):
# Not imported at module scope to avoid import loop
- from mailman.queue import Switchboard
- virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ virginq = config.switchboards['virgin']
# The message metadata better have a `recip' attribute
virginq.enqueue(self,
listname=mlist.fqdn_listname,
diff --git a/mailman/Utils.py b/mailman/Utils.py
index 607c457d9..b53dccf92 100644
--- a/mailman/Utils.py
+++ b/mailman/Utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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 = '@'
@@ -475,7 +475,7 @@ def findtext(templatefile, dict=None, raw=False, lang=None, mlist=None):
languages.add(lang)
if mlist is not None:
languages.add(mlist.preferred_language)
- languages.add(config.DEFAULT_SERVER_LANGUAGE)
+ languages.add(config.mailman.default_language)
assert None not in languages, 'None in languages'
# Calculate the locations to scan
searchdirs = []
diff --git a/mailman/app/bounces.py b/mailman/app/bounces.py
index 716928fa3..24daf9a88 100644
--- a/mailman/app/bounces.py
+++ b/mailman/app/bounces.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/app/commands.py b/mailman/app/commands.py
index 6ff6fdf0a..9bcd027a0 100644
--- a/mailman/app/commands.py
+++ b/mailman/app/commands.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..5401c1e12 100644
--- a/mailman/app/lifecycle.py
+++ b/mailman/app/lifecycle.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..748d7f204 100644
--- a/mailman/app/membership.py
+++ b/mailman/app/membership.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..e5d37e80f 100644
--- a/mailman/app/moderator.py
+++ b/mailman/app/moderator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -37,11 +37,10 @@ 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
-from mailman.queue import Switchboard
_ = i18n._
@@ -141,8 +140,7 @@ def handle_message(mlist, id, action,
msg.get('message-id', 'n/a'))
# Stick the message back in the incoming queue for further
# processing.
- inq = Switchboard(config.INQUEUE_DIR)
- inq.enqueue(msg, _metadata=msgdata)
+ config.switchboards['in'].enqueue(msg, _metadata=msgdata)
else:
raise AssertionError('Unexpected action: %s' % action)
# Forward the message.
diff --git a/mailman/app/notifications.py b/mailman/app/notifications.py
index 41180de7d..62c9964c0 100644
--- a/mailman/app/notifications.py
+++ b/mailman/app/notifications.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -27,10 +27,10 @@ __all__ = [
from email.utils import formataddr
+from mailman import Defaults
from mailman import Message
from mailman import Utils
from mailman import i18n
-from mailman.configuration import config
from mailman.interfaces.member import DeliveryMode
_ = 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=config.VERP_PERSONALIZED_DELIVERIES)
+ msg.send(mlist, verp=Defaults.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=config.VERP_PERSONALIZED_DELIVERIES)
+ msg.send(mlist, verp=Defaults.VERP_PERSONALIZED_DELIVERIES)
diff --git a/mailman/app/registrar.py b/mailman/app/registrar.py
index 320086ec7..56501bacd 100644
--- a/mailman/app/registrar.py
+++ b/mailman/app/registrar.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..0a8cdd5b7 100644
--- a/mailman/app/replybot.py
+++ b/mailman/app/replybot.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -29,9 +29,9 @@ __all__ = [
import logging
import datetime
+from mailman import Defaults
from mailman import Utils
from mailman import i18n
-from mailman.configuration import config
log = logging.getLogger('mailman.vette')
@@ -48,7 +48,7 @@ def autorespond_to_sender(mlist, sender, lang=None):
"""
if lang is None:
lang = mlist.preferred_language
- if config.MAX_AUTORESPONSES_PER_DAY == 0:
+ if Defaults.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 >= config.MAX_AUTORESPONSES_PER_DAY:
+ if count >= Defaults.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/archiving/__init__.py b/mailman/archiving/__init__.py
index 41dff720c..93b7ae3ab 100644
--- a/mailman/archiving/__init__.py
+++ b/mailman/archiving/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..20a3ea483 100644
--- a/mailman/archiving/mailarchive.py
+++ b/mailman/archiving/mailarchive.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -30,9 +30,8 @@ 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
@@ -52,7 +51,7 @@ class MailArchive:
"""See `IArchiver`."""
if mlist.archive_private:
return None
- return urljoin(config.MAIL_ARCHIVE_BASEURL,
+ return urljoin(config.archiver.mail_archive.base_url,
quote(mlist.posting_address))
@staticmethod
@@ -73,15 +72,13 @@ class MailArchive:
message_id_hash = urlsafe_b64encode(sha.digest())
del msg['x-message-id-hash']
msg['X-Message-ID-Hash'] = message_id_hash
- return urljoin(config.MAIL_ARCHIVE_BASEURL, message_id_hash)
+ return urljoin(config.archiver.mail_archive.base_url, message_id_hash)
@staticmethod
def archive_message(mlist, msg):
"""See `IArchiver`."""
- if mlist.archive_private:
- return
- outq = Switchboard(config.OUTQUEUE_DIR)
- outq.enqueue(
- msg,
- listname=mlist.fqdn_listname,
- recips=[config.MAIL_ARCHIVE_RECIPIENT])
+ if not mlist.archive_private:
+ config.switchboards['out'].enqueue(
+ msg,
+ listname=mlist.fqdn_listname,
+ recips=[config.archiver.mail_archive.recipient])
diff --git a/mailman/archiving/mhonarc.py b/mailman/archiving/mhonarc.py
index 7f31a6fb1..3cc83170c 100644
--- a/mailman/archiving/mhonarc.py
+++ b/mailman/archiving/mhonarc.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -32,7 +32,8 @@ from string import Template
from urlparse import urljoin
from zope.interface import implements
-from mailman.configuration import config
+from mailman import Defaults
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver
@@ -53,7 +54,7 @@ class MHonArc:
"""See `IArchiver`."""
# XXX What about private MHonArc archives?
web_host = config.domains[mlist.host_name].url_host
- return Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
+ return Template(Defaults.PUBLIC_ARCHIVE_URL).safe_substitute(
listname=mlist.fqdn_listname,
hostname=web_host,
fqdn_listname=mlist.fqdn_listname,
@@ -82,7 +83,7 @@ class MHonArc:
"""See `IArchiver`."""
substitutions = config.__dict__.copy()
substitutions['listname'] = mlist.fqdn_listname
- command = Template(config.MHONARC_COMMAND).safe_substitute(
+ command = Template(config.archiver.mhonarc.command).safe_substitute(
substitutions)
proc = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
diff --git a/mailman/archiving/pipermail.py b/mailman/archiving/pipermail.py
index df16e6e98..d534f1600 100644
--- a/mailman/archiving/pipermail.py
+++ b/mailman/archiving/pipermail.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -30,7 +30,9 @@ from string import Template
from zope.interface import implements
from zope.interface.interface import adapter_hooks
-from mailman.configuration import config
+from mailman import Defaults
+from mailman.Utils import makedirs
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver, IPipermailMailingList
from mailman.interfaces.mailinglist import IMailingList
@@ -55,7 +57,10 @@ class PipermailMailingListAdapter:
basedir = config.PRIVATE_ARCHIVE_FILE_DIR
else:
basedir = config.PUBLIC_ARCHIVE_FILE_DIR
- return os.path.join(basedir, self._mlist.fqdn_listname)
+ # Make sure the archive directory exists.
+ archive_dir = os.path.join(basedir, self._mlist.fqdn_listname)
+ makedirs(archive_dir)
+ return archive_dir
def adapt_mailing_list_for_pipermail(iface, obj):
@@ -91,7 +96,7 @@ class Pipermail:
url = mlist.script_url('private') + '/index.html'
else:
web_host = config.domains[mlist.host_name].url_host
- url = Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
+ url = Template(config.archiver.pipermail.base_url).safe_substitute(
listname=mlist.fqdn_listname,
hostname=web_host,
fqdn_listname=mlist.fqdn_listname,
diff --git a/mailman/archiving/prototype.py b/mailman/archiving/prototype.py
index 5e86a606f..e17a6f177 100644
--- a/mailman/archiving/prototype.py
+++ b/mailman/archiving/prototype.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/attic/Bouncer.py b/mailman/attic/Bouncer.py
index 690525b37..e2de3c915 100644
--- a/mailman/attic/Bouncer.py
+++ b/mailman/attic/Bouncer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/attic/Deliverer.py b/mailman/attic/Deliverer.py
index 5fcc78edc..0ba3a01bb 100644
--- a/mailman/attic/Deliverer.py
+++ b/mailman/attic/Deliverer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/attic/Digester.py b/mailman/attic/Digester.py
index d27ee62a6..a88d08abc 100644
--- a/mailman/attic/Digester.py
+++ b/mailman/attic/Digester.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/attic/MailList.py b/mailman/attic/MailList.py
index 705189751..2d538f026 100644
--- a/mailman/attic/MailList.py
+++ b/mailman/attic/MailList.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/attic/SecurityManager.py b/mailman/attic/SecurityManager.py
index 45801d10a..8d4a30592 100644
--- a/mailman/attic/SecurityManager.py
+++ b/mailman/attic/SecurityManager.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/bin/clone_member b/mailman/attic/bin/clone_member
index 1f2a03aca..1f2a03aca 100755
--- a/bin/clone_member
+++ b/mailman/attic/bin/clone_member
diff --git a/bin/discard b/mailman/attic/bin/discard
index c30198441..c30198441 100644
--- a/bin/discard
+++ b/mailman/attic/bin/discard
diff --git a/bin/fix_url.py b/mailman/attic/bin/fix_url.py
index 805323af3..30618a1a3 100644
--- a/bin/fix_url.py
+++ b/mailman/attic/bin/fix_url.py
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/bin/list_admins b/mailman/attic/bin/list_admins
index c628a42dc..c628a42dc 100644
--- a/bin/list_admins
+++ b/mailman/attic/bin/list_admins
diff --git a/bin/msgfmt.py b/mailman/attic/bin/msgfmt.py
index 8a2d4e66e..8a2d4e66e 100755..100644
--- a/bin/msgfmt.py
+++ b/mailman/attic/bin/msgfmt.py
diff --git a/bin/po2templ.py b/mailman/attic/bin/po2templ.py
index 8f3cd4138..86eae96b9 100755..100644
--- a/bin/po2templ.py
+++ b/mailman/attic/bin/po2templ.py
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2005-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2005-2009 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/bin/pygettext.py b/mailman/attic/bin/pygettext.py
index 84421ee8c..84421ee8c 100755..100644
--- a/bin/pygettext.py
+++ b/mailman/attic/bin/pygettext.py
diff --git a/bin/remove_members b/mailman/attic/bin/remove_members
index a7b4ebb47..a7b4ebb47 100755
--- a/bin/remove_members
+++ b/mailman/attic/bin/remove_members
diff --git a/bin/reset_pw.py b/mailman/attic/bin/reset_pw.py
index aca79ba6d..453c8b849 100644
--- a/bin/reset_pw.py
+++ b/mailman/attic/bin/reset_pw.py
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2004-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2004-2009 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/bin/sync_members b/mailman/attic/bin/sync_members
index 4a21624c1..4a21624c1 100755
--- a/bin/sync_members
+++ b/mailman/attic/bin/sync_members
diff --git a/bin/templ2pot.py b/mailman/attic/bin/templ2pot.py
index 0253cc2cd..0253cc2cd 100755..100644
--- a/bin/templ2pot.py
+++ b/mailman/attic/bin/templ2pot.py
diff --git a/bin/transcheck b/mailman/attic/bin/transcheck
index 73910e771..73910e771 100755
--- a/bin/transcheck
+++ b/mailman/attic/bin/transcheck
diff --git a/mailman/bin/__init__.py b/mailman/bin/__init__.py
index 4c3fc1673..d61693c5e 100644
--- a/mailman/bin/__init__.py
+++ b/mailman/bin/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/add_members.py b/mailman/bin/add_members.py
index 0ee0e8e84..e94484a9b 100644
--- a/mailman/bin/add_members.py
+++ b/mailman/bin/add_members.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/arch.py b/mailman/bin/arch.py
index 39ad9e343..a27fa8d7f 100644
--- a/mailman/bin/arch.py
+++ b/mailman/bin/arch.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/bounces.py b/mailman/bin/bounces.py
index ab3dbe635..e5e4e16b6 100644
--- a/mailman/bin/bounces.py
+++ b/mailman/bin/bounces.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/bumpdigests.py b/mailman/bin/bumpdigests.py
index 2739a0fe6..b1ed37a21 100644
--- a/mailman/bin/bumpdigests.py
+++ b/mailman/bin/bumpdigests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/check_perms.py b/mailman/bin/check_perms.py
index 116d8a245..4b75aa9f6 100644
--- a/mailman/bin/check_perms.py
+++ b/mailman/bin/check_perms.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/checkdbs.py b/mailman/bin/checkdbs.py
index 79406dcbc..2ce08aab7 100644
--- a/mailman/bin/checkdbs.py
+++ b/mailman/bin/checkdbs.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/cleanarch.py b/mailman/bin/cleanarch.py
index 0f2176029..325fad91a 100644
--- a/mailman/bin/cleanarch.py
+++ b/mailman/bin/cleanarch.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/config_list.py b/mailman/bin/config_list.py
index 7fb3e73a7..a5cec9480 100644
--- a/mailman/bin/config_list.py
+++ b/mailman/bin/config_list.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/confirm.py b/mailman/bin/confirm.py
index 87c5e893d..c3f1d49f6 100644
--- a/mailman/bin/confirm.py
+++ b/mailman/bin/confirm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/create_list.py b/mailman/bin/create_list.py
index 83c3c7c5d..36aa5c1d1 100644
--- a/mailman/bin/create_list.py
+++ b/mailman/bin/create_list.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/disabled.py b/mailman/bin/disabled.py
index 31fd0c014..cc8eb2c69 100644
--- a/mailman/bin/disabled.py
+++ b/mailman/bin/disabled.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/docs/master.txt b/mailman/bin/docs/master.txt
index 7565e93b1..0d3cade77 100644
--- a/mailman/bin/docs/master.txt
+++ b/mailman/bin/docs/master.txt
@@ -6,14 +6,19 @@ directories. In normal operation, a command line script called 'mailmanctl'
is used to start, stop and manage the queue runners. mailmanctl actually is
just a wrapper around the real queue runner watcher script called master.py.
- >>> from mailman.configuration import config
>>> from mailman.testing.helpers import TestableMaster
Start the master in a subthread.
>>> master = TestableMaster()
>>> master.start()
- >>> len(list(master.qrunner_pids)) == len(config.qrunners)
+
+There should be a process id for every qrunner that claims to be startable.
+
+ >>> from lazr.config import as_boolean
+ >>> startable_qrunners = [qconf for qconf in config.qrunner_configs
+ ... if as_boolean(qconf.start)]
+ >>> len(list(master.qrunner_pids)) == len(startable_qrunners)
True
Now verify that all the qrunners are running.
diff --git a/mailman/bin/dumpdb.py b/mailman/bin/dumpdb.py
index cb7ca7fd7..4642ac361 100644
--- a/mailman/bin/dumpdb.py
+++ b/mailman/bin/dumpdb.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/export.py b/mailman/bin/export.py
index e494d5a8d..f0bd28da0 100644
--- a/mailman/bin/export.py
+++ b/mailman/bin/export.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/find_member.py b/mailman/bin/find_member.py
index 605e243b4..0982724a0 100644
--- a/mailman/bin/find_member.py
+++ b/mailman/bin/find_member.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/gate_news.py b/mailman/bin/gate_news.py
index 25de5677d..eac30422d 100644
--- a/mailman/bin/gate_news.py
+++ b/mailman/bin/gate_news.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/genaliases.py b/mailman/bin/genaliases.py
index ec49b6a57..a09bc6318 100644
--- a/mailman/bin/genaliases.py
+++ b/mailman/bin/genaliases.py
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/import.py b/mailman/bin/import.py
index 2617cca99..d2361e808 100644
--- a/mailman/bin/import.py
+++ b/mailman/bin/import.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/inject.py b/mailman/bin/inject.py
index d4fb6fb6f..2bc8a49e3 100644
--- a/mailman/bin/inject.py
+++ b/mailman/bin/inject.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/join.py b/mailman/bin/join.py
index 475b3c142..29ae4c752 100644
--- a/mailman/bin/join.py
+++ b/mailman/bin/join.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/leave.py b/mailman/bin/leave.py
index 05146ef59..64f4f01c5 100644
--- a/mailman/bin/leave.py
+++ b/mailman/bin/leave.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/list_lists.py b/mailman/bin/list_lists.py
index 2750fed5b..d19044f35 100644
--- a/mailman/bin/list_lists.py
+++ b/mailman/bin/list_lists.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/list_members.py b/mailman/bin/list_members.py
index a5b047504..925105b51 100644
--- a/mailman/bin/list_members.py
+++ b/mailman/bin/list_members.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/list_owners.py b/mailman/bin/list_owners.py
index 7c2912ab0..953fb8941 100644
--- a/mailman/bin/list_owners.py
+++ b/mailman/bin/list_owners.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/mailmanctl.py b/mailman/bin/mailmanctl.py
index 5492892c5..6d424442a 100644
--- a/mailman/bin/mailmanctl.py
+++ b/mailman/bin/mailmanctl.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/make_instance.py b/mailman/bin/make_instance.py
index b63576fb1..cf20902ba 100644
--- a/mailman/bin/make_instance.py
+++ b/mailman/bin/make_instance.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/master.py b/mailman/bin/master.py
index 1c45e04f8..d3676629d 100644
--- a/mailman/bin/master.py
+++ b/mailman/bin/master.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -32,12 +32,13 @@ import socket
import logging
from datetime import timedelta
+from lazr.config import as_boolean
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 +238,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.')
@@ -269,7 +270,9 @@ class Loop:
:param spec: A queue runner spec, in a format acceptable to
bin/qrunner's --runner argument, e.g. name:slice:count
+ :type spec: string
:return: The process id of the child queue runner.
+ :rtype: int
"""
pid = os.fork()
if pid:
@@ -292,26 +295,43 @@ class Loop:
# We should never get here.
raise RuntimeError('os.execl() failed')
- def start_qrunners(self, qrunners=None):
+ def start_qrunners(self, qrunner_names=None):
"""Start all the configured qrunners.
:param qrunners: If given, a sequence of queue runner names to start.
If not given, this sequence is taken from the configuration file.
+ :type qrunners: a sequence of strings
"""
- if not qrunners:
- spec_parts = config.qrunners.items()
- else:
- spec_parts = []
- for qrname in qrunners:
- if '.' in qrname:
- spec_parts.append((qrname, 1))
- else:
- spec_parts.append((config.qrunner_shortcuts[qrname], 1))
- for qrname, count in spec_parts:
+ if not qrunner_names:
+ qrunner_names = []
+ for qrunner_config in config.qrunner_configs:
+ # Strip off the 'qrunner.' prefix.
+ assert qrunner_config.name.startswith('qrunner.'), (
+ 'Unexpected qrunner configuration section name: %s',
+ qrunner_config.name)
+ qrunner_names.append(qrunner_config.name[8:])
+ # For each qrunner we want to start, find their config section, which
+ # will tell us the name of the class to instantiate, along with the
+ # number of hash space slices to manage.
+ for name in qrunner_names:
+ section_name = 'qrunner.' + name
+ # Let AttributeError propagate.
+ qrunner_config = getattr(config, section_name)
+ if not as_boolean(qrunner_config.start):
+ continue
+ package, class_name = qrunner_config['class'].rsplit(DOT, 1)
+ __import__(package)
+ # Let AttributeError propagate.
+ class_ = getattr(sys.modules[package], class_name)
+ # Find out how many qrunners to instantiate. This must be a power
+ # of 2.
+ count = int(qrunner_config.instances)
+ assert (count & (count - 1)) == 0, (
+ 'Queue runner "%s", not a power of 2: %s', name, count)
for slice_number in range(count):
# qrunner name, slice #, # of slices, restart count
- info = (qrname, slice_number, count, 0)
- spec = '%s:%d:%d' % (qrname, slice_number, count)
+ info = (name, slice_number, count, 0)
+ spec = '%s:%d:%d' % (name, slice_number, count)
pid = self._start_runner(spec)
log = logging.getLogger('mailman.qrunner')
log.debug('[%d] %s', pid, spec)
@@ -349,12 +369,14 @@ class Loop:
# command line switch was not given. This lets us better handle
# runaway restarts (e.g. if the subprocess had a syntax error!)
qrname, slice_number, count, restarts = self._kids.pop(pid)
+ config_name = 'qrunner.' + qrname
restart = False
if why == signal.SIGUSR1 and self._restartable:
restart = True
# Have we hit the maximum number of restarts?
restarts += 1
- if restarts > config.MAX_RESTARTS:
+ max_restarts = int(getattr(config, config_name).max_restarts)
+ if restarts > max_restarts:
restart = False
# Are we permanently non-restartable?
log.debug("""\
@@ -363,10 +385,10 @@ Master detected subprocess exit
pid, why, qrname, slice_number + 1, count,
('[restarting]' if restart else ''))
# See if we've reached the maximum number of allowable restarts
- if restarts > config.MAX_RESTARTS:
+ if restarts > max_restarts:
log.info("""\
qrunner %s reached maximum restart limit of %d, not restarting.""",
- qrname, config.MAX_RESTARTS)
+ qrname, max_restarts)
# Now perhaps restart the process unless it exited with a
# SIGTERM or we aren't restarting.
if restart:
diff --git a/mailman/bin/mmsitepass.py b/mailman/bin/mmsitepass.py
index 6de72a2e1..132803fc9 100644
--- a/mailman/bin/mmsitepass.py
+++ b/mailman/bin/mmsitepass.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/nightly_gzip.py b/mailman/bin/nightly_gzip.py
index c21b6f8d5..f886e5801 100644
--- a/mailman/bin/nightly_gzip.py
+++ b/mailman/bin/nightly_gzip.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/owner.py b/mailman/bin/owner.py
index ad17a9246..e7c40b7e5 100644
--- a/mailman/bin/owner.py
+++ b/mailman/bin/owner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/post.py b/mailman/bin/post.py
index b34486c10..8511d52dc 100644
--- a/mailman/bin/post.py
+++ b/mailman/bin/post.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/qrunner.py b/mailman/bin/qrunner.py
index 422809fa3..a71bb2ef5 100644
--- a/mailman/bin/qrunner.py
+++ b/mailman/bin/qrunner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -19,8 +19,8 @@ import sys
import signal
import logging
-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
@@ -112,10 +112,6 @@ This should only be used when running qrunner as a subprocess of the
mailmanctl startup script. It changes some of the exit-on-error behavior to
work better with that framework."""))
- def initialize(self):
- """Override initialization to propagate logs correctly."""
- super(ScriptOptions, self).initialize(not self.options.subproc)
-
def sanity_check(self):
if self.arguments:
self.parser.error(_('Unexpected arguments'))
@@ -126,28 +122,30 @@ work better with that framework."""))
def make_qrunner(name, slice, range, once=False):
# Several conventions for specifying the runner name are supported. It
- # could be one of the shortcut names. Or the name is a full module path,
+ # could be one of the shortcut names. If the name is a full module path,
# use it explicitly. If the name starts with a dot, it's a class name
# relative to the Mailman.queue package.
- if name in config.qrunner_shortcuts:
- classpath = config.qrunner_shortcuts[name]
+ qrunner_config = getattr(config, 'qrunner.' + name, None)
+ if qrunner_config is not None:
+ # It was a shortcut name.
+ class_path = qrunner_config['class']
elif name.startswith('.'):
- classpath = 'mailman.queue' + name
+ class_path = 'mailman.queue' + name
else:
- classpath = name
- modulename, classname = classpath.rsplit('.', 1)
+ class_path = name
+ module_name, class_name = class_path.rsplit('.', 1)
try:
- __import__(modulename)
+ __import__(module_name)
except ImportError, e:
if config.options.options.subproc:
# Exit with SIGTERM exit code so the master watcher won't try to
# restart us.
- print >> sys.stderr, _('Cannot import runner module: $modulename')
+ print >> sys.stderr, _('Cannot import runner module: $module_name')
print >> sys.stderr, e
sys.exit(signal.SIGTERM)
else:
raise
- qrclass = getattr(sys.modules[modulename], classname)
+ qrclass = getattr(sys.modules[module_name], class_name)
if once:
# Subclass to hack in the setting of the stop flag in _do_periodic()
class Once(qrclass):
@@ -191,7 +189,7 @@ def set_signals(loop):
signal.signal(signal.SIGUSR1, sigusr1_handler)
# SIGHUP just tells us to rotate our log files.
def sighup_handler(signum, frame):
- loginit.reopen()
+ reopen()
log.info('%s qrunner caught SIGHUP. Reopening logs.', loop.name())
signal.signal(signal.SIGHUP, sighup_handler)
diff --git a/mailman/bin/remove_list.py b/mailman/bin/remove_list.py
index b83c56bbf..fb5d4cdbf 100644
--- a/mailman/bin/remove_list.py
+++ b/mailman/bin/remove_list.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/request.py b/mailman/bin/request.py
index b3d9f3f52..af62b4f51 100644
--- a/mailman/bin/request.py
+++ b/mailman/bin/request.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/senddigests.py b/mailman/bin/senddigests.py
index 344ef2f42..fb057d6b9 100644
--- a/mailman/bin/senddigests.py
+++ b/mailman/bin/senddigests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/set_members.py b/mailman/bin/set_members.py
index 70c90b13b..cdd11c56f 100644
--- a/mailman/bin/set_members.py
+++ b/mailman/bin/set_members.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/show_config.py b/mailman/bin/show_config.py
index c97df19e2..8d26c5c97 100644
--- a/mailman/bin/show_config.py
+++ b/mailman/bin/show_config.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/show_qfiles.py b/mailman/bin/show_qfiles.py
index c9156ebb0..08697a54e 100644
--- a/mailman/bin/show_qfiles.py
+++ b/mailman/bin/show_qfiles.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/testall.py b/mailman/bin/testall.py
index 83029060c..61b20b13b 100644
--- a/mailman/bin/testall.py
+++ b/mailman/bin/testall.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/unshunt.py b/mailman/bin/unshunt.py
index 4c44331a7..8a1dba081 100644
--- a/mailman/bin/unshunt.py
+++ b/mailman/bin/unshunt.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/update.py b/mailman/bin/update.py
index b5b28f2f7..d26548aa0 100644
--- a/mailman/bin/update.py
+++ b/mailman/bin/update.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/version.py b/mailman/bin/version.py
index 978432956..0fb2c5a5b 100644
--- a/mailman/bin/version.py
+++ b/mailman/bin/version.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/bin/withlist.py b/mailman/bin/withlist.py
index 32bfb1206..8862501d5 100644
--- a/mailman/bin/withlist.py
+++ b/mailman/bin/withlist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..d0c570c69 100644
--- a/mailman/chains/accept.py
+++ b/mailman/chains/accept.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -23,9 +23,8 @@ __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
log = logging.getLogger('mailman.vette')
@@ -50,6 +49,6 @@ class AcceptChain(TerminalChainBase):
rule_misses = msgdata.get('rule_misses')
if rule_misses:
msg['X-Mailman-Rule-Misses'] = SEMISPACE.join(rule_misses)
- accept_queue = Switchboard(config.PIPELINEQUEUE_DIR)
+ accept_queue = config.switchboards['pipeline']
accept_queue.enqueue(msg, msgdata)
log.info('ACCEPT: %s', msg.get('message-id', 'n/a'))
diff --git a/mailman/chains/base.py b/mailman/chains/base.py
index 39968a1fe..c9edcba44 100644
--- a/mailman/chains/base.py
+++ b/mailman/chains/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..8f460ba09 100644
--- a/mailman/chains/builtin.py
+++ b/mailman/chains/builtin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/discard.py b/mailman/chains/discard.py
index 166aed908..525505e36 100644
--- a/mailman/chains/discard.py
+++ b/mailman/chains/discard.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/chains/headers.py b/mailman/chains/headers.py
index d53f67e06..311e5feee 100644
--- a/mailman/chains/headers.py
+++ b/mailman/chains/headers.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..655771fcb 100644
--- a/mailman/chains/hold.py
+++ b/mailman/chains/hold.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/chains/reject.py b/mailman/chains/reject.py
index 34e72fa86..c7ec04fec 100644
--- a/mailman/chains/reject.py
+++ b/mailman/chains/reject.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/__init__.py b/mailman/commands/__init__.py
index 52374888a..6e89bc6da 100644
--- a/mailman/commands/__init__.py
+++ b/mailman/commands/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_confirm.py b/mailman/commands/cmd_confirm.py
index 20fa0169e..b5e4182bd 100644
--- a/mailman/commands/cmd_confirm.py
+++ b/mailman/commands/cmd_confirm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..eeee33ca7 100644
--- a/mailman/commands/cmd_help.py
+++ b/mailman/commands/cmd_help.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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_info.py b/mailman/commands/cmd_info.py
index c14ade110..3bdea178f 100644
--- a/mailman/commands/cmd_info.py
+++ b/mailman/commands/cmd_info.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_leave.py b/mailman/commands/cmd_leave.py
index 7b808925a..5844824f7 100644
--- a/mailman/commands/cmd_leave.py
+++ b/mailman/commands/cmd_leave.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_lists.py b/mailman/commands/cmd_lists.py
index b7b5a3b74..234ef46fc 100644
--- a/mailman/commands/cmd_lists.py
+++ b/mailman/commands/cmd_lists.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..545da0cb5 100644
--- a/mailman/commands/cmd_password.py
+++ b/mailman/commands/cmd_password.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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_remove.py b/mailman/commands/cmd_remove.py
index 6c37ba32d..8f3ce9669 100644
--- a/mailman/commands/cmd_remove.py
+++ b/mailman/commands/cmd_remove.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_set.py b/mailman/commands/cmd_set.py
index 94ba9192f..020bc3636 100644
--- a/mailman/commands/cmd_set.py
+++ b/mailman/commands/cmd_set.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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_stop.py b/mailman/commands/cmd_stop.py
index 0e4ba2b0e..fc3df69fd 100644
--- a/mailman/commands/cmd_stop.py
+++ b/mailman/commands/cmd_stop.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_unsubscribe.py b/mailman/commands/cmd_unsubscribe.py
index 68f09607c..456b8089d 100644
--- a/mailman/commands/cmd_unsubscribe.py
+++ b/mailman/commands/cmd_unsubscribe.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/cmd_who.py b/mailman/commands/cmd_who.py
index 725040f4d..6c66610b3 100644
--- a/mailman/commands/cmd_who.py
+++ b/mailman/commands/cmd_who.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/docs/echo.txt b/mailman/commands/docs/echo.txt
index d2781d330..181cc58c8 100644
--- a/mailman/commands/docs/echo.txt
+++ b/mailman/commands/docs/echo.txt
@@ -4,7 +4,6 @@ The 'echo' command
The mail command 'echo' simply replies with the original command and arguments
to the sender.
- >>> from mailman.configuration import config
>>> command = config.commands['echo']
>>> command.name
'echo'
diff --git a/mailman/commands/docs/end.txt b/mailman/commands/docs/end.txt
index bd632de48..4f6af26cb 100644
--- a/mailman/commands/docs/end.txt
+++ b/mailman/commands/docs/end.txt
@@ -4,7 +4,6 @@ The 'end' command
The mail command processor recognized an 'end' command which tells it to stop
processing email messages.
- >>> from mailman.configuration import config
>>> command = config.commands['end']
>>> command.name
'end'
diff --git a/mailman/commands/docs/join.txt b/mailman/commands/docs/join.txt
index 492297787..fd382d0f0 100644
--- a/mailman/commands/docs/join.txt
+++ b/mailman/commands/docs/join.txt
@@ -4,7 +4,6 @@ The 'join' command
The mail command 'join' subscribes an email address to the mailing list.
'subscribe' is an alias for 'join'.
- >>> from mailman.configuration import config
>>> command = config.commands['join']
>>> print command.name
join
@@ -84,8 +83,7 @@ first.
Mailman has sent her the confirmation message.
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> qmsg, qdata = virginq.dequeue(virginq.files[0])
>>> print qmsg.as_string()
MIME-Version: 1.0
diff --git a/mailman/commands/echo.py b/mailman/commands/echo.py
index 9a7b2eba8..d2719e19b 100644
--- a/mailman/commands/echo.py
+++ b/mailman/commands/echo.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/end.py b/mailman/commands/end.py
index 831b0c045..e744ec7ba 100644
--- a/mailman/commands/end.py
+++ b/mailman/commands/end.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/commands/join.py b/mailman/commands/join.py
index 17fb071a6..58fbb6428 100644
--- a/mailman/commands/join.py
+++ b/mailman/commands/join.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..6ac060cb2
--- /dev/null
+++ b/mailman/config/__init__.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+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..3f717d3be
--- /dev/null
+++ b/mailman/config/config.py
@@ -0,0 +1,188 @@
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""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, 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
+
+
+SPACE = ' '
+
+
+
+class Configuration(object):
+ """The core global configuration object."""
+
+ def __init__(self):
+ self.domains = {} # email host -> IDomain
+ self.switchboards = {}
+ self.languages = LanguageManager()
+ self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION
+ self._config = None
+ self.filename = None
+ # Create various registries.
+ self.archivers = {}
+ self.chains = {}
+ self.rules = {}
+ self.handlers = {}
+ self.pipelines = {}
+ self.commands = {}
+
+ def _clear(self):
+ """Clear the cached configuration variables."""
+ self.domains.clear()
+ self.switchboards.clear()
+ self.languages = LanguageManager()
+
+ 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_string = resource_string('mailman.config', 'schema.cfg')
+ schema = ConfigSchema('schema.cfg', StringIO(schema_string))
+ # If a configuration file was given, load it now too. First, load the
+ # absolute minimum default configuration, then if a configuration
+ # filename was given by the user, push it.
+ config_string = resource_string('mailman.config', 'mailman.cfg')
+ self._config = schema.loadFile(StringIO(config_string), 'mailman.cfg')
+ if filename is not None:
+ self.filename = filename
+ with open(filename) as user_config:
+ self._config.push(filename, user_config.read())
+ self._post_process()
+
+ def push(self, config_name, config_string):
+ """Push a new configuration onto the stack."""
+ self._clear()
+ self._config.push(config_name, config_string)
+ self._post_process()
+
+ def pop(self, config_name):
+ """Pop a configuration from the stack."""
+ self._clear()
+ self._config.pop(config_name)
+ self._post_process()
+
+ def _post_process(self):
+ """Perform post-processing after loading the configuration files."""
+ # Set up the domains.
+ domains = self._config.getByCategory('domain', [])
+ 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 directories.
+ self.BIN_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
+ self.VAR_DIR = 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.QUEUE_DIR = join(var_dir, 'qfiles')
+ self.MESSAGES_DIR = join(var_dir, 'messages')
+ self.PUBLIC_ARCHIVE_FILE_DIR = join(var_dir, 'archives', 'public')
+ self.PRIVATE_ARCHIVE_FILE_DIR = join(var_dir, 'archives', 'private')
+ # 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 the switchboards.
+ from mailman.queue import Switchboard
+ Switchboard.initialize()
+ # Set up all the languages.
+ languages = self._config.getByCategory('language', [])
+ for language in languages:
+ code = language.name.split('.')[1]
+ self.languages.add_language(code, language.description,
+ language.charset, language.enabled)
+ # Always enable the server default language, which must be defined.
+ self.languages.enable_language(self._config.mailman.default_language)
+ self.ensure_directories_exist()
+
+ @property
+ def logger_configs(self):
+ """Return all log config sections."""
+ return self._config.getByCategory('logging', [])
+
+ @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 qrunner_configs(self):
+ for section in self._config.getByCategory('qrunner', []):
+ yield section
+
+ @property
+ def header_matches(self):
+ """Iterate over all spam matching headers.
+
+ Values are 3-tuples of (header, pattern, chain)
+ """
+ matches = self._config.getByCategory('spam.headers', [])
+ for match in matches:
+ yield (matches.header, matches.pattern, matches.chain)
diff --git a/mailman/config/mailman.cfg b/mailman/config/mailman.cfg
new file mode 100644
index 000000000..d88947975
--- /dev/null
+++ b/mailman/config/mailman.cfg
@@ -0,0 +1,67 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+# This is the absolute bare minimum base configuration file. User supplied
+# configurations are pushed onto this.
+
+[language.en]
+
+[qrunner.archive]
+class: mailman.queue.archive.ArchiveRunner
+
+[qrunner.bad]
+class: mailman.queue.fake.BadRunner
+# The shunt runner is just a placeholder for its switchboard.
+start: no
+
+[qrunner.bounces]
+class: mailman.queue.bounce.BounceRunner
+
+[qrunner.command]
+class: mailman.queue.command.CommandRunner
+
+[qrunner.in]
+class: mailman.queue.incoming.IncomingRunner
+
+[qrunner.lmtp]
+class: mailman.queue.lmtp.LMTPRunner
+
+[qrunner.maildir]
+class: mailman.queue.maildir.MaildirRunner
+# This is still experimental.
+start: no
+
+[qrunner.news]
+class: mailman.queue.news.NewsRunner
+
+[qrunner.out]
+class: mailman.queue.outgoing.OutgoingRunner
+
+[qrunner.pipeline]
+class: mailman.queue.pipeline.PipelineRunner
+
+[qrunner.retry]
+class: mailman.queue.retry.RetryRunner
+sleep_time: 15m
+
+[qrunner.shunt]
+class: mailman.queue.fake.ShuntRunner
+# The shunt runner is just a placeholder for its switchboard.
+start: no
+
+[qrunner.virgin]
+class: mailman.queue.virgin.VirginRunner
diff --git a/mailman/config/schema.cfg b/mailman/config/schema.cfg
new file mode 100644
index 000000000..3cc4eab79
--- /dev/null
+++ b/mailman/config/schema.cfg
@@ -0,0 +1,255 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+# 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.
+
+[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
+
+# When allowing only members to post to a mailing list, how is the sender of
+# the message determined? If this variable is set to Yes, then first the
+# message's envelope sender is used, with a fallback to the sender if there is
+# no envelope sender. Set this variable to No to always use the sender.
+#
+# The envelope sender is set by the SMTP delivery and is thus less easily
+# spoofed than the sender, which is typically just taken from the From: header
+# and thus easily spoofed by the end-user. However, sometimes the envelope
+# sender isn't set correctly and this will manifest itself by postings being
+# held for approval even if they appear to come from a list member. If you
+# are having this problem, set this variable to No, but understand that some
+# spoofed messages may get through.
+use_envelope_sender: no
+
+# Mail command processor will ignore mail command lines after designated max.
+email_commands_max_lines: 10
+
+
+[qrunner.master]
+# Define which process queue runners, and how many of them, to start.
+
+# The full import path to the class for this queue runner.
+class: mailman.queue.runner.Runner
+
+# The directory path that this queue runner scans.
+path: $VAR_DIR/qfiles/$name
+
+# The number of parallel queue runners. This must be a power of 2.
+instances: 1
+
+# Whether to start this queue runner or not.
+start: yes
+
+# The maximum number of restarts for this queue runner. When the runner exits
+# because of an error or other unexpected problem, it is automatically
+# restarted, until the maximum number of restarts has been reached.
+max_restarts: 10
+
+# The sleep interval for the queue runner. It wakes up once every interval to
+# process the files in its slice of the queue directory.
+sleep_time: 1s
+
+[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.master]
+# 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.master]
+# 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.
+enabled: yes
+
+
+[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
+
+
+[mta]
+# The class defining the interface to the incoming mail transport agent.
+incoming: mailman.mta.postfix.LMTP
+
+# The class defining the interface to the outgoing mail transport agent.
+outgoing: mailman.mta.direct.SMTPDirect
+
+# How to connect to the outgoing MTA.
+smtp_host: localhost
+smtp_port: 25
+
+# Where the LMTP server listens for connections.
+lmtp_host: localhost
+lmtp_port: 8025
+
+
+[archiver.master]
+base_url: http://archive.example.com/
+recipient: archive@archive.example.com
+command: /bin/echo
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/constants.py b/mailman/constants.py
index 6d015470f..472331ffb 100644
--- a/mailman/constants.py
+++ b/mailman/constants.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/core/chains.py b/mailman/core/chains.py
index bebbf5bee..ba34a426e 100644
--- a/mailman/core/chains.py
+++ b/mailman/core/chains.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/core/errors.py b/mailman/core/errors.py
index 0704acb4a..e83f32932 100644
--- a/mailman/core/errors.py
+++ b/mailman/core/errors.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/initialize.py b/mailman/core/initialize.py
index ea7c294c8..d7a2fde5a 100644
--- a/mailman/initialize.py
+++ b/mailman/core/initialize.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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
@@ -42,7 +42,7 @@ from mailman.interfaces import IDatabase
# initialization, but before database initialization. Generally all other
# code will just call initialize().
-def initialize_1(config_path, propagate_logs):
+def initialize_1(config_path=None, propagate_logs=None):
"""First initialization step.
* The configuration system
@@ -52,7 +52,7 @@ def initialize_1(config_path, propagate_logs):
:param config_path: The path to the configuration file.
:type config_path: string
:param propagate_logs: Should the log output propagate to stderr?
- :type propagate_logs: boolean
+ :type propagate_logs: boolean or None
"""
# By default, set the umask so that only owner and group can read and
# write our files. Specifically we must have g+rw and we probably want
@@ -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
@@ -93,6 +93,7 @@ def initialize_2(debug=False):
from mailman.core.chains import initialize as initialize_chains
from mailman.core.pipelines import initialize as initialize_pipelines
from mailman.core.rules import initialize as initialize_rules
+ # Order here is somewhat important.
initialize_archivers()
initialize_rules()
initialize_chains()
@@ -110,7 +111,7 @@ def initialize_3():
-def initialize(config_path=None, propagate_logs=False):
+def initialize(config_path=None, propagate_logs=None):
initialize_1(config_path, propagate_logs)
initialize_2()
initialize_3()
diff --git a/mailman/core/logging.py b/mailman/core/logging.py
new file mode 100644
index 000000000..d1f46f951
--- /dev/null
+++ b/mailman/core/logging.py
@@ -0,0 +1,154 @@
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Logging initialization, using Python's standard logging package."""
+
+from __future__ import absolute_import
+
+__metaclass__ = type
+__all__ = [
+ 'initialize',
+ 'reopen',
+ ]
+
+
+import os
+import sys
+import codecs
+import logging
+import ConfigParser
+
+from lazr.config import as_boolean, as_log_level
+
+from mailman.config import config
+
+
+_handlers = {}
+
+
+
+class ReopenableFileHandler(logging.Handler):
+ """A file handler that supports reopening."""
+
+ def __init__(self, name, filename):
+ self.name = name
+ 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, filename=None):
+ """Reopen the output stream.
+
+ :param filename: If given, this reopens the output stream to a new
+ file. This is used in the test suite.
+ :type filename: string
+ """
+ if filename is not None:
+ self._filename = filename
+ self._stream.close()
+ self._stream = self._open()
+
+
+
+def initialize(propagate=None):
+ """Initialize all logs.
+
+ :param propagate: Flag specifying whether logs should propagate their
+ messages to the root logger. If omitted, propagation is determined
+ from the configuration files.
+ :type propagate: bool or None
+ """
+ # First, find the root logger and configure the logging subsystem.
+ # Initialize the root logger, then create a formatter for all the
+ # sublogs. The root logger should log to stderr.
+ logging.basicConfig(format=config.logging.root.format,
+ datefmt=config.logging.root.datefmt,
+ level=as_log_level(config.logging.root.level),
+ stream=sys.stderr)
+ # Create the subloggers.
+ for logger_config in config.logger_configs:
+ sub_name = logger_config.name.split('.')[-1]
+ if sub_name == 'root':
+ continue
+ logger_name = 'mailman.' + sub_name
+ 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)
+ if propagate is None else 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(sub_name, path_abs)
+ _handlers[sub_name] = handler
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+
+
+
+def reopen():
+ """Re-open all log files."""
+ for handler in _handlers.values():
+ handler.reopen()
+
+
+
+def get_handler(sub_name):
+ """Return the handler associated with a named logger.
+
+ :param sub_name: The logger name, sans the 'mailman.' prefix.
+ :type sub_name: string
+ :return: The file handler associated with the named logger.
+ :rtype: `ReopenableFileHandler`
+ """
+ return _handlers[sub_name]
diff --git a/mailman/core/pipelines.py b/mailman/core/pipelines.py
index c790901b2..bc4a70b87 100644
--- a/mailman/core/pipelines.py
+++ b/mailman/core/pipelines.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/plugins.py b/mailman/core/plugins.py
index cf22ad377..cce95fddd 100644
--- a/mailman/core/plugins.py
+++ b/mailman/core/plugins.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/core/rules.py b/mailman/core/rules.py
index 2c1e4fb3b..62c643937 100644
--- a/mailman/core/rules.py
+++ b/mailman/core/rules.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..66b8baaf2 100644
--- a/mailman/core/styles.py
+++ b/mailman/core/styles.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -23,14 +23,17 @@ __all__ = [
'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.configuration import config
+from mailman.config import config
from mailman.core.plugins import get_plugins
from mailman.i18n import _
from mailman.interfaces import (
@@ -54,75 +57,77 @@ class DefaultStyle:
# Most of these were ripped from the old MailList.InitVars() method.
mlist.volume = 1
mlist.post_id = 1
- mlist.new_member_options = config.DEFAULT_NEW_MEMBER_OPTIONS
+ mlist.new_member_options = Defaults.DEFAULT_NEW_MEMBER_OPTIONS
# This stuff is configurable
mlist.real_name = mlist.list_name.capitalize()
mlist.respond_to_post_requests = True
- mlist.advertised = config.DEFAULT_LIST_ADVERTISED
- mlist.max_num_recipients = config.DEFAULT_MAX_NUM_RECIPIENTS
- mlist.max_message_size = config.DEFAULT_MAX_MESSAGE_SIZE
- mlist.reply_goes_to_list = config.DEFAULT_REPLY_GOES_TO_LIST
+ 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.reply_to_address = u''
- mlist.first_strip_reply_to = config.DEFAULT_FIRST_STRIP_REPLY_TO
- mlist.admin_immed_notify = config.DEFAULT_ADMIN_IMMED_NOTIFY
+ mlist.first_strip_reply_to = Defaults.DEFAULT_FIRST_STRIP_REPLY_TO
+ mlist.admin_immed_notify = Defaults.DEFAULT_ADMIN_IMMED_NOTIFY
mlist.admin_notify_mchanges = (
- config.DEFAULT_ADMIN_NOTIFY_MCHANGES)
+ Defaults.DEFAULT_ADMIN_NOTIFY_MCHANGES)
mlist.require_explicit_destination = (
- config.DEFAULT_REQUIRE_EXPLICIT_DESTINATION)
- mlist.acceptable_aliases = config.DEFAULT_ACCEPTABLE_ALIASES
- mlist.send_reminders = config.DEFAULT_SEND_REMINDERS
- mlist.send_welcome_msg = config.DEFAULT_SEND_WELCOME_MSG
- mlist.send_goodbye_msg = config.DEFAULT_SEND_GOODBYE_MSG
+ 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 = (
- config.DEFAULT_BOUNCE_MATCHING_HEADERS)
+ Defaults.DEFAULT_BOUNCE_MATCHING_HEADERS)
mlist.header_matches = []
- mlist.anonymous_list = config.DEFAULT_ANONYMOUS_LIST
+ mlist.anonymous_list = Defaults.DEFAULT_ANONYMOUS_LIST
mlist.description = u''
mlist.info = u''
mlist.welcome_msg = u''
mlist.goodbye_msg = u''
- mlist.subscribe_policy = config.DEFAULT_SUBSCRIBE_POLICY
- mlist.subscribe_auto_approval = config.DEFAULT_SUBSCRIBE_AUTO_APPROVAL
- mlist.unsubscribe_policy = config.DEFAULT_UNSUBSCRIBE_POLICY
- mlist.private_roster = config.DEFAULT_PRIVATE_ROSTER
- mlist.obscure_addresses = config.DEFAULT_OBSCURE_ADDRESSES
- mlist.admin_member_chunksize = config.DEFAULT_ADMIN_MEMBER_CHUNKSIZE
- mlist.administrivia = config.DEFAULT_ADMINISTRIVIA
- mlist.preferred_language = config.DEFAULT_SERVER_LANGUAGE
+ 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.include_rfc2369_headers = True
mlist.include_list_post_header = True
- mlist.filter_mime_types = config.DEFAULT_FILTER_MIME_TYPES
- mlist.pass_mime_types = config.DEFAULT_PASS_MIME_TYPES
+ mlist.filter_mime_types = Defaults.DEFAULT_FILTER_MIME_TYPES
+ mlist.pass_mime_types = Defaults.DEFAULT_PASS_MIME_TYPES
mlist.filter_filename_extensions = (
- config.DEFAULT_FILTER_FILENAME_EXTENSIONS)
- mlist.pass_filename_extensions = config.DEFAULT_PASS_FILENAME_EXTENSIONS
- mlist.filter_content = config.DEFAULT_FILTER_CONTENT
- mlist.collapse_alternatives = config.DEFAULT_COLLAPSE_ALTERNATIVES
+ 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 = (
- config.DEFAULT_CONVERT_HTML_TO_PLAINTEXT)
- mlist.filter_action = config.DEFAULT_FILTER_ACTION
+ Defaults.DEFAULT_CONVERT_HTML_TO_PLAINTEXT)
+ mlist.filter_action = Defaults.DEFAULT_FILTER_ACTION
# Digest related variables
- mlist.digestable = config.DEFAULT_DIGESTABLE
- mlist.digest_is_default = config.DEFAULT_DIGEST_IS_DEFAULT
- mlist.mime_is_default_digest = config.DEFAULT_MIME_IS_DEFAULT_DIGEST
- mlist.digest_size_threshhold = config.DEFAULT_DIGEST_SIZE_THRESHHOLD
- mlist.digest_send_periodic = config.DEFAULT_DIGEST_SEND_PERIODIC
- mlist.digest_header = config.DEFAULT_DIGEST_HEADER
- mlist.digest_footer = config.DEFAULT_DIGEST_FOOTER
- mlist.digest_volume_frequency = config.DEFAULT_DIGEST_VOLUME_FREQUENCY
+ 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.one_last_digest = {}
- mlist.digest_members = {}
mlist.next_digest_number = 1
- mlist.nondigestable = config.DEFAULT_NONDIGESTABLE
+ mlist.nondigestable = Defaults.DEFAULT_NONDIGESTABLE
mlist.personalize = Personalization.none
# New sender-centric moderation (privacy) options
mlist.default_member_moderation = (
- config.DEFAULT_DEFAULT_MEMBER_MODERATION)
+ Defaults.DEFAULT_DEFAULT_MEMBER_MODERATION)
# Archiver
- mlist.archive = config.DEFAULT_ARCHIVE
- mlist.archive_private = config.DEFAULT_ARCHIVE_PRIVATE
+ mlist.archive = Defaults.DEFAULT_ARCHIVE
+ mlist.archive_private = Defaults.DEFAULT_ARCHIVE_PRIVATE
mlist.archive_volume_frequency = (
- config.DEFAULT_ARCHIVE_VOLUME_FREQUENCY)
+ Defaults.DEFAULT_ARCHIVE_VOLUME_FREQUENCY)
mlist.emergency = False
mlist.member_moderation_action = Action.hold
mlist.member_moderation_notice = u''
@@ -130,9 +135,9 @@ class DefaultStyle:
mlist.hold_these_nonmembers = []
mlist.reject_these_nonmembers = []
mlist.discard_these_nonmembers = []
- mlist.forward_auto_discards = config.DEFAULT_FORWARD_AUTO_DISCARDS
+ mlist.forward_auto_discards = Defaults.DEFAULT_FORWARD_AUTO_DISCARDS
mlist.generic_nonmember_action = (
- config.DEFAULT_GENERIC_NONMEMBER_ACTION)
+ Defaults.DEFAULT_GENERIC_NONMEMBER_ACTION)
mlist.nonmember_rejection_notice = u''
# Ban lists
mlist.ban_list = []
@@ -140,9 +145,9 @@ 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 = _(config.DEFAULT_SUBJECT_PREFIX)
- mlist.msg_header = config.DEFAULT_MSG_HEADER
- mlist.msg_footer = config.DEFAULT_MSG_FOOTER
+ mlist.subject_prefix = _(Defaults.DEFAULT_SUBJECT_PREFIX)
+ mlist.msg_header = Defaults.DEFAULT_MSG_HEADER
+ mlist.msg_footer = Defaults.DEFAULT_MSG_FOOTER
# 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':
@@ -150,9 +155,9 @@ class DefaultStyle:
else:
mlist.encode_ascii_prefixes = 2
# scrub regular delivery
- mlist.scrub_nondigest = config.DEFAULT_SCRUB_NONDIGEST
+ mlist.scrub_nondigest = Defaults.DEFAULT_SCRUB_NONDIGEST
# automatic discarding
- mlist.max_days_to_hold = config.DEFAULT_MAX_DAYS_TO_HOLD
+ mlist.max_days_to_hold = Defaults.DEFAULT_MAX_DAYS_TO_HOLD
# Autoresponder
mlist.autorespond_postings = False
mlist.autorespond_admin = False
@@ -169,19 +174,20 @@ class DefaultStyle:
mlist.admin_responses = {}
mlist.request_responses = {}
# Bounces
- mlist.bounce_processing = config.DEFAULT_BOUNCE_PROCESSING
- mlist.bounce_score_threshold = config.DEFAULT_BOUNCE_SCORE_THRESHOLD
- mlist.bounce_info_stale_after = config.DEFAULT_BOUNCE_INFO_STALE_AFTER
+ 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 = (
- config.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS)
+ Defaults.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS)
mlist.bounce_you_are_disabled_warnings_interval = (
- config.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS_INTERVAL)
+ Defaults.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS_INTERVAL)
mlist.bounce_unrecognized_goes_to_list_owner = (
- config.DEFAULT_BOUNCE_UNRECOGNIZED_GOES_TO_LIST_OWNER)
+ Defaults.DEFAULT_BOUNCE_UNRECOGNIZED_GOES_TO_LIST_OWNER)
mlist.bounce_notify_owner_on_disable = (
- config.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_DISABLE)
+ Defaults.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_DISABLE)
mlist.bounce_notify_owner_on_removal = (
- config.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_REMOVAL)
+ Defaults.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_REMOVAL)
# 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
@@ -190,7 +196,7 @@ class DefaultStyle:
# New style delivery status
mlist.delivery_status = {}
# NNTP gateway
- mlist.nntp_host = config.DEFAULT_NNTP_HOST
+ mlist.nntp_host = Defaults.DEFAULT_NNTP_HOST
mlist.linked_newsgroup = u''
mlist.gateway_to_news = False
mlist.gateway_to_mail = False
diff --git a/mailman/database/__init__.py b/mailman/database/__init__.py
index dfafe4473..4c2a60e5d 100644
--- a/mailman/database/__init__.py
+++ b/mailman/database/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -21,8 +21,10 @@ __all__ = [
]
import os
+import logging
from locknix.lockfile import Lock
+from lazr.config import as_boolean
from pkg_resources import resource_string
from storm.locals import create_database, Store
from string import Template
@@ -31,14 +33,16 @@ from zope.interface import implements
import mailman.version
-from mailman.configuration import config
+from mailman.config import config
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
+
+log = logging.getLogger('mailman.config')
@@ -82,8 +86,8 @@ 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)
+ log.debug('Database url: %s', url)
# 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 +105,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..f5039cf15 100644
--- a/mailman/database/address.py
+++ b/mailman/database/address.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/language.py b/mailman/database/language.py
index 82ad247c8..192c9a142 100644
--- a/mailman/database/language.py
+++ b/mailman/database/language.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/database/listmanager.py b/mailman/database/listmanager.py
index c4cebce4c..f6a0f5185 100644
--- a/mailman/database/listmanager.py
+++ b/mailman/database/listmanager.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..641245daf 100644
--- a/mailman/database/mailinglist.py
+++ b/mailman/database/mailinglist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -21,8 +21,9 @@ import string
from storm.locals import *
from zope.interface import implements
+from mailman import Defaults
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
@@ -218,7 +219,7 @@ class MailingList(Model):
@property
def no_reply_address(self):
- return '%s@%s' % (config.NO_REPLY_ADDRESS, self.host_name)
+ return '%s@%s' % (config.mailman.noreply_address, self.host_name)
@property
def owner_address(self):
@@ -249,7 +250,7 @@ class MailingList(Model):
return '%s-unsubscribe@%s' % (self.list_name, self.host_name)
def confirm_address(self, cookie):
- template = string.Template(config.VERP_CONFIRM_FORMAT)
+ template = string.Template(Defaults.VERP_CONFIRM_FORMAT)
local_part = template.safe_substitute(
address = '%s-confirm' % self.list_name,
cookie = cookie)
diff --git a/mailman/database/member.py b/mailman/database/member.py
index a4011840a..244e0853b 100644
--- a/mailman/database/member.py
+++ b/mailman/database/member.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..b62fe580b 100644
--- a/mailman/database/message.py
+++ b/mailman/database/message.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..934015b10 100644
--- a/mailman/database/messagestore.py
+++ b/mailman/database/messagestore.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/model.py b/mailman/database/model.py
index fa4de3420..598f537e8 100644
--- a/mailman/database/model.py
+++ b/mailman/database/model.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/database/pending.py b/mailman/database/pending.py
index 31cc4e285..ff794c83c 100644
--- a/mailman/database/pending.py
+++ b/mailman/database/pending.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -27,7 +27,8 @@ from storm.locals import *
from zope.interface import implements
from zope.interface.verify import verifyObject
-from mailman.configuration import config
+from mailman import Defaults
+from mailman.config import config
from mailman.database.model import Model
from mailman.interfaces import (
IPendable, IPended, IPendedKeyValue, IPendings)
@@ -79,7 +80,7 @@ class Pendings(object):
verifyObject(IPendable, pendable)
# Calculate the token and the lifetime.
if lifetime is None:
- lifetime = config.PENDING_REQUEST_LIFE
+ lifetime = Defaults.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/database/preferences.py b/mailman/database/preferences.py
index 54d40bb2f..d7d899c44 100644
--- a/mailman/database/preferences.py
+++ b/mailman/database/preferences.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/database/requests.py b/mailman/database/requests.py
index 963d34cc4..addaf08eb 100644
--- a/mailman/database/requests.py
+++ b/mailman/database/requests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..d044cc386 100644
--- a/mailman/database/roster.py
+++ b/mailman/database/roster.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/transaction.py b/mailman/database/transaction.py
index 14c494f89..4663f6110 100644
--- a/mailman/database/transaction.py
+++ b/mailman/database/transaction.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -23,7 +23,7 @@ __all__ = [
]
-from mailman.configuration import config
+from mailman.config import config
diff --git a/mailman/database/types.py b/mailman/database/types.py
index 133fdd3e1..26bdb0aff 100644
--- a/mailman/database/types.py
+++ b/mailman/database/types.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/database/user.py b/mailman/database/user.py
index 9d8e87a9f..d54bb048f 100644
--- a/mailman/database/user.py
+++ b/mailman/database/user.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..87a8cd208 100644
--- a/mailman/database/usermanager.py
+++ b/mailman/database/usermanager.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/database/version.py b/mailman/database/version.py
index d5281cde0..83e50b821 100644
--- a/mailman/database/version.py
+++ b/mailman/database/version.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/docs/addresses.txt b/mailman/docs/addresses.txt
index 749068433..6ddb8b8a9 100644
--- a/mailman/docs/addresses.txt
+++ b/mailman/docs/addresses.txt
@@ -6,7 +6,6 @@ those addresses, such as their registration date, and whether and when they've
been validated. Addresses may be linked to the users that Mailman knows
about. Addresses are subscribed to mailing lists though members.
- >>> from mailman.configuration import config
>>> usermgr = config.db.user_manager
diff --git a/mailman/docs/archivers.txt b/mailman/docs/archivers.txt
index c8ddb73e4..b8da86809 100644
--- a/mailman/docs/archivers.txt
+++ b/mailman/docs/archivers.txt
@@ -24,7 +24,6 @@ Pipermail does not support a permalink, so that interface returns None.
Mailman defines a draft spec for how list servers and archivers can
interoperate.
- >>> from mailman.configuration import config
>>> for archiver_name, archiver in sorted(config.archivers.items()):
... print archiver.name
... print ' ', archiver.list_url(mlist)
@@ -88,7 +87,7 @@ address at the Mail-Archive.
>>> from mailman.queue.outgoing import OutgoingRunner
>>> from mailman.testing.helpers import make_testable_runner
- >>> outgoing = make_testable_runner(OutgoingRunner)
+ >>> outgoing = make_testable_runner(OutgoingRunner, 'out')
>>> outgoing.run()
>>> from operator import itemgetter
diff --git a/mailman/docs/bounces.txt b/mailman/docs/bounces.txt
index ff110c509..9e8bcd23b 100644
--- a/mailman/docs/bounces.txt
+++ b/mailman/docs/bounces.txt
@@ -13,7 +13,6 @@ Mailman can also bounce messages back to the original sender. This is
essentially equivalent to rejecting the message with notification. Mailing
lists can bounce a message with an optional error message.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
@@ -31,8 +30,7 @@ Bounce a message by passing in the original message, and an optional error
message. The bounced message ends up in the virgin queue, awaiting sending
to the original messageauthor.
- >>> from mailman.queue import Switchboard
- >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> switchboard = config.switchboards['virgin']
>>> from mailman.app.bounces import bounce_message
>>> bounce_message(mlist, msg)
>>> len(switchboard.files)
diff --git a/mailman/docs/chains.txt b/mailman/docs/chains.txt
index 1118df687..6c2137e27 100644
--- a/mailman/docs/chains.txt
+++ b/mailman/docs/chains.txt
@@ -15,7 +15,6 @@ The Discard chain
The Discard chain simply throws the message away.
>>> from zope.interface.verify import verifyObject
- >>> from mailman.configuration import config
>>> from mailman.interfaces import IChain
>>> chain = config.chains['discard']
>>> verifyObject(IChain, chain)
@@ -71,8 +70,7 @@ this action.
The bounce message is now sitting in the Virgin queue.
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> len(virginq.files)
1
>>> qmsg, qdata = virginq.dequeue(virginq.files[0])
@@ -269,7 +267,7 @@ processed and sent on to the list membership.
>>> print 'LOG:', fp.read()
LOG: ... ACCEPT: <first>
- >>> pipelineq = Switchboard(config.PIPELINEQUEUE_DIR)
+ >>> pipelineq = config.switchboards['pipeline']
>>> len(pipelineq.files)
1
>>> qmsg, qdata = pipelineq.dequeue(pipelineq.files[0])
diff --git a/mailman/docs/domains.txt b/mailman/docs/domains.txt
index d29e6ef9f..b71689520 100644
--- a/mailman/docs/domains.txt
+++ b/mailman/docs/domains.txt
@@ -2,55 +2,16 @@ Domains
=======
Domains are how Mailman interacts with email host names and web host names.
-Generally, new domains are registered in the mailman.cfg configuration file by
-calling the add_domain() method.
+Generally, new domains are registered in the mailman.cfg configuration file.
+We simulate that here by pushing new configurations.
-At a minimum, the email host name must be specified.
-
- >>> from mailman.configuration import config
- >>> config.add_domain('example.net')
-
-The domain object can be looked up by email host name.
-
- >>> from zope.interface.verify import verifyObject
- >>> from mailman.interfaces.domain import IDomain
- >>> domain = config.domains['example.net']
- >>> verifyObject(IDomain, domain)
- True
-
- >>> print domain.email_host
- example.net
-
-The base url is calculated by default if not given.
-
- >>> print domain.base_url
- http://example.net
-
-There is no description by default.
-
- >>> print domain.description
- None
-
-By default, the contact address is the domain's postmaster.
-
- >>> print domain.contact_address
- postmaster@example.net
-
-And the url_host is by default the same as the email host.
-
- >>> print domain.url_host
- example.net
-
-
-Full specification
-------------------
-
-The domain can also be much more fully defined.
-
- >>> config.add_domain(
- ... 'example.org', 'https://mail.example.org',
- ... 'The example domain',
- ... 'postmaster@mail.example.org')
+ >>> config.push('example.org', """
+ ... [domain.example_dot_org]
+ ... email_host: example.org
+ ... base_url: https://mail.example.org
+ ... description: The example domain
+ ... contact_address: postmaster@mail.example.org
+ ... """)
>>> domain = config.domains['example.org']
>>> print domain.email_host
@@ -77,3 +38,9 @@ Confirmation tokens can be added to either the email confirmation address...
>>> print domain.confirm_url('abc')
https://mail.example.org/confirm/abc
+
+
+Clean up
+--------
+
+ >>> config.pop('example.org')
diff --git a/mailman/docs/lifecycle.txt b/mailman/docs/lifecycle.txt
index 69f656208..ab5e6ac23 100644
--- a/mailman/docs/lifecycle.txt
+++ b/mailman/docs/lifecycle.txt
@@ -57,6 +57,7 @@ Start by registering a test style.
... # Applies to any test list
... if 'test' in mailing_list.fqdn_listname:
... styles.append(self)
+
>>> from mailman.core.styles import style_manager
>>> style_manager.register(TestStyle())
@@ -102,7 +103,6 @@ However, all addresses are linked to users.
If you create a mailing list with owner addresses that are already known to
the system, they won't be created again.
- >>> from mailman.configuration import config
>>> usermgr = config.db.user_manager
>>> user_a = usermgr.get_user(u'aperson@example.com')
>>> user_b = usermgr.get_user(u'bperson@example.com')
diff --git a/mailman/docs/listmanager.txt b/mailman/docs/listmanager.txt
index 48968da61..1925e9466 100644
--- a/mailman/docs/listmanager.txt
+++ b/mailman/docs/listmanager.txt
@@ -6,7 +6,6 @@ objects. The Mailman system instantiates an IListManager for you based on the
configuration variable MANAGERS_INIT_FUNCTION. The instance is accessible
on the global config object.
- >>> from mailman.configuration import config
>>> from mailman.interfaces import IListManager
>>> listmgr = config.db.list_manager
>>> IListManager.providedBy(listmgr)
diff --git a/mailman/docs/membership.txt b/mailman/docs/membership.txt
index 8ae2159e5..cb6515532 100644
--- a/mailman/docs/membership.txt
+++ b/mailman/docs/membership.txt
@@ -14,7 +14,6 @@ store mailing list data in a different database than user data.
When we create a mailing list, it starts out with no members...
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist
<mailing list "_xtest@example.com" at ...>
diff --git a/mailman/docs/message.txt b/mailman/docs/message.txt
index 25c38300c..dab9ddf0e 100644
--- a/mailman/docs/message.txt
+++ b/mailman/docs/message.txt
@@ -12,7 +12,6 @@ When Mailman needs to send a message to a user, it creates a UserNotification
instance, and then calls the .send() method on this object. This method
requires a mailing list instance.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
@@ -29,8 +28,7 @@ address, an optional subject, optional body text, and optional language.
The message will end up in the virgin queue.
- >>> from mailman.queue import Switchboard
- >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> switchboard = config.switchboards['virgin']
>>> len(switchboard.files)
1
>>> filebase = switchboard.files[0]
diff --git a/mailman/docs/messagestore.txt b/mailman/docs/messagestore.txt
index 8b9706ad9..6e04568c5 100644
--- a/mailman/docs/messagestore.txt
+++ b/mailman/docs/messagestore.txt
@@ -7,7 +7,6 @@ message's List-Archive header to create a globally unique URI to the message
object in the internet facing interface of the message store. The
X-Message-ID-Hash is the Base32 SHA1 hash of the Message-ID.
- >>> from mailman.configuration import config
>>> store = config.db.message_store
If you try to add a message to the store which is missing the Message-ID
diff --git a/mailman/docs/mlist-addresses.txt b/mailman/docs/mlist-addresses.txt
index 6dc35a249..fe76fb4d5 100644
--- a/mailman/docs/mlist-addresses.txt
+++ b/mailman/docs/mlist-addresses.txt
@@ -4,7 +4,6 @@ Mailing list addresses
Every mailing list has a number of addresses which are publicly available.
These are defined in the IMailingListAddresses interface.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
The posting address is where people send messages to be posted to the mailing
@@ -68,8 +67,9 @@ dependent on the VERP_CONFIRM_FORMAT configuration variable.
>>> mlist.confirm_address('wookie')
u'_xtest-confirm+wookie@example.com'
- >>> old_format = config.VERP_CONFIRM_FORMAT
- >>> config.VERP_CONFIRM_FORMAT = '$address---$cookie'
+ >>> from mailman import Defaults
+ >>> old_format = Defaults.VERP_CONFIRM_FORMAT
+ >>> Defaults.VERP_CONFIRM_FORMAT = '$address---$cookie'
>>> mlist.confirm_address('cookie')
u'_xtest-confirm---cookie@example.com'
>>> config.VERP_CONFIRM_FORMAT = old_format
diff --git a/mailman/docs/pending.txt b/mailman/docs/pending.txt
index 457705352..f6895b818 100644
--- a/mailman/docs/pending.txt
+++ b/mailman/docs/pending.txt
@@ -6,7 +6,6 @@ are stored. These can include email address registration events, held
messages (but only for user confirmation), auto-approvals, and probe bounces.
This is not where messages held for administrator approval are kept.
- >>> from mailman.configuration import config
>>> from zope.interface import implements
>>> from zope.interface.verify import verifyObject
diff --git a/mailman/docs/pipelines.txt b/mailman/docs/pipelines.txt
index ab6b99aa3..94cc792cd 100644
--- a/mailman/docs/pipelines.txt
+++ b/mailman/docs/pipelines.txt
@@ -21,7 +21,6 @@ Processing a message
Messages hit the pipeline after they've been accepted for posting.
- >>> from mailman.configuration import config
>>> config.archivers['pipermail'].is_enabled = True
>>> msg = message_from_string("""\
... From: aperson@example.com
@@ -71,7 +70,7 @@ However there are currently no recipients for this message.
And the message is now sitting in various other processing queues.
>>> from mailman.testing.helpers import get_queue_messages
- >>> messages = get_queue_messages(config.ARCHQUEUE_DIR)
+ >>> messages = get_queue_messages('archive')
>>> len(messages)
1
>>> print messages[0].msg.as_string()
@@ -105,13 +104,13 @@ And the message is now sitting in various other processing queues.
This mailing list is not linked to an NNTP newsgroup, so there's nothing in
the outgoing nntp queue.
- >>> messages = get_queue_messages(config.NEWSQUEUE_DIR)
+ >>> messages = get_queue_messages('news')
>>> len(messages)
0
This is the message that will actually get delivered to end recipients.
- >>> messages = get_queue_messages(config.OUTQUEUE_DIR)
+ >>> messages = get_queue_messages('out')
>>> len(messages)
1
>>> print messages[0].msg.as_string()
diff --git a/mailman/docs/registration.txt b/mailman/docs/registration.txt
index 73fb149e6..a91980e0c 100644
--- a/mailman/docs/registration.txt
+++ b/mailman/docs/registration.txt
@@ -8,7 +8,6 @@ may supply. All registered email addresses must be verified before Mailman
will send them any list traffic.
>>> from mailman.app.registrar import Registrar
- >>> from mailman.configuration import config
>>> from mailman.interfaces import IRegistrar
The IUserManager manages users, but it does so at a fairly low level.
@@ -19,7 +18,13 @@ stuff.
Add a domain, which will provide the context for the verification email
message.
- >>> config.add_domain('mail.example.com', 'http://mail.example.com')
+ >>> config.push('mail', """
+ ... [domain.mail_example_dot_com]
+ ... email_host: mail.example.com
+ ... base_url: http://mail.example.com
+ ... contact_address: postmaster@mail.example.com
+ ... """)
+
>>> domain = config.domains['mail.example.com']
Get a registrar by adapting a context to the interface.
@@ -115,8 +120,7 @@ Verification by email
There is also a verification email sitting in the virgin queue now. This
message is sent to the user in order to verify the registered address.
- >>> from mailman.queue import Switchboard
- >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> switchboard = config.switchboards['virgin']
>>> len(switchboard.files)
1
>>> filebase = switchboard.files[0]
@@ -351,3 +355,9 @@ But after confirmation, he is.
>>> print mlist.members.get_member(u'fred.person@example.com')
<Member: Fred Person <fred.person@example.com>
on alpha@example.com as MemberRole.member>
+
+
+Clean up
+--------
+
+ >>> config.pop('mail')
diff --git a/mailman/docs/requests.txt b/mailman/docs/requests.txt
index a1401b7ff..c67a7e06e 100644
--- a/mailman/docs/requests.txt
+++ b/mailman/docs/requests.txt
@@ -5,8 +5,6 @@ Various actions will be held for moderator approval, such as subscriptions to
closed lists, or postings by non-members. The requests database is the low
level interface to these actions requiring approval.
- >>> from mailman.configuration import config
-
Here is a helper function for printing out held requests.
>>> def show_holds(requests):
@@ -18,8 +16,7 @@ Here is a helper function for printing out held requests.
And another helper for displaying messages in the virgin queue.
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> def dequeue(whichq=None, expected_count=1):
... if whichq is None:
... whichq = virginq
@@ -304,7 +301,7 @@ indicates that the message has been approved.
>>> id_3 = moderator.hold_message(mlist, msg, msgdata, 'Needs approval')
>>> moderator.handle_message(mlist, id_3, Action.accept)
- >>> inq = Switchboard(config.INQUEUE_DIR)
+ >>> inq = config.switchboards['in']
>>> qmsg, qdata = dequeue(inq)
>>> print qmsg.as_string()
From: aperson@example.org
diff --git a/mailman/docs/styles.txt b/mailman/docs/styles.txt
index 37b3b20e2..f75a34798 100644
--- a/mailman/docs/styles.txt
+++ b/mailman/docs/styles.txt
@@ -13,9 +13,9 @@ modify the mailing list any way it wants.
Let's start with a vanilla mailing list and a default style manager.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
- >>> from mailman.core.styles import style_manager
+ >>> from mailman.core.styles import StyleManager
+ >>> style_manager = StyleManager()
The default style
@@ -48,7 +48,8 @@ would pick this up and apply it to the mailing list.
>>> print mlist.msg_footer
None
- >>> config.DEFAULT_MSG_FOOTER = u'default footer'
+ >>> from mailman import Defaults
+ >>> Defaults.DEFAULT_MSG_FOOTER = u'default footer'
>>> default_style.apply(mlist)
>>> mlist.msg_footer
u'default footer'
diff --git a/mailman/docs/usermanager.txt b/mailman/docs/usermanager.txt
index 01822eed2..5f03d84a6 100644
--- a/mailman/docs/usermanager.txt
+++ b/mailman/docs/usermanager.txt
@@ -6,7 +6,6 @@ system instantiates an IUserManager for you based on the configuration
variable MANAGERS_INIT_FUNCTION. The instance is accessible on the global
config object.
- >>> from mailman.configuration import config
>>> from mailman.interfaces import IUserManager
>>> from zope.interface.verify import verifyObject
>>> usermgr = config.db.user_manager
diff --git a/mailman/docs/users.txt b/mailman/docs/users.txt
index 0b8c9a648..e1f0e3302 100644
--- a/mailman/docs/users.txt
+++ b/mailman/docs/users.txt
@@ -7,7 +7,6 @@ they control. A user also knows which mailing lists they are subscribed to.
See usermanager.txt for examples of how to create, delete, and find users.
- >>> from mailman.configuration import config
>>> usermgr = config.db.user_manager
diff --git a/mailman/domain.py b/mailman/domain.py
index ff306aee2..03c1ad39c 100644
--- a/mailman/domain.py
+++ b/mailman/domain.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/i18n.py b/mailman/i18n.py
index 186965509..627d509f7 100644
--- a/mailman/i18n.py
+++ b/mailman/i18n.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/inject.py b/mailman/inject.py
index 763a161ff..27edf827f 100644
--- a/mailman/inject.py
+++ b/mailman/inject.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -26,23 +26,26 @@ from email import message_from_string
from email.utils import formatdate, make_msgid
from mailman.Message import Message
-from mailman.configuration import config
-from mailman.queue import Switchboard
+from mailman.config import config
-def inject_message(mlist, msg, recips=None, qdir=None):
+def inject_message(mlist, msg, recips=None, switchboard=None):
"""Inject a message into a queue.
:param mlist: The mailing list this message is destined for.
+ :type mlist: IMailingList
:param msg: The Message object to inject.
+ :type msg: a Message object
:param recips: Optional set of recipients to put into the message's
metadata.
- :param qdir: Optional queue directory to inject this message into. If not
- given, the incoming queue is used.
+ :type recips: sequence of strings
+ :param switchboard: Optional name of switchboard to inject this message
+ into. If not given, the 'in' switchboard is used.
+ :type switchboard: string
"""
- if qdir is None:
- qdir = config.INQUEUE_DIR
+ if switchboard is None:
+ switchboard = 'in'
# Since we're crafting the message from whole cloth, let's make sure this
# message has a Message-ID.
if 'message-id' not in msg:
@@ -50,7 +53,6 @@ def inject_message(mlist, msg, recips=None, qdir=None):
# Ditto for Date: as required by RFC 2822.
if 'date' not in msg:
msg['Date'] = formatdate(localtime=True)
- queue = Switchboard(qdir)
kws = dict(
listname=mlist.fqdn_listname,
tolist=True,
@@ -58,21 +60,25 @@ def inject_message(mlist, msg, recips=None, qdir=None):
)
if recips is not None:
kws['recips'] = recips
- queue.enqueue(msg, **kws)
+ config.switchboards[switchboard].enqueue(msg, **kws)
-def inject_text(mlist, text, recips=None, qdir=None):
+def inject_text(mlist, text, recips=None, switchboard=None):
"""Inject a message into a queue.
:param mlist: The mailing list this message is destined for.
+ :type mlist: IMailingList
:param text: The text of the message to inject. This will be parsed into
a Message object.
+ :type text: string
:param recips: Optional set of recipients to put into the message's
metadata.
- :param qdir: Optional queue directory to inject this message into. If not
- given, the incoming queue is used.
+ :type recips: sequence of strings
+ :param switchboard: Optional name of switchboard to inject this message
+ into. If not given, the 'in' switchboard is used.
+ :type switchboard: string
"""
message = message_from_string(text, Message)
message.original_size = len(text)
- inject_message(mlist, message, recips, qdir)
+ inject_message(mlist, message, recips, switchboard)
diff --git a/mailman/interact.py b/mailman/interact.py
index e714195f0..e8ff09b16 100644
--- a/mailman/interact.py
+++ b/mailman/interact.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/__init__.py b/mailman/interfaces/__init__.py
index 4a2ea58c6..c39dd55ad 100644
--- a/mailman/interfaces/__init__.py
+++ b/mailman/interfaces/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/address.py b/mailman/interfaces/address.py
index 705e9a52d..802952774 100644
--- a/mailman/interfaces/address.py
+++ b/mailman/interfaces/address.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/archiver.py b/mailman/interfaces/archiver.py
index 5b0b7a298..0159567cc 100644
--- a/mailman/interfaces/archiver.py
+++ b/mailman/interfaces/archiver.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/chain.py b/mailman/interfaces/chain.py
index 4ea0d651f..2a18d3dea 100644
--- a/mailman/interfaces/chain.py
+++ b/mailman/interfaces/chain.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/command.py b/mailman/interfaces/command.py
index 8be29a3e2..202d2a148 100644
--- a/mailman/interfaces/command.py
+++ b/mailman/interfaces/command.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/database.py b/mailman/interfaces/database.py
index 440128676..bf4aaa87c 100644
--- a/mailman/interfaces/database.py
+++ b/mailman/interfaces/database.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/domain.py b/mailman/interfaces/domain.py
index 26e2be6b1..9ce402a70 100644
--- a/mailman/interfaces/domain.py
+++ b/mailman/interfaces/domain.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/errors.py b/mailman/interfaces/errors.py
index 74f34621c..b174aa3cf 100644
--- a/mailman/interfaces/errors.py
+++ b/mailman/interfaces/errors.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/handler.py b/mailman/interfaces/handler.py
index 408f0da10..9d03b7263 100644
--- a/mailman/interfaces/handler.py
+++ b/mailman/interfaces/handler.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/languages.py b/mailman/interfaces/languages.py
index 3675c93de..d1cdf9f43 100644
--- a/mailman/interfaces/languages.py
+++ b/mailman/interfaces/languages.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/listmanager.py b/mailman/interfaces/listmanager.py
index 09ac63dd8..6a774a04e 100644
--- a/mailman/interfaces/listmanager.py
+++ b/mailman/interfaces/listmanager.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/mailinglist.py b/mailman/interfaces/mailinglist.py
index c9a9ef79e..970c1ac07 100644
--- a/mailman/interfaces/mailinglist.py
+++ b/mailman/interfaces/mailinglist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/member.py b/mailman/interfaces/member.py
index 009b18c91..590ad1b9b 100644
--- a/mailman/interfaces/member.py
+++ b/mailman/interfaces/member.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/messages.py b/mailman/interfaces/messages.py
index 6dd07e05e..0da595d0b 100644
--- a/mailman/interfaces/messages.py
+++ b/mailman/interfaces/messages.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/mlistrequest.py b/mailman/interfaces/mlistrequest.py
index 7d23d77d4..f348d617c 100644
--- a/mailman/interfaces/mlistrequest.py
+++ b/mailman/interfaces/mlistrequest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/pending.py b/mailman/interfaces/pending.py
index d9a8f73cb..7fcde07ad 100644
--- a/mailman/interfaces/pending.py
+++ b/mailman/interfaces/pending.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/permissions.py b/mailman/interfaces/permissions.py
index f8f7795a5..fb36f35b5 100644
--- a/mailman/interfaces/permissions.py
+++ b/mailman/interfaces/permissions.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/pipeline.py b/mailman/interfaces/pipeline.py
index a73eb7bff..a95fb7628 100644
--- a/mailman/interfaces/pipeline.py
+++ b/mailman/interfaces/pipeline.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/preferences.py b/mailman/interfaces/preferences.py
index 14a77a1ca..fbd81c801 100644
--- a/mailman/interfaces/preferences.py
+++ b/mailman/interfaces/preferences.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/registrar.py b/mailman/interfaces/registrar.py
index e5c14544b..823298d5e 100644
--- a/mailman/interfaces/registrar.py
+++ b/mailman/interfaces/registrar.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/requests.py b/mailman/interfaces/requests.py
index 85fd6ad1b..b9c0802f4 100644
--- a/mailman/interfaces/requests.py
+++ b/mailman/interfaces/requests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/roster.py b/mailman/interfaces/roster.py
index 6dcd458a1..f7b2125fd 100644
--- a/mailman/interfaces/roster.py
+++ b/mailman/interfaces/roster.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/rules.py b/mailman/interfaces/rules.py
index 65d793809..24501848f 100644
--- a/mailman/interfaces/rules.py
+++ b/mailman/interfaces/rules.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/runner.py b/mailman/interfaces/runner.py
index 28b15968c..500efd541 100644
--- a/mailman/interfaces/runner.py
+++ b/mailman/interfaces/runner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -30,9 +30,10 @@ class IRunner(Interface):
def stop():
"""Stop the queue runner on the next iteration through the loop."""
- QDIR = Attribute('The queue directory. Overridden in subclasses.')
+ queue_directory = Attribute(
+ 'The queue directory. Overridden in subclasses.')
- SLEEPTIME = Attribute("""\
+ sleep_time = Attribute("""\
The number of seconds this queue runner will sleep between iterations
through the main loop. If given, overrides
`config.QRUNNER_SLEEP_TIME`
diff --git a/mailman/interfaces/styles.py b/mailman/interfaces/styles.py
index 59730a545..b2b52db4e 100644
--- a/mailman/interfaces/styles.py
+++ b/mailman/interfaces/styles.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/switchboard.py b/mailman/interfaces/switchboard.py
index 9c6fd348d..96cf1aea2 100644
--- a/mailman/interfaces/switchboard.py
+++ b/mailman/interfaces/switchboard.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/user.py b/mailman/interfaces/user.py
index e30c69362..8824a2d7c 100644
--- a/mailman/interfaces/user.py
+++ b/mailman/interfaces/user.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/interfaces/usermanager.py b/mailman/interfaces/usermanager.py
index e07643b28..7454faea8 100644
--- a/mailman/interfaces/usermanager.py
+++ b/mailman/interfaces/usermanager.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/languages.py b/mailman/languages.py
index 295a0d6a6..dd37fbc34 100644
--- a/mailman/languages.py
+++ b/mailman/languages.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
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..32f80d426 100644
--- a/mailman/options.py
+++ b/mailman/options.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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
@@ -95,16 +95,18 @@ class Options:
'-C', '--config',
help=_('Alternative configuration file to use'))
- def initialize(self, propagate_logs=False):
+ def initialize(self, propagate_logs=None):
"""Initialize the configuration system.
After initialization of the configuration system, perform sanity
checks. We do it in this order because some sanity checks require the
configuration to be initialized.
- :param propagate_logs: Flag specifying whether log messages in
- sub-loggers should be propagated to the master logger (and hence
- to the root logger).
+ :param propagate_logs: Optional flag specifying whether log messages
+ in sub-loggers should be propagated to the master logger (and
+ hence to the root logger). If not given, propagation is taken
+ from the configuration files.
+ :type propagate_logs: bool or None.
"""
initialize(self.options.config, propagate_logs=propagate_logs)
self.sanity_check()
diff --git a/mailman/passwords.py b/mailman/passwords.py
index 1e46cd42e..9ce403cc7 100644
--- a/mailman/passwords.py
+++ b/mailman/passwords.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/__init__.py b/mailman/pipeline/__init__.py
index b59953f47..a77e00915 100644
--- a/mailman/pipeline/__init__.py
+++ b/mailman/pipeline/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/acknowledge.py b/mailman/pipeline/acknowledge.py
index 41fc931ae..57817b6b0 100644
--- a/mailman/pipeline/acknowledge.py
+++ b/mailman/pipeline/acknowledge.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/after_delivery.py b/mailman/pipeline/after_delivery.py
index 5d062462a..e5bc98fcd 100644
--- a/mailman/pipeline/after_delivery.py
+++ b/mailman/pipeline/after_delivery.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/avoid_duplicates.py b/mailman/pipeline/avoid_duplicates.py
index d228c6ad9..ddfbc4578 100644
--- a/mailman/pipeline/avoid_duplicates.py
+++ b/mailman/pipeline/avoid_duplicates.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..18d237ec0 100644
--- a/mailman/pipeline/calculate_recipients.py
+++ b/mailman/pipeline/calculate_recipients.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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.py b/mailman/pipeline/cleanse.py
index f381d78e1..a2b19545e 100644
--- a/mailman/pipeline/cleanse.py
+++ b/mailman/pipeline/cleanse.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/cleanse_dkim.py b/mailman/pipeline/cleanse_dkim.py
index ae51fc27c..4edd8193d 100644
--- a/mailman/pipeline/cleanse_dkim.py
+++ b/mailman/pipeline/cleanse_dkim.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -31,7 +31,7 @@ __all__ = ['CleanseDKIM']
from zope.interface import implements
-from mailman.configuration import config
+from mailman import Defaults
from mailman.i18n import _
from mailman.interfaces import IHandler
@@ -47,7 +47,7 @@ class CleanseDKIM:
def process(self, mlist, msg, msgdata):
"""See `IHandler`."""
- if config.REMOVE_DKIM_HEADERS:
+ if Defaults.REMOVE_DKIM_HEADERS:
del msg['domainkey-signature']
del msg['dkim-signature']
del msg['authentication-results']
diff --git a/mailman/pipeline/cook_headers.py b/mailman/pipeline/cook_headers.py
index 362c8ecf7..a37a92a69 100644
--- a/mailman/pipeline/cook_headers.py
+++ b/mailman/pipeline/cook_headers.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..3059bde38 100644
--- a/mailman/pipeline/decorate.py
+++ b/mailman/pipeline/decorate.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -28,9 +28,10 @@ from email.MIMEText import MIMEText
from string import Template
from zope.interface import implements
+from mailman import Defaults
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
@@ -204,7 +205,7 @@ def decorate(mlist, template, extradict=None):
web_page_url = mlist.web_page_url,
description = mlist.description,
info = mlist.info,
- cgiext = config.CGIEXT,
+ cgiext = Defaults.CGIEXT,
)
if extradict is not None:
d.update(extradict)
diff --git a/mailman/pipeline/docs/ack-headers.txt b/mailman/pipeline/docs/ack-headers.txt
index 28a8eed9e..ca41df03e 100644
--- a/mailman/pipeline/docs/ack-headers.txt
+++ b/mailman/pipeline/docs/ack-headers.txt
@@ -7,7 +7,6 @@ transformations. Some headers get added, others get changed. Some of these
changes depend on mailing list settings and others depend on how the message
is getting sent through the system. We'll take things one-by-one.
- >>> from mailman.configuration import config
>>> from mailman.pipeline.cook_headers import process
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.subject_prefix = u''
diff --git a/mailman/pipeline/docs/acknowledge.txt b/mailman/pipeline/docs/acknowledge.txt
index 76c8fdf21..d1206b6f3 100644
--- a/mailman/pipeline/docs/acknowledge.txt
+++ b/mailman/pipeline/docs/acknowledge.txt
@@ -5,7 +5,6 @@ When a user posts a message to a mailing list, and that user has chosen to
receive acknowledgments of their postings, Mailman will sent them such an
acknowledgment.
- >>> from mailman.configuration import config
>>> handler = config.handlers['acknowledge']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.real_name = u'XTest'
@@ -16,8 +15,7 @@ acknowledgment.
>>> # Ensure that the virgin queue is empty, since we'll be checking this
>>> # for new auto-response messages.
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> virginq.files
[]
diff --git a/mailman/pipeline/docs/after-delivery.txt b/mailman/pipeline/docs/after-delivery.txt
index 5bc9b5936..b910e89a6 100644
--- a/mailman/pipeline/docs/after-delivery.txt
+++ b/mailman/pipeline/docs/after-delivery.txt
@@ -6,7 +6,6 @@ by the rest of the handlers in the incoming queue pipeline, a couple of
bookkeeping pieces of information are updated.
>>> import datetime
- >>> from mailman.configuration import config
>>> handler = config.handlers['after-delivery']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> post_time = datetime.datetime.now() - datetime.timedelta(minutes=10)
diff --git a/mailman/pipeline/docs/archives.txt b/mailman/pipeline/docs/archives.txt
index 67ad45c89..d81f6e27b 100644
--- a/mailman/pipeline/docs/archives.txt
+++ b/mailman/pipeline/docs/archives.txt
@@ -8,11 +8,9 @@ archivers to work in a separate process from the main Mailman delivery
processes.
>>> from mailman.app.lifecycle import create_list
- >>> from mailman.configuration import config
- >>> from mailman.queue import Switchboard
>>> handler = config.handlers['to-archive']
>>> mlist = create_list(u'_xtest@example.com')
- >>> switchboard = Switchboard(config.ARCHQUEUE_DIR)
+ >>> switchboard = config.switchboards['archive']
A helper function.
diff --git a/mailman/pipeline/docs/avoid-duplicates.txt b/mailman/pipeline/docs/avoid-duplicates.txt
index 9fd332d1b..e1d31716a 100644
--- a/mailman/pipeline/docs/avoid-duplicates.txt
+++ b/mailman/pipeline/docs/avoid-duplicates.txt
@@ -6,7 +6,6 @@ reduce the reception of duplicate messages. It does this by removing certain
recipients from the list of recipients that earlier handler modules
(e.g. CalcRecips) calculates.
- >>> from mailman.configuration import config
>>> handler = config.handlers['avoid-duplicates']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
diff --git a/mailman/pipeline/docs/calc-recips.txt b/mailman/pipeline/docs/calc-recips.txt
index 057351873..550edff51 100644
--- a/mailman/pipeline/docs/calc-recips.txt
+++ b/mailman/pipeline/docs/calc-recips.txt
@@ -5,7 +5,6 @@ Every message that makes it through to the list membership gets sent to a set
of recipient addresses. These addresses are calculated by one of the handler
modules and depends on a host of factors.
- >>> from mailman.configuration import config
>>> handler = config.handlers['calculate-recipients']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
diff --git a/mailman/pipeline/docs/cleanse.txt b/mailman/pipeline/docs/cleanse.txt
index 1597095b3..0940cdb4b 100644
--- a/mailman/pipeline/docs/cleanse.txt
+++ b/mailman/pipeline/docs/cleanse.txt
@@ -5,7 +5,6 @@ All messages posted to a list get their headers cleansed. Some headers are
related to additional permissions that can be granted to the message and other
headers can be used to fish for membership.
- >>> from mailman.configuration import config
>>> handler = config.handlers['cleanse']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
diff --git a/mailman/pipeline/docs/cook-headers.txt b/mailman/pipeline/docs/cook-headers.txt
index 4fbdf58bb..985214079 100644
--- a/mailman/pipeline/docs/cook-headers.txt
+++ b/mailman/pipeline/docs/cook-headers.txt
@@ -8,7 +8,6 @@ changes depend on mailing list settings and others depend on how the message
is getting sent through the system. We'll take things one-by-one.
>>> from mailman.pipeline.cook_headers import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.subject_prefix = u''
>>> mlist.include_list_post_header = False
diff --git a/mailman/pipeline/docs/decorate.txt b/mailman/pipeline/docs/decorate.txt
index 60afb0170..b805e23cf 100644
--- a/mailman/pipeline/docs/decorate.txt
+++ b/mailman/pipeline/docs/decorate.txt
@@ -6,7 +6,6 @@ original message. A handler module takes care of this based on the settings
of the mailing list and the type of message being processed.
>>> from mailman.pipeline.decorate import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> msg_text = """\
... From: aperson@example.org
diff --git a/mailman/pipeline/docs/digests.txt b/mailman/pipeline/docs/digests.txt
index df01379b9..1d7112fd5 100644
--- a/mailman/pipeline/docs/digests.txt
+++ b/mailman/pipeline/docs/digests.txt
@@ -7,15 +7,13 @@ digests, although only two are currently supported: MIME digests and RFC 1153
(a.k.a. plain text) digests.
>>> from mailman.pipeline.to_digest import process
- >>> from mailman.queue import Switchboard
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
>>> mlist.web_page_url = u'http://www.example.com/'
>>> mlist.real_name = u'XTest'
>>> mlist.subject_prefix = u'[_XTest] '
>>> mlist.one_last_digest = set()
- >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> switchboard = config.switchboards['virgin']
This is a helper function used to iterate through all the accumulated digest
messages, in the order in which they were posted. This makes it easier to
@@ -407,11 +405,16 @@ When messages come in with a content-type character set different than that of
the list's preferred language, recipients wil get an internationalized
digest. French is not enabled by default site-wide, so enable that now.
-XXX We also have to set the default server language to French, otherwise the
-English template will be found and the masthead won't be translated.
-
>>> config.languages.enable_language('fr')
- >>> config.DEFAULT_SERVER_LANGUAGE = u'fr'
+
+ # Simulate the site administrator setting the default server language to
+ # French in the configuration file. Without this, the English template
+ # will be found and the masthead won't be translated.
+ >>> config.push('french', """
+ ... [mailman]
+ ... default_language: fr
+ ... """)
+
>>> mlist.preferred_language = u'fr'
>>> msg = message_from_string("""\
... From: aperson@example.org
diff --git a/mailman/pipeline/docs/file-recips.txt b/mailman/pipeline/docs/file-recips.txt
index e93bba9aa..d006151ba 100644
--- a/mailman/pipeline/docs/file-recips.txt
+++ b/mailman/pipeline/docs/file-recips.txt
@@ -5,7 +5,6 @@ Mailman can calculate the recipients for a message from a Sendmail-style
include file. This file must be called members.txt and it must live in the
list's data directory.
- >>> from mailman.configuration import config
>>> handler = config.handlers['file-recipients']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
diff --git a/mailman/pipeline/docs/filtering.txt b/mailman/pipeline/docs/filtering.txt
index c5dca1531..70ca3098d 100644
--- a/mailman/pipeline/docs/filtering.txt
+++ b/mailman/pipeline/docs/filtering.txt
@@ -7,7 +7,6 @@ message. It does this with the MimeDel handler module, although other
handlers can potentially do other kinds of finer level content filtering.
>>> from mailman.pipeline.mime_delete import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
diff --git a/mailman/pipeline/docs/nntp.txt b/mailman/pipeline/docs/nntp.txt
index 5652d7924..0120de394 100644
--- a/mailman/pipeline/docs/nntp.txt
+++ b/mailman/pipeline/docs/nntp.txt
@@ -5,12 +5,10 @@ Mailman has an NNTP gateway, whereby messages posted to the mailing list can
be forwarded onto an NNTP newsgroup. Typically this means Usenet, but since
NNTP is to Usenet as IP is to the web, it's more general than that.
- >>> from mailman.queue import Switchboard
- >>> from mailman.configuration import config
>>> handler = config.handlers['to-usenet']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
- >>> switchboard = Switchboard(config.NEWSQUEUE_DIR)
+ >>> switchboard = config.switchboards['news']
Gatewaying from the mailing list to the newsgroup happens through a separate
'nntp' queue and happen immediately when the message is posted through to the
diff --git a/mailman/pipeline/docs/reply-to.txt b/mailman/pipeline/docs/reply-to.txt
index ad9100ce1..570ffb7ea 100644
--- a/mailman/pipeline/docs/reply-to.txt
+++ b/mailman/pipeline/docs/reply-to.txt
@@ -8,7 +8,6 @@ changes depend on mailing list settings and others depend on how the message
is getting sent through the system. We'll take things one-by-one.
>>> from mailman.pipeline.cook_headers import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.subject_prefix = u''
diff --git a/mailman/pipeline/docs/replybot.txt b/mailman/pipeline/docs/replybot.txt
index 2e3765cab..f9f824e4e 100644
--- a/mailman/pipeline/docs/replybot.txt
+++ b/mailman/pipeline/docs/replybot.txt
@@ -7,15 +7,13 @@ responses are subject to various conditions, such as headers in the original
message or the amount of time since the last auto-response.
>>> from mailman.pipeline.replybot import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.real_name = u'XTest'
>>> mlist.web_page_url = u'http://www.example.com/'
>>> # Ensure that the virgin queue is empty, since we'll be checking this
>>> # for new auto-response messages.
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> virginq.files
[]
diff --git a/mailman/pipeline/docs/scrubber.txt b/mailman/pipeline/docs/scrubber.txt
index 744925f34..eddd1939d 100644
--- a/mailman/pipeline/docs/scrubber.txt
+++ b/mailman/pipeline/docs/scrubber.txt
@@ -7,7 +7,6 @@ scrub attachments from messages so that binary goop doesn't end up in an
archive message.
>>> from mailman.pipeline.scrubber import process, save_attachment
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
@@ -51,7 +50,8 @@ filename suggested in the message's Content-Disposition: header or not. If
enabled, the filename will be used when this header attribute is present (yes,
this is an unfortunate double negative).
- >>> config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = False
+ >>> from mailman import Defaults
+ >>> Defaults.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = False
>>> msg = message_from_string("""\
... Content-Type: image/gif; name="xtest.gif"
... Content-Transfer-Encoding: base64
@@ -80,7 +80,7 @@ The site administrator can also configure Mailman to ignore the
Content-Disposition: filename. This is the default for reasons described in
the Defaults.py.in file.
- >>> config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = True
+ >>> Defaults.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = True
>>> msg = message_from_string("""\
... Content-Type: image/gif; name="xtest.gif"
... Content-Transfer-Encoding: base64
diff --git a/mailman/pipeline/docs/subject-munging.txt b/mailman/pipeline/docs/subject-munging.txt
index 02677d6e2..b2972683b 100644
--- a/mailman/pipeline/docs/subject-munging.txt
+++ b/mailman/pipeline/docs/subject-munging.txt
@@ -8,7 +8,6 @@ changes depend on mailing list settings and others depend on how the message
is getting sent through the system. We'll take things one-by-one.
>>> from mailman.pipeline.cook_headers import process
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.subject_prefix = u''
diff --git a/mailman/pipeline/docs/tagger.txt b/mailman/pipeline/docs/tagger.txt
index 778f7cc73..9f0bcd4b2 100644
--- a/mailman/pipeline/docs/tagger.txt
+++ b/mailman/pipeline/docs/tagger.txt
@@ -9,8 +9,6 @@ its Subject: and Keywords: headers compared against these regular
expressions. The message then gets tagged with the topic names of each hit.
>>> from mailman.pipeline.tagger import process
- >>> from mailman.queue import Switchboard
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
Topics must be enabled for Mailman to do any topic matching, even if topics
diff --git a/mailman/pipeline/docs/to-outgoing.txt b/mailman/pipeline/docs/to-outgoing.txt
index 3840b71ee..81e870e6c 100644
--- a/mailman/pipeline/docs/to-outgoing.txt
+++ b/mailman/pipeline/docs/to-outgoing.txt
@@ -9,11 +9,9 @@ term somewhat incorrectly, but within the spirit of the standard, which
basically describes how to encode the recipient's address in the originator
headers for unambigous bounce processing.
- >>> from mailman.queue import Switchboard
- >>> from mailman.configuration import config
>>> handler = config.handlers['to-outgoing']
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
- >>> switchboard = Switchboard(config.OUTQUEUE_DIR)
+ >>> switchboard = config.switchboards['out']
>>> def queue_size():
... size = len(switchboard.files)
@@ -67,8 +65,9 @@ option to VERP personalized deliveries is set, then the message will be
VERP'd.
# Save the original value for clean up.
- >>> verp_personalized_delivieries = config.VERP_PERSONALIZED_DELIVERIES
- >>> config.VERP_PERSONALIZED_DELIVERIES = True
+ >>> from mailman import Defaults
+ >>> verp_personalized_delivieries = Defaults.VERP_PERSONALIZED_DELIVERIES
+ >>> Defaults.VERP_PERSONALIZED_DELIVERIES = True
>>> from mailman.interfaces import Personalization
>>> mlist.personalize = Personalization.individual
>>> msgdata = dict(foo=1, bar=2)
@@ -81,7 +80,7 @@ VERP'd.
However, if the global configuration variable prohibits VERP'ing, even
personalized lists will not VERP.
- >>> config.VERP_PERSONALIZED_DELIVERIES = False
+ >>> Defaults.VERP_PERSONALIZED_DELIVERIES = False
>>> msgdata = dict(foo=1, bar=2)
>>> handler.process(mlist, msg, msgdata)
>>> print msgdata.get('verp')
@@ -95,8 +94,8 @@ Mailman how often to VERP even non-personalized mailing lists. It can be set
to zero, which means non-personalized messages will never be VERP'd.
# Save the original value for clean up.
- >>> verp_delivery_interval = config.VERP_DELIVERY_INTERVAL
- >>> config.VERP_DELIVERY_INTERVAL = 0
+ >>> verp_delivery_interval = Defaults.VERP_DELIVERY_INTERVAL
+ >>> Defaults.VERP_DELIVERY_INTERVAL = 0
>>> mlist.personalize = Personalization.none
>>> msgdata = dict(foo=1, bar=2)
>>> handler.process(mlist, msg, msgdata)
@@ -107,7 +106,7 @@ to zero, which means non-personalized messages will never be VERP'd.
If the interval is set to 1, then every message will be VERP'd.
- >>> config.VERP_DELIVERY_INTERVAL = 1
+ >>> Defaults.VERP_DELIVERY_INTERVAL = 1
>>> for i in range(10):
... msgdata = dict(foo=1, bar=2)
... handler.process(mlist, msg, msgdata)
@@ -128,7 +127,7 @@ If the interval is set to 1, then every message will be VERP'd.
If the interval is set to some other number, then one out of that many posts
will be VERP'd.
- >>> config.VERP_DELIVERY_INTERVAL = 3
+ >>> Defaults.VERP_DELIVERY_INTERVAL = 3
>>> for i in range(10):
... mlist.post_id = i
... msgdata = dict(foo=1, bar=2)
@@ -151,5 +150,5 @@ will be VERP'd.
Clean up
========
- >>> config.VERP_PERSONALIZED_DELIVERIES = verp_personalized_delivieries
- >>> config.VERP_DELIVERY_INTERVAL = verp_delivery_interval
+ >>> Defaults.VERP_PERSONALIZED_DELIVERIES = verp_personalized_delivieries
+ >>> Defaults.VERP_DELIVERY_INTERVAL = verp_delivery_interval
diff --git a/mailman/pipeline/file_recipients.py b/mailman/pipeline/file_recipients.py
index fd7ff0b69..75a00c14e 100644
--- a/mailman/pipeline/file_recipients.py
+++ b/mailman/pipeline/file_recipients.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/mime_delete.py b/mailman/pipeline/mime_delete.py
index 9cb34297f..57d529112 100644
--- a/mailman/pipeline/mime_delete.py
+++ b/mailman/pipeline/mime_delete.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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..ec0a555d8 100644
--- a/mailman/pipeline/moderate.py
+++ b/mailman/pipeline/moderate.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/owner_recipients.py b/mailman/pipeline/owner_recipients.py
index 592e9e127..046cac50c 100644
--- a/mailman/pipeline/owner_recipients.py
+++ b/mailman/pipeline/owner_recipients.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/replybot.py b/mailman/pipeline/replybot.py
index 39f6cc058..e889e58af 100644
--- a/mailman/pipeline/replybot.py
+++ b/mailman/pipeline/replybot.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/scrubber.py b/mailman/pipeline/scrubber.py
index 4b8d9f770..b8beb22ad 100644
--- a/mailman/pipeline/scrubber.py
+++ b/mailman/pipeline/scrubber.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -38,8 +38,9 @@ from locknix.lockfile import Lock
from mimetypes import guess_all_extensions
from zope.interface import implements
+from mailman import Defaults
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 _
@@ -158,7 +159,7 @@ def replace_payload_by_text(msg, text, charset):
def process(mlist, msg, msgdata=None):
- sanitize = config.ARCHIVE_HTML_SANITIZER
+ sanitize = Defaults.ARCHIVE_HTML_SANITIZER
outer = True
if msgdata is None:
msgdata = {}
@@ -409,7 +410,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 config.SCRUBBER_USE_ATTACHMENT_FILENAME_EXTENSION:
+ if Defaults.SCRUBBER_USE_ATTACHMENT_FILENAME_EXTENSION:
# HTML message doesn't have filename :-(
ext = fnext or guess_extension(ctype, fnext)
else:
@@ -430,7 +431,7 @@ 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 config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME:
+ if not filename or Defaults.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME:
filebase = 'attachment'
else:
# Sanitize the filename given in the message headers
@@ -475,7 +476,7 @@ def save_attachment(mlist, msg, dir, filter_html=True):
try:
fp.write(decodedpayload)
fp.close()
- cmd = config.ARCHIVE_HTML_SANITIZER % {'filename' : tmppath}
+ cmd = Defaults.ARCHIVE_HTML_SANITIZER % {'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 7d9242417..051ba0096 100644
--- a/mailman/pipeline/smtp_direct.py
+++ b/mailman/pipeline/smtp_direct.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -27,37 +27,35 @@ for a threaded implementation.
"""
__metaclass__ = type
-__all__ = ['SMTPDirect']
+__all__ = [
+ 'SMTPDirect',
+ ]
import copy
import time
import email
import socket
-import string
import logging
import smtplib
from email.Charset import Charset
from email.Header import Header
from email.Utils import formataddr
+from string import Template
from zope.interface import implements
+from mailman import Defaults
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')
@@ -68,8 +66,11 @@ class Connection:
def __connect(self):
self.__conn = smtplib.SMTP()
- self.__conn.connect(config.SMTPHOST, config.SMTPPORT)
- self.__numsessions = config.SMTP_MAX_SESSIONS_PER_CONNECTION
+ host = config.mta.smtp_host
+ 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
def sendmail(self, envsender, recips, msgtext):
if self.__conn is None:
@@ -101,20 +102,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:
@@ -139,10 +126,10 @@ def process(mlist, msg, msgdata):
chunks = [[recip] for recip in recips]
msgdata['personalize'] = 1
deliveryfunc = verpdeliver
- elif config.SMTP_MAX_RCPTS <= 0:
+ elif Defaults.SMTP_MAX_RCPTS <= 0:
chunks = [recips]
else:
- chunks = chunkify(recips, config.SMTP_MAX_RCPTS)
+ chunks = chunkify(recips, Defaults.SMTP_MAX_RCPTS)
# See if this is an unshunted message for which some were undelivered
if msgdata.has_key('undelivered'):
chunks = msgdata['undelivered']
@@ -192,38 +179,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 +232,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)
@@ -331,7 +320,8 @@ def verpdeliver(mlist, msg, msgdata, envsender, failures, conn):
'mailbox': rmailbox,
'host' : DOT.join(rdomain),
}
- envsender = '%s@%s' % ((config.VERP_FORMAT % d), DOT.join(bdomain))
+ envsender = '%s@%s' % ((Defaults.VERP_FORMAT % d),
+ 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
@@ -393,10 +383,10 @@ def bulkdeliver(mlist, msg, msgdata, envsender, failures, conn):
# Send the message
refused = conn.sendmail(envsender, recips, msgtext)
except smtplib.SMTPRecipientsRefused, e:
- flog.error('%s recipients refused: %s', msgid, e)
+ log.error('%s recipients refused: %s', msgid, e)
refused = e.recipients
except smtplib.SMTPResponseException, e:
- flog.error('%s SMTP session failure: %s, %s',
+ log.error('%s SMTP session failure: %s, %s',
msgid, e.smtp_code, e.smtp_error)
# If this was a permanent failure, don't add the recipients to the
# refused, because we don't want them to be added to failures.
@@ -412,7 +402,7 @@ def bulkdeliver(mlist, msg, msgdata, envsender, failures, conn):
# MTA not responding, or other socket problems, or any other kind of
# SMTPException. In that case, nothing got delivered, so treat this
# as a temporary failure.
- flog.error('%s low level smtp error: %s', msgid, e)
+ log.error('%s low level smtp error: %s', msgid, e)
error = str(e)
for r in recips:
refused[r] = (-1, error)
diff --git a/mailman/pipeline/tagger.py b/mailman/pipeline/tagger.py
index 13ad7ba49..d631342d3 100644
--- a/mailman/pipeline/tagger.py
+++ b/mailman/pipeline/tagger.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/pipeline/to_archive.py b/mailman/pipeline/to_archive.py
index b693d8341..5c32be53d 100644
--- a/mailman/pipeline/to_archive.py
+++ b/mailman/pipeline/to_archive.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -23,10 +23,9 @@ __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
@@ -48,7 +47,5 @@ class ToArchive:
# presence. I'm keeping "X-Archive: no" for backwards compatibility.
if 'x-no-archive' in msg or msg.get('x-archive', '').lower() == 'no':
return
- # Send the message to the archiver queue
- archq = Switchboard(config.ARCHQUEUE_DIR)
- # Send the message to the queue
- archq.enqueue(msg, msgdata)
+ # Send the message to the archiver queue.
+ config.switchboards['archive'].enqueue(msg, msgdata)
diff --git a/mailman/pipeline/to_digest.py b/mailman/pipeline/to_digest.py
index cec2fa1fc..96bfcdf47 100644
--- a/mailman/pipeline/to_digest.py
+++ b/mailman/pipeline/to_digest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -48,17 +48,17 @@ 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
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
from mailman.pipeline.scrubber import process as scrubber
-from mailman.queue import Switchboard
_ = i18n._
@@ -268,8 +268,8 @@ def send_i18n_digests(mlist, mboxfp):
# for the specific MIME or plain digests.
keeper = {}
all_keepers = {}
- for header in (config.MIME_DIGEST_KEEP_HEADERS +
- config.PLAIN_DIGEST_KEEP_HEADERS):
+ for header in (Defaults.MIME_DIGEST_KEEP_HEADERS +
+ Defaults.PLAIN_DIGEST_KEEP_HEADERS):
all_keepers[header] = True
all_keepers = all_keepers.keys()
for keep in all_keepers:
@@ -325,7 +325,7 @@ def send_i18n_digests(mlist, mboxfp):
print >> plainmsg, _('[Message discarded by content filter]')
continue
# Honor the default setting
- for h in config.PLAIN_DIGEST_KEEP_HEADERS:
+ for h in Defaults.PLAIN_DIGEST_KEEP_HEADERS:
if msg[h]:
uh = Utils.wrap('%s: %s' % (h, Utils.oneline(msg[h],
in_unicode=True)))
@@ -378,7 +378,7 @@ def send_i18n_digests(mlist, mboxfp):
# Do our final bit of housekeeping, and then send each message to the
# outgoing queue for delivery.
mlist.next_digest_number += 1
- virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ virginq = config.switchboards['virgin']
# Calculate the recipients lists
plainrecips = set()
mimerecips = set()
diff --git a/mailman/pipeline/to_outgoing.py b/mailman/pipeline/to_outgoing.py
index 48633da96..fdf201793 100644
--- a/mailman/pipeline/to_outgoing.py
+++ b/mailman/pipeline/to_outgoing.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -28,10 +28,10 @@ __all__ = ['ToOutgoing']
from zope.interface import implements
-from mailman.configuration import config
+from mailman import Defaults
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import IHandler, Personalization
-from mailman.queue import Switchboard
@@ -45,7 +45,7 @@ class ToOutgoing:
def process(self, mlist, msg, msgdata):
"""See `IHandler`."""
- interval = config.VERP_DELIVERY_INTERVAL
+ interval = Defaults.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
@@ -57,7 +57,7 @@ class ToOutgoing:
if 'verp' in msgdata:
pass
elif mlist.personalize <> Personalization.none:
- if config.VERP_PERSONALIZED_DELIVERIES:
+ if Defaults.VERP_PERSONALIZED_DELIVERIES:
msgdata['verp'] = True
elif interval == 0:
# Never VERP
@@ -69,5 +69,5 @@ class ToOutgoing:
# VERP every `interval' number of times
msgdata['verp'] = not (int(mlist.post_id) % interval)
# And now drop the message in qfiles/out
- outq = Switchboard(config.OUTQUEUE_DIR)
- outq.enqueue(msg, msgdata, listname=mlist.fqdn_listname)
+ config.switchboards['out'].enqueue(
+ msg, msgdata, listname=mlist.fqdn_listname)
diff --git a/mailman/pipeline/to_usenet.py b/mailman/pipeline/to_usenet.py
index 4ebd94bec..08e785d54 100644
--- a/mailman/pipeline/to_usenet.py
+++ b/mailman/pipeline/to_usenet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -25,10 +25,9 @@ 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
COMMASPACE = ', '
@@ -62,5 +61,5 @@ class ToUsenet:
COMMASPACE.join(error))
return
# Put the message in the news runner's queue
- newsq = Switchboard(config.NEWSQUEUE_DIR)
- newsq.enqueue(msg, msgdata, listname=mlist.fqdn_listname)
+ config.switchboards['news'].enqueue(
+ msg, msgdata, listname=mlist.fqdn_listname)
diff --git a/mailman/queue/__init__.py b/mailman/queue/__init__.py
index 961a46283..52686b3ab 100644
--- a/mailman/queue/__init__.py
+++ b/mailman/queue/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -32,6 +32,7 @@ __all__ = [
import os
+import sys
import time
import email
import errno
@@ -43,13 +44,16 @@ import marshal
import traceback
from cStringIO import StringIO
+from lazr.config import as_boolean, as_timedelta
+from string import Template
from zope.interface import implements
-from mailman import i18n
from mailman import Message
from mailman import Utils
-from mailman.configuration import config
-from mailman.interfaces import IRunner, ISwitchboard
+from mailman import i18n
+from mailman.config import config
+from mailman.interfaces.runner import IRunner
+from mailman.interfaces.switchboard import ISwitchboard
# 20 bytes of all bits set, maximum hashlib.sha.digest() value
shamax = 0xffffffffffffffffffffffffffffffffffffffffL
@@ -57,6 +61,7 @@ shamax = 0xffffffffffffffffffffffffffffffffffffffffL
# Small increment to add to time in case two entries have the same time. This
# prevents skipping one of two entries with the same time until the next pass.
DELTA = .0001
+DOT = '.'
elog = logging.getLogger('mailman.error')
dlog = logging.getLogger('mailman.debug')
@@ -66,11 +71,24 @@ dlog = logging.getLogger('mailman.debug')
class Switchboard:
implements(ISwitchboard)
- def __init__(self, whichq, slice=None, numslices=1, recover=False):
+ @staticmethod
+ def initialize():
+ """Initialize the global switchboards for input/output."""
+ for conf in config.qrunner_configs:
+ name = conf.name.split('.')[-1]
+ assert name not in config.switchboards, (
+ 'Duplicate qrunner name: %s' % name)
+ substitutions = config.paths
+ substitutions['name'] = name
+ path = Template(conf.path).safe_substitute(substitutions)
+ config.switchboards[name] = Switchboard(path)
+
+ def __init__(self, queue_directory,
+ slice=None, numslices=1, recover=False):
"""Create a switchboard object.
- :param whichq: The queue directory.
- :type whichq: str
+ :param queue_directory: The queue directory.
+ :type queue_directory: str
:param slice: The slice number for this switchboard, or None. If not
None, it must be [0..`numslices`).
:type slice: int or None
@@ -80,9 +98,11 @@ class Switchboard:
:param recover: True if backup files should be recovered.
:type recover: bool
"""
- self._whichq = whichq
+ assert (numslices & (numslices - 1)) == 0, (
+ 'Not a power of 2: %s' % numslices)
+ self.queue_directory = queue_directory
# Create the directory if it doesn't yet exist.
- Utils.makedirs(self._whichq, 0770)
+ Utils.makedirs(self.queue_directory, 0770)
# Fast track for no slices
self._lower = None
self._upper = None
@@ -93,11 +113,6 @@ class Switchboard:
if recover:
self.recover_backup_files()
- @property
- def queue_directory(self):
- """See `ISwitchboard`."""
- return self._whichq
-
def enqueue(self, _msg, _metadata=None, **_kws):
"""See `ISwitchboard`."""
if _metadata is None:
@@ -125,7 +140,7 @@ class Switchboard:
# and the sha hex digest.
rcvtime = data.setdefault('received_time', now)
filebase = repr(rcvtime) + '+' + hashlib.sha1(hashfood).hexdigest()
- filename = os.path.join(self._whichq, filebase + '.pck')
+ filename = os.path.join(self.queue_directory, filebase + '.pck')
tmpfile = filename + '.tmp'
# Always add the metadata schema version number
data['version'] = config.QFILE_SCHEMA_VERSION
@@ -148,8 +163,8 @@ class Switchboard:
def dequeue(self, filebase):
"""See `ISwitchboard`."""
# Calculate the filename from the given filebase.
- filename = os.path.join(self._whichq, filebase + '.pck')
- backfile = os.path.join(self._whichq, filebase + '.bak')
+ filename = os.path.join(self.queue_directory, filebase + '.pck')
+ backfile = os.path.join(self.queue_directory, filebase + '.bak')
# Read the message object and metadata.
with open(filename) as fp:
# Move the file to the backup file name for processing. If this
@@ -172,13 +187,13 @@ class Switchboard:
return msg, data
def finish(self, filebase, preserve=False):
- bakfile = os.path.join(self._whichq, filebase + '.bak')
+ bakfile = os.path.join(self.queue_directory, filebase + '.bak')
try:
if preserve:
- psvfile = os.path.join(config.SHUNTQUEUE_DIR,
- filebase + '.psv')
+ shunt_dir = config.switchboards['shunt'].queue_directory
+ psvfile = os.path.join(shunt_dir, filebase + '.psv')
# Create the directory if it doesn't yet exist.
- Utils.makedirs(config.SHUNTQUEUE_DIR, 0770)
+ Utils.makedirs(shunt_dir, 0770)
os.rename(bakfile, psvfile)
else:
os.unlink(bakfile)
@@ -196,7 +211,7 @@ class Switchboard:
times = {}
lower = self._lower
upper = self._upper
- for f in os.listdir(self._whichq):
+ for f in os.listdir(self.queue_directory):
# By ignoring anything that doesn't end in .pck, we ignore
# tempfiles and avoid a race condition.
filebase, ext = os.path.splitext(f)
@@ -220,8 +235,8 @@ class Switchboard:
# to exist at the same time, so the move is enough to ensure that our
# normal dequeuing process will handle them.
for filebase in self.get_files('.bak'):
- src = os.path.join(self._whichq, filebase + '.bak')
- dst = os.path.join(self._whichq, filebase + '.pck')
+ src = os.path.join(self.queue_directory, filebase + '.bak')
+ dst = os.path.join(self.queue_directory, filebase + '.pck')
os.rename(src, dst)
@@ -229,27 +244,31 @@ class Switchboard:
class Runner:
implements(IRunner)
- QDIR = None
- SLEEPTIME = None
-
- def __init__(self, slice=None, numslices=1):
+ def __init__(self, name, slice=None):
"""Create a queue runner.
:param slice: The slice number for this queue runner. This is passed
directly to the underlying `ISwitchboard` object.
:type slice: int or None
- :param numslices: The number of slices for this queue. Must be a
- power of 2.
- :type numslices: int
"""
- # Create our own switchboard. Don't use the switchboard cache because
- # we want to provide slice and numslice arguments.
- self._switchboard = Switchboard(self.QDIR, slice, numslices, True)
- # Create the shunt switchboard
- self._shunt = Switchboard(config.SHUNTQUEUE_DIR)
+ # Grab the configuration section.
+ self.name = name
+ section = getattr(config, 'qrunner.' + name)
+ substitutions = config.paths
+ substitutions['name'] = name
+ self.queue_directory = Template(section.path).safe_substitute(
+ substitutions)
+ numslices = int(section.instances)
+ self.switchboard = Switchboard(
+ self.queue_directory, slice, numslices, True)
+ self.sleep_time = as_timedelta(section.sleep_time)
+ # 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.max_restarts = int(section.max_restarts)
+ self.start = as_boolean(section.start)
self._stop = False
- if self.SLEEPTIME is None:
- self.SLEEPTIME = config.QRUNNER_SLEEP_TIME
def __repr__(self):
return '<%s at %s>' % (self.__class__.__name__, id(self))
@@ -286,13 +305,13 @@ class Runner:
dlog.debug('[%s] starting oneloop', me)
# List all the files in our queue directory. The switchboard is
# guaranteed to hand us the files in FIFO order.
- files = self._switchboard.files
+ files = self.switchboard.files
for filebase in files:
dlog.debug('[%s] processing filebase: %s', me, filebase)
try:
# Ask the switchboard for the message and metadata objects
# associated with this queue file.
- msg, msgdata = self._switchboard.dequeue(filebase)
+ msg, msgdata = self.switchboard.dequeue(filebase)
except Exception, e:
# This used to just catch email.Errors.MessageParseError, but
# other problems can occur in message parsing, e.g.
@@ -302,14 +321,14 @@ class Runner:
self._log(e)
elog.error('Skipping and preserving unparseable message: %s',
filebase)
- self._switchboard.finish(filebase, preserve=True)
+ self.switchboard.finish(filebase, preserve=True)
config.db.abort()
continue
try:
dlog.debug('[%s] processing onefile', me)
self._process_one_file(msg, msgdata)
dlog.debug('[%s] finishing filebase: %s', me, filebase)
- self._switchboard.finish(filebase)
+ self.switchboard.finish(filebase)
except Exception, e:
# All runners that implement _dispose() must guarantee that
# exceptions are caught and dealt with properly. Still, there
@@ -319,14 +338,15 @@ class Runner:
# intervention.
self._log(e)
# Put a marker in the metadata for unshunting.
- msgdata['whichq'] = self._switchboard.queue_directory
+ msgdata['whichq'] = self.switchboard.queue_directory
# It is possible that shunting can throw an exception, e.g. a
# permissions problem or a MemoryError due to a really large
# message. Try to be graceful.
try:
- new_filebase = self._shunt.enqueue(msg, msgdata)
+ shunt = config.switchboards['shunt']
+ new_filebase = shunt.enqueue(msg, msgdata)
elog.error('SHUNTING: %s', new_filebase)
- self._switchboard.finish(filebase)
+ self.switchboard.finish(filebase)
except Exception, e:
# The message wasn't successfully shunted. Log the
# exception and try to preserve the original queue entry
@@ -335,13 +355,13 @@ class Runner:
elog.error(
'SHUNTING FAILED, preserving original entry: %s',
filebase)
- self._switchboard.finish(filebase, preserve=True)
+ self.switchboard.finish(filebase, preserve=True)
config.db.abort()
# Other work we want to do each time through the loop.
dlog.debug('[%s] doing periodic', me)
self._do_periodic()
dlog.debug('[%s] checking short circuit', me)
- if self._short_curcuit():
+ if self._short_circuit():
dlog.debug('[%s] short circuiting', me)
break
dlog.debug('[%s] commiting', me)
@@ -363,7 +383,7 @@ class Runner:
if mlist is None:
elog.error('Dequeuing message destined for missing list: %s',
listname)
- self._shunt.enqueue(msg, msgdata)
+ config.switchboards['shunt'].enqueue(msg, msgdata)
return
# Now process this message. We also want to set up the language
# context for this message. The context will be the preferred
@@ -380,7 +400,7 @@ class Runner:
msgdata['lang'] = language
keepqueued = self._dispose(mlist, msg, msgdata)
if keepqueued:
- self._switchboard.enqueue(msg, msgdata)
+ self.switchboard.enqueue(msg, msgdata)
def _log(self, exc):
elog.error('Uncaught runner exception: %s', exc)
@@ -401,10 +421,10 @@ class Runner:
def _snooze(self, filecnt):
"""See `IRunner`."""
- if filecnt or float(self.SLEEPTIME) <= 0:
+ if filecnt or self.sleep_float <= 0:
return
- time.sleep(float(self.SLEEPTIME))
+ time.sleep(self.sleep_float)
- def _short_curcuit(self):
+ def _short_circuit(self):
"""See `IRunner`."""
return self._stop
diff --git a/mailman/queue/archive.py b/mailman/queue/archive.py
index 6dda70387..69ec46f4b 100644
--- a/mailman/queue/archive.py
+++ b/mailman/queue/archive.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -25,19 +25,22 @@ __all__ = [
import os
import time
+import logging
from datetime import datetime
from email.Utils import parsedate_tz, mktime_tz, formatdate
from locknix.lockfile import Lock
-from mailman.configuration import config
+from mailman import Defaults
from mailman.core.plugins import get_plugins
from mailman.queue import Runner
+log = logging.getLogger('mailman.error')
+
class ArchiveRunner(Runner):
- QDIR = config.ARCHQUEUE_DIR
+ """The archive runner."""
def _dispose(self, mlist, msg, msgdata):
# Support clobber_date, i.e. setting the date in the archive to the
@@ -48,9 +51,9 @@ class ArchiveRunner(Runner):
received_time = formatdate(msgdata['received_time'])
if not original_date:
clobber = True
- elif config.ARCHIVER_CLOBBER_DATE_POLICY == 1:
+ elif Defaults.ARCHIVER_CLOBBER_DATE_POLICY == 1:
clobber = True
- elif config.ARCHIVER_CLOBBER_DATE_POLICY == 2:
+ elif Defaults.ARCHIVER_CLOBBER_DATE_POLICY == 2:
# What's the timestamp on the original message?
timetup = parsedate_tz(original_date)
now = datetime.now()
@@ -60,7 +63,7 @@ class ArchiveRunner(Runner):
else:
utc_timestamp = datetime.fromtimestamp(mktime_tz(timetup))
clobber = (abs(now - utc_timestamp) >
- config.ARCHIVER_ALLOWABLE_SANE_DATE_SKEW)
+ Defaults.ARCHIVER_ALLOWABLE_SANE_DATE_SKEW)
except (ValueError, OverflowError):
# The likely cause of this is that the year in the Date: field
# is horribly incorrect, e.g. (from SF bug # 571634):
@@ -78,5 +81,10 @@ class ArchiveRunner(Runner):
# While a list archiving lock is acquired, archive the message.
with Lock(os.path.join(mlist.data_path, 'archive.lck')):
for archive_factory in get_plugins('mailman.archiver'):
- archive_factory().archive_message(mlist, msg)
-
+ # A problem in one archiver should not prevent any other
+ # archiver from running.
+ try:
+ archive = archive_factory()
+ archive.archive_message(mlist, msg)
+ except Exception:
+ log.exception('Broken archiver: %s' % archive.name)
diff --git a/mailman/queue/bounce.py b/mailman/queue/bounce.py
index 0c5788174..e098ba866 100644
--- a/mailman/queue/bounce.py
+++ b/mailman/queue/bounce.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -27,10 +27,11 @@ from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from email.Utils import parseaddr
+from mailman import Defaults
from mailman import Utils
from mailman.Bouncers import BouncerAPI
from mailman.Message import UserNotification
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.queue import Runner, Switchboard
@@ -80,7 +81,7 @@ class BounceMixin:
self._bounce_events_fp = None
self._bouncecnt = 0
self._nextaction = (datetime.datetime.now() +
- config.REGISTER_BOUNCES_EVERY)
+ Defaults.REGISTER_BOUNCES_EVERY)
def _queue_bounces(self, listname, addrs, msg):
today = datetime.date.today()
@@ -132,7 +133,7 @@ class BounceMixin:
if self._nextaction > now or self._bouncecnt == 0:
return
# Let's go ahead and register the bounces we've got stored up
- self._nextaction = now + config.REGISTER_BOUNCES_EVERY
+ self._nextaction = now + Defaults.REGISTER_BOUNCES_EVERY
self._register_bounces()
def _probe_bounce(self, mlist, token):
@@ -153,7 +154,7 @@ class BounceMixin:
class BounceRunner(Runner, BounceMixin):
- QDIR = config.BOUNCEQUEUE_DIR
+ """The bounce runner."""
def __init__(self, slice=None, numslices=1):
Runner.__init__(self, slice, numslices)
@@ -162,7 +163,6 @@ class BounceRunner(Runner, BounceMixin):
def _dispose(self, mlist, msg, msgdata):
# Make sure we have the most up-to-date state
mlist.Load()
- outq = Switchboard(config.OUTQUEUE_DIR)
# There are a few possibilities here:
#
# - the message could have been VERP'd in which case, we know exactly
@@ -176,14 +176,15 @@ class BounceRunner(Runner, BounceMixin):
# owner address. That way, if a list owner address bounces, at least
# some human has a chance to deal with it. Is this a bounce for a
# message to a list owner, coming to the site owner?
- if msg.get('to', '') == config.SITE_OWNER_ADDRESS:
+ if msg.get('to', '') == config.mailman.site_owner:
# Send it on to the site owners, but craft the envelope sender to
# be the noreply address, so if the site owner bounce, we won't
# get stuck in a bounce loop.
- outq.enqueue(msg, msgdata,
- recips=[config.SITE_OWNER_ADDRESS],
- envsender=config.NO_REPLY_ADDRESS,
- )
+ config.switchboards['out'].enqueue(
+ msg, msgdata,
+ recips=[config.mailman.site_owner],
+ envsender=config.mailman.noreply_address,
+ )
# List isn't doing bounce processing?
if not mlist.bounce_processing:
return
@@ -241,7 +242,7 @@ def verp_bounce(mlist, msg):
to = parseaddr(field)[1]
if not to:
continue # empty header
- mo = re.search(config.VERP_REGEXP, to)
+ mo = re.search(Defaults.VERP_REGEXP, to)
if not mo:
continue # no match of regexp
try:
@@ -251,7 +252,7 @@ def verp_bounce(mlist, msg):
addr = '%s@%s' % mo.group('mailbox', 'host')
except IndexError:
elog.error("VERP_REGEXP doesn't yield the right match groups: %s",
- config.VERP_REGEXP)
+ Defaults.VERP_REGEXP)
return []
return [addr]
@@ -272,7 +273,7 @@ def verp_probe(mlist, msg):
to = parseaddr(field)[1]
if not to:
continue # empty header
- mo = re.search(config.VERP_PROBE_REGEXP, to)
+ mo = re.search(Defaults.VERP_PROBE_REGEXP, to)
if not mo:
continue # no match of regexp
try:
@@ -286,7 +287,7 @@ def verp_probe(mlist, msg):
except IndexError:
elog.error(
"VERP_PROBE_REGEXP doesn't yield the right match groups: %s",
- config.VERP_PROBE_REGEXP)
+ Defaults.VERP_PROBE_REGEXP)
return None
diff --git a/mailman/queue/command.py b/mailman/queue/command.py
index a02827de0..db6feba57 100644
--- a/mailman/queue/command.py
+++ b/mailman/queue/command.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -40,10 +40,11 @@ from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from zope.interface import implements
+from mailman import Defaults
from mailman import Message
from mailman import Utils
from mailman.app.replybot import autorespond_to_sender
-from mailman.configuration import config
+from mailman.config import config
from mailman.i18n import _
from mailman.interfaces import ContinueProcessing, IEmailResults
from mailman.queue import Runner
@@ -70,7 +71,7 @@ class CommandFinder:
elif msgdata.get('toleave'):
self.command_lines.append('leave')
elif msgdata.get('toconfirm'):
- mo = re.match(config.VERP_CONFIRM_REGEXP, msg.get('to', ''))
+ mo = re.match(Defaults.VERP_CONFIRM_REGEXP, msg.get('to', ''))
if mo:
self.command_lines.append('confirm ' + mo.group('cookie'))
# Extract the subject header and do RFC 2047 decoding.
@@ -99,8 +100,8 @@ class CommandFinder:
assert isinstance(body, basestring), 'Non-string decoded payload'
lines = body.splitlines()
# Use no more lines than specified
- self.command_lines.extend(lines[:config.EMAIL_COMMANDS_MAX_LINES])
- self.ignored_lines.extend(lines[config.EMAIL_COMMANDS_MAX_LINES:])
+ self.command_lines.extend(lines[:Defaults.EMAIL_COMMANDS_MAX_LINES])
+ self.ignored_lines.extend(lines[Defaults.EMAIL_COMMANDS_MAX_LINES:])
def __iter__(self):
"""Return each command line, split into commands and arguments.
@@ -141,7 +142,7 @@ The results of your email command are provided below.
class CommandRunner(Runner):
- QDIR = config.CMDQUEUE_DIR
+ """The email command runner."""
def _dispose(self, mlist, msg, msgdata):
message_id = msg.get('message-id', 'n/a')
diff --git a/mailman/queue/docs/archiver.txt b/mailman/queue/docs/archiver.txt
index 8c34e3537..ed7c26d45 100644
--- a/mailman/queue/docs/archiver.txt
+++ b/mailman/queue/docs/archiver.txt
@@ -5,7 +5,6 @@ Mailman can archive to any number of archivers that adhere to the IArchiver
interface. By default, there's a Pipermail archiver.
>>> from mailman.app.lifecycle import create_list
- >>> from mailman.configuration import config
>>> mlist = create_list(u'test@example.com')
>>> mlist.web_page_url = u'http://www.example.com/'
>>> config.db.commit()
@@ -19,8 +18,7 @@ interface. By default, there's a Pipermail archiver.
... First post!
... """)
- >>> from mailman.queue import Switchboard
- >>> archiver_queue = Switchboard(config.ARCHQUEUE_DIR)
+ >>> archiver_queue = config.switchboards['archive']
>>> ignore = archiver_queue.enqueue(msg, {}, listname=mlist.fqdn_listname)
>>> from mailman.queue.archive import ArchiveRunner
diff --git a/mailman/queue/docs/command.txt b/mailman/queue/docs/command.txt
index 470a632b7..0b384de01 100644
--- a/mailman/queue/docs/command.txt
+++ b/mailman/queue/docs/command.txt
@@ -24,9 +24,8 @@ sender. The command can be in the Subject header.
...
... """)
- >>> from mailman.configuration import config
>>> from mailman.inject import inject_message
- >>> inject_message(mlist, msg, qdir=config.CMDQUEUE_DIR)
+ >>> inject_message(mlist, msg, switchboard='command')
>>> from mailman.queue.command import CommandRunner
>>> from mailman.testing.helpers import make_testable_runner
>>> command = make_testable_runner(CommandRunner)
@@ -35,11 +34,11 @@ sender. The command can be in the Subject header.
And now the response is in the virgin queue.
>>> from mailman.queue import Switchboard
- >>> virgin_queue = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virgin_queue = config.switchboards['virgin']
>>> len(virgin_queue.files)
1
>>> from mailman.testing.helpers import get_queue_messages
- >>> item = get_queue_messages(virgin_queue)[0]
+ >>> item = get_queue_messages('virgin')[0]
>>> print item.msg.as_string()
Subject: The results of your email commands
From: test-bounces@example.com
@@ -79,11 +78,11 @@ message is plain text.
... echo foo bar
... """)
- >>> inject_message(mlist, msg, qdir=config.CMDQUEUE_DIR)
+ >>> inject_message(mlist, msg, switchboard='command')
>>> command.run()
>>> len(virgin_queue.files)
1
- >>> item = get_queue_messages(virgin_queue)[0]
+ >>> item = get_queue_messages('virgin')[0]
>>> print item.msg.as_string()
Subject: The results of your email commands
From: test-bounces@example.com
@@ -122,11 +121,11 @@ at by the command queue.
... echo baz qux
... """)
- >>> inject_message(mlist, msg, qdir=config.CMDQUEUE_DIR)
+ >>> inject_message(mlist, msg, switchboard='command')
>>> command.run()
>>> len(virgin_queue.files)
1
- >>> item = get_queue_messages(virgin_queue)[0]
+ >>> item = get_queue_messages('virgin')[0]
>>> print item.msg.as_string()
Subject: The results of your email commands
...
@@ -152,11 +151,11 @@ The 'stop' command is an alias for 'end'.
... echo baz qux
... """)
- >>> inject_message(mlist, msg, qdir=config.CMDQUEUE_DIR)
+ >>> inject_message(mlist, msg, switchboard='command')
>>> command.run()
>>> len(virgin_queue.files)
1
- >>> item = get_queue_messages(virgin_queue)[0]
+ >>> item = get_queue_messages('virgin')[0]
>>> print item.msg.as_string()
Subject: The results of your email commands
...
diff --git a/mailman/queue/docs/incoming.txt b/mailman/queue/docs/incoming.txt
index 997eac07e..22b32d828 100644
--- a/mailman/queue/docs/incoming.txt
+++ b/mailman/queue/docs/incoming.txt
@@ -43,21 +43,19 @@ The incoming queue runner runs until it is empty.
>>> from mailman.queue.incoming import IncomingRunner
>>> from mailman.testing.helpers import make_testable_runner
- >>> incoming = make_testable_runner(IncomingRunner)
+ >>> incoming = make_testable_runner(IncomingRunner, 'in')
>>> incoming.run()
And now the message is in the pipeline queue.
- >>> from mailman.configuration import config
- >>> from mailman.queue import Switchboard
- >>> pipeline_queue = Switchboard(config.PIPELINEQUEUE_DIR)
+ >>> pipeline_queue = config.switchboards['pipeline']
>>> len(pipeline_queue.files)
1
- >>> incoming_queue = Switchboard(config.INQUEUE_DIR)
+ >>> incoming_queue = config.switchboards['in']
>>> len(incoming_queue.files)
0
>>> from mailman.testing.helpers import get_queue_messages
- >>> item = get_queue_messages(pipeline_queue)[0]
+ >>> item = get_queue_messages('pipeline')[0]
>>> print item.msg.as_string()
From: aperson@example.com
To: _xtest@example.com
@@ -153,8 +151,8 @@ just create a new chain that does.
The virgin queue needs to be cleared out due to artifacts from the previous
tests above.
- >>> virgin_queue = Switchboard(config.VIRGINQUEUE_DIR)
- >>> ignore = get_queue_messages(virgin_queue)
+ >>> virgin_queue = config.switchboards['virgin']
+ >>> ignore = get_queue_messages('virgin')
>>> inject_message(mlist, msg)
>>> file_pos = fp.tell()
@@ -166,7 +164,7 @@ tests above.
>>> len(virgin_queue.files)
1
- >>> item = get_queue_messages(virgin_queue)[0]
+ >>> item = get_queue_messages('virgin')[0]
>>> print item.msg.as_string()
Subject: My first post
From: _xtest-owner@example.com
diff --git a/mailman/queue/docs/lmtp.txt b/mailman/queue/docs/lmtp.txt
index bb77203b4..75e91fd4e 100644
--- a/mailman/queue/docs/lmtp.txt
+++ b/mailman/queue/docs/lmtp.txt
@@ -25,7 +25,7 @@ It also helps to have a nice LMTP client.
Posting address
---------------
-If the mail server tries to send a message to a non-existant mailing list, it
+If the mail server tries to send a message to a nonexistent mailing list, it
will get a 550 error.
>>> lmtp.sendmail(
diff --git a/mailman/queue/docs/news.txt b/mailman/queue/docs/news.txt
index 0b89de2bc..3375b3d54 100644
--- a/mailman/queue/docs/news.txt
+++ b/mailman/queue/docs/news.txt
@@ -6,7 +6,6 @@ NNTP newsgroup. One of the most important things this runner does is prepare
the message for Usenet (yes, I know that NNTP is not Usenet, but this runner
was originally written to gate to Usenet, which has its own rules).
- >>> from mailman.configuration import config
>>> from mailman.queue.news import prepare_message
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.linked_newsgroup = u'comp.lang.python'
diff --git a/mailman/queue/docs/outgoing.txt b/mailman/queue/docs/outgoing.txt
index edc806d47..851bdf474 100644
--- a/mailman/queue/docs/outgoing.txt
+++ b/mailman/queue/docs/outgoing.txt
@@ -43,13 +43,11 @@ Normally, messages would show up in the outgoing queue after the message has
been processed by the rule set and pipeline. But we can simulate that here by
injecting a message directly into the outgoing queue.
- >>> from mailman.configuration import config
>>> msgdata = {}
>>> handler = config.handlers['calculate-recipients']
>>> handler.process(mlist, msg, msgdata)
- >>> from mailman.queue import Switchboard
- >>> outgoing_queue = Switchboard(config.OUTQUEUE_DIR)
+ >>> outgoing_queue = config.switchboards['out']
>>> ignore = outgoing_queue.enqueue(
... msg, msgdata,
... verp=True, listname=mlist.fqdn_listname, tolist=True,
@@ -60,7 +58,7 @@ upstream SMTP, which happens to be our test server.
>>> from mailman.queue.outgoing import OutgoingRunner
>>> from mailman.testing.helpers import make_testable_runner
- >>> outgoing = make_testable_runner(OutgoingRunner)
+ >>> outgoing = make_testable_runner(OutgoingRunner, 'out')
>>> outgoing.run()
Three messages have been delivered to our SMTP server, one for each recipient.
diff --git a/mailman/queue/docs/runner.txt b/mailman/queue/docs/runner.txt
index a9e17370b..db493110c 100644
--- a/mailman/queue/docs/runner.txt
+++ b/mailman/queue/docs/runner.txt
@@ -14,21 +14,21 @@ The basic architecture of qrunner is implemented in the base class that all
runners inherit from. This base class implements a .run() method that runs
continuously in a loop until the .stop() method is called.
- >>> import os
- >>> from mailman.queue import Runner, Switchboard
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.preferred_language = u'en'
-Here is a very simple derived qrunner class. The class attribute QDIR tells
-the qrunner which queue directory it is responsible for. Derived classes
-should also implement various methods to provide the special functionality.
-This is about as simple as a qrunner can be.
+Here is a very simple derived qrunner class. Queue runners use a
+configuration section in the configuration files to determine run
+characteristics, such as the queue directory to use. Here we push a
+configuration section for the test runner.
- >>> queue_directory = os.path.join(config.QUEUE_DIR, 'test')
+ >>> config.push('test-runner', """
+ ... [qrunner.test]
+ ... max_restarts: 1
+ ... """)
+
+ >>> from mailman.queue import Runner
>>> class TestableRunner(Runner):
- ... QDIR = queue_directory
- ...
... def _dispose(self, mlist, msg, msgdata):
... self.msg = msg
... self.msgdata = msgdata
@@ -40,8 +40,7 @@ This is about as simple as a qrunner can be.
... def _snooze(self, filecnt):
... return
- >>> runner = TestableRunner()
- >>> switchboard = Switchboard(queue_directory)
+ >>> runner = TestableRunner('test')
This qrunner doesn't do much except run once, storing the message and metadata
on instance variables.
@@ -52,6 +51,7 @@ on instance variables.
...
... A test message.
... """)
+ >>> switchboard = config.switchboards['test']
>>> filebase = switchboard.enqueue(msg, listname=mlist.fqdn_listname,
... foo='yes', bar='no')
>>> runner.run()
diff --git a/mailman/queue/docs/switchboard.txt b/mailman/queue/docs/switchboard.txt
index 633bdabe6..7baee7b54 100644
--- a/mailman/queue/docs/switchboard.txt
+++ b/mailman/queue/docs/switchboard.txt
@@ -14,7 +14,6 @@ instance of a switchboard is responsible for one queue directory.
Create a switchboard by giving its queue directory.
>>> import os
- >>> from mailman.configuration import config
>>> queue_directory = os.path.join(config.QUEUE_DIR, 'test')
>>> from mailman.queue import Switchboard
>>> switchboard = Switchboard(queue_directory)
diff --git a/mailman/queue/http.py b/mailman/queue/http.py
index cb6940b29..941b6d131 100644
--- a/mailman/queue/http.py
+++ b/mailman/queue/http.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -25,7 +25,7 @@ from cStringIO import StringIO
from wsgiref.simple_server import make_server, WSGIRequestHandler
from mailman.Cgi.wsgi_app import mailman_app
-from mailman.configuration import config
+from mailman.config import config
from mailman.queue import Runner
hlog = logging.getLogger('mailman.http')
diff --git a/mailman/queue/incoming.py b/mailman/queue/incoming.py
index d4decd435..ae78e1a81 100644
--- a/mailman/queue/incoming.py
+++ b/mailman/queue/incoming.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -26,14 +26,14 @@ prepared for delivery. Rejections, discards, and holds are processed
immediately.
"""
-from mailman.configuration import config
+from mailman.config import config
from mailman.core.chains import process
from mailman.queue import Runner
class IncomingRunner(Runner):
- QDIR = config.INQUEUE_DIR
+ """The incoming queue runner."""
def _dispose(self, mlist, msg, msgdata):
if msgdata.get('envsender') is None:
diff --git a/mailman/queue/lmtp.py b/mailman/queue/lmtp.py
index b4688653b..f0895ee1f 100644
--- a/mailman/queue/lmtp.py
+++ b/mailman/queue/lmtp.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -42,10 +42,11 @@ import asyncore
from email.utils import parseaddr
+from mailman import Defaults
from mailman.Message import Message
-from mailman.configuration import config
+from mailman.config import config
from mailman.database.transaction import txn
-from mailman.queue import Runner, Switchboard
+from mailman.queue import Runner
elog = logging.getLogger('mailman.error')
qlog = logging.getLogger('mailman.qrunner')
@@ -63,7 +64,7 @@ CRLF = '\r\n'
ERR_451 = '451 Requested action aborted: error in processing'
ERR_501 = '501 Message has defects'
ERR_502 = '502 Error: command HELO not implemented'
-ERR_550 = config.LMTP_ERR_550
+ERR_550 = Defaults.LMTP_ERR_550
# XXX Blech
smtpd.__version__ = 'Python LMTP queue runner 1.0'
@@ -86,7 +87,7 @@ def split_recipient(address):
subaddress may be None if this is the list's posting address.
"""
localpart, domain = address.split('@', 1)
- localpart = localpart.split(config.VERP_DELIMITER, 1)[0]
+ localpart = localpart.split(Defaults.VERP_DELIMITER, 1)[0]
parts = localpart.split(DASH)
if parts[-1] in SUBADDRESS_NAMES:
listname = DASH.join(parts[:-1])
@@ -121,11 +122,11 @@ class LMTPRunner(Runner, smtpd.SMTPServer):
# connections from the MTA. slice and numslices are ignored and are
# necessary only to satisfy the API.
def __init__(self, slice=None, numslices=1):
- localaddr = config.LMTP_HOST, config.LMTP_PORT
+ localaddr = config.mta.lmtp_host, int(config.mta.lmtp_port)
# Do not call Runner's constructor because there's no QDIR to create
smtpd.SMTPServer.__init__(self, localaddr, remoteaddr=None)
qlog.debug('LMTP server listening on %s:%s',
- config.LMTP_HOST, config.LMTP_PORT)
+ localaddr[0], localaddr[1])
def handle_accept(self):
conn, addr = self.accept()
@@ -138,6 +139,7 @@ class LMTPRunner(Runner, smtpd.SMTPServer):
# Refresh the list of list names every time we process a message
# since the set of mailing lists could have changed.
listnames = set(config.db.list_manager.names)
+ qlog.debug('listnames: %s', listnames)
# Parse the message data. If there are any defects in the
# message, reject it right away; it's probably spam.
msg = email.message_from_string(data, Message)
@@ -169,29 +171,29 @@ class LMTPRunner(Runner, smtpd.SMTPServer):
queue = None
msgdata = dict(listname=listname)
if subaddress in ('bounces', 'admin'):
- queue = Switchboard(config.BOUNCEQUEUE_DIR)
+ queue = 'bounce'
elif subaddress == 'confirm':
msgdata['toconfirm'] = True
- queue = Switchboard(config.CMDQUEUE_DIR)
+ queue = 'command'
elif subaddress in ('join', 'subscribe'):
msgdata['tojoin'] = True
- queue = Switchboard(config.CMDQUEUE_DIR)
+ queue = 'command'
elif subaddress in ('leave', 'unsubscribe'):
msgdata['toleave'] = True
- queue = Switchboard(config.CMDQUEUE_DIR)
+ queue = 'command'
elif subaddress == 'owner':
msgdata.update(dict(
toowner=True,
- envsender=config.SITE_OWNER_ADDRESS,
- pipeline=config.OWNER_PIPELINE,
+ envsender=config.mailman.site_owner,
+ pipeline=Defaults.OWNER_PIPELINE,
))
- queue = Switchboard(config.INQUEUE_DIR)
+ queue = 'in'
elif subaddress is None:
msgdata['tolist'] = True
- queue = Switchboard(config.INQUEUE_DIR)
+ queue = 'in'
elif subaddress == 'request':
msgdata['torequest'] = True
- queue = Switchboard(config.CMDQUEUE_DIR)
+ queue = 'command'
else:
elog.error('Unknown sub-address: %s', subaddress)
status.append(ERR_550)
@@ -199,7 +201,7 @@ class LMTPRunner(Runner, smtpd.SMTPServer):
# If we found a valid subaddress, enqueue the message and add
# a success status for this recipient.
if queue is not None:
- queue.enqueue(msg, msgdata)
+ config.switchboards[queue].enqueue(msg, msgdata)
status.append('250 Ok')
except Exception, e:
elog.exception('Queue detection: %s', msg['message-id'])
diff --git a/mailman/queue/maildir.py b/mailman/queue/maildir.py
index 71bac67dc..e12550cb5 100644
--- a/mailman/queue/maildir.py
+++ b/mailman/queue/maildir.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -57,7 +57,7 @@ from email.Parser import Parser
from email.Utils import parseaddr
from mailman.Message import Message
-from mailman.configuration import config
+from mailman.config import config
from mailman.queue import Runner
log = logging.getLogger('mailman.error')
diff --git a/mailman/queue/news.py b/mailman/queue/news.py
index 8415f7d95..98735d498 100644
--- a/mailman/queue/news.py
+++ b/mailman/queue/news.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -28,8 +28,8 @@ from email.utils import getaddresses, make_msgid
COMMASPACE = ', '
+from mailman import Defaults
from mailman import Utils
-from mailman.configuration import config
from mailman.interfaces import NewsModeration
from mailman.queue import Runner
@@ -51,8 +51,6 @@ mcre = re.compile(r"""
class NewsRunner(Runner):
- QDIR = config.NEWSQUEUE_DIR
-
def _dispose(self, mlist, msg, msgdata):
# Make sure we have the most up-to-date state
mlist.Load()
@@ -67,8 +65,8 @@ class NewsRunner(Runner):
nntp_host, nntp_port = Utils.nntpsplit(mlist.nntp_host)
conn = nntplib.NNTP(nntp_host, nntp_port,
readermode=True,
- user=config.NNTP_USERNAME,
- password=config.NNTP_PASSWORD)
+ user=Defaults.NNTP_USERNAME,
+ password=Defaults.NNTP_PASSWORD)
conn.post(fp)
except nntplib.error_temp, e:
log.error('(NNTPDirect) NNTP error for list "%s": %s',
@@ -150,9 +148,9 @@ def prepare_message(mlist, msg, msgdata):
# woon't completely sanitize the message, but it will eliminate the bulk
# of the rejections based on message headers. The NNTP server may still
# reject the message because of other problems.
- for header in config.NNTP_REMOVE_HEADERS:
+ for header in Defaults.NNTP_REMOVE_HEADERS:
del msg[header]
- for header, rewrite in config.NNTP_REWRITE_DUPLICATE_HEADERS:
+ for header, rewrite in Defaults.NNTP_REWRITE_DUPLICATE_HEADERS:
values = msg.get_all(header, [])
if len(values) < 2:
# We only care about duplicates
diff --git a/mailman/queue/outgoing.py b/mailman/queue/outgoing.py
index 3ab67eaad..14ba869dc 100644
--- a/mailman/queue/outgoing.py
+++ b/mailman/queue/outgoing.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -26,8 +26,9 @@ import logging
from datetime import datetime
+from mailman import Defaults
from mailman import Message
-from mailman.configuration import config
+from mailman.config import config
from mailman.core import errors
from mailman.queue import Runner, Switchboard
from mailman.queue.bounce import BounceMixin
@@ -41,19 +42,19 @@ log = logging.getLogger('mailman.error')
class OutgoingRunner(Runner, BounceMixin):
- QDIR = config.OUTQUEUE_DIR
+ """The outgoing queue runner."""
def __init__(self, slice=None, numslices=1):
Runner.__init__(self, slice, numslices)
BounceMixin.__init__(self)
# We look this function up only at startup time
- handler = config.handlers[config.DELIVERY_MODULE]
+ handler = config.handlers[Defaults.DELIVERY_MODULE]
self._func = handler.process
# This prevents smtp server connection problems from filling up the
# error log. It gets reset if the message was successfully sent, and
# set if there was a socket.error.
self._logged = False
- self._retryq = Switchboard(config.RETRYQUEUE_DIR)
+ self._retryq = config.switchboards['retry']
def _dispose(self, mlist, msg, msgdata):
# See if we should retry delivery of this message again.
@@ -73,13 +74,13 @@ class OutgoingRunner(Runner, BounceMixin):
# There was a problem connecting to the SMTP server. Log this
# once, but crank up our sleep time so we don't fill the error
# log.
- port = config.SMTPPORT
+ port = int(config.mta.port)
if port == 0:
port = 'smtp'
# Log this just once.
if not self._logged:
log.error('Cannot connect to SMTP server %s on port %s',
- config.SMTPHOST, port)
+ config.mta.host, port)
self._logged = True
return True
except errors.SomeRecipientsFailed, e:
@@ -115,7 +116,7 @@ class OutgoingRunner(Runner, BounceMixin):
return False
else:
# Keep trying to delivery this message for a while
- deliver_until = now + config.DELIVERY_RETRY_PERIOD
+ deliver_until = now + Defaults.DELIVERY_RETRY_PERIOD
msgdata['last_recip_count'] = len(recips)
msgdata['deliver_until'] = deliver_until
msgdata['recips'] = recips
diff --git a/mailman/queue/pipeline.py b/mailman/queue/pipeline.py
index 665bfce77..f0a42f729 100644
--- a/mailman/queue/pipeline.py
+++ b/mailman/queue/pipeline.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -22,15 +22,13 @@ through the 'preparation pipeline'. This pipeline adds, deletes and modifies
headers, calculates message recipients, and more.
"""
-from mailman.app.pipelines import process
-from mailman.configuration import config
+from mailman.core.pipelines import process
+from mailman.config import config
from mailman.queue import Runner
class PipelineRunner(Runner):
- QDIR = config.PIPELINEQUEUE_DIR
-
def _dispose(self, mlist, msg, msgdata):
# Process the message through the mailing list's pipeline.
process(mlist, msg, msgdata, mlist.pipeline)
diff --git a/mailman/queue/retry.py b/mailman/queue/retry.py
index f8e1b4665..2b5a6afad 100644
--- a/mailman/queue/retry.py
+++ b/mailman/queue/retry.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2003-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2003-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -17,24 +17,21 @@
import time
-from mailman.configuration import config
-from mailman.queue import Runner, Switchboard
+from mailman.config import config
+from mailman.queue import Runner
class RetryRunner(Runner):
- QDIR = config.RETRYQUEUE_DIR
- SLEEPTIME = config.minutes(15)
-
def __init__(self, slice=None, numslices=1):
Runner.__init__(self, slice, numslices)
- self.__outq = Switchboard(config.OUTQUEUE_DIR)
+ self._outq = config.switchboards['out']
def _dispose(self, mlist, msg, msgdata):
# Move it to the out queue for another retry
- self.__outq.enqueue(msg, msgdata)
+ self._outq.enqueue(msg, msgdata)
return False
def _snooze(self, filecnt):
# We always want to snooze
- time.sleep(float(self.SLEEPTIME))
+ time.sleep(self.sleep_float)
diff --git a/mailman/queue/virgin.py b/mailman/queue/virgin.py
index 503337ea1..ca61074bf 100644
--- a/mailman/queue/virgin.py
+++ b/mailman/queue/virgin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -23,15 +23,13 @@ to go through some minimal processing before they can be sent out to the
recipient.
"""
-from mailman.app.pipelines import process
-from mailman.configuration import config
+from mailman.core.pipelines import process
+from mailman.config import config
from mailman.queue import Runner
class VirginRunner(Runner):
- QDIR = config.VIRGINQUEUE_DIR
-
def _dispose(self, mlist, msg, msgdata):
# We need to fast track this message through any pipeline handlers
# that touch it, e.g. especially cook-headers.
diff --git a/mailman/rules/__init__.py b/mailman/rules/__init__.py
index caf469fa6..f7cf3da38 100644
--- a/mailman/rules/__init__.py
+++ b/mailman/rules/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/administrivia.py b/mailman/rules/administrivia.py
index 1c09d98e1..802229101 100644
--- a/mailman/rules/administrivia.py
+++ b/mailman/rules/administrivia.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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
@@ -80,7 +82,7 @@ class Administrivia:
if line == '':
continue
lineno += 1
- if lineno > config.EMAIL_COMMANDS_MAX_LINES:
+ if lineno > config.mailman.email_commands_max_lines:
break
lines_to_check.append(line)
# Only look at the first text/plain part.
diff --git a/mailman/rules/any.py b/mailman/rules/any.py
index 1525bdc3d..14e01ce5a 100644
--- a/mailman/rules/any.py
+++ b/mailman/rules/any.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/approved.py b/mailman/rules/approved.py
index 5101db08d..3ad14b195 100644
--- a/mailman/rules/approved.py
+++ b/mailman/rules/approved.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/docs/administrivia.txt b/mailman/rules/docs/administrivia.txt
index 65742fba2..df6685074 100644
--- a/mailman/rules/docs/administrivia.txt
+++ b/mailman/rules/docs/administrivia.txt
@@ -6,7 +6,6 @@ commands in the Subject header or first few lines of the payload. This is
used to catch messages posted to the list which should have been sent to the
-request robot address.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.administrivia = True
>>> rule = config.rules['administrivia']
diff --git a/mailman/rules/docs/approve.txt b/mailman/rules/docs/approve.txt
index 3b5065849..cb3093e0d 100644
--- a/mailman/rules/docs/approve.txt
+++ b/mailman/rules/docs/approve.txt
@@ -13,7 +13,6 @@ approval queue. This has several use cases:
In order to support this, a mailing list can be given a 'moderator password'
which is shared among all the administrators.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.moderator_password = u'abcxyz'
diff --git a/mailman/rules/docs/emergency.txt b/mailman/rules/docs/emergency.txt
index 6437ba626..e71566853 100644
--- a/mailman/rules/docs/emergency.txt
+++ b/mailman/rules/docs/emergency.txt
@@ -27,9 +27,7 @@ There are two messages in the virgin queue. The one addressed to the original
sender will contain a token we can use to grab the held message out of the
pending requests.
- >>> from mailman.configuration import config
- >>> from mailman.queue import Switchboard
- >>> virginq = Switchboard(config.VIRGINQUEUE_DIR)
+ >>> virginq = config.switchboards['virgin']
>>> def get_held_message():
... import re
diff --git a/mailman/rules/docs/header-matching.txt b/mailman/rules/docs/header-matching.txt
index 0dd917a71..5e8d01ead 100644
--- a/mailman/rules/docs/header-matching.txt
+++ b/mailman/rules/docs/header-matching.txt
@@ -12,7 +12,6 @@ Because the default HEADER_MATCHES variable is empty when the configuration
file is read, we'll just extend the current header matching chain with a
pattern that matches 4 or more stars, discarding the message if it hits.
- >>> from mailman.configuration import config
>>> chain = config.chains['header-match']
>>> chain.extend('x-spam-score', '[*]{4,}', 'discard')
diff --git a/mailman/rules/docs/implicit-dest.txt b/mailman/rules/docs/implicit-dest.txt
index 8857a397e..30db86611 100644
--- a/mailman/rules/docs/implicit-dest.txt
+++ b/mailman/rules/docs/implicit-dest.txt
@@ -4,7 +4,6 @@ Implicit destination
The 'implicit-dest' rule matches when the mailing list's posting address is
not explicitly mentioned in the set of message recipients.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['implicit-dest']
>>> rule.name
diff --git a/mailman/rules/docs/loop.txt b/mailman/rules/docs/loop.txt
index ba3cbbc1d..6391864b2 100644
--- a/mailman/rules/docs/loop.txt
+++ b/mailman/rules/docs/loop.txt
@@ -4,7 +4,6 @@ Posting loops
To avoid a posting loop, Mailman has a rule to check for the existence of an
X-BeenThere header with the value of the list's posting address.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['loop']
>>> rule.name
diff --git a/mailman/rules/docs/max-size.txt b/mailman/rules/docs/max-size.txt
index 7ece6a54a..ae7921f9c 100644
--- a/mailman/rules/docs/max-size.txt
+++ b/mailman/rules/docs/max-size.txt
@@ -6,7 +6,6 @@ specified maximum. Generally this is used to prevent huge attachments from
getting posted to the list. This value is calculated in terms of KB (1024
bytes).
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['max-size']
>>> rule.name
diff --git a/mailman/rules/docs/moderation.txt b/mailman/rules/docs/moderation.txt
index 3af5f2520..9f3663517 100644
--- a/mailman/rules/docs/moderation.txt
+++ b/mailman/rules/docs/moderation.txt
@@ -6,7 +6,6 @@ postings, then only members with a cleared moderation flag will be able to
email the list without having those messages be held for approval. The
'moderation' rule determines whether the message should be moderated or not.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['moderation']
>>> rule.name
diff --git a/mailman/rules/docs/news-moderation.txt b/mailman/rules/docs/news-moderation.txt
index 1ecbe12cf..36310797c 100644
--- a/mailman/rules/docs/news-moderation.txt
+++ b/mailman/rules/docs/news-moderation.txt
@@ -8,7 +8,6 @@ posted to the newsgroup, and from there, gated to the mailing list. It's a
circuitous route, but it works nonetheless by holding all messages posted
directly to the mailing list.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['news-moderation']
>>> rule.name
diff --git a/mailman/rules/docs/no-subject.txt b/mailman/rules/docs/no-subject.txt
index 0a67ccbef..4fa001308 100644
--- a/mailman/rules/docs/no-subject.txt
+++ b/mailman/rules/docs/no-subject.txt
@@ -4,7 +4,6 @@ No Subject header
This rule matches if the message has no Subject header, or if the header is
the empty string when stripped.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['no-subject']
>>> rule.name
diff --git a/mailman/rules/docs/recipients.txt b/mailman/rules/docs/recipients.txt
index 3408e7e51..b364dd031 100644
--- a/mailman/rules/docs/recipients.txt
+++ b/mailman/rules/docs/recipients.txt
@@ -4,7 +4,6 @@ Maximum number of recipients
The 'max-recipients' rule matches when there are more than the maximum allowed
number of explicit recipients addressed by the message.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['max-recipients']
>>> rule.name
diff --git a/mailman/rules/docs/rules.txt b/mailman/rules/docs/rules.txt
index fff833462..bae9f594a 100644
--- a/mailman/rules/docs/rules.txt
+++ b/mailman/rules/docs/rules.txt
@@ -13,7 +13,6 @@ Rules are maintained in the configuration object as a dictionary mapping rule
names to rule objects.
>>> from zope.interface.verify import verifyObject
- >>> from mailman.configuration import config
>>> from mailman.interfaces import IRule
>>> for rule_name in sorted(config.rules):
... rule = config.rules[rule_name]
diff --git a/mailman/rules/docs/suspicious.txt b/mailman/rules/docs/suspicious.txt
index df2bc64af..0cc515ae4 100644
--- a/mailman/rules/docs/suspicious.txt
+++ b/mailman/rules/docs/suspicious.txt
@@ -5,7 +5,6 @@ Suspicious headers are a way for Mailman to hold messages that match a
particular regular expression. This mostly historical feature is fairly
confusing to users, and the list attribute that controls this is misnamed.
- >>> from mailman.configuration import config
>>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> rule = config.rules['suspicious-header']
>>> rule.name
diff --git a/mailman/rules/docs/truth.txt b/mailman/rules/docs/truth.txt
index 3c11e4954..f331e852b 100644
--- a/mailman/rules/docs/truth.txt
+++ b/mailman/rules/docs/truth.txt
@@ -4,7 +4,6 @@ Truth
The 'truth' rule always matches. This makes it useful as a terminus rule for
unconditionally jumping to another chain.
- >>> from mailman.configuration import config
>>> rule = config.rules['truth']
>>> rule.check(False, False, False)
True
diff --git a/mailman/rules/emergency.py b/mailman/rules/emergency.py
index d751d1d4c..deff0c4fd 100644
--- a/mailman/rules/emergency.py
+++ b/mailman/rules/emergency.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/implicit_dest.py b/mailman/rules/implicit_dest.py
index 04989e247..f50f88f1d 100644
--- a/mailman/rules/implicit_dest.py
+++ b/mailman/rules/implicit_dest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/loop.py b/mailman/rules/loop.py
index 8e6e057d2..74d46b8cd 100644
--- a/mailman/rules/loop.py
+++ b/mailman/rules/loop.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/max_recipients.py b/mailman/rules/max_recipients.py
index f5e782ada..1f8ecda2e 100644
--- a/mailman/rules/max_recipients.py
+++ b/mailman/rules/max_recipients.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/max_size.py b/mailman/rules/max_size.py
index 4866e53c1..33d6a8df0 100644
--- a/mailman/rules/max_size.py
+++ b/mailman/rules/max_size.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/moderation.py b/mailman/rules/moderation.py
index 26a218807..99b4b0a30 100644
--- a/mailman/rules/moderation.py
+++ b/mailman/rules/moderation.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/news_moderation.py b/mailman/rules/news_moderation.py
index 6317de3b4..3c55a724f 100644
--- a/mailman/rules/news_moderation.py
+++ b/mailman/rules/news_moderation.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/no_subject.py b/mailman/rules/no_subject.py
index 592c4d3a1..f77688aae 100644
--- a/mailman/rules/no_subject.py
+++ b/mailman/rules/no_subject.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/suspicious.py b/mailman/rules/suspicious.py
index 4b658fce3..92f885558 100644
--- a/mailman/rules/suspicious.py
+++ b/mailman/rules/suspicious.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/rules/truth.py b/mailman/rules/truth.py
index 73d51da5c..aa5599fb0 100644
--- a/mailman/rules/truth.py
+++ b/mailman/rules/truth.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/testing/helpers.py b/mailman/testing/helpers.py
index 47c20ca2f..05ca9253f 100644
--- a/mailman/testing/helpers.py
+++ b/mailman/testing/helpers.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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
@@ -51,21 +51,30 @@ log = logging.getLogger('mailman.debug')
-def make_testable_runner(runner_class):
+def make_testable_runner(runner_class, name=None):
"""Create a queue runner that runs until its queue is empty.
- :param runner_class: An IRunner
+ :param runner_class: The queue runner's class.
+ :type runner_class: class
+ :param name: Optional queue name; if not given, it is calculated from the
+ class name.
+ :type name: string or None
:return: A runner instance.
"""
+ if name is None:
+ assert runner_class.__name__.endswith('Runner'), (
+ 'Unparseable runner class name: %s' % runner_class.__name__)
+ name = runner_class.__name__[:-6].lower()
+
class EmptyingRunner(runner_class):
"""Stop processing when the queue is empty."""
def _do_periodic(self):
"""Stop when the queue is empty."""
- self._stop = (len(self._switchboard.files) == 0)
+ self._stop = (len(self.switchboard.files) == 0)
- return EmptyingRunner()
+ return EmptyingRunner(name)
@@ -75,15 +84,14 @@ class _Bag:
setattr(self, key, value)
-def get_queue_messages(queue):
+def get_queue_messages(queue_name):
"""Return and clear all the messages in the given queue.
- :param queue: An ISwitchboard or a string naming a queue.
+ :param queue_name: A string naming a queue.
:return: A list of 2-tuples where each item contains the message and
message metadata.
"""
- if isinstance(queue, basestring):
- queue = Switchboard(queue)
+ queue = config.switchboards[queue_name]
messages = []
for filebase in queue.files:
msg, msgdata = queue.dequeue(filebase)
@@ -159,12 +167,11 @@ class TestableMaster(Master):
class SMTPServer:
"""An smtp server for testing."""
- host = 'localhost'
- port = 10825
-
def __init__(self):
self._messages = []
self._queue = Queue()
+ self.host = config.mta.smtp_host
+ self.port = int(config.mta.smtp_port)
self._server = Server((self.host, self.port), self._queue)
self._thread = threading.Thread(target=self._server.start)
@@ -173,9 +180,11 @@ class SMTPServer:
log.info('test SMTP server starting')
self._thread.start()
smtpd = smtplib.SMTP()
+ log.info('connecting to %s:%s', self.host, self.port)
smtpd.connect(self.host, self.port)
- smtpd.helo('test.localhost')
+ response = smtpd.helo('test.localhost')
smtpd.quit()
+ log.info('SMTP server is running: %s', response)
def stop(self):
"""Stop the smtp server."""
@@ -227,7 +236,8 @@ def get_lmtp_client():
lmtp = LMTP()
for attempts in range(3):
try:
- response = lmtp.connect(config.LMTP_HOST, config.LMTP_PORT)
+ response = lmtp.connect(
+ config.mta.lmtp_host, int(config.mta.lmtp_port))
print response
return lmtp
except socket.error, error:
diff --git a/mailman/testing/layers.py b/mailman/testing/layers.py
new file mode 100644
index 000000000..ef4535038
--- /dev/null
+++ b/mailman/testing/layers.py
@@ -0,0 +1,208 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Mailman test layers."""
+
+__metaclass__ = type
+__all__ = [
+ 'ConfigLayer',
+ 'SMTPLayer',
+ ]
+
+
+import os
+import sys
+import shutil
+import logging
+import tempfile
+
+from pkg_resources import resource_string
+from string import Template
+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
+
+
+NL = '\n'
+
+
+
+class ConfigLayer:
+ """Layer for pushing and popping test configurations."""
+
+ var_dir = None
+
+ @classmethod
+ def setUp(cls):
+ # Set up the basic configuration stuff.
+ initialize.initialize_1()
+ assert cls.var_dir is None, 'Layer already set up'
+ # Calculate a temporary VAR_DIR directory so that run-time artifacts
+ # of the tests won't tread on the installation's data. This also
+ # makes it easier to clean up after the tests are done, and insures
+ # isolation of test suite runs.
+ cls.var_dir = tempfile.mkdtemp()
+ # We need a test configuration both for the foreground process and any
+ # child processes that get spawned. lazr.config would allow us to do
+ # it all in a string that gets pushed, and we'll do that for the
+ # foreground, but because we may be spawning processes (such as queue
+ # runners) we'll need a file that we can specify to the with the -C
+ # option. Craft the full test configuration string here, push it, and
+ # also write it out to a temp file for -C.
+ test_config = dedent("""
+ [mailman]
+ var_dir: %s
+ """ % cls.var_dir)
+ # Read the testing config and push it.
+ test_config += resource_string('mailman.testing', 'testing.cfg')
+ config.push('test config', test_config)
+ # Initialize everything else.
+ initialize.initialize_2()
+ initialize.initialize_3()
+ # When stderr debugging is enabled, subprocess root loggers should
+ # also be more verbose.
+ if cls.stderr:
+ test_config += dedent("""
+ [logging.root]
+ propagate: yes
+ level: debug
+ """)
+ # Enable log message propagation and reset the log paths so that the
+ # doctests can check the output. XXX Switch to using the log support
+ # in zope.testing.
+ for logger_config in config.logger_configs:
+ sub_name = logger_config.name.split('.')[-1]
+ if sub_name == 'root':
+ continue
+ logger_name = 'mailman.' + sub_name
+ log = logging.getLogger(logger_name)
+ log.propagate = True
+ # Reopen the file to a new path that tests can get at. Instead of
+ # using the configuration file path though, use a path that's
+ # specific to the logger so that tests can find expected output
+ # more easily.
+ path = os.path.join(config.LOG_DIR, sub_name)
+ get_handler(sub_name).reopen(path)
+ log.setLevel(logging.DEBUG)
+ # If stderr debugging is enabled, make sure subprocesses are also
+ # more verbose.
+ if cls.stderr:
+ test_config += Template(dedent("""
+ [logging.$name]
+ propagate: yes
+ level: debug
+ """)).substitute(name=sub_name, path=path)
+ # zope.testing sets up logging before we get to our own initialization
+ # function. This messes with the root logger, so explicitly set it to
+ # go to stderr.
+ if cls.stderr:
+ console = logging.StreamHandler(sys.stderr)
+ formatter = logging.Formatter(config.logging.root.format,
+ config.logging.root.datefmt)
+ console.setFormatter(formatter)
+ logging.getLogger().addHandler(console)
+ # Write the configuration file for subprocesses and set up the config
+ # object to pass that properly on the -C option.
+ config_file = os.path.join(cls.var_dir, 'test.cfg')
+ with open(config_file, 'w') as fp:
+ fp.write(test_config)
+ print >> fp
+ config.filename = config_file
+
+ @classmethod
+ def tearDown(cls):
+ assert cls.var_dir is not None, 'Layer not set up'
+ config.pop('test config')
+ shutil.rmtree(cls.var_dir)
+ cls.var_dir = None
+
+ @classmethod
+ 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)
+
+ @classmethod
+ def testTearDown(cls):
+ # Reset the database between tests.
+ config.db._reset()
+ # Remove all residual queue files.
+ for dirpath, dirnames, filenames in os.walk(config.QUEUE_DIR):
+ for filename in filenames:
+ os.remove(os.path.join(dirpath, filename))
+ # Clear out messages in the message store.
+ for message in config.db.message_store.messages:
+ 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
+ for style in new_styles:
+ style_manager.unregister(style)
+ cls.styles = None
+
+ # Flag to indicate that loggers should propagate to the console.
+ stderr = False
+
+ @classmethod
+ def handle_stderr(cls, *ignore):
+ cls.stderr = True
+
+ @classmethod
+ def hack_options_parser(cls):
+ """Hack our way into the zc.testing framework.
+
+ Add our custom command line option parsing into zc.testing's. We do
+ the imports here so that if zc.testing isn't invoked, this stuff never
+ gets in the way. This is pretty fragile, depend on changes in the
+ zc.testing package. There should be a better way!
+ """
+ from zope.testing.testrunner.options import parser
+ parser.add_option('-e', '--stderr',
+ action='callback', callback=cls.handle_stderr,
+ help=_('Propagate log errors to stderr.'))
+
+
+
+class SMTPLayer(ConfigLayer):
+ """Layer for starting, stopping, and accessing a test SMTP server."""
+
+ smtpd = None
+
+ @classmethod
+ def setUp(cls):
+ assert cls.smtpd is None, 'Layer already set up'
+ cls.smtpd = SMTPServer()
+ cls.smtpd.start()
+
+ @classmethod
+ def tearDown(cls):
+ assert cls.smtpd is not None, 'Layer not set up'
+ cls.smtpd.clear()
+ cls.smtpd.stop()
+
+ @classmethod
+ def testSetUp(cls):
+ pass
+
+ @classmethod
+ def testTearDown(cls):
+ pass
diff --git a/mailman/testing/smtplistener.py b/mailman/testing/smtplistener.py
index a7e289ea1..cb9d9b323 100644
--- a/mailman/testing/smtplistener.py
+++ b/mailman/testing/smtplistener.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/testing/testing.cfg b/mailman/testing/testing.cfg
new file mode 100644
index 000000000..ff9bb89da
--- /dev/null
+++ b/mailman/testing/testing.cfg
@@ -0,0 +1,80 @@
+# Copyright (C) 2008-2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+# A testing configuration.
+
+[mta]
+smtp_port: 9025
+
+[qrunner.archive]
+max_restarts: 1
+
+[qrunner.bounces]
+max_restarts: 1
+
+[qrunner.command]
+max_restarts: 1
+
+[qrunner.in]
+max_restarts: 1
+
+[qrunner.lmtp]
+max_restarts: 1
+
+[qrunner.maildir]
+max_restarts: 1
+
+[qrunner.news]
+max_restarts: 1
+
+[qrunner.out]
+max_restarts: 1
+
+[qrunner.pipeline]
+max_restarts: 1
+
+[qrunner.retry]
+max_restarts: 1
+
+[qrunner.shunt]
+max_restarts: 1
+
+[qrunner.virgin]
+max_restarts: 1
+
+[archiver.mail_archive]
+base_url: http://go.mail-archive.dev/
+recipient: archive@mail-archive.dev
+
+[archiver.pipermail]
+base_url: http://www.example.com/pipermail/$listname
+
+[archiver.mhonarc]
+command: /bin/echo "/usr/bin/mhonarc -add -dbfile $PRIVATE_ARCHIVE_FILE_DIR/${listname}.mbox/mhonarc.db -outdir $VAR_DIR/mhonarc/${listname} -stderr $LOG_DIR/mhonarc -stdout $LOG_DIR/mhonarc -spammode -umask 022"
+
+[domain.example_dot_com]
+email_host: example.com
+base_url: http://www.example.com
+contact_address: postmaster@example.com
+
+[language.ja]
+description: Japanese
+charset: euc-jp
+
+[language.fr]
+description: French
+charset: iso-8859-1
diff --git a/mailman/testing/testing.cfg.in b/mailman/testing/testing.cfg.in
deleted file mode 100644
index e544242d0..000000000
--- a/mailman/testing/testing.cfg.in
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- python -*-
-
-# Configuration file template for the unit test suite. We need this because
-# both the process running the tests and all sub-processes (e.g. qrunners)
-# must share the same configuration file.
-
-MAX_RESTARTS = 1
-MTA = None
-USE_LMTP = Yes
-
-# Make sure these goes to fake domains.
-MAIL_ARCHIVE_BASEURL = 'http://go.mail-archive.dev/'
-MAIL_ARCHIVE_RECIPIENT = 'archive@mail-archive.dev'
-
-add_domain('example.com', 'http://www.example.com')
-
-# bin/testall will add additional runtime configuration variables here.
diff --git a/mailman/tests/test_bounces.py b/mailman/tests/test_bounces.py
index 473691dfd..564c285c8 100644
--- a/mailman/tests/test_bounces.py
+++ b/mailman/tests/test_bounces.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/tests/test_documentation.py b/mailman/tests/test_documentation.py
index cf53be245..b43b4378e 100644
--- a/mailman/tests/test_documentation.py
+++ b/mailman/tests/test_documentation.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -15,7 +15,17 @@
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
-"""Harness for testing Mailman's documentation."""
+"""Harness for testing Mailman's documentation.
+
+Note that doctest extraction does not currently work for zip file
+distributions. doctest discovery currently requires file system traversal.
+"""
+
+__metaclass__ = type
+__all__ = [
+ 'test_suite',
+ ]
+
import os
import random
@@ -27,9 +37,8 @@ from email import message_from_string
import mailman
from mailman.Message import Message
-from mailman.configuration import config
-from mailman.core.styles import style_manager
-from mailman.testing.helpers import SMTPServer
+from mailman.config import config
+from mailman.testing.layers import SMTPLayer
DOT = '.'
@@ -37,6 +46,23 @@ COMMASPACE = ', '
+class chdir:
+ """A context manager for temporary directory changing."""
+ def __init__(self, directory):
+ self._curdir = None
+ self._directory = directory
+
+ def __enter__(self):
+ self._curdir = os.getcwd()
+ os.chdir(self._directory)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ os.chdir(self._curdir)
+ # Don't suppress exceptions.
+ return False
+
+
+
def specialized_message_from_string(text):
"""Parse text into a message object.
@@ -63,47 +89,15 @@ def stop():
def setup(testobj):
"""Test setup."""
- smtpd = SMTPServer()
- smtpd.start()
# In general, I don't like adding convenience functions, since I think
# doctests should do the imports themselves. It makes for better
# documentation that way. However, a few are really useful, or help to
# hide some icky test implementation details.
- testobj.globs['message_from_string'] = specialized_message_from_string
testobj.globs['commit'] = config.db.commit
- testobj.globs['smtpd'] = smtpd
+ testobj.globs['config'] = config
+ testobj.globs['message_from_string'] = specialized_message_from_string
+ testobj.globs['smtpd'] = SMTPLayer.smtpd
testobj.globs['stop'] = stop
- # Stash the current state of the global domains away for restoration in
- # the teardown.
- testobj._domains = config.domains.copy()
-
-
-
-def cleaning_teardown(testobj):
- """Clear all persistent data at the end of a doctest."""
- # Clear the database of all rows.
- config.db._reset()
- # Reset the global domains.
- config.domains = testobj._domains
- # Remove all but the default style.
- for style in style_manager.styles:
- if style.name <> 'default':
- style_manager.unregister(style)
- # Remove all queue files.
- for dirpath, dirnames, filenames in os.walk(config.QUEUE_DIR):
- for filename in filenames:
- os.remove(os.path.join(dirpath, filename))
- # Clear out messages in the message store.
- for message in config.db.message_store.messages:
- config.db.message_store.delete_message(message['message-id'])
- config.db.commit()
- # Reset all archivers by disabling them.
- for archiver in config.archivers.values():
- archiver.is_enabled = False
- # Shutdown the smtp server.
- smtpd = testobj.globs['smtpd']
- smtpd.clear()
- smtpd.stop()
@@ -120,27 +114,29 @@ def test_suite():
flags = (doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE |
doctest.REPORT_NDIFF)
- if config.tests.verbosity <= 2:
- flags |= doctest.REPORT_ONLY_FIRST_FAILURE
+## if config.tests.verbosity <= 2:
+## flags |= doctest.REPORT_ONLY_FIRST_FAILURE
# Add all the doctests in all subpackages.
doctest_files = {}
- for docsdir in packages:
- for filename in os.listdir(os.path.join('mailman', docsdir)):
- if os.path.splitext(filename)[1] == '.txt':
- doctest_files[filename] = os.path.join(docsdir, filename)
+ with chdir(topdir):
+ for docsdir in packages:
+ for filename in os.listdir(docsdir):
+ if os.path.splitext(filename)[1] == '.txt':
+ doctest_files[filename] = os.path.join(docsdir, filename)
# Sort or randomize the tests.
- if config.tests.randomize:
- files = doctest_files.keys()
- random.shuffle(files)
- else:
- files = sorted(doctest_files)
+## if config.tests.randomize:
+## files = doctest_files.keys()
+## random.shuffle(files)
+## else:
+## files = sorted(doctest_files)
+ files = sorted(doctest_files)
for filename in files:
path = doctest_files[filename]
test = doctest.DocFileSuite(
path,
package='mailman',
optionflags=flags,
- setUp=setup,
- tearDown=cleaning_teardown)
+ setUp=setup)
+ test.layer = SMTPLayer
suite.addTest(test)
return suite
diff --git a/mailman/tests/test_membership.py b/mailman/tests/test_membership.py
index 792681472..b50b2390e 100644
--- a/mailman/tests/test_membership.py
+++ b/mailman/tests/test_membership.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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_passwords.py b/mailman/tests/test_passwords.py
index 7c9b9671e..b84307c19 100644
--- a/mailman/tests/test_passwords.py
+++ b/mailman/tests/test_passwords.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/tests/test_security_mgr.py b/mailman/tests/test_security_mgr.py
index 835530496..76f242104 100644
--- a/mailman/tests/test_security_mgr.py
+++ b/mailman/tests/test_security_mgr.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -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/mailman/version.py b/mailman/version.py
index a42c5e0db..26fd21ebc 100644
--- a/mailman/version.py
+++ b/mailman/version.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -16,7 +16,7 @@
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
# Mailman version
-VERSION = "3.0.0a1+"
+VERSION = "3.0.0a2"
CODENAME = 'Grand Designs'
# And as a hex number in the manner of PY_VERSION_HEX
diff --git a/mailman/web/Cgi/Auth.py b/mailman/web/Cgi/Auth.py
index 996aa21c5..825d972f4 100644
--- a/mailman/web/Cgi/Auth.py
+++ b/mailman/web/Cgi/Auth.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/admin.py b/mailman/web/Cgi/admin.py
index ca90805a7..e5c6ee14b 100644
--- a/mailman/web/Cgi/admin.py
+++ b/mailman/web/Cgi/admin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/admindb.py b/mailman/web/Cgi/admindb.py
index 3934c7d42..5d756fc78 100644
--- a/mailman/web/Cgi/admindb.py
+++ b/mailman/web/Cgi/admindb.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/confirm.py b/mailman/web/Cgi/confirm.py
index b9c87f788..188e43068 100644
--- a/mailman/web/Cgi/confirm.py
+++ b/mailman/web/Cgi/confirm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/create.py b/mailman/web/Cgi/create.py
index 3caf9fcc0..4bb650957 100644
--- a/mailman/web/Cgi/create.py
+++ b/mailman/web/Cgi/create.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/edithtml.py b/mailman/web/Cgi/edithtml.py
index e06fb7956..dfc871ec1 100644
--- a/mailman/web/Cgi/edithtml.py
+++ b/mailman/web/Cgi/edithtml.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/listinfo.py b/mailman/web/Cgi/listinfo.py
index 656801a90..149be715f 100644
--- a/mailman/web/Cgi/listinfo.py
+++ b/mailman/web/Cgi/listinfo.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/options.py b/mailman/web/Cgi/options.py
index 3b9331fd1..c529a3ea4 100644
--- a/mailman/web/Cgi/options.py
+++ b/mailman/web/Cgi/options.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/private.py b/mailman/web/Cgi/private.py
index 3199fb842..87cad7966 100644
--- a/mailman/web/Cgi/private.py
+++ b/mailman/web/Cgi/private.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/rmlist.py b/mailman/web/Cgi/rmlist.py
index 21d54a4a4..4b62f09fb 100644
--- a/mailman/web/Cgi/rmlist.py
+++ b/mailman/web/Cgi/rmlist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/roster.py b/mailman/web/Cgi/roster.py
index 697786af1..2351d6915 100644
--- a/mailman/web/Cgi/roster.py
+++ b/mailman/web/Cgi/roster.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/subscribe.py b/mailman/web/Cgi/subscribe.py
index 78fae7230..0eefd0111 100644
--- a/mailman/web/Cgi/subscribe.py
+++ b/mailman/web/Cgi/subscribe.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Cgi/wsgi_app.py b/mailman/web/Cgi/wsgi_app.py
index 08a92fdf9..b22dbf452 100644
--- a/mailman/web/Cgi/wsgi_app.py
+++ b/mailman/web/Cgi/wsgi_app.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Archive.py b/mailman/web/Gui/Archive.py
index 5929f097b..4090e74e9 100644
--- a/mailman/web/Gui/Archive.py
+++ b/mailman/web/Gui/Archive.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Autoresponse.py b/mailman/web/Gui/Autoresponse.py
index 04cefa0d9..72ef42cad 100644
--- a/mailman/web/Gui/Autoresponse.py
+++ b/mailman/web/Gui/Autoresponse.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Bounce.py b/mailman/web/Gui/Bounce.py
index 0ea128205..a2f6f887a 100644
--- a/mailman/web/Gui/Bounce.py
+++ b/mailman/web/Gui/Bounce.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/ContentFilter.py b/mailman/web/Gui/ContentFilter.py
index d7f26321b..09817f4aa 100644
--- a/mailman/web/Gui/ContentFilter.py
+++ b/mailman/web/Gui/ContentFilter.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Digest.py b/mailman/web/Gui/Digest.py
index 278fa808d..821d0684f 100644
--- a/mailman/web/Gui/Digest.py
+++ b/mailman/web/Gui/Digest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/GUIBase.py b/mailman/web/Gui/GUIBase.py
index c521d940e..b2846eb7b 100644
--- a/mailman/web/Gui/GUIBase.py
+++ b/mailman/web/Gui/GUIBase.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/General.py b/mailman/web/Gui/General.py
index 1d0424de9..27ef354be 100644
--- a/mailman/web/Gui/General.py
+++ b/mailman/web/Gui/General.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Language.py b/mailman/web/Gui/Language.py
index 71065d93d..05824be5e 100644
--- a/mailman/web/Gui/Language.py
+++ b/mailman/web/Gui/Language.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Membership.py b/mailman/web/Gui/Membership.py
index 6dd751807..bbfdb438b 100644
--- a/mailman/web/Gui/Membership.py
+++ b/mailman/web/Gui/Membership.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/NonDigest.py b/mailman/web/Gui/NonDigest.py
index 6ed0e4612..92fb768ad 100644
--- a/mailman/web/Gui/NonDigest.py
+++ b/mailman/web/Gui/NonDigest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Passwords.py b/mailman/web/Gui/Passwords.py
index 234859bc1..b2fea0fb5 100644
--- a/mailman/web/Gui/Passwords.py
+++ b/mailman/web/Gui/Passwords.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Privacy.py b/mailman/web/Gui/Privacy.py
index ccc8a2e29..8d60f9203 100644
--- a/mailman/web/Gui/Privacy.py
+++ b/mailman/web/Gui/Privacy.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Topics.py b/mailman/web/Gui/Topics.py
index 501c21329..00df988be 100644
--- a/mailman/web/Gui/Topics.py
+++ b/mailman/web/Gui/Topics.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/Usenet.py b/mailman/web/Gui/Usenet.py
index 713114e1b..9c1b50809 100644
--- a/mailman/web/Gui/Usenet.py
+++ b/mailman/web/Gui/Usenet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/Gui/__init__.py b/mailman/web/Gui/__init__.py
index f88274a6e..2e12526c0 100644
--- a/mailman/web/Gui/__init__.py
+++ b/mailman/web/Gui/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/HTMLFormatter.py b/mailman/web/HTMLFormatter.py
index 1802a36fc..594f4adea 100644
--- a/mailman/web/HTMLFormatter.py
+++ b/mailman/web/HTMLFormatter.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/mailman/web/htmlformat.py b/mailman/web/htmlformat.py
index 3a95999e8..608d0e647 100644
--- a/mailman/web/htmlformat.py
+++ b/mailman/web/htmlformat.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
diff --git a/setup.py b/setup.py
index 5a3a6f423..1e3613611 100644
--- a/setup.py
+++ b/setup.py
@@ -57,7 +57,7 @@ for dirpath, dirnames, filenames in os.walk(start_dir):
# XXX The 'bin/' prefix here should be configurable.
-template = Template('bin/$script = mailman.bin.$script:main')
+template = Template('$script = mailman.bin.$script:main')
scripts = set(
template.substitute(script=script)
for script in mailman.bin.__all__
@@ -90,7 +90,6 @@ case second `m'. Any other spelling is incorrect.""",
include_package_data = True,
entry_points = {
'console_scripts': list(scripts),
- # Entry point for plugging in different database backends.
'mailman.archiver' : [
'mail-archive = mailman.archiving.mailarchive:MailArchive',
'mhonarc = mailman.archiving.mhonarc:MHonArc',
@@ -107,6 +106,7 @@ case second `m'. Any other spelling is incorrect.""",
'mailman.handlers' : 'default = mailman.pipeline:initialize',
},
install_requires = [
+ 'lazr.config',
'locknix',
'munepy',
'storm',