mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
Email forwarding.
This commit is contained in:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user