mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
More work about webmail. It's almost possible to view emails content!
This commit is contained in:
@@ -16,6 +16,7 @@ def dologin(request):
|
||||
if user:
|
||||
if user.is_active:
|
||||
login(request, user)
|
||||
|
||||
request.session["password"] = request.POST["password"]
|
||||
next = request.POST["next"]
|
||||
if next == "None":
|
||||
|
||||
@@ -7,10 +7,7 @@ import time
|
||||
import email
|
||||
import re
|
||||
import os
|
||||
import lxml.html
|
||||
from lxml.html.clean import Cleaner
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.template import Template
|
||||
from django.utils import simplejson
|
||||
from django.conf.urls.defaults import *
|
||||
from django.utils.translation import ugettext as _
|
||||
@@ -24,16 +21,6 @@ from mailng.admin.models import Mailbox
|
||||
from lib import AMrelease
|
||||
from sql_listing import *
|
||||
|
||||
attached_map = {}
|
||||
|
||||
def map_cid(url):
|
||||
map = globals()["attached_map"]
|
||||
m = re.match(".*cid:([^\"]+)", url)
|
||||
if m:
|
||||
if map.has_key(m.group(1)):
|
||||
return map[m.group(1)]
|
||||
return url
|
||||
|
||||
def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
parameters.register("amavis_quarantine", "MAX_MESSAGES_AGE", "int", 14,
|
||||
@@ -69,25 +56,10 @@ def index(request, message=None):
|
||||
lst = SQLlisting(filter)
|
||||
return lst.render(request, pageid=int(pageid), start=start)
|
||||
|
||||
@login_required
|
||||
def viewmail_plain(request, content):
|
||||
body = decode(content)
|
||||
return (True, body)
|
||||
|
||||
@login_required
|
||||
def viewmail_html(request, content):
|
||||
links = request.GET.has_key("links") and request.GET["links"] or "0"
|
||||
html = lxml.html.fromstring(content)
|
||||
if links == "0":
|
||||
html.rewrite_links(lambda x: None)
|
||||
else:
|
||||
html.rewrite_links(map_cid)
|
||||
body = lxml.html.tostring(html)
|
||||
body = Template(decode(body)).render({})
|
||||
return (False, body)
|
||||
|
||||
@login_required
|
||||
def getmailcontent(request, mail_id):
|
||||
from mailng.lib.email_listing import Email
|
||||
|
||||
conn = db.getconnection("amavis_quarantine")
|
||||
status, cursor = db.execute(conn, """
|
||||
SELECT mail_text
|
||||
@@ -100,41 +72,8 @@ WHERE quarantine.mail_id='%s'
|
||||
msg = email.message_from_string(content)
|
||||
links = request.GET.has_key("links") and request.GET["links"] or "0"
|
||||
mode = request.GET.has_key("mode") and request.GET["mode"] or "plain"
|
||||
contents = {"html" : "", "plain" : ""}
|
||||
for part in msg.walk():
|
||||
#print part.get_content_type()
|
||||
if part.get_content_maintype() == 'multipart':
|
||||
continue
|
||||
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":
|
||||
continue
|
||||
|
||||
if part.get_content_maintype() == "image":
|
||||
if part.has_key("Content-Location"):
|
||||
fname = part["Content-Location"]
|
||||
if re.match("^http:", fname):
|
||||
path = fname
|
||||
else:
|
||||
path = "/%s" % os.path.join("static/tmp", fname)
|
||||
fp = open(path, "wb")
|
||||
fp.write(part.get_payload(decode=True))
|
||||
fp.close()
|
||||
m = re.match("<(.+)>", part["Content-ID"])
|
||||
if m:
|
||||
attached_map[m.group(1)] = path
|
||||
else:
|
||||
attached_map[part["Content-ID"]] = path
|
||||
|
||||
if not contents.has_key(mode) or contents[mode] == "":
|
||||
if mode == "html":
|
||||
mode = "plain"
|
||||
else:
|
||||
mode = "html"
|
||||
(pre, body) = globals()["viewmail_%s" % mode](request, contents[mode])
|
||||
return _render(request, 'amavis_quarantine/getmailcontent.html', {
|
||||
"body" : body, "pre" : pre
|
||||
})
|
||||
mail = Email(msg, mode, links)
|
||||
return mail.render(request)
|
||||
|
||||
@login_required
|
||||
def viewmail(request, mail_id):
|
||||
|
||||
@@ -82,20 +82,27 @@ class IMAPconnector(MBconnector):
|
||||
result += [name]
|
||||
return sorted(result)
|
||||
|
||||
def fetch(self, start=None, stop=None, folder=None):
|
||||
if not start or not stop:
|
||||
def fetch(self, start=None, stop=None, folder=None, all=False):
|
||||
if not start and not stop:
|
||||
return []
|
||||
result = []
|
||||
self.m.select(self._encodefolder(folder))
|
||||
range = "%d:%d" % (start, stop)
|
||||
typ, data = self.m.fetch(range, '(BODY[HEADER.FIELDS (DATE FROM SUBJECT)])')
|
||||
imapid = start
|
||||
if start and stop:
|
||||
range = "%d:%d" % (start, stop)
|
||||
else:
|
||||
range = start
|
||||
if not all:
|
||||
query = '(BODY[HEADER.FIELDS (DATE FROM TO SUBJECT)])'
|
||||
else:
|
||||
query = '(RFC822)'
|
||||
typ, data = self.m.fetch(range, query)
|
||||
imapid = int(start)
|
||||
for response_part in data:
|
||||
if isinstance(response_part, tuple):
|
||||
msg = email.message_from_string(response_part[1])
|
||||
msg["imapid"] = imapid
|
||||
result += [msg]
|
||||
imapid += 1
|
||||
imapid = imapid + 1
|
||||
return result
|
||||
|
||||
class ImapListing(EmailListing):
|
||||
|
||||
@@ -41,7 +41,8 @@ def index(request):
|
||||
|
||||
@login_required
|
||||
def folder(request, folder):
|
||||
lst = ImapListing(folder=folder)
|
||||
lst = ImapListing(request.user.username, request.session["password"],
|
||||
folder=folder)
|
||||
try:
|
||||
pageid = request.GET["page"]
|
||||
except KeyError:
|
||||
@@ -55,3 +56,28 @@ def folder(request, folder):
|
||||
navbar = ""
|
||||
ctx = {"status" : "ok", "listing" : content, "navbar" : navbar}
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
|
||||
def fetchmail(request, mail_id, all=False):
|
||||
mbc = IMAPconnector(parameters.get("webmail", "SERVER_ADDRESS"), 143)
|
||||
mbc.login(request.user.username, request.session["password"])
|
||||
res = mbc.fetch(start=mail_id, all=all)
|
||||
if len(res):
|
||||
return res[0]
|
||||
return None
|
||||
|
||||
@login_required
|
||||
def viewmail(request, mail_id):
|
||||
header = fetchmail(request, mail_id)
|
||||
pageid = request.GET.has_key("page") and request.GET["page"] or "1"
|
||||
if header:
|
||||
return _render(request, "webmail/viewmail.html", {
|
||||
"header" : header, "pageid" : pageid
|
||||
})
|
||||
|
||||
@login_required
|
||||
def getmailcontent(request, mail_id):
|
||||
from mailng.lib.email_listing import Email
|
||||
|
||||
msg = fetchmail(request, mail_id, True)
|
||||
email = Email(msg)
|
||||
return email.render(request)
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
$("navbar").set("html", resp.navbar);
|
||||
}}).get();
|
||||
});
|
||||
{% url extensions.webmail.main.viewmail as view_url %}
|
||||
bindRows("{{ view_url }}", "{{ current_page }}");
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Webmail" %}{% endblock %}
|
||||
{% block menu %}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
{% extends "nlayout.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<style type="text/css">
|
||||
#mailcontent {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
td {
|
||||
font-size: 1em;
|
||||
height: 20px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #F7F9Fb;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
window.addEvent("domready", function() {
|
||||
var spage = $("page").getSize();
|
||||
var stable = $("table-container").getSize();
|
||||
var slogo = $("header").getSize();
|
||||
var iheight = spage.y - stable.y - slogo.y;
|
||||
|
||||
$("mailcontent").setStyle("height", iheight + "px");
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Email content" %}{% endblock %}
|
||||
{% block menu %}
|
||||
{% load webextras %}
|
||||
{% viewm_menu "" header.imapid pageid perms %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="table-container">
|
||||
<table id="headers">
|
||||
<tr><th>{% trans "Subject" %}</th><td>{{ header.Subject }}</td></tr>
|
||||
<tr><th>{% trans "From" %}</th><td>{{ header.From }}</td></tr>
|
||||
<tr><th>{% trans "To" %}</th><td>{{ header.To }}</td></tr>
|
||||
<tr><th>{% trans "Date" %}</th><td>{{ header.Date }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% url extensions.webmail.main.getmailcontent header.imapid as geturl %}
|
||||
<iframe id="mailcontent" src="{{ geturl }}"></iframe>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,20 @@
|
||||
from django import template
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from mailng.extensions import webmail
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def viewm_menu(selection, mail_id, page_id, perms):
|
||||
entries = [
|
||||
{"name" : "back",
|
||||
"url" : reverse(webmail.main.index) + "?page=%s" % page_id,
|
||||
"img" : "/static/pics/back.png",
|
||||
"label" : _("Back to list")},
|
||||
]
|
||||
|
||||
return render_to_string('main/menu.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
@@ -2,5 +2,9 @@ from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.extensions.webmail.main',
|
||||
(r'^$', "index"),
|
||||
(r'^(?P<folder>.+)/$', "folder"),
|
||||
url(r'^viewmail/(?P<mail_id>[\w\-\+]+)/$', 'viewmail',
|
||||
name="viewmail_std"),
|
||||
url(r'^viewmail/$', 'viewmail', name="viewmail_null"),
|
||||
(r'^getmailcontent/(?P<mail_id>[\w\-\+]+)/$', 'getmailcontent'),
|
||||
# (r'^(?P<folder>.+)/$', "folder"),
|
||||
)
|
||||
|
||||
+71
-1
@@ -1,7 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import lxml
|
||||
from django.template.loader import render_to_string
|
||||
from mailng.lib import _render
|
||||
from django.template import Template
|
||||
from mailng.lib import _render, decode
|
||||
|
||||
attached_map = {}
|
||||
|
||||
class MBconnector(object):
|
||||
def __init__(self, address, port):
|
||||
@@ -93,3 +97,69 @@ class EmailListing:
|
||||
"selection" : self.folder,
|
||||
"current_page" : pageid
|
||||
})
|
||||
|
||||
class Email(object):
|
||||
def __init__(self, msg, mode="plain", links="0"):
|
||||
self.attached_map = {}
|
||||
contents = {"html" : "", "plain" : ""}
|
||||
for part in msg.walk():
|
||||
if part.get_content_maintype() == 'multipart':
|
||||
continue
|
||||
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":
|
||||
continue
|
||||
|
||||
if part.get_content_maintype() == "image":
|
||||
if part.has_key("Content-Location"):
|
||||
fname = part["Content-Location"]
|
||||
if re.match("^http:", fname):
|
||||
path = fname
|
||||
else:
|
||||
path = "/%s" % os.path.join("static/tmp", fname)
|
||||
fp = open(path, "wb")
|
||||
fp.write(part.get_payload(decode=True))
|
||||
fp.close()
|
||||
m = re.match("<(.+)>", part["Content-ID"])
|
||||
if m:
|
||||
self.attached_map[m.group(1)] = path
|
||||
else:
|
||||
self.attached_map[part["Content-ID"]] = path
|
||||
|
||||
if not contents.has_key(mode) or contents[mode] == "":
|
||||
if mode == "html":
|
||||
mode = "plain"
|
||||
else:
|
||||
mode = "html"
|
||||
self.pre, self.body = \
|
||||
getattr(self, "viewmail_%s" % mode)(contents[mode], links=links)
|
||||
|
||||
def map_cid(self, url):
|
||||
import re
|
||||
|
||||
map = globals()["attached_map"]
|
||||
m = re.match(".*cid:([^\"]+)", url)
|
||||
if m:
|
||||
if map.has_key(m.group(1)):
|
||||
return map[m.group(1)]
|
||||
return url
|
||||
|
||||
def render(self, request):
|
||||
return _render(request, 'common/getmailcontent.html', {
|
||||
"body" : self.body, "pre" : self.pre
|
||||
})
|
||||
|
||||
def viewmail_plain(self, content, **kwargs):
|
||||
body = decode(content)
|
||||
return (True, body)
|
||||
|
||||
def viewmail_html(self, content, **kwargs):
|
||||
links = kwargs.has_key("links") and kwargs["links"] or "0"
|
||||
html = lxml.html.fromstring(content)
|
||||
if links == "0":
|
||||
html.rewrite_links(lambda x: None)
|
||||
else:
|
||||
html.rewrite_links(self.map_cid)
|
||||
body = lxml.html.tostring(html)
|
||||
body = Template(decode(body)).render({})
|
||||
return (False, body)
|
||||
|
||||
@@ -4,7 +4,7 @@ html, body {
|
||||
background: #153F65;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#topmenubar {
|
||||
|
||||
@@ -10,8 +10,13 @@ html, body {
|
||||
margin: 100px auto;
|
||||
width: 610px;
|
||||
padding-bottom: 15px;
|
||||
border: 5px solid #333;
|
||||
background: white;
|
||||
|
||||
border: 5px solid #333;
|
||||
/*-moz-box-shadow: 0 10px 30px #222;*/
|
||||
-webkit-box-shadow: 0 10px 30px #222;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#loginbox h2 {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{% if pre %}<pre>{% endif %}{{ body }}{% if pre %}</pre>{% endif %}
|
||||
@@ -22,8 +22,13 @@
|
||||
<div id="topmenubar" class="menubar">
|
||||
<div class="left">
|
||||
<ul>
|
||||
<li>
|
||||
{% url main.views.index as index_url %}
|
||||
<a href="{{ index_url }}">
|
||||
<img src="/static/pics/user.png" border="0" />{% trans "Preferences" %}</a>
|
||||
</li>
|
||||
{% loadextmenu perms %}
|
||||
{% if user.is_superuser or perms.admin.view_domain %}
|
||||
{% if user.is_superuser or perms.admin.view_domains %}
|
||||
<li class="dropdown">
|
||||
<img src="/static/pics/settings.png" border="0" />
|
||||
<label>{% trans "Admin" %}</label>
|
||||
|
||||
Reference in New Issue
Block a user