summaryrefslogtreecommitdiffstats
path: root/hyperkitty
diff options
context:
space:
mode:
Diffstat (limited to 'hyperkitty')
-rw-r--r--hyperkitty/lib/compat.py53
-rw-r--r--hyperkitty/static/css/style.css3
-rw-r--r--hyperkitty/urls.py16
-rw-r--r--hyperkitty/views/compat.py112
4 files changed, 179 insertions, 5 deletions
diff --git a/hyperkitty/lib/compat.py b/hyperkitty/lib/compat.py
new file mode 100644
index 0000000..cb0a864
--- /dev/null
+++ b/hyperkitty/lib/compat.py
@@ -0,0 +1,53 @@
+#-*- coding: utf-8 -*-
+# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
+#
+# This file is part of HyperKitty.
+#
+# HyperKitty 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.
+#
+# HyperKitty 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
+# HyperKitty. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import re
+import datetime
+
+PORT_IN_URL = re.compile(':\d+$')
+
+
+def get_list_by_name(list_name, store, request):
+ arch_list_names = store.get_list_names()
+ matching = []
+ for name in arch_list_names:
+ if name[:name.index("@")] == list_name:
+ matching.append(name)
+
+ if len(matching) == 0: # no candidate found
+ return None
+ if len(matching) == 1: # only one candidate
+ return store.get_list(matching[0])
+
+ # more than one result, try using the hostname
+ domain = request.get_host()
+ domain = PORT_IN_URL.sub('', domain)
+ list_fqdn = "%s@%s" % (list_name, domain)
+ if list_fqdn in matching:
+ return store.get_list(list_fqdn)
+
+ # return the first match, arbitrarily
+ return store.get_list(matching[0])
+
+def month_name_to_num(month_name):
+ """map month names to months numbers"""
+ today = datetime.date.today()
+ months = dict( (today.replace(month=num).strftime('%B'), num)
+ for num in range(1, 12) )
+ return months[month_name]
diff --git a/hyperkitty/static/css/style.css b/hyperkitty/static/css/style.css
index ae32605..9c8e73c 100644
--- a/hyperkitty/static/css/style.css
+++ b/hyperkitty/static/css/style.css
@@ -408,7 +408,8 @@ li.attachments a.attachments {
li.attachments ul {
position: absolute;
background-color: #F6F6F6;
- margin-left: 0;
+ padding-left: 20px;
+ margin-left: 1em;
}
li.attachments ul li {
list-style-position: inside;
diff --git a/hyperkitty/urls.py b/hyperkitty/urls.py
index bc52699..ab2719e 100644
--- a/hyperkitty/urls.py
+++ b/hyperkitty/urls.py
@@ -57,7 +57,6 @@ urlpatterns = patterns('hyperkitty.views',
### MESSAGE LEVEL VIEWS ###
- # Vote a message
url(r'^message/(?P<mlist_fqdn>.*@.*)/(?P<hashid>\w+)/$',
'message.index', name='message_index'),
@@ -68,7 +67,7 @@ urlpatterns = patterns('hyperkitty.views',
'message.vote', name='message_vote'),
### MESSAGE LEVEL VIEW ENDS ###
-
+
### THREAD LEVEL VIEWS ###
# Thread view page
@@ -80,7 +79,7 @@ urlpatterns = patterns('hyperkitty.views',
'thread.add_tag', name='add_tag'),
### THREAD LEVEL VIEW ENDS ###
-
+
# REST API
url(r'^api/$', 'api.api'),
url(r'^api/email\/(?P<mlist_fqdn>.*@.*)\/(?P<hashid>.*)/',
@@ -93,7 +92,7 @@ urlpatterns = patterns('hyperkitty.views',
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
- # Admin
+ # Admin
url(r'^admin/', include(admin.site.urls)),
# Robots.txt
@@ -103,6 +102,15 @@ urlpatterns = patterns('hyperkitty.views',
# Social Auth
url(r'', include('social_auth.urls')),
+ # Mailman 2.X compatibility
+ url(r'^listinfo/?$', 'compat.summary'),
+ url(r'^listinfo/(?P<list_name>[^/]+)/?$', 'compat.summary'),
+ url(r'^pipermail/(?P<list_name>[^/]+)/?$', 'compat.summary'),
+ url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/?$', 'compat.arch_month'),
+ url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/(?P<summary_type>[a-z]+)\.html$', 'compat.arch_month'),
+ url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)\.txt.gz', 'compat.arch_month_mbox'),
+ url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/(?P<msg_num>\d+)\.html$', 'compat.message'),
+
)
#) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += staticfiles_urlpatterns()
diff --git a/hyperkitty/views/compat.py b/hyperkitty/views/compat.py
new file mode 100644
index 0000000..dea2174
--- /dev/null
+++ b/hyperkitty/views/compat.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
+#
+# This file is part of HyperKitty.
+#
+# HyperKitty 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.
+#
+# HyperKitty 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
+# HyperKitty. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from __future__ import with_statement
+
+import os
+import mailbox
+import datetime
+import tempfile
+import gzip
+from cStringIO import StringIO
+
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseRedirect, Http404
+
+from hyperkitty.lib import get_store
+from hyperkitty.lib.compat import get_list_by_name, month_name_to_num
+
+
+def summary(request, list_name=None):
+ if list_name is None:
+ return HttpResponseRedirect(reverse('root'))
+ store = get_store(request)
+ mlist = get_list_by_name(list_name, store, request)
+ if mlist is None:
+ raise Http404("No archived mailing-list by that name.")
+ url = reverse('list_overview', kwargs={'mlist_fqdn': mlist.name})
+ #return HttpResponse(request.build_absolute_uri(url))
+ return HttpResponseRedirect(url)
+
+
+def arch_month(request, list_name, year, month_name, summary_type="thread"):
+ store = get_store(request)
+ mlist = get_list_by_name(list_name, store, request)
+ if mlist is None:
+ raise Http404("No archived mailing-list by that name.")
+ url = reverse('archives_with_month', kwargs={
+ 'mlist_fqdn': mlist.name,
+ 'year': year,
+ 'month': str(month_name_to_num(month_name)).rjust(2, "0"),
+ })
+ #return HttpResponse(request.build_absolute_uri(url))
+ return HttpResponseRedirect(url)
+
+
+def arch_month_mbox(request, list_name, year, month_name):
+ store = get_store(request)
+ mlist = get_list_by_name(list_name, store, request)
+ if mlist is None:
+ raise Http404("No archived mailing-list by that name.")
+ month = month_name_to_num(month_name)
+ year = int(year)
+ begin_date = datetime.datetime(year, month, 1)
+ if month != 12:
+ end_month = month + 1
+ else:
+ end_month = 1
+ end_date = datetime.datetime(year, end_month, 1)
+ messages = store.get_messages(mlist.name, start=begin_date, end=end_date)
+ messages.reverse() # they are sorted recent first by default
+ mboxfile, mboxfilepath = tempfile.mkstemp(prefix="hyperkitty-",
+ suffix=".mbox.gz")
+ os.close(mboxfile)
+ mbox = mailbox.mbox(mboxfilepath)
+ for message in messages:
+ mbox.add(message.full)
+ mbox.close()
+ content = StringIO()
+ zipped_content = gzip.GzipFile(fileobj=content)
+ with gzip.GzipFile(fileobj=content, mode="wb") as zipped_content:
+ with open(mboxfilepath, "rb") as mboxfile:
+ zipped_content.write(mboxfile.read())
+ response = HttpResponse(content.getvalue())
+ content.close()
+ response['Content-Type'] = "application/mbox+gz"
+ response['Content-Disposition'] = 'attachment; filename=%d-%s.txt.gz' \
+ % (year, month_name)
+ response['Content-Length'] = len(response.content)
+ os.remove(mboxfilepath)
+ return response
+
+
+def message(request, list_name, year, month_name, msg_num):
+ store = get_store(request)
+ mlist = get_list_by_name(list_name, store, request)
+ if mlist is None:
+ raise Http404("No archived mailing-list by that name.")
+ message = store.get_message_by_number(mlist.name, int(msg_num))
+ if message is None:
+ raise Http404("No such message in this mailing-list.")
+ url = reverse('message_index', kwargs={
+ 'mlist_fqdn': mlist.name,
+ 'hashid': message.message_id_hash,
+ })
+ #return HttpResponse(request.build_absolute_uri(url))
+ return HttpResponseRedirect(url)