summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Handlers/Cleanse.py4
-rw-r--r--Mailman/Handlers/CookHeaders.py18
-rw-r--r--Mailman/Handlers/Scrubber.py11
-rw-r--r--Mailman/app/archiving.py65
-rw-r--r--Mailman/docs/cook-headers.txt13
-rw-r--r--Mailman/docs/scrubber.txt16
-rw-r--r--Mailman/interfaces/archiver.py58
-rw-r--r--setup.py5
8 files changed, 157 insertions, 33 deletions
diff --git a/Mailman/Handlers/Cleanse.py b/Mailman/Handlers/Cleanse.py
index d84f988e3..bf25a4591 100644
--- a/Mailman/Handlers/Cleanse.py
+++ b/Mailman/Handlers/Cleanse.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -54,3 +54,5 @@ def process(mlist, msg, msgdata):
del msg['x-confirm-reading-to']
# Pegasus mail uses this one... sigh
del msg['x-pmrqc']
+ # Don't let this header be spoofed. See RFC 5064.
+ del msg['archived-at']
diff --git a/Mailman/Handlers/CookHeaders.py b/Mailman/Handlers/CookHeaders.py
index cb14853d5..4797de62b 100644
--- a/Mailman/Handlers/CookHeaders.py
+++ b/Mailman/Handlers/CookHeaders.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -26,7 +26,7 @@ from email.Utils import parseaddr, formataddr, getaddresses
from Mailman import Utils
from Mailman import Version
-from Mailman.app.archiving import get_base_archive_url
+from Mailman.app.archiving import get_archiver
from Mailman.configuration import config
from Mailman.i18n import _
from Mailman.interfaces import Personalization, ReplyToMunging
@@ -200,6 +200,7 @@ def process(mlist, msg, msgdata):
'List-Unsubscribe': subfieldfmt % (listinfo, mlist.leave_address),
'List-Subscribe' : subfieldfmt % (listinfo, mlist.join_address),
})
+ archiver = get_archiver()
if msgdata.get('reduced_list_headers'):
headers['X-List-Administrivia'] = 'yes'
else:
@@ -208,10 +209,17 @@ def process(mlist, msg, msgdata):
headers['List-Post'] = '<mailto:%s>' % mlist.posting_address
# Add this header if we're archiving
if mlist.archive:
- archiveurl = get_base_archive_url(mlist)
- if archiveurl.endswith('/'):
- archiveurl = archiveurl[:-1]
+ archiveurl = archiver.get_list_url(mlist)
headers['List-Archive'] = '<%s>' % archiveurl
+ # XXX RFC 2369 also defines a List-Owner header which we are not currently
+ # supporting, but should.
+ #
+ # Draft RFC 5064 defines an Archived-At header which contains the pointer
+ # directly to the message in the archive. If the currently defined
+ # archiver can tell us the URL, go ahead and include this header.
+ archived_at = archiver.get_message_url(mlist, msg)
+ if archived_at is not None:
+ headers['Archived-At'] = archived_at
# First we delete any pre-existing headers because the RFC permits only
# one copy of each, and we want to be sure it's ours.
for h, v in headers.items():
diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py
index 6946de7f4..fb1b6e602 100644
--- a/Mailman/Handlers/Scrubber.py
+++ b/Mailman/Handlers/Scrubber.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2008 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
@@ -35,7 +35,7 @@ from mimetypes import guess_all_extensions
from Mailman import Utils
from Mailman.Errors import DiscardMessage
-from Mailman.app.archiving import get_base_archive_url
+from Mailman.app.archiving import get_archiver
from Mailman.configuration import config
from Mailman.i18n import _
@@ -490,10 +490,9 @@ def save_attachment(mlist, msg, dir, filter_html=True):
fp = open(path, 'w')
fp.write(decodedpayload)
fp.close()
- # Now calculate the url
- baseurl = get_base_archive_url(mlist)
- # Private archives will likely have a trailing slash. Normalize.
- if baseurl[-1] <> '/':
+ # Now calculate the url to the list's archive.
+ baseurl = get_archiver().get_list_url(mlist)
+ if not baseurl.endswith('/'):
baseurl += '/'
# Trailing space will definitely be a problem with format=flowed.
# Bracket the URL instead.
diff --git a/Mailman/app/archiving.py b/Mailman/app/archiving.py
index 6ab3479eb..febd8b4d5 100644
--- a/Mailman/app/archiving.py
+++ b/Mailman/app/archiving.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2007-2008 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
@@ -17,20 +17,61 @@
"""Application level archiving support."""
+__all__ = [
+ 'Pipermail',
+ 'get_archiver',
+ ]
+__metaclass__ = type
+
+
from string import Template
+from zope.interface import implements
+from zope.interface.verify import verifyObject
+from Mailman.app.plugins import get_plugin
from Mailman.configuration import config
+from Mailman.interfaces import IArchiver
-def get_base_archive_url(mlist):
- if mlist.archive_private:
- url = mlist.script_url('private') + '/index.html'
- else:
- web_host = config.domains.get(mlist.host_name, mlist.host_name)
- url = Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
- listname=mlist.fqdn_listname,
- hostname=web_host,
- fqdn_listname=mlist.fqdn_listname,
- )
- return url
+class Pipermail:
+ """The stock Pipermail archiver."""
+
+ implements(IArchiver)
+
+ def get_list_url(self, mlist):
+ """See `IArchiver`."""
+ if mlist.archive_private:
+ url = mlist.script_url('private') + '/index.html'
+ else:
+ web_host = config.domains.get(mlist.host_name, mlist.host_name)
+ url = Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
+ listname=mlist.fqdn_listname,
+ hostname=web_host,
+ fqdn_listname=mlist.fqdn_listname,
+ )
+ return url
+
+ def get_message_url(self, mlist, message):
+ """See `IArchiver`."""
+ # Not currently implemented.
+ return None
+
+ def archive_message(self, mlist, message):
+ """See `IArchiver`."""
+ return None
+
+
+
+_archiver = None
+
+def get_archiver():
+ """Return the currently registered global archiver.
+
+ Uses the plugin architecture to find the IArchiver instance.
+ """
+ global _archiver
+ if _archiver is None:
+ _archiver = get_plugin('mailman.archiver')()
+ verifyObject(IArchiver, _archiver)
+ return _archiver
diff --git a/Mailman/docs/cook-headers.txt b/Mailman/docs/cook-headers.txt
index 1b7705d1c..a6954e5c6 100644
--- a/Mailman/docs/cook-headers.txt
+++ b/Mailman/docs/cook-headers.txt
@@ -285,6 +285,19 @@ List-Archive header either.
---end---
+Archived-At
+-----------
+
+RFC 5064 (draft) defines a new Archived-At header which contains the url to
+the individual message in the archives. The stock Pipermail archiver doesn't
+support this because the url can't be calculated until after the message is
+archived. Because this is done by the archive runner, this information isn't
+available to us now.
+
+ >>> print msg['archived-at']
+ None
+
+
Personalization
---------------
diff --git a/Mailman/docs/scrubber.txt b/Mailman/docs/scrubber.txt
index e4259361d..564405378 100644
--- a/Mailman/docs/scrubber.txt
+++ b/Mailman/docs/scrubber.txt
@@ -59,9 +59,9 @@ this is an unfortunate double negative).
...
... R0lGODdhAQABAIAAAAAAAAAAACwAAAAAAQABAAACAQUAOw==
... """)
- >>> save_attachment(mlist, msg, '')
- u'<http://www.example.com/pipermail/_xtest@example.com//xtest.gif>'
- >>> data = read_attachment('xtest.gif')
+ >>> save_attachment(mlist, msg, 'dir')
+ u'<http://www.example.com/pipermail/_xtest@example.com/dir/xtest.gif>'
+ >>> data = read_attachment('dir/xtest.gif')
>>> data[:6]
'GIF87a'
>>> len(data)
@@ -88,13 +88,13 @@ the Defaults.py.in file.
...
... R0lGODdhAQABAIAAAAAAAAAAACwAAAAAAQABAAACAQUAOw==
... """)
- >>> save_attachment(mlist, msg, '')
- u'<http://www.example.com/pipermail/_xtest@example.com/.../attachment.gif>'
- >>> data = read_attachment('xtest.gif')
+ >>> save_attachment(mlist, msg, 'dir')
+ u'<http://www.example.com/pipermail/_xtest@example.com/dir/attachment.gif>'
+ >>> data = read_attachment('dir/xtest.gif')
Traceback (most recent call last):
IOError: [Errno ...] No such file or directory:
- u'.../archives/private/_xtest@example.com/xtest.gif'
- >>> data = read_attachment('attachment.gif')
+ u'.../archives/private/_xtest@example.com/dir/xtest.gif'
+ >>> data = read_attachment('dir/attachment.gif')
>>> data[:6]
'GIF87a'
>>> len(data)
diff --git a/Mailman/interfaces/archiver.py b/Mailman/interfaces/archiver.py
new file mode 100644
index 000000000..3b96c5c53
--- /dev/null
+++ b/Mailman/interfaces/archiver.py
@@ -0,0 +1,58 @@
+# Copyright (C) 2008 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
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interface for archiving schemes."""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IArchiver(Interface):
+ """An interface to the archiver."""
+
+ def get_list_url(mlist):
+ """Return the url to the top of the list's archive.
+
+ :param mlist: The IMailingList object.
+ :returns: The url string.
+ """
+
+ def get_message_url(mlist, message):
+ """Return the url to the message in the archive.
+
+ This url points directly to the message in the archive. This method
+ only calculates the url, it does not actually archive the message.
+
+ :param mlist: The IMailingList object.
+ :param message: The message object.
+ :returns: The url string or None if the message's archive url cannot
+ be calculated.
+ """
+
+ def archive_message(mlist, message):
+ """Send the message to the archiver.
+
+ This uses `get_message_url()` to calculate and return the url to the
+ message in the archives.
+
+ :param mlist: The IMailingList object.
+ :param message: The message object.
+ :returns: The url string or None if the message's archive url cannot
+ be calculated.
+ """
+
+ # XXX How to handle attachments?
diff --git a/setup.py b/setup.py
index e35202b06..437f6ba2c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 Barry A. Warsaw
+# Copyright (C) 2007-2008 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 as published by the Free
@@ -83,7 +83,10 @@ Any other spelling is incorrect.""",
entry_points = {
'console_scripts': list(scripts),
'setuptools.file_finders': 'bzr = setuptools_bzr:find_files_for_bzr',
+ # Entry point for plugging in different database backends.
+ 'mailman.archiver' : 'stock = Mailman.app.archiving:Pipermail',
'mailman.database' : 'stock = Mailman.database:StockDatabase',
+ 'mailman.mta' : 'stock = Mailman.MTA:Manual',
'mailman.styles' : 'default = Mailman.app.styles:DefaultStyle',
'mailman.mta' : 'stock = Mailman.MTA:Manual',
'mailman.rules' : 'default = Mailman.rules:initialize',