mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merged in jpcaruana/modoboa/menage (pull request #2)
1st run througth the webmail module
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
|
||||
class Webmail(ModoExtension):
|
||||
@@ -11,23 +10,23 @@ class Webmail(ModoExtension):
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Simple IMAP webmail")
|
||||
needs_media = True
|
||||
|
||||
|
||||
def load(self):
|
||||
parameters.register_app(uparams_opts=dict(needs_mailbox=True))
|
||||
|
||||
parameters.register_admin("IMAP_SERVER", type="string",
|
||||
|
||||
parameters.register_admin("IMAP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your IMAP server"))
|
||||
parameters.register_admin("IMAP_SECURED", type="list_yesno",
|
||||
parameters.register_admin("IMAP_SECURED", type="list_yesno",
|
||||
deflt="no",
|
||||
help=ugettext_lazy("Use a secured connection to access IMAP server"))
|
||||
parameters.register_admin("IMAP_PORT", type="int", deflt="143",
|
||||
help=ugettext_lazy("Listening port of your IMAP server"))
|
||||
parameters.register_admin("SMTP_SERVER", type="string",
|
||||
parameters.register_admin("SMTP_SERVER", type="string",
|
||||
deflt="127.0.0.1",
|
||||
help=ugettext_lazy("Address of your SMTP server"))
|
||||
parameters.register_admin("SMTP_SECURED_MODE", type="list",
|
||||
values=[("none", ugettext_lazy("None")),
|
||||
parameters.register_admin("SMTP_SECURED_MODE", type="list",
|
||||
values=[("none", ugettext_lazy("None")),
|
||||
("starttls", "STARTTLS"),
|
||||
("ssl", "SSL/TLS")],
|
||||
deflt="none",
|
||||
@@ -39,7 +38,7 @@ class Webmail(ModoExtension):
|
||||
help=ugettext_lazy("Server needs authentication"))
|
||||
parameters.register_admin("MAX_ATTACHMENT_SIZE", type="int", deflt=2048,
|
||||
help=ugettext_lazy("Maximum attachment size in bytes (or KB, MB, GB if specified)"))
|
||||
|
||||
|
||||
parameters.register_user("MESSAGES_PER_PAGE", type="int", deflt=40,
|
||||
label=ugettext_lazy("Number of displayed emails per page"),
|
||||
help=ugettext_lazy("Sets the maximum number of messages displayed in a page"))
|
||||
@@ -99,9 +98,10 @@ def userlogout(request):
|
||||
try:
|
||||
m = IMAPconnector(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
# TODO silent exception are bad : we should at least log it
|
||||
return
|
||||
|
||||
|
||||
# The following statement may fail under Python 2.6...
|
||||
try:
|
||||
m.logout()
|
||||
|
||||
@@ -61,8 +61,7 @@ def parse_bodystructure(buf, depth=0, prefix=""):
|
||||
if nb_bodystruct == 0:
|
||||
ret.append(subret)
|
||||
elif nb_bodystruct == 1:
|
||||
newret = [ret.pop(-1)]
|
||||
newret.append(subret)
|
||||
newret = [ret.pop(-1), subret]
|
||||
ret.append(newret)
|
||||
else:
|
||||
ret[-1].append(subret)
|
||||
@@ -97,7 +96,7 @@ def parse_fetch_response(data):
|
||||
|
||||
We extract the message number, the UID and its value and consider
|
||||
what remains as the response data.
|
||||
|
||||
|
||||
:param data: the data returned by the ``imaplib`` command
|
||||
:return: a dictionnary
|
||||
"""
|
||||
@@ -182,7 +181,7 @@ def dump_bodystructure(bs, depth=0):
|
||||
dump_bodystructure(part, depth + 1)
|
||||
else:
|
||||
print "%s/%s" % (struct[0], struct[1])
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# resp = [('855 (UID 46931 BODYSTRUCTURE ((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 886 32 NIL NIL NIL NIL)("text" "html" ("charset" "us-ascii") NIL NIL "quoted-printable" 1208 16 NIL NIL NIL NIL) "alternative" ("boundary" "----=_NextPart_001_0003_01CCC564.B2F64FF0") NIL NIL NIL)("application" "octet-stream" ("name" "Carte Verte_2.pdf") NIL NIL "base64" 285610 NIL ("attachment" ("filename" "Carte Verte_2.pdf")) NIL NIL) "mixed" ("boundary" "----=_NextPart_000_0002_01CCC564.B2F64FF0") NIL NIL NIL) BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)] {153}', 'From: <Service.client10@maaf.fr>\r\nTo: <TONIO@NGYN.ORG>\r\nCc: \r\nSubject: Notre contact du 28/12/2011 - 192175092\r\nDate: Wed, 28 Dec 2011 13:29:17 +0100\r\n\r\n'), ')']
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# coding: utf-8
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
@@ -9,7 +10,7 @@ class ComposeMailForm(forms.Form):
|
||||
subject = forms.CharField(label=_("Subject"), max_length=255, required=False)
|
||||
|
||||
origmsgid = forms.CharField(label="", widget=forms.HiddenInput(), required=False)
|
||||
|
||||
|
||||
class FolderForm(forms.Form):
|
||||
oldname = forms.CharField(label="", widget=forms.HiddenInput(), required=False)
|
||||
name = forms.CharField()
|
||||
|
||||
@@ -9,10 +9,10 @@ import time
|
||||
from functools import wraps
|
||||
from django.utils.translation import ugettext as _
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.connections import *
|
||||
from modoboa.lib.connections import ConnectionsManager
|
||||
from modoboa.lib.webutils import static_url
|
||||
from exceptions import ImapError, WebmailError
|
||||
from fetch_parser import *
|
||||
from fetch_parser import parse_fetch_response
|
||||
|
||||
#imaplib.Debug = 4
|
||||
|
||||
@@ -75,12 +75,12 @@ class BodyStructure(object):
|
||||
* Any other MIME type is considered as an attachment (for now)
|
||||
|
||||
:param definition: a part definition (list)
|
||||
:param prefix: the part's number
|
||||
:param pnum: the part's number
|
||||
:param multisubtype: the multipart subtype
|
||||
"""
|
||||
pnum = "1" if pnum is None else pnum
|
||||
params = dict(pnum=pnum, params=definition[2], cid=definition[3],
|
||||
description=definition[4], encoding=definition[5],
|
||||
description=definition[4], encoding=definition[5],
|
||||
size=definition[6])
|
||||
mtype = definition[0].lower()
|
||||
subtype = definition[1].lower()
|
||||
@@ -122,7 +122,7 @@ class BodyStructure(object):
|
||||
for part in struct[0]:
|
||||
self.load_from_definition(part, struct[1])
|
||||
return
|
||||
|
||||
|
||||
self.__store_part(struct, pnum, multisubtype)
|
||||
|
||||
def has_attachments(self):
|
||||
@@ -214,7 +214,7 @@ class IMAPconnector(object):
|
||||
cpt += 1
|
||||
else:
|
||||
if bodystruct[0].lower() == mtype and bodystruct[1].lower() == stype:
|
||||
return ("1" if not len(prefix) else prefix,
|
||||
return ("1" if not len(prefix) else prefix,
|
||||
bodystruct[5], int(bodystruct[6]))
|
||||
return (None, None, 0)
|
||||
|
||||
@@ -230,12 +230,12 @@ class IMAPconnector(object):
|
||||
if hasattr(self, "current_mailbox"):
|
||||
del self.current_mailbox
|
||||
else:
|
||||
return
|
||||
return
|
||||
self.login(user, password)
|
||||
|
||||
def login(self, user, passwd):
|
||||
"""Custom login method
|
||||
|
||||
|
||||
We connect to the server, issue a LOGIN command. If
|
||||
successfull, we try to record a eventuel CAPABILITY untagged
|
||||
response. Otherwise, we issue the command.
|
||||
@@ -305,9 +305,9 @@ class IMAPconnector(object):
|
||||
"""Issue a SELECT/EXAMINE command to the server
|
||||
|
||||
The given name is first 'imap-utf7' encoded.
|
||||
|
||||
|
||||
:param name: mailbox's name
|
||||
:param readonly:
|
||||
:param readonly:
|
||||
"""
|
||||
if hasattr(self, "current_mailbox"):
|
||||
if self.current_mailbox == name and not force:
|
||||
@@ -348,35 +348,35 @@ class IMAPconnector(object):
|
||||
break
|
||||
if sdescr is None:
|
||||
sdescr = {"name" : parts[0], "path" : path, "sub" : []}
|
||||
descr += [sdescr]
|
||||
descr += [sdescr]
|
||||
if self._parse_mailbox_name(sdescr["sub"], path, delimiter, parts[1:]):
|
||||
sdescr["class"] = "subfolders"
|
||||
return True
|
||||
|
||||
def _listmboxes_simple(self, topmailbox='INBOX', mailboxes=[], **kwargs):
|
||||
def _listmboxes_simple(self, topmailbox='INBOX', mailboxes=None, **kwargs):
|
||||
#data = self._cmd("LIST", "", "*")
|
||||
if not mailboxes: mailboxes = []
|
||||
(status, data) = self.m.list()
|
||||
result = []
|
||||
newmboxes = []
|
||||
for mb in data:
|
||||
flags, delimiter, name = self.list_response_pattern.match(mb).groups()
|
||||
name = name.strip('"').decode("imap4-utf-7")
|
||||
pos = -1
|
||||
mdm_found = False
|
||||
for idx, mdm in enumerate(mailboxes):
|
||||
if mdm["name"] == name:
|
||||
pos = idx
|
||||
mdm_found = True
|
||||
descr = mailboxes[idx]
|
||||
break
|
||||
if pos == -1:
|
||||
if not mdm_found:
|
||||
descr = dict(name=name)
|
||||
newmboxes += [descr]
|
||||
else:
|
||||
descr = mailboxes[idx]
|
||||
|
||||
if re.search("\%s" % delimiter, name):
|
||||
parts = name.split(".")
|
||||
if not descr.has_key("path"):
|
||||
descr["path"] = parts[0]
|
||||
descr["sub"] = []
|
||||
if self._parse_mailbox_name(descr["sub"], parts[0], delimiter,
|
||||
if self._parse_mailbox_name(descr["sub"], parts[0], delimiter,
|
||||
parts[1:]):
|
||||
descr["class"] = "subfolders"
|
||||
continue
|
||||
@@ -385,7 +385,8 @@ class IMAPconnector(object):
|
||||
mailboxes += sorted(newmboxes, key=itemgetter("name"))
|
||||
|
||||
@capability('LIST-EXTENDED', '_listmboxes_simple')
|
||||
def _listmboxes(self, topmailbox='', mailboxes=[], until_mailbox=None):
|
||||
def _listmboxes(self, topmailbox='', mailboxes=None, until_mailbox=None):
|
||||
if not mailboxes: mailboxes = []
|
||||
pattern = ("%s.%%" % topmailbox.encode("imap4-utf-7")) if len(topmailbox) else "%"
|
||||
resp = self._cmd("LIST", "", pattern, "RETURN", "(CHILDREN)")
|
||||
newmboxes = []
|
||||
@@ -394,17 +395,16 @@ class IMAPconnector(object):
|
||||
self.listextended_response_pattern.match(mb).groups()
|
||||
flags = flags.split(' ')
|
||||
name = name.decode("imap4-utf-7")
|
||||
pos = -1
|
||||
mdm_found = False
|
||||
for idx, mdm in enumerate(mailboxes):
|
||||
if mdm["name"] == name:
|
||||
pos = idx
|
||||
mdm_found = True
|
||||
descr = mailboxes[idx]
|
||||
break
|
||||
if pos == -1:
|
||||
if not mdm_found:
|
||||
descr = dict(name=name)
|
||||
newmboxes += [descr]
|
||||
else:
|
||||
descr = mailboxes[idx]
|
||||
|
||||
|
||||
if r'\Marked' in flags or not r'\UnMarked' in flags:
|
||||
descr["send_status"] = True
|
||||
if r'\HasChildren' in flags:
|
||||
@@ -433,7 +433,7 @@ class IMAPconnector(object):
|
||||
md_mailboxes = []
|
||||
else:
|
||||
md_mailboxes = [{"name" : "INBOX", "class" : "icon-inbox"},
|
||||
{"name" : parameters.get_user(user, "DRAFTS_FOLDER"),
|
||||
{"name" : parameters.get_user(user, "DRAFTS_FOLDER"),
|
||||
"class" : "icon-file"},
|
||||
{"name" : 'Junk', "class" : "icon-fire"},
|
||||
{"name" : parameters.get_user(user, "SENT_FOLDER"),
|
||||
@@ -515,7 +515,7 @@ class IMAPconnector(object):
|
||||
"""Compact a specific mailbox
|
||||
|
||||
Issue an EXPUNGE command for the specified mailbox.
|
||||
|
||||
|
||||
:param mbox: the mailbox's name
|
||||
"""
|
||||
self.select_mailbox(mbox, False)
|
||||
@@ -547,12 +547,12 @@ class IMAPconnector(object):
|
||||
self.quota_limit = self.quota_actual = None
|
||||
return
|
||||
|
||||
data = self._cmd("GETQUOTAROOT", self._encode_mbox_name(mailbox),
|
||||
data = self._cmd("GETQUOTAROOT", self._encode_mbox_name(mailbox),
|
||||
responses=["QUOTAROOT", "QUOTA"])
|
||||
if data is None:
|
||||
self.quota_limit = self.quota_actual = None
|
||||
return
|
||||
|
||||
|
||||
quotadef = data[1][0]
|
||||
m = re.match("[^\s]+ \(STORAGE (\d+) (\d+)\)", quotadef)
|
||||
if not m:
|
||||
@@ -628,14 +628,14 @@ class IMAPconnector(object):
|
||||
:param mbox: the mailbox containing the message
|
||||
:param mailid: the message's unique id
|
||||
:param readonly:
|
||||
:param extraheaders:
|
||||
:param headers:
|
||||
"""
|
||||
self.select_mailbox(mbox, readonly)
|
||||
if headers is None:
|
||||
headers = ['DATE', 'FROM', 'TO', 'CC', 'SUBJECT']
|
||||
bcmd = "BODY.PEEK" if readonly else "BODY"
|
||||
data = self._cmd(
|
||||
"FETCH", mailid,
|
||||
"FETCH", mailid,
|
||||
"(BODYSTRUCTURE %s[HEADER.FIELDS (%s)])" % (bcmd, " ".join(headers))
|
||||
)
|
||||
return data[int(mailid)]
|
||||
@@ -658,7 +658,7 @@ def get_imapconnector(request):
|
||||
|
||||
:param request: a ``Request`` object
|
||||
"""
|
||||
imapc = IMAPconnector(user=request.user.username,
|
||||
imapc = IMAPconnector(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
return imapc
|
||||
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
# coding: utf-8
|
||||
|
||||
import sys, os
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
import email
|
||||
import lxml
|
||||
import chardet
|
||||
from django.core.files.uploadhandler import FileUploadHandler, StopUpload, SkipFile
|
||||
from django.http import HttpResponse
|
||||
|
||||
from django.core.files.uploadhandler import FileUploadHandler, SkipFile
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.conf import settings
|
||||
from modoboa.lib import u2u_decode, tables, imap_utf7, parameters
|
||||
from modoboa.lib.webutils import static_url, size2integer
|
||||
from modoboa.lib.connections import ConnectionsManager
|
||||
from modoboa.lib.email_listing import MBconnector, EmailListing
|
||||
from modoboa.lib.emailutils import *
|
||||
|
||||
from imaputils import *
|
||||
from exceptions import *
|
||||
import os
|
||||
import re
|
||||
from modoboa.lib import u2u_decode, tables, parameters
|
||||
from modoboa.lib.webutils import size2integer
|
||||
from modoboa.lib.email_listing import EmailListing
|
||||
from modoboa.extensions.webmail.exceptions import WebmailError
|
||||
from modoboa.extensions.webmail.imaputils import IMAPconnector, get_imapconnector, BodyStructure
|
||||
from modoboa.lib.emailutils import EmailAddress, Email
|
||||
|
||||
|
||||
class WMtable(tables.Table):
|
||||
tableid = "emails"
|
||||
styles = "table-condensed"
|
||||
idkey = "imapid"
|
||||
select = tables.ImgColumn(
|
||||
"select", cssclass="draggable left", width="2%",
|
||||
"select", cssclass="draggable left", width="2%",
|
||||
defvalue="%spics/grippy.png" % settings.STATIC_URL,
|
||||
header="<input type='checkbox' name='toggleselect' id='toggleselect' />"
|
||||
)
|
||||
@@ -112,7 +111,7 @@ class ImapListing(EmailListing):
|
||||
deflocation = "INBOX/"
|
||||
defcallback = "wm_updatelisting"
|
||||
reset_wm_url = False
|
||||
|
||||
|
||||
def __init__(self, user, password, **kwargs):
|
||||
self.user = user
|
||||
self.mbc = IMAPconnector(user=user.username, password=password)
|
||||
@@ -165,7 +164,7 @@ class ImapEmail(Email):
|
||||
('Subject', True),
|
||||
]
|
||||
|
||||
def __init__(self, mbox, mailid, request, dformat="DISPLAYMODE", addrfull=False,
|
||||
def __init__(self, mbox, mailid, request, dformat="DISPLAYMODE", addrfull=False,
|
||||
links=0):
|
||||
mformat = parameters.get_user(request.user, "DISPLAYMODE")
|
||||
self.dformat = parameters.get_user(request.user, dformat)
|
||||
@@ -179,7 +178,7 @@ class ImapEmail(Email):
|
||||
self.mailid = mailid
|
||||
headers = msg['BODY[HEADER.FIELDS (%s)]' % self.headers_as_text]
|
||||
fallback_fmt = "html" if self.dformat == "plain" else "plain"
|
||||
|
||||
|
||||
self.bs = BodyStructure(msg['BODYSTRUCTURE'])
|
||||
data = None
|
||||
|
||||
@@ -206,7 +205,7 @@ class ImapEmail(Email):
|
||||
getattr(self, "viewmail_%s" % mformat)(bodyc, links=links)
|
||||
else:
|
||||
self.body = None
|
||||
|
||||
|
||||
self._find_attachments()
|
||||
|
||||
msg = email.message_from_string(headers)
|
||||
@@ -257,7 +256,7 @@ class ImapEmail(Email):
|
||||
att.has_key("disposition") and len(att["disposition"]) > 1:
|
||||
params = att["disposition"][1]
|
||||
key = "filename"
|
||||
|
||||
|
||||
if key and params:
|
||||
for pos, value in enumerate(params):
|
||||
if value == key:
|
||||
@@ -311,7 +310,7 @@ class Modifier(ImapEmail):
|
||||
def _modify_html(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class ReplyModifier(Modifier):
|
||||
headernames = ImapEmail.headernames + \
|
||||
[("Reply-To", True),
|
||||
@@ -358,13 +357,13 @@ class ReplyModifier(Modifier):
|
||||
body += "\n"
|
||||
body += ">%s" % l
|
||||
self.body = body
|
||||
|
||||
|
||||
class ForwardModifier(Modifier):
|
||||
def __init__(self, mbox, mailid, request, form, **kwargs):
|
||||
super(ForwardModifier, self).__init__(
|
||||
mbox, mailid, request, dformat="EDITOR", **kwargs
|
||||
)
|
||||
|
||||
|
||||
self._header()
|
||||
form.fields["from_"].initial = request.user.username
|
||||
form.fields["subject"].initial = "Fwd: %s" % self.Subject
|
||||
@@ -488,7 +487,7 @@ def find_images_in_body(body):
|
||||
% (ct, os.path.basename(fname)))
|
||||
p["Content-Disposition"] = "inline"
|
||||
parts.append(p)
|
||||
|
||||
|
||||
return lxml.html.tostring(html), parts
|
||||
|
||||
def set_compose_session(request):
|
||||
@@ -557,7 +556,7 @@ def html2plaintext(content):
|
||||
if p is None:
|
||||
continue
|
||||
plaintext += p + "\n"
|
||||
|
||||
|
||||
return plaintext
|
||||
|
||||
def get_current_url(request):
|
||||
@@ -603,7 +602,7 @@ def send_mail(request, posturl=None):
|
||||
"""
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from forms import ComposeMailForm
|
||||
from modoboa.lib.webutils import getctx, ajax_simple_response, _render_to_string
|
||||
from modoboa.lib.webutils import _render_to_string
|
||||
from modoboa.auth.lib import get_password
|
||||
|
||||
form = ComposeMailForm(request.POST)
|
||||
@@ -623,13 +622,13 @@ def send_mail(request, posturl=None):
|
||||
submsg.attach(MIMEText(textbody.encode(charset),
|
||||
_subtype="plain", _charset=charset))
|
||||
body, images = find_images_in_body(body)
|
||||
submsg.attach(MIMEText(body.encode(charset), _subtype=editormode,
|
||||
submsg.attach(MIMEText(body.encode(charset), _subtype=editormode,
|
||||
_charset=charset))
|
||||
msg.attach(submsg)
|
||||
for img in images:
|
||||
msg.attach(img)
|
||||
else:
|
||||
text = MIMEText(body.encode(charset),
|
||||
text = MIMEText(body.encode(charset),
|
||||
_subtype=editormode, _charset=charset)
|
||||
if len(request.session["compose_mail"]["attachments"]):
|
||||
msg = MIMEMultipart()
|
||||
@@ -686,7 +685,7 @@ def send_mail(request, posturl=None):
|
||||
del request.session["compose_mail"]
|
||||
return True, dict(url=get_current_url(request))
|
||||
|
||||
listing = _render_to_string(request, "webmail/compose.html",
|
||||
listing = _render_to_string(request, "webmail/compose.html",
|
||||
{"form" : form, "noerrors" : True,
|
||||
"body" : request.POST["id_body"].strip(),
|
||||
"posturl" : posturl})
|
||||
@@ -698,19 +697,19 @@ class AttachmentUploadHandler(FileUploadHandler):
|
||||
Simple upload handler to limit the size of the attachments users
|
||||
can upload.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, request=None):
|
||||
super(AttachmentUploadHandler, self).__init__(request)
|
||||
self.total_upload = 0
|
||||
self.toobig = False
|
||||
self.maxsize = size2integer(parameters.get_admin("MAX_ATTACHMENT_SIZE"))
|
||||
|
||||
|
||||
def receive_data_chunk(self, raw_data, start):
|
||||
self.total_upload += len(raw_data)
|
||||
if self.total_upload >= self.maxsize:
|
||||
self.toobig = True
|
||||
raise SkipFile()
|
||||
return raw_data
|
||||
|
||||
|
||||
def file_complete(self, file_size):
|
||||
return None
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# coding: utf-8
|
||||
|
||||
from modoboa.lib.webutils import ajax_response, _render_error
|
||||
from modoboa.extensions.webmail.exceptions import *
|
||||
from modoboa.extensions.webmail.exceptions import WebmailError, ImapError
|
||||
|
||||
class WebmailErrorMiddleware(object):
|
||||
def process_exception(self, request, exception):
|
||||
@@ -10,6 +9,6 @@ class WebmailErrorMiddleware(object):
|
||||
json = request.GET.get("json", False) if request.method == "GET" \
|
||||
else request.POST.get("json", False)
|
||||
if json:
|
||||
return ajax_response(request, status="ko",
|
||||
return ajax_response(request, status="ko",
|
||||
respmsg=str(exception), norefresh=True)
|
||||
return _render_error(request, user_context=dict(error=str(exception)))
|
||||
|
||||
@@ -5,15 +5,13 @@ from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from modoboa.extensions import webmail
|
||||
from modoboa.extensions.webmail.lib import IMAPheader
|
||||
from modoboa.extensions.webmail.imaputils import separate_mailbox
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.webutils import static_url
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def viewmail_menu(selection, folder, user, mail_id=None):
|
||||
def viewmail_menu(selection, folder, user, mail_id=None):
|
||||
entries = [
|
||||
{"name" : "reply",
|
||||
"url" : "action=reply&mbox=%s&mailid=%s" % (folder, mail_id),
|
||||
@@ -34,21 +32,21 @@ def viewmail_menu(selection, folder, user, mail_id=None):
|
||||
{"name" : "display_options",
|
||||
"label" : _("Display options"),
|
||||
"menu" : [
|
||||
{"name" : "activate_links",
|
||||
{"name" : "activate_links",
|
||||
"label" : _("Activate links")},
|
||||
{"name" : "disable_links",
|
||||
{"name" : "disable_links",
|
||||
"label" : _("Disable links")}
|
||||
]
|
||||
}
|
||||
]
|
||||
menu = render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
menu = render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"user" : user, "extraclasses" : "pull-left"})
|
||||
|
||||
entries = [{"name" : "close",
|
||||
"title" : _("Close this message"),
|
||||
"img" : "icon-remove"}]
|
||||
menu += render_to_string('common/buttons_list.html',
|
||||
menu += render_to_string('common/buttons_list.html',
|
||||
{"entries" : entries, "extraclasses" : "pull-right"})
|
||||
|
||||
return menu
|
||||
@@ -65,8 +63,8 @@ def compose_menu(selection, backurl, user):
|
||||
"img" : "icon-envelope",
|
||||
"label" : _("Send")},
|
||||
]
|
||||
return render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
return render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"user" : user})
|
||||
|
||||
@register.simple_tag
|
||||
@@ -136,7 +134,7 @@ def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False):
|
||||
ul_state = "hidden"
|
||||
div_state = "collapsed"
|
||||
result += "<div class='clickbox %s'></div>" % div_state
|
||||
|
||||
|
||||
cssclass = "block"
|
||||
extra_attrs = ""
|
||||
if withunseen and mbox.has_key("unseen"):
|
||||
@@ -148,7 +146,7 @@ def print_mailboxes(tree, selected=None, withunseen=False, selectonly=False):
|
||||
<i class="%s"></i>
|
||||
%s
|
||||
</a>
|
||||
""" % (mbox.has_key("path") and mbox["path"] or mbox["name"], cssclass,
|
||||
""" % (mbox.has_key("path") and mbox["path"] or mbox["name"], cssclass,
|
||||
'selectfolder' if selectonly else 'loadfolder', extra_attrs, iclass, label)
|
||||
if mbox.has_key("sub") and len(mbox["sub"]):
|
||||
result += "<ul name='%s' class='nav nav-list %s'>" % (mbox["path"], ul_state) \
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.conf.urls.defaults import *
|
||||
# coding: utf-8
|
||||
from django.conf.urls.defaults import patterns
|
||||
|
||||
urlpatterns = patterns(
|
||||
'modoboa.extensions.webmail.views',
|
||||
@@ -6,7 +7,7 @@ urlpatterns = patterns(
|
||||
(r'^submailboxes', "submailboxes"),
|
||||
(r'^getmailcontent', 'getmailcontent'),
|
||||
(r'^unseenmsgs', 'check_unseen_messages'),
|
||||
|
||||
|
||||
(r'^delete/$', 'delete'),
|
||||
(r'^move/$', "move"),
|
||||
(r'^mark/(?P<name>.+)/$', "mark"),
|
||||
@@ -15,8 +16,8 @@ urlpatterns = patterns(
|
||||
(r'^newfolder/$', "newfolder"),
|
||||
(r'^editfolder/$', 'editfolder'),
|
||||
(r'^delfolder/$', 'delfolder'),
|
||||
|
||||
|
||||
(r'^attachments/$', 'attachments'),
|
||||
(r'^delattachment/$', 'delattachment'),
|
||||
(r'^getattachment/$', 'getattachment'),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
# coding: utf-8
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.conf import settings
|
||||
import os
|
||||
from django.http import HttpResponse
|
||||
from django.template import Template, Context
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.webutils import _render, _render_error, \
|
||||
getctx, _render_to_string, ajax_response, ajax_simple_response
|
||||
from modoboa.lib.email_listing import parse_search_parameters
|
||||
from modoboa.lib.webutils import _render, _render_to_string, ajax_response, ajax_simple_response
|
||||
from modoboa.lib.decorators import needs_mailbox
|
||||
from modoboa.auth.lib import *
|
||||
from lib import *
|
||||
from forms import *
|
||||
from exceptions import WebmailError
|
||||
from forms import FolderForm, AttachmentForm, ComposeMailForm
|
||||
from imaputils import get_imapconnector, IMAPconnector, separate_mailbox
|
||||
from lib import decode_payload, AttachmentUploadHandler, save_attachment, ImapListing, EmailSignature, clean_attachments, set_compose_session, send_mail, ImapEmail
|
||||
from templatetags import webextras
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def getattachment(request):
|
||||
"""Fetch a message attachment
|
||||
|
||||
|
||||
FIXME: par manque de caching, le bodystructure du message est
|
||||
redemandé pour accéder aux headers de cette pièce jointe.
|
||||
|
||||
:param request: a ``Request`` object
|
||||
:param folder
|
||||
"""
|
||||
mbox = request.GET.get("mbox", None)
|
||||
mailid = request.GET.get("mailid", None)
|
||||
pnum = request.GET.get("partnumber", None)
|
||||
if not mbox or not mailid or not pnum:
|
||||
raise WebmailError(_("Invalid request"))
|
||||
|
||||
|
||||
headers = {"Content-Type" : "text/plain",
|
||||
"Content-Transfer-Encoding" : None}
|
||||
imapc = get_imapconnector(request)
|
||||
@@ -51,7 +51,7 @@ def getattachment(request):
|
||||
resp["Content-Disposition"] = cd
|
||||
resp["Content-Length"] = partdef["size"]
|
||||
return resp
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def move(request):
|
||||
@@ -115,17 +115,17 @@ def compact(request, name):
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def newfolder(request, tplname="webmail/folder.html"):
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
ctx = {"title" : _("Create a new mailbox"),
|
||||
"formid" : "mboxform",
|
||||
"action" : reverse(newfolder),
|
||||
"action_label" : _("Create"),
|
||||
"action_classes" : "submit",
|
||||
"withunseen" : False,
|
||||
"selectonly" : True}
|
||||
ctx = {"title": _("Create a new mailbox"),
|
||||
"formid": "mboxform",
|
||||
"action": reverse(newfolder),
|
||||
"action_label": _("Create"),
|
||||
"action_classes": "submit",
|
||||
"withunseen": False,
|
||||
"selectonly": True,
|
||||
"mboxes": mbc.getmboxes(request.user)}
|
||||
|
||||
ctx["mboxes"] = mbc.getmboxes(request.user)
|
||||
if request.method == "POST":
|
||||
form = FolderForm(request.POST)
|
||||
if form.is_valid():
|
||||
@@ -134,11 +134,11 @@ def newfolder(request, tplname="webmail/folder.html"):
|
||||
return ajax_simple_response(dict(
|
||||
status="ok", respmsg=_("Mailbox created"), newmb=form.cleaned_data["name"], parent=pf
|
||||
))
|
||||
|
||||
|
||||
ctx["form"] = form
|
||||
ctx["selected"] = None
|
||||
return ajax_response(request, status="ko", template=tplname, **ctx)
|
||||
|
||||
|
||||
ctx["form"] = FolderForm()
|
||||
ctx["selected"] = None
|
||||
return _render(request, tplname, ctx)
|
||||
@@ -146,7 +146,7 @@ def newfolder(request, tplname="webmail/folder.html"):
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def editfolder(request, tplname="webmail/folder.html"):
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
ctx = {"title" : _("Edit mailbox"),
|
||||
"formid" : "mboxform",
|
||||
@@ -197,7 +197,7 @@ def delfolder(request):
|
||||
name = request.GET.get("name", None)
|
||||
if name is None:
|
||||
raise WebmailError(_("Bad request"))
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
mbc = IMAPconnector(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
mbc.delete_folder(name)
|
||||
if request.session.has_key("mbox"):
|
||||
@@ -217,7 +217,7 @@ def attachments(request, tplname="webmail/attachments.html"):
|
||||
fobj = request.FILES["attachment"]
|
||||
tmpname = save_attachment(fobj)
|
||||
request.session["compose_mail"]["attachments"] \
|
||||
+= [{"fname" : str(fobj),
|
||||
+= [{"fname" : str(fobj),
|
||||
"content-type" : fobj.content_type,
|
||||
"size" : fobj.size,
|
||||
"tmpname" : os.path.basename(tmpname)}]
|
||||
@@ -225,7 +225,7 @@ def attachments(request, tplname="webmail/attachments.html"):
|
||||
return _render(request, "webmail/upload_done.html", {
|
||||
"status" : "ok", "fname" : request.FILES["attachment"],
|
||||
"tmpname" : os.path.basename(tmpname)
|
||||
});
|
||||
})
|
||||
except WebmailError, inst:
|
||||
error = _("Failed to save attachment: ") + str(inst)
|
||||
|
||||
@@ -234,7 +234,7 @@ def attachments(request, tplname="webmail/attachments.html"):
|
||||
% parameters.get_admin("MAX_ATTACHMENT_SIZE"))
|
||||
return _render(request, "webmail/upload_done.html", {
|
||||
"status" : "ko", "error" : error
|
||||
});
|
||||
})
|
||||
ctx = {
|
||||
"title" : _("Attachments"),
|
||||
"formid" : "uploadfile",
|
||||
@@ -274,7 +274,7 @@ def render_mboxes_list(request, imapc):
|
||||
"""Return the HTML representation of a mailboxes list
|
||||
|
||||
:param request: a ``Request`` object
|
||||
:param imap: an ``IMAPconnector` object
|
||||
:param imapc: an ``IMAPconnector` object
|
||||
:return: a string
|
||||
"""
|
||||
curmbox = request.session.get("mbox", "INBOX")
|
||||
@@ -287,7 +287,7 @@ def render_mboxes_list(request, imapc):
|
||||
def set_nav_params(request):
|
||||
if not request.session.has_key("navparams"):
|
||||
request.session["navparams"] = {}
|
||||
|
||||
|
||||
request.session["pageid"] = \
|
||||
int(request.GET.get("page", 1))
|
||||
if not request.GET.get("order", False):
|
||||
@@ -320,7 +320,7 @@ def listmailbox(request, defmailbox="INBOX", update_session=True):
|
||||
|
||||
lst = ImapListing(request.user, request.session["password"],
|
||||
baseurl="?action=listmailbox&mbox=%s&" % mbox,
|
||||
folder=mbox,
|
||||
folder=mbox,
|
||||
elems_per_page=int(parameters.get_user(request.user, "MESSAGES_PER_PAGE")),
|
||||
**request.session["navparams"])
|
||||
return lst.render(request, request.session["pageid"])
|
||||
@@ -348,7 +348,7 @@ def render_compose(request, form, posturl, email=None, insert_signature=False):
|
||||
attachments = request.session["compose_mail"]["attachments"]
|
||||
if len(attachments):
|
||||
short_att_list = "(%s)" \
|
||||
% ", ".join(map(lambda att: att["fname"],
|
||||
% ", ".join(map(lambda att: att["fname"],
|
||||
attachments[:2] + [{"fname" : "..."}] \
|
||||
if len(attachments) > 2 else attachments))
|
||||
else:
|
||||
@@ -412,7 +412,7 @@ def getmailcontent(request):
|
||||
raise WebmailError(_("Invalid request"))
|
||||
email = ImapEmail(mbox, mailid, request, links=int(request.GET["links"]))
|
||||
return _render(request, "common/viewmail.html", {
|
||||
"headers" : email.render_headers(folder=mbox, mail_id=mailid),
|
||||
"headers" : email.render_headers(folder=mbox, mail_id=mailid),
|
||||
"folder" : mbox, "imapid" : mailid, "mailbody" : email.body if email.body else ""
|
||||
})
|
||||
|
||||
@@ -484,7 +484,7 @@ def index(request):
|
||||
if action is not None:
|
||||
if not globals().has_key(action):
|
||||
raise WebmailError(_("Undefined action"))
|
||||
response = globals()[action](request)
|
||||
response = globals()[action](request)
|
||||
else:
|
||||
if request.is_ajax():
|
||||
raise WebmailError(_("Bad request"))
|
||||
@@ -499,11 +499,11 @@ def index(request):
|
||||
response["refreshrate"] = \
|
||||
int(parameters.get_user(request.user, "REFRESH_INTERVAL"))
|
||||
response["quota"] = ImapListing.computequota(imapc)
|
||||
response["ro_mboxes"] = ["INBOX", "Junk",
|
||||
response["ro_mboxes"] = ["INBOX", "Junk",
|
||||
parameters.get_user(request.user, "SENT_FOLDER"),
|
||||
parameters.get_user(request.user, "TRASH_FOLDER"),
|
||||
parameters.get_user(request.user, "DRAFTS_FOLDER")]
|
||||
|
||||
|
||||
return _render(request, "webmail/index.html", response)
|
||||
|
||||
if action in ["reply", "forward"]:
|
||||
|
||||
Reference in New Issue
Block a user