From 35f840fbaba758d837bfd04e3eb5a723327714d0 Mon Sep 17 00:00:00 2001 From: tonio Date: Fri, 5 Mar 2010 11:33:53 +0100 Subject: [PATCH] It is now possible to access emails attachments. --- extensions/webmail/imap_listing.py | 1 + extensions/webmail/main.py | 49 +++++++++++++++------- extensions/webmail/templates/headers.html | 12 ++++++ extensions/webmail/templates/viewmail.html | 7 ++++ extensions/webmail/urls.py | 1 + lib/email_listing.py | 21 ++++++++-- 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/extensions/webmail/imap_listing.py b/extensions/webmail/imap_listing.py index 92c84d1d4..7d5bd9371 100644 --- a/extensions/webmail/imap_listing.py +++ b/extensions/webmail/imap_listing.py @@ -243,3 +243,4 @@ class ImapEmail(Email): self.headers += [{"name" : label, "value" : getattr(IMAPheader, "parse_%s" % f.lower())(msg[f])}] except AttributeError: self.headers += [{"name" : label, "value" : msg[f]}] + diff --git a/extensions/webmail/main.py b/extensions/webmail/main.py index 69bf4d0db..06157f57e 100644 --- a/extensions/webmail/main.py +++ b/extensions/webmail/main.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import time import sys -from django.http import HttpResponse +from django.http import HttpResponse, Http404 from django.template import Template, Context from django.template.loader import render_to_string from django.utils import simplejson @@ -114,19 +114,40 @@ def viewmail(request, folder, mail_id=None): @login_required def getmailcontent(request, folder, mail_id): - msg = fetchmail(request, folder, mail_id, True) - if "class" in msg.keys() and msg["class"] == "unseen": - IMAPconnector(request).msgseen(msg["imapid"]) - email = ImapEmail(msg, mode="html", links="1") - try: - pageid = request.session["page"] - except KeyError: - pageid = "1" - folder, imapid = msg["imapid"].split("/") - return _render(request, "webmail/viewmail.html", { - "headers" : email.render_headers(), "folder" : folder, - "imapid" : imapid, "mailbody" : email.body, "pre" : email.pre - }) + msg = fetchmail(request, folder, mail_id, True) + if "class" in msg.keys() and msg["class"] == "unseen": + IMAPconnector(request).msgseen(msg["imapid"]) + email = ImapEmail(msg, mode="html", links="1") + try: + pageid = request.session["page"] + except KeyError: + pageid = "1" + folder, imapid = msg["imapid"].split("/") + return _render(request, "webmail/viewmail.html", { + "headers" : email.render_headers(folder, mail_id), + "folder" : folder, "imapid" : imapid, "mailbody" : email.body, + "pre" : email.pre + }) + +@login_required +def getattachment(request, folder, mail_id): + msg = fetchmail(request, folder, mail_id, True) + for part in msg.walk(): + fname = part.get_filename() + if fname is None: + continue + decoded = decode_header(fname) + if decoded[0][1] is None: + fname = unicode(decoded[0][0]) + else: + fname = unicode(decoded[0][0], decoded[0][1]) + if fname == request.GET["fname"]: + resp = HttpResponse(part.get_payload(decode=1)) + for hdr in ["Content-Disposition", "Content-Type"]: + resp[hdr] = re.sub("\s", "", part[hdr]) + resp["Content-Length"] = len(resp.content) + return resp + raise Http404 @login_required def move(request): diff --git a/extensions/webmail/templates/headers.html b/extensions/webmail/templates/headers.html index 4c06206cc..213b8a759 100644 --- a/extensions/webmail/templates/headers.html +++ b/extensions/webmail/templates/headers.html @@ -1,5 +1,17 @@ +{% load i18n %} {% for hdr in headers %} {% endfor %} + {% if attachments %} + + + + + {% endif %}
{{ hdr.name }}{{ hdr.value }}
{% trans "Attachments" %} + {% url extensions.webmail.main.getattachment folder mail_id as test %} + {% for attachment in attachments %} + {{ attachment }} + {% endfor %} +
diff --git a/extensions/webmail/templates/viewmail.html b/extensions/webmail/templates/viewmail.html index 5830936cd..640958ad4 100644 --- a/extensions/webmail/templates/viewmail.html +++ b/extensions/webmail/templates/viewmail.html @@ -33,6 +33,13 @@ #emailheaders th { background: #F7F9Fb; } + #emailheaders a, #emailheaders a:visited { + color: blue; + text-decoration: none; + } + #emailheaders a:hover { + text-decoration: underline; + } diff --git a/extensions/webmail/urls.py b/extensions/webmail/urls.py index 7ef16e31b..e088de8ed 100644 --- a/extensions/webmail/urls.py +++ b/extensions/webmail/urls.py @@ -5,6 +5,7 @@ urlpatterns = patterns('mailng.extensions.webmail.main', (r'^compose/$', "compose"), (r'^move/$', "move"), (r'^empty/(?P.+)/', "empty"), + (r'^(?P.+)/(?P[\w\-\+]+)/part/$', 'getattachment'), (r'^(?P.+)/(?P[\w\-\+]+)/content/$', 'getmailcontent'), (r'^(?P.+)/(?P[\w\-\+]+)/reply/$', 'reply'), (r'^(?P.+)/(?P[\w\-\+]+)/$', 'viewmail'), diff --git a/lib/email_listing.py b/lib/email_listing.py index c879d1371..216143ae2 100644 --- a/lib/email_listing.py +++ b/lib/email_listing.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- import time import re +from email.header import decode_header import lxml import lxml.html from lxml import etree from django.template.loader import render_to_string from django.template import Template, Context +from django.utils.translation import ugettext as _ from mailng.lib import _render, decode attached_map = {} @@ -126,9 +128,13 @@ class Email(object): self.attached_map = {} contents = {"html" : "", "plain" : ""} self.headers = [] + self.attachments = [] for part in msg.walk(): if part.get_content_maintype() == 'multipart': continue + if part.has_key("Content-Disposition"): + if re.match("^attachment", part["Content-Disposition"]): + self.attachments += [part] if part.get_content_type() in ("text/html", "text/plain"): contents[part.get_content_subtype()] += part.get_payload(decode=True) if mode != "html" or links == "0": @@ -168,9 +174,18 @@ class Email(object): return map[m.group(1)] return url - def render_headers(self): + def render_headers(self, folder, mail_id): + attachments = [] + for part in self.attachments: + decoded = decode_header(part.get_filename()) + if decoded[0][1] is None: + attachments += [decoded[0][0]] + else: + attachments += [unicode(decoded[0][0], decoded[0][1])] return render_to_string("webmail/headers.html", { - "headers" : self.headers + "headers" : self.headers, + "folder" : folder, "mail_id" : mail_id, + "attachments" : attachments != [] and attachments or None }) def render(self, request): @@ -190,7 +205,7 @@ class Email(object): else: html.rewrite_links(self.map_cid) body = html.find("body") - if not body: + if body is None: body = lxml.html.tostring(html) else: body = lxml.html.tostring(body)