Compose, Reply, Reply all.

New paramaters to configure connections to IMAP and SMTP servers.
This commit is contained in:
tonio
2010-03-05 17:56:55 +01:00
parent a3ea75ff22
commit 312ebe57ec
11 changed files with 138 additions and 55 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ AND quarantine.chunk_ind=1
ORDER BY msgs.time_num DESC
""" % self.filter
def messages_count(self, folder=None):
def messages_count(self, **kwargs):
return self.count
def fetch(self, start=None, stop=None, **kwargs):
+1 -1
View File
@@ -4,6 +4,6 @@ from django.utils.translation import ugettext as _
class ComposeMailForm(forms.Form):
from_ = forms.CharField(label=_("From"))
to = forms.CharField(label=_("To"), widget=forms.Textarea())
cc = forms.CharField(label=_("Cc"), widget=forms.Textarea())
cc = forms.CharField(label=_("Cc"), widget=forms.Textarea(), required=False)
subject = forms.CharField(label=_("Subject"), max_length=255)
+44 -19
View File
@@ -31,21 +31,36 @@ class WMtable(tables.Table):
except AttributeError:
return value
class IMAPheader(object):
addr_exp = re.compile("([^<\(]+)<|\(([^>\)]+)>|\)")
name_exp = re.compile("\"(.+)\"")
class EmailAddress(object):
addr_exp = re.compile("([^<\(]+)[<(]([^>)]+)[>)]")
name_exp = re.compile('"([^"]+)"')
def __init__(self, address):
self.fulladdress = address
self.name = self.address = None
m = EmailAddress.addr_exp.match(self.fulladdress)
if m is None:
return
name = m.group(1).strip()
self.address = m.group(2).strip()
m2 = EmailAddress.name_exp.match(name)
if m2:
name = m2.group(1)
self.name = ""
for part in decode_header(name):
if self.name != "":
self.name += " "
if part[1] is None:
self.name += part[0]
else:
self.name += unicode(part[0], part[1])
self.fulladdress = "%s <%s>" % (self.name, self.address)
class IMAPheader(object):
@staticmethod
def parse_address(value):
m = IMAPheader.addr_exp.match(value)
if m:
name = m.group(1)
name = name.strip()
m2 = IMAPheader.name_exp.match(name)
if m2:
return IMAPheader.parse_subject(m2.group(1))
return IMAPheader.parse_subject(name)
return value
addr = EmailAddress(value)
return addr.name and addr.name or value
@staticmethod
def parse_address_list(values):
@@ -126,16 +141,27 @@ class IMAPconnector(object):
return "INBOX"
return folder.encode("imap4-utf-7")
def messages_count(self, folder=None, order=None):
if order:
sign = order[:1]
criterion = order[1:].upper()
def messages_count(self, **kwargs):
"""An enhanced version of messages_count
With IMAP, to know how many messages a mailbox contains, we
have to make a request to the server. To avoid requests
multiplications, we sort messages in the same time. This will
be usefull for other methods.
:param order: sorting order
:param folder: mailbox to scan
"""
if "order" in kwargs.keys() and kwargs["order"]:
sign = kwargs["order"][:1]
criterion = kwargs["order"][1:].upper()
if sign == '-':
criterion = "REVERSE %s" % criterion
else:
criterion = "REVERSE DATE"
print criterion
folder = kwargs.has_key("folder") and kwargs["folder"] or None
(status, data) = self.m.select(self._encodefolder(folder))
(status, data) = self.m.sort("(%s)" % criterion, "UTF-8", "(NOT DELETED)")
self.messages = data[0].split()
@@ -210,9 +236,8 @@ class ImapListing(EmailListing):
tpl = "webmail/index.html"
tbltype = WMtable
def __init__(self, user, password, baseurl=None, navparams={}, **kwargs):
def __init__(self, user, password, baseurl=None, **kwargs):
self.mbc = IMAPconnector(user=user, password=password)
self.navparams = navparams
EmailListing.__init__(self, **kwargs)
if baseurl:
self.paginator.baseurl = baseurl
@@ -232,7 +257,7 @@ class ImapEmail(Email):
def __init__(self, msg, **kwargs):
Email.__init__(self, msg, **kwargs)
fields = ["Subject", "From", "To", "Cc", "Date"]
fields = ["Subject", "From", "To", "Reply-To", "Cc", "Date"]
for f in fields:
label = f
if not f in msg.keys():
+61 -23
View File
@@ -22,13 +22,18 @@ def init():
parameters.register("webmail", "IMAP_SERVER", "string", "127.0.0.1",
help=_("Address of your IMAP server"))
parameters.register("webmail", "IMAP_SECURED", "list_yesno", "no",
help=_("Use a secure connexion to access IMAP server"))
help=_("Use a secured connection to access IMAP server"))
parameters.register("webmail", "IMAP_PORT", "int", "143",
help=_("Listening port of your IMAP server"))
parameters.register("webmail", "SMTP_SERVER", "string", "127.0.0.1",
help=_("Address of your SMTP server"))
parameters.register("webmail", "SMTP_PORT", "int", "25",
help=_("Listening port of your SMTP server"))
parameters.register("webmail", "SMTP_AUTHENTICATION", "list_yesno", "no",
help=_("Server needs authentication"))
parameters.register("webmail", "SMTP_SECURED", "list_yesno", "no",
help=_("Use a secured connection to access SMTP server"))
def urls():
return (r'^mailng/webmail/',
@@ -57,7 +62,7 @@ def getctx(status, level=1, **kwargs):
def folder(request, name, updatenav=True):
if not name:
name = "INBOX"
order = request.GET.has_key("order") and request.GET["order"] or None
order = request.GET.has_key("order") and request.GET["order"] or "-date"
if updatenav:
pageid = request.GET.has_key("page") and int(request.GET["page"]) or 1
if not "navparams" in request.session.keys():
@@ -183,23 +188,40 @@ def render_compose(request, form, bodyheader=None, body=None):
ctx = getctx("ok", level=2, menu=menu, listing=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
def send_mail(request):
form = ComposeMailForm(request.POST)
if form.is_valid():
from email.mime.text import MIMEText
import smtplib
msg = MIMEText(request.POST["id_body"].encode("utf-8"),
_charset="utf-8")
msg["Subject"] = request.POST["subject"]
msg["From"] = request.POST["from_"]
msg["To"] = request.POST["to"]
rcpts = msg['To'].split(',')
if "cc" in request.POST.keys():
msg["Cc"] = request.POST["cc"]
rcpts += msg["Cc"].split(",")
try:
s = smtplib.SMTP(parameters.get("webmail", "SMTP_SERVER"))
if parameters.get("webmail", "SMTP_SECURED") == "yes":
s.starttls()
except (smtplib.SMTPException, ssl.SSLError), error:
print error
if parameters.get("webmail", "SMTP_AUTHENTICATION") == "yes":
s.login(request.user.username, request.session["password"])
s.sendmail(msg['From'], rcpts, msg.as_string())
s.quit()
ctx = getctx("ok", url="%s?page=%s" % (request.session["folder"],
request.session["page"]))
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
@login_required
def compose(request):
if request.method == "POST":
form = ComposeMailForm(request.POST)
if form.is_valid():
from email.mime.text import MIMEText
import smtplib
msg = MIMEText(request.POST["id_body"].encode("utf-8"),
_charset="utf-8")
msg["Subject"] = request.POST["subject"]
msg["From"] = request.POST["from_"]
msg["to"] = request.POST["to"]
s = smtplib.SMTP(parameters.get("webmail", "SMTP_SERVER"))
s.sendmail(msg['From'], [msg['To']], msg.as_string())
s.quit()
return folder(request, request.session["navparams"]["folder"], False)
return send_mail(request)
form = ComposeMailForm()
form.fields["from_"].initial = request.user.username
@@ -208,7 +230,7 @@ def compose(request):
@login_required
def reply(request, folder, mail_id):
if request.method == "POST":
return
return send_mail(request)
msg = fetchmail(request, folder, mail_id, True)
email = ImapEmail(msg)
lines = email.body.split('\n')
@@ -219,11 +241,27 @@ def reply(request, folder, mail_id):
body += ">%s" % l
form = ComposeMailForm()
form.fields["from_"].initial = request.user.username
form.fields["to"].initial = msg["From"]
m = re.match("re\s*:\s*.+", msg["Subject"].lower())
if m:
form.fields["subject"].initial = msg["Subject"]
if not "Reply-To" in msg.keys():
form.fields["to"].initial = msg["From"]
else:
form.fields["subject"].initial = "Re: %s" % msg["Subject"]
textheader = msg["From"] + " " + _("wrote:")
form.fields["to"].initial = msg["Reply-To"]
if request.GET.has_key("all"):
form.fields["cc"].initial = ""
toparse = msg["To"].split(",")
if "Cc" in msg.keys():
toparse += msg["Cc"].split(",")
for addr in toparse:
tmp = EmailAddress(addr)
if tmp.address and tmp.address == request.user.username:
continue
if form.fields["cc"].initial != "":
form.fields["cc"].initial += ", "
form.fields["cc"].initial += tmp.fulladdress
subject = IMAPheader.parse_subject(msg["Subject"])
m = re.match("re\s*:\s*.+", subject.lower())
if m:
form.fields["subject"].initial = subject
else:
form.fields["subject"].initial = "Re: %s" % subject
textheader = EmailAddress(msg["From"]).fulladdress + " " + _("wrote:")
return render_compose(request, form, textheader, body)
+6 -1
View File
@@ -43,8 +43,13 @@
<div id="mailheader">
{% include "common/genericform.html" %}
</div>
{% if body %}
<textarea id="id_body" name="id_body">
{% if bodyheader %}{{ bodyheader }}{% endif %}
{% if body %}{{ body }}{% endif %}</textarea>
{{ body }}
</textarea>
{% else %}
<textarea id="id_body" name="id_body"></textarea>
{% endif %}
</div>
</form>
+11 -5
View File
@@ -160,6 +160,7 @@ tr.selected {
updatelisting(resp, "hidden");
$$("a[name=back]").addEvent("click", loadFolder);
$$("a[name=reply]").addEvent("click", reply);
$$("a[name=replyall]").addEvent("click", replyall);
$$("a[name=delete]").addEvent("click", function(event) {
var lnk = event.target;
@@ -173,16 +174,16 @@ tr.selected {
compose_callback = function(resp) {
updatelisting(resp);
window.addEvent("resize", function(evt) {
var bodysize = $("listing").getSize().y - $("mailheader").getSize().y;
$("id_body").setStyle("height", bodysize + "px");
setDivHeight("id_body", $("mailheader").getSize().y, 0);
});
$$("a[name=back]").addEvent("click", loadFolder);
$$("a[name=sendmail]").addEvent("click", function(evt) {
evt.stop();
$("composemail").set("send", {
onSuccess: function(res) {
updatelisting(JSON.decode(res));
$$("tr").addEvent("dblclick", viewmail);
onSuccess: function(resp) {
resp = JSON.decode(resp);
current_anchor.parse_string(resp.url, true).setparams(navparams);
current_anchor.update();
}
});
$("composemail").send();
@@ -201,6 +202,11 @@ tr.selected {
location.hash += event.target.get("href");
}
register_callback("reply", compose_callback);
replyall = function(event) {
event.stop();
location.hash += event.target.get("href") + "?all=1";
}
register_callback("replyall", compose_callback);
loadFolder = function(event, obj) {
if (!$defined(obj)) {
@@ -40,6 +40,9 @@
#emailheaders a:hover {
text-decoration: underline;
}
pre {
font-size: medium;
}
</style>
</head>
<body>
+2 -2
View File
@@ -34,8 +34,8 @@ def viewm_menu(selection, session, mail_id, perms):
"url" : "reply/",
"img" : "/static/pics/reply.png",
"label" : _("Reply")},
{"name" : "reply-all",
"url" : "",
{"name" : "replyall",
"url" : "reply/",
"img" : "/static/pics/reply-all.png",
"label" : _("Reply all")},
{"name" : "forward",
+8 -2
View File
@@ -17,6 +17,9 @@ class MBconnector(object):
self.address = address
self.port = port
def messages_count(self, **kwargs):
pass
class Page(object):
def __init__(self, pageid, id_start, id_stop, items,
items_per_page, has_previous, has_next,
@@ -80,11 +83,13 @@ class Paginator(object):
return p
class EmailListing:
def __init__(self, folder=None, elems_per_page=40, **kwargs):
def __init__(self, folder=None, elems_per_page=40, navparams={}, **kwargs):
self.folder = folder
self.elems_per_page = elems_per_page
self.navparams = navparams
order = "order" in kwargs.keys() and kwargs["order"] or None
self.paginator = Paginator(self.mbc.messages_count(self.folder, order),
self.paginator = Paginator(self.mbc.messages_count(folder=self.folder,
order=order),
elems_per_page)
def render_navbar(self, page):
@@ -212,3 +217,4 @@ class Email(object):
body = re.sub("<(/?)body", lambda m: "<%sdiv" % m.group(1), body)
body = Template(decode(body)).render({})
return (False, body)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 629 B

+1 -1
View File
@@ -32,7 +32,7 @@
{% loadextmenu perms %}
{% if user.is_superuser or perms.admin.view_domains %}
<li class="dropdown topdropdown">
<img src="/static/pics/settings.png" border="0" />
<img src="/static/pics/admin.png" border="0" />
<label>{% trans "Admin" %}</label>
<ul class="links">
<li>