summaryrefslogtreecommitdiff
path: root/mailman/app/archiving.py
diff options
context:
space:
mode:
Diffstat (limited to 'mailman/app/archiving.py')
-rw-r--r--mailman/app/archiving.py69
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