diff --git a/extensions/webmail/imap_listing.py b/extensions/webmail/imap_listing.py index 2a3fc2dbb..a09c55aa8 100644 --- a/extensions/webmail/imap_listing.py +++ b/extensions/webmail/imap_listing.py @@ -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 diff --git a/extensions/webmail/main.py b/extensions/webmail/main.py index d25263f7a..bb1a4158c 100644 --- a/extensions/webmail/main.py +++ b/extensions/webmail/main.py @@ -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) diff --git a/extensions/webmail/templates/compose.html b/extensions/webmail/templates/compose.html index 369cbbd62..99c3d3a7b 100644 --- a/extensions/webmail/templates/compose.html +++ b/extensions/webmail/templates/compose.html @@ -37,8 +37,7 @@ } -{% url extensions.webmail.main.compose as compurl %} -
+
{% include "common/genericform.html" %} diff --git a/extensions/webmail/templates/index.html b/extensions/webmail/templates/index.html index 80be116bb..9bbf339a4 100644 --- a/extensions/webmail/templates/index.html +++ b/extensions/webmail/templates/index.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)) { diff --git a/extensions/webmail/templatetags/webextras.py b/extensions/webmail/templatetags/webextras.py index 1941a9fe5..f36817730 100644 --- a/extensions/webmail/templatetags/webextras.py +++ b/extensions/webmail/templatetags/webextras.py @@ -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", diff --git a/extensions/webmail/urls.py b/extensions/webmail/urls.py index 84a3f3374..7bab03060 100644 --- a/extensions/webmail/urls.py +++ b/extensions/webmail/urls.py @@ -8,6 +8,7 @@ urlpatterns = patterns('mailng.extensions.webmail.main', (r'^(?P.+)/(?P[\w\-\+]+)/part/$', 'getattachment'), (r'^(?P.+)/(?P[\w\-\+]+)/delete/$', 'delete'), (r'^(?P.+)/(?P[\w\-\+]+)/content/$', 'getmailcontent'), + (r'^(?P.+)/(?P[\w\-\+]+)/forward/$', 'forward'), (r'^(?P.+)/(?P[\w\-\+]+)/reply/$', 'reply'), (r'^(?P.+)/(?P[\w\-\+]+)/$', 'viewmail'), (r'^(?P.+)/$', "folder"), diff --git a/static/stylesheets/default.css b/static/stylesheets/default.css index 9e8e6e7a2..809492b69 100644 --- a/static/stylesheets/default.css +++ b/static/stylesheets/default.css @@ -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; } \ No newline at end of file