Email forwarding.

This commit is contained in:
tonio
2010-03-09 15:39:43 +01:00
parent 312ebe57ec
commit 6b542225d7
7 changed files with 107 additions and 29 deletions
+33 -13
View File
@@ -56,36 +56,45 @@ class EmailAddress(object):
self.name += unicode(part[0], part[1])
self.fulladdress = "%s <%s>" % (self.name, self.address)
def __str__(self):
return self.fulladdress
class IMAPheader(object):
@staticmethod
def parse_address(value):
def parse_address(value, **kwargs):
addr = EmailAddress(value)
if "full" in kwargs.keys() and kwargs["full"]:
return addr.fulladdress
return addr.name and addr.name or value
@staticmethod
def parse_address_list(values):
def parse_address_list(values, **kwargs):
lst = values.split(",")
result = ""
for addr in lst:
if result != "":
result += ", "
result += IMAPheader.parse_address(addr)
result += IMAPheader.parse_address(addr, **kwargs)
return result
@staticmethod
def parse_from(value):
return IMAPheader.parse_address(value)
def parse_from(value, **kwargs):
return IMAPheader.parse_address(value, **kwargs)
@staticmethod
def parse_to(value):
return IMAPheader.parse_address_list(value)
def parse_to(value, **kwargs):
return IMAPheader.parse_address_list(value, **kwargs)
@staticmethod
def parse_cc(value):
return IMAPheader.parse_address_list(value)
def parse_cc(value, **kwargs):
return IMAPheader.parse_address_list(value, **kwargs)
@staticmethod
def parse_date(value):
def parse_reply_to(value, **kwargs):
return IMAPheader.parse_address_list(value, **kwargs)
@staticmethod
def parse_date(value, **kwargs):
tmp = email.utils.parsedate_tz(value)
if not tmp:
return value
@@ -96,7 +105,7 @@ class IMAPheader(object):
return ndate.strftime("%a %H:%M")
@staticmethod
def parse_subject(value):
def parse_subject(value, **kwargs):
res = ""
dcd = decode_header(value)
for part in dcd:
@@ -186,6 +195,10 @@ class IMAPconnector(object):
folder, id = imapid.split("/")
self.m.store(id, "+FLAGS", "\\Seen")
def msgforwarded(self, folder, imapid):
self.m.select(self._encodefolder(folder), True)
self.m.store(imapid, "+FLAGS", "$Forwarded")
def move(self, msgset, oldfolder, newfolder):
self.m.select(self._encodefolder(oldfolder), True)
self.m.copy(msgset, newfolder)
@@ -254,7 +267,7 @@ class ImapListing(EmailListing):
return md_folders
class ImapEmail(Email):
def __init__(self, msg, **kwargs):
def __init__(self, msg, addrfull=False, **kwargs):
Email.__init__(self, msg, **kwargs)
fields = ["Subject", "From", "To", "Reply-To", "Cc", "Date"]
@@ -265,7 +278,14 @@ class ImapEmail(Email):
if not f in msg.keys():
continue
try:
self.headers += [{"name" : label, "value" : getattr(IMAPheader, "parse_%s" % f.lower())(msg[f])}]
key = re.sub("-", "_", f).lower()
value = getattr(IMAPheader, "parse_%s" % key)(msg[f], full=addrfull)
self.headers += [{"name" : label, "value" : value}]
except AttributeError:
self.headers += [{"name" : label, "value" : msg[f]}]
try:
label = re.sub("-", "_", label)
setattr(self, label, value)
except:
pass
+48 -13
View File
@@ -180,15 +180,16 @@ def empty(request, name):
mbc.empty(name)
return folder(request, name, False)
def render_compose(request, form, bodyheader=None, body=None):
def render_compose(request, form, posturl, bodyheader=None, body=None):
menu = compose_menu("", request.session, request.user.get_all_permissions())
content = render_to_string("webmail/compose.html", {
"form" : form, "bodyheader" : bodyheader, "body" : body
"form" : form, "bodyheader" : bodyheader, "body" : body,
"posturl" : posturl
})
ctx = getctx("ok", level=2, menu=menu, listing=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
def send_mail(request):
def send_mail(request, withctx=False):
form = ComposeMailForm(request.POST)
if form.is_valid():
from email.mime.text import MIMEText
@@ -209,6 +210,7 @@ def send_mail(request):
s.starttls()
except (smtplib.SMTPException, ssl.SSLError), error:
print error
# Prévoir la remontée de cette erreur au niveau du client!!
if parameters.get("webmail", "SMTP_AUTHENTICATION") == "yes":
s.login(request.user.username, request.session["password"])
@@ -216,7 +218,12 @@ def send_mail(request):
s.quit()
ctx = getctx("ok", url="%s?page=%s" % (request.session["folder"],
request.session["page"]))
else:
ctx = getctx("ko", level=2, listing=render_to_string("webmail/compose.html",
{"form" : form}))
if not withctx:
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ctx, HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
@login_required
def compose(request):
@@ -225,14 +232,14 @@ def compose(request):
form = ComposeMailForm()
form.fields["from_"].initial = request.user.username
return render_compose(request, form)
return render_compose(request, form, reverse(compose))
@login_required
def reply(request, folder, mail_id):
if request.method == "POST":
return send_mail(request)
msg = fetchmail(request, folder, mail_id, True)
email = ImapEmail(msg)
email = ImapEmail(msg, True)
lines = email.body.split('\n')
body = ""
for l in lines:
@@ -242,9 +249,9 @@ def reply(request, folder, mail_id):
form = ComposeMailForm()
form.fields["from_"].initial = request.user.username
if not "Reply-To" in msg.keys():
form.fields["to"].initial = msg["From"]
form.fields["to"].initial = email.From
else:
form.fields["to"].initial = msg["Reply-To"]
form.fields["to"].initial = email.Reply_To
if request.GET.has_key("all"):
form.fields["cc"].initial = ""
toparse = msg["To"].split(",")
@@ -257,11 +264,39 @@ def reply(request, folder, mail_id):
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())
m = re.match("re\s*:\s*.+", email.Subject.lower())
if m:
form.fields["subject"].initial = subject
form.fields["subject"].initial = email.Subject
else:
form.fields["subject"].initial = "Re: %s" % subject
textheader = EmailAddress(msg["From"]).fulladdress + " " + _("wrote:")
return render_compose(request, form, textheader, body)
form.fields["subject"].initial = "Re: %s" % email.Subject
textheader = "%s %s" % (email.From, _("wrote:"))
return render_compose(request, form, reverse(reply, args[folder, mail_id]),
textheader, body)
@login_required
def forward(request, folder, mail_id):
if request.method == "POST":
ctx, response = send_mail(request, True)
if ctx["status"] == "ok":
IMAPconnector(request).msgforwarded(folder, mail_id)
return response
msg = fetchmail(request, folder, mail_id, True)
email = ImapEmail(msg, True)
textheader = "----- %s -----" % _("Original message")
textheader += "\n%s: %s" % (_("Subject"), email.Subject)
textheader += "\n%s: %s" % (_("Date"), msg["Date"])
for hdr in ["From", "To", "Reply-To"]:
try:
key = re.sub("-", "_", hdr)
value = getattr(email, key)
textheader += "\n%s: %s" % (_(hdr), value)
except:
pass
textheader += "\n"
form = ComposeMailForm()
form.fields["from_"].initial = request.user.username
form.fields["subject"].initial = "Fwd: %s" % email.Subject
return render_compose(request, form, reverse(forward, args=[folder, mail_id]),
textheader, email.body)
+1 -2
View File
@@ -37,8 +37,7 @@
}
</style>
{% url extensions.webmail.main.compose as compurl %}
<form method="POST" action="{{ compurl }}" id="composemail">
<form method="POST" action="{{ posturl }}" id="composemail">
<div id="compose-container">
<div id="mailheader">
{% include "common/genericform.html" %}
+11
View File
@@ -161,6 +161,7 @@ tr.selected {
$$("a[name=back]").addEvent("click", loadFolder);
$$("a[name=reply]").addEvent("click", reply);
$$("a[name=replyall]").addEvent("click", replyall);
$$("a[name=forward]").addEvent("click", forward);
$$("a[name=delete]").addEvent("click", function(event) {
var lnk = event.target;
@@ -182,6 +183,11 @@ tr.selected {
$("composemail").set("send", {
onSuccess: function(resp) {
resp = JSON.decode(resp);
if (resp.status == "ko") {
updatelisting(resp);
window.fireEvent("resize");
return;
}
current_anchor.parse_string(resp.url, true).setparams(navparams);
current_anchor.update();
}
@@ -207,6 +213,11 @@ tr.selected {
location.hash += event.target.get("href") + "?all=1";
}
register_callback("replyall", compose_callback);
forward = function(event) {
event.stop();
location.hash += event.target.get("href");
}
register_callback("forward", compose_callback);
loadFolder = function(event, obj) {
if (!$defined(obj)) {
+1 -1
View File
@@ -39,7 +39,7 @@ def viewm_menu(selection, session, mail_id, perms):
"img" : "/static/pics/reply-all.png",
"label" : _("Reply all")},
{"name" : "forward",
"url" : "",
"url" : "forward/",
"img" : "/static/pics/alias.png",
"label" : _("Forward")},
{"name" : "delete",
+1
View File
@@ -8,6 +8,7 @@ urlpatterns = patterns('mailng.extensions.webmail.main',
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/part/$', 'getattachment'),
(r'^(?P<fdname>.+)/(?P<mail_id>[\w\-\+]+)/delete/$', 'delete'),
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/content/$', 'getmailcontent'),
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/forward/$', 'forward'),
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/reply/$', 'reply'),
(r'^(?P<folder>.+)/(?P<mail_id>[\w\-\+]+)/$', 'viewmail'),
(r'^(?P<name>.+)/$', "folder"),
+12
View File
@@ -346,4 +346,16 @@ div.row label {
background-color: #F9D2D2;
border: 3px solid #FF2A2A;
color: #FF2A00;
}
.errorlist ul {
float: left;
list-style: none;
}
.errorlist li {
margin-left: 10px;
float: left;
display: inline;
color: red;
}