diff options
Diffstat (limited to 'mailman/app/archiving.py')
| -rw-r--r-- | mailman/app/archiving.py | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/mailman/app/archiving.py b/mailman/app/archiving.py index 5a752063d..15e987daf 100644 --- a/mailman/app/archiving.py +++ b/mailman/app/archiving.py @@ -20,25 +20,34 @@ __metaclass__ = type __all__ = [ 'Pipermail', + 'Prototype', ] import os +import hashlib +from base64 import b32encode +from cStringIO import StringIO +from email.utils import make_msgid from string import Template +from urlparse import urljoin from zope.interface import implements +from zope.interface.interface import adapter_hooks from mailman.configuration import config -from mailman.interfaces import IArchiver +from mailman.interfaces.archiver import IArchiver, IPipermailMailingList +from mailman.interfaces.mailinglist import IMailingList from mailman.Archiver.HyperArch import HyperArchive -from cStringIO import StringIO class PipermailMailingListAdapter: """An adapter for MailingList objects to work with Pipermail.""" + implements(IPipermailMailingList) + def __init__(self, mlist): self._mlist = mlist @@ -46,7 +55,7 @@ class PipermailMailingListAdapter: return getattr(self._mlist, name) def archive_dir(self): - """The directory for storing Pipermail artifacts.""" + """See `IPipermailMailingList`.""" if self._mlist.archive_private: basedir = config.PRIVATE_ARCHIVE_FILE_DIR else: @@ -54,12 +63,24 @@ class PipermailMailingListAdapter: return os.path.join(basedir, self._mlist.fqdn_listname) +def adapt_mailing_list_for_pipermail(iface, obj): + """Adapt IMailingLists to IPipermailMailingList.""" + if IMailingList.providedBy(obj) and iface is IPipermailMailingList: + return PipermailMailingListAdapter(obj) + return None + +adapter_hooks.append(adapt_mailing_list_for_pipermail) + + class Pipermail: """The stock Pipermail archiver.""" implements(IArchiver) + name = 'pipermail' + is_enabled = True + @staticmethod def list_url(mlist): """See `IArchiver`.""" @@ -85,9 +106,49 @@ class Pipermail: """See `IArchiver`.""" text = str(message) fileobj = StringIO(text) - h = HyperArchive(PipermailMailingListAdapter(mlist)) + h = HyperArchive(IPipermailMailingList(mlist)) h.processUnixMailbox(fileobj) h.close() fileobj.close() # There's no good way to know the url for the archived message. return None + + + +class Prototype: + """A prototype of a third party archiver. + + Mailman proposes a draft specification for interoperability between list + servers and archivers: <http://wiki.list.org/display/DEV/Stable+URLs>. + """ + + implements(IArchiver) + + name = 'prototype' + is_enabled = False + + @staticmethod + def list_url(mlist): + """See `IArchiver`.""" + web_host = config.domains.get(mlist.host_name, mlist.host_name) + return 'http://' + web_host + + @staticmethod + def permalink(mlist, msg): + """See `IArchiver`.""" + message_id = msg.get('message-id') + # It is not the archiver's job to ensure the message has a Message-ID. + assert message_id is not None, 'No Message-ID found' + # The angle brackets are not part of the Message-ID. See RFC 2822. + if message_id.startswith('<') and message_id.endswith('>'): + message_id = message_id[1:-1] + digest = hashlib.sha1(message_id).digest() + message_id_hash = b32encode(digest) + del msg['x-message-id-hash'] + msg['X-Message-ID-Hash'] = message_id_hash + return urljoin(Prototype.list_url(mlist), message_id_hash) + + @staticmethod + def archive_message(mlist, message): + """See `IArchiver`.""" + raise NotImplementedError |
