diff options
| author | Barry Warsaw | 2008-01-14 23:24:43 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2008-01-14 23:24:43 -0500 |
| commit | 2efcac1ef273b407668826c587c15a0fd8ec3d3c (patch) | |
| tree | 13d435fb62a24e5c0fb8928721c61be434e11bc7 /Mailman | |
| parent | 0bf7659000d2736839919c1ac2adc99b9bcb1b46 (diff) | |
| parent | 7c5b4d64df6532548742460d405a8a64e35b22c2 (diff) | |
| download | mailman-2efcac1ef273b407668826c587c15a0fd8ec3d3c.tar.gz mailman-2efcac1ef273b407668826c587c15a0fd8ec3d3c.tar.zst mailman-2efcac1ef273b407668826c587c15a0fd8ec3d3c.zip | |
Diffstat (limited to 'Mailman')
| -rw-r--r-- | Mailman/Handlers/Cleanse.py | 4 | ||||
| -rw-r--r-- | Mailman/Handlers/CookHeaders.py | 18 | ||||
| -rw-r--r-- | Mailman/Handlers/Scrubber.py | 11 | ||||
| -rw-r--r-- | Mailman/app/archiving.py | 65 | ||||
| -rw-r--r-- | Mailman/docs/cook-headers.txt | 13 | ||||
| -rw-r--r-- | Mailman/docs/scrubber.txt | 16 | ||||
| -rw-r--r-- | Mailman/interfaces/archiver.py | 58 |
7 files changed, 153 insertions, 32 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? |
