mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Some work about quarantine management.
This commit is contained in:
@@ -2,15 +2,24 @@
|
||||
|
||||
"""
|
||||
"""
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render_to_response
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import Template
|
||||
from django.conf.urls.defaults import *
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.paginator import Paginator
|
||||
from django.contrib.auth.decorators \
|
||||
import login_required
|
||||
from mailng.lib import events
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko, decode
|
||||
from mailng.lib import db
|
||||
from mailng.admin.models import Mailbox
|
||||
from datetime import datetime
|
||||
import email
|
||||
import re
|
||||
import os
|
||||
|
||||
def init():
|
||||
events.register("UserMenuDisplay", menu)
|
||||
@@ -26,33 +35,33 @@ def menu(**kwargs):
|
||||
"img" : "/static/pics/quarantine.png"}
|
||||
]
|
||||
|
||||
def index(request):
|
||||
@login_required
|
||||
def index(request, message=None):
|
||||
if not request.user.is_superuser:
|
||||
mb = Mailbox.objects.get(user=request.user.id)
|
||||
filter = "AND maddr.email='%s'" % mb.full_address
|
||||
else:
|
||||
filter = ""
|
||||
cursor = db.getconnection("amavis_quarantine").cursor()
|
||||
cursor.execute("""
|
||||
SELECT msgs.from_addr, maddr.email, msgs.subject, msgs.content, quarantine.mail_id
|
||||
conn = db.getconnection("amavis_quarantine")
|
||||
status, cursor = db.execute(conn, """
|
||||
SELECT msgs.from_addr, maddr.email, msgs.subject, msgs.content, quarantine.mail_id,
|
||||
msgs.time_num, msgs.content
|
||||
FROM quarantine, maddr, msgrcpt, msgs
|
||||
WHERE quarantine.mail_id=msgrcpt.mail_id
|
||||
AND msgrcpt.rid=maddr.id
|
||||
AND msgrcpt.mail_id=msgs.mail_id
|
||||
AND quarantine.chunk_ind=1
|
||||
%s
|
||||
ORDER BY msgs.time_num DESC
|
||||
""" % filter)
|
||||
emails = []
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
emails.append({"from" : row[0], "to" : row[1],
|
||||
"subject" : row[2], "content" : row[3],
|
||||
"mailid" : row[4]})
|
||||
"mailid" : row[4], "time" : datetime.fromtimestamp(row[5]),
|
||||
"type" : row[6]})
|
||||
|
||||
# cursor.execute("SELECT count(*) AS cnt FROM quarantine")
|
||||
# row = cursor.fetchone()
|
||||
# cnt = row[0]
|
||||
|
||||
paginator = Paginator(emails, 10)
|
||||
try:
|
||||
pagenum = int(request.GET.get('page', '1'))
|
||||
@@ -62,3 +71,94 @@ AND quarantine.chunk_ind=1
|
||||
return _render(request, 'amavis_quarantine/index.html', {
|
||||
"count" : len(rows), "emails" : page
|
||||
})
|
||||
|
||||
@login_required
|
||||
def viewmail(request, mail_id):
|
||||
conn = db.getconnection("amavis_quarantine")
|
||||
status, cursor = db.execute(conn, """
|
||||
SELECT mail_text
|
||||
FROM quarantine
|
||||
WHERE quarantine.mail_id='%s'
|
||||
""" % mail_id)
|
||||
content = ""
|
||||
for part in cursor.fetchall():
|
||||
content += part[0]
|
||||
msg = email.message_from_string(content)
|
||||
|
||||
html_body = ""
|
||||
text_body = ""
|
||||
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"):
|
||||
html_body += part.get_payload()
|
||||
if part.get_content_type() in ("text/plain"):
|
||||
text_body += part.get_payload(decode=True)
|
||||
pre = None
|
||||
if html_body != "":
|
||||
html_body = email.utils.quote(html_body)
|
||||
html_body = re.sub('(\n|\r|\r\n)', '\\\\n', html_body)
|
||||
body = Template(decode(html_body)).render({})
|
||||
else:
|
||||
text_body = email.utils.quote(text_body)
|
||||
text_body = re.sub('(\n|\r|\r\n)', '\\\\n', text_body)
|
||||
body = decode(text_body)
|
||||
pre = True
|
||||
|
||||
|
||||
return _render(request, 'amavis_quarantine/viewmail.html', {
|
||||
"headers" : msg.items(),
|
||||
"body" : body,
|
||||
"pre" : pre
|
||||
})
|
||||
|
||||
@login_required
|
||||
def process(request):
|
||||
if request.POST.has_key("deleteall"):
|
||||
return
|
||||
ids = ""
|
||||
count = len(request.POST.getlist("selection"))
|
||||
for id in request.POST.getlist("selection"):
|
||||
if ids != "":
|
||||
ids += ","
|
||||
ids += "'%s'" % id
|
||||
if ids == "":
|
||||
return
|
||||
conn = db.getconnection("amavis_quarantine")
|
||||
if request.POST.has_key("release"):
|
||||
status, cursor = db.execute(conn, """
|
||||
SELECT msgs.mail_id,secret_id,quar_type,maddr.email FROM msgs, maddr, msgrcpt
|
||||
WHERE msgrcpt.mail_id=msgs.mail_id AND msgrcpt.rid=maddr.id AND msgs.mail_id IN (%s)
|
||||
""" % (ids))
|
||||
emails = {}
|
||||
for row in cursor.fetchall():
|
||||
if not emails.has_key(row[0]):
|
||||
emails[row[0]] = {}
|
||||
emails[row[0]]["rcpts"] = []
|
||||
emails[row[0]]["secret"] = row[1]
|
||||
emails[row[0]]["rcpts"] += [row[3]]
|
||||
count = 0
|
||||
for k, values in emails.iteritems():
|
||||
cmd = "/tmp/amavisd-release "
|
||||
cmd += "%s %s" % (k, values["secret"])
|
||||
for rcpt in values["rcpts"]:
|
||||
cmd += " %s" % rcpt
|
||||
cmd += "\n"
|
||||
result = os.system(cmd)
|
||||
# if re.search("250 [^\s]+ Ok", result):
|
||||
if not result:
|
||||
count += 1
|
||||
message = _("%d message%s released successfully" \
|
||||
% (count, count > 1 and "s" or ""))
|
||||
|
||||
if request.POST.has_key("delete"):
|
||||
status, error = db.execute(conn,
|
||||
"DELETE FROM msgs WHERE mail_id IN (%s)" % ids)
|
||||
if status:
|
||||
message = _("%d message%s deleted successfully" \
|
||||
% (count, count > 1 and "s" or ""))
|
||||
else:
|
||||
message = error
|
||||
request.user.message_set.create(message=message)
|
||||
return HttpResponseRedirect(reverse(index))
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import socket
|
||||
import sys
|
||||
import re
|
||||
import struct
|
||||
from optparse import OptionParser
|
||||
|
||||
def getsocket(options):
|
||||
if options.mode == "net":
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((options.host, options.port))
|
||||
|
||||
return s
|
||||
|
||||
def from_stdin():
|
||||
res = []
|
||||
for line in sys.stdin:
|
||||
res += [line]
|
||||
return res
|
||||
|
||||
def decodevalue(val):
|
||||
def pack(match):
|
||||
return struct.pack('B', match.group(0))
|
||||
res = re.sub("%([0-9a-fA-F]{2})", pack, val)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-o", "--host", default="127.0.0.1",
|
||||
help="")
|
||||
parser.add_option("-p", "--port", default=9998,
|
||||
help="")
|
||||
parser.add_option("-s", "--socket", default="",
|
||||
help="")
|
||||
parser.add_option("-m", "--mode", default="unix",
|
||||
help="")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if not len(args):
|
||||
print "Nothing to do, exiting."
|
||||
sys.exit(1)
|
||||
|
||||
s = getsocket(options)
|
||||
# if args[0] == '-':
|
||||
# worklist = from_stdin()
|
||||
# else:
|
||||
# worklist = [args[0]]
|
||||
|
||||
# for message in worklist:
|
||||
# params = message.split()
|
||||
params = ["k1URJIk76bKa", "k1URJIk76bKa", "antoine.nguyen@streamcore.com"]
|
||||
cmd = """request=release
|
||||
mail_id=%s
|
||||
secret_id=%s
|
||||
quar_type=Q
|
||||
recipient=%s
|
||||
|
||||
""" % (params[0], params[1], params[2])
|
||||
s.send(cmd)
|
||||
answer = s.recv(1024)
|
||||
print answer
|
||||
|
||||
s.close()
|
||||
@@ -19,6 +19,11 @@
|
||||
float: left;
|
||||
}
|
||||
|
||||
#listing {
|
||||
margin: 0 auto;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: smaller;
|
||||
height: 40px;
|
||||
@@ -36,17 +41,19 @@ td {
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div id="subcontent">
|
||||
{% url extensions.amavis_quarantine.main.process as actionurl %}
|
||||
<form method="POST" action="{{ actionurl }}">
|
||||
<div id="listing">
|
||||
<b> Il y a {{ count }} messages dans la quarantaine.</b>
|
||||
|
||||
<div id="quarmenu">
|
||||
<div id="actionbar">
|
||||
<input type="button" name="release" value="{% trans "Release" %}" />
|
||||
<input type="button" name="delete" value="{% trans "Delete" %}" />
|
||||
<input type="button" name="deleteall" value="{% trans "Delete all" %}" />
|
||||
<input type="submit" name="release" value="{% trans "Release" %}" />
|
||||
<input type="submit" name="delete" value="{% trans "Delete" %}" />
|
||||
<input type="submit" name="deleteall" value="{% trans "Delete all" %}" />
|
||||
</div>
|
||||
<div id="navbar">
|
||||
{% if emails.has_previous %}
|
||||
<a href="?page=1">{% trans "First" %}</a>
|
||||
<a href="?page={{ emails.previous_page_number }}">{% trans "Previous" %}</a>
|
||||
{% endif %}
|
||||
{% if emails.has_next %}
|
||||
@@ -57,15 +64,23 @@ td {
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th width="150px">{% trans "From" %}</th>
|
||||
<th width="150px">{% trans "To" %}</th>
|
||||
<th>{% trans "Subject" %}</th>
|
||||
<th width="100px">{% trans "Date" %}</th>
|
||||
</tr>
|
||||
{% for m in emails.object_list %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<td><input type="checkbox" name="selection" id="selection" /></td>
|
||||
<td>{{ m.from }}</td><td>{{ m.to }}</td><td>{{ m.subject }}</td></tr>
|
||||
<td><input type="checkbox" name="selection" id="selection"
|
||||
value="{{ m.mailid }}" /></td>
|
||||
<td>{{ m.type }}</td>
|
||||
{% if user.is_superuser %}<td>{{ m.to }}</td>{% endif %}
|
||||
{% url extensions.amavis_quarantine.main.viewmail m.mailid as view_url %}
|
||||
<td><a href="{{ view_url }}">{{ m.subject }}</a></td>
|
||||
<td>{{ m.time }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,47 @@
|
||||
{% extends "layout.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<script type="text/javascript">
|
||||
window.addEvent("domready", function() {
|
||||
doc = $("mailcontent").contentWindow.document;
|
||||
doc.open();
|
||||
{% if pre %}
|
||||
doc.write("<pre>{{ body }}</pre>");
|
||||
{% else %}
|
||||
doc.write("{{ body }}");
|
||||
{% endif %}
|
||||
doc.close();
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/stylesheets/box.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
font-size: smaller;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
td.left {
|
||||
background: #F7F9Fb;
|
||||
}
|
||||
|
||||
#mailcontent {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<iframe id="mailcontent"></iframe>
|
||||
|
||||
<table border="0">
|
||||
<tr><th colspan="2">{% trans "Message headers" %}</th></tr>
|
||||
{% for k, v in headers %}
|
||||
<tr>
|
||||
<td class="left">{{ k }}</td><td>{{ v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
@@ -2,4 +2,6 @@ from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.extensions.amavis_quarantine.main',
|
||||
(r'^$', 'index'),
|
||||
(r'^view/(?P<mail_id>[\w\-\+]+)/$', 'viewmail'),
|
||||
(r'^process/$', 'process')
|
||||
)
|
||||
|
||||
@@ -62,3 +62,11 @@ def _ctx_ok(url):
|
||||
|
||||
def _ctx_ko(tpl, ctx):
|
||||
return {"status" : "ko", "content" : render_to_string(tpl, ctx)}
|
||||
|
||||
def decode(s, encodings=('ascii', 'utf8', 'latin1')):
|
||||
for encoding in encodings:
|
||||
try:
|
||||
return s.decode(encoding)
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
return s.decode('ascii', 'ignore')
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
import re
|
||||
import MySQLdb
|
||||
|
||||
connections = {}
|
||||
|
||||
def mysql_newconnection(host, dbname, login, password):
|
||||
@@ -20,3 +23,13 @@ def getconnection(name):
|
||||
connections[name] = conn
|
||||
return connections[name]
|
||||
|
||||
def execute(conn, query):
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(query)
|
||||
if re.search("INSERT|DELETE|UPDATE", query):
|
||||
conn.commit()
|
||||
return (True, None)
|
||||
return (True, cursor)
|
||||
except MySQLdb.Error, e:
|
||||
return (False, "Error %d: %s" % (e.args[0], e.args[1]))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{% for entry in menu %}
|
||||
<li><a href="{{ entry.url }}"><img src="{{ entry.img }}" border="0" />
|
||||
{{ entry.name }}
|
||||
</a></li>
|
||||
{% endfor %}
|
||||
Reference in New Issue
Block a user