wip: Webmail big refactoring and performance improvment

Better IMAP commands.
This commit is contained in:
Antoine Nguyen
2011-11-16 22:34:44 +01:00
parent 487266ecb5
commit f04862b28f
3 changed files with 71 additions and 41 deletions
+66 -40
View File
@@ -6,12 +6,14 @@
import imaplib, ssl, email
import re
from functools import wraps
from imapclient.response_parser import *
from imapclient.response_parser import parse_fetch_response
from modoboa.lib import parameters
from modoboa.lib.connections import *
from modoboa.lib.webutils import static_url
from exceptions import ImapError
imaplib.Debug = 4
class capability(object):
"""
Simple decorator to check if the server presents the required
@@ -66,12 +68,14 @@ class IMAPconnector(object):
"""
if name in ['FETCH', 'SORT', 'STORE']:
try:
typ, data = self.m.uid(name, *args, **kwargs)
typ, data = self.m.uid(name, *args)
except imaplib.IMAP4.error, e:
raise ImapError(e)
if typ == "NO":
raise ImapError(data)
return parse_fetch_response(data)
if name == 'FETCH':
return parse_fetch_response(data)
return data
try:
typ, data = self.m._simple_command(name, *args)
@@ -140,20 +144,39 @@ class IMAPconnector(object):
else:
criterion = "REVERSE DATE"
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.criterions)
self.select_mailbox(folder, False)
data = self._cmd("SORT", "(%s)" % criterion, "UTF-8", "(NOT DELETED)",
*self.criterions)
self.messages = data[0].split()
self.getquota(folder)
return len(self.messages)
def unseen_messages(self, folder):
"""Return the number of unseen messages for folder"""
self.m.select(self._encodefolder(folder), True)
status, data = self.m.search("UTF-8", "(NOT DELETED UNSEEN)")
if status != "OK":
return
return len(data[0].split())
def select_mailbox(self, name, readonly=True):
"""Issue a SELECT/EXAMINE command to the server
The given name is first 'imap-utf7' encoded.
:param name: mailbox's name
:param readonly:
"""
name = name.encode("imap4-utf-7")
if readonly:
self._cmd("EXAMINE", name)
else:
self._cmd("SELECT", name)
def unseen_messages(self, mailbox):
"""Return the number of unseen messages
:param mailbox: the mailbox's name
:return: an integer
"""
# self.select_mailbox(mailbox)
# data = self._cmd("SEARCH", "UTF-8", "(NOT DELETED UNSEEN)")
# return len(data[0].split())
data = self._cmd("STATUS", mailbox.encode("imap4-utf-7"), "(UNSEEN)")
print data
return 0
def _encodefolder(self, folder):
if not folder:
@@ -205,13 +228,27 @@ class IMAPconnector(object):
@capability('LIST-EXTENDED', '_listfolders_simple')
def _listfolders(self, topmailbox='', md_mailboxes=[]):
resp = self._cmd("LSUB", topmailbox, "%", "RETURN", "(CHILDREN)")
print resp
result = []
for mb in resp:
flags, delimiter, name, childinfo = \
self.listextended_response_pattern.match(mb).groups()
flags = flags.split(' ')
print flags
return []
name = name.decode("imap4-utf-7")
present = False
for mdm in md_mailboxes:
if mdm["name"] == name:
present = True
break
if present:
continue
descr = dict(name=name)
if r'\HasChildren' in flags:
descr["path"] = name
descr["sub"] = []
descr["class"] = "subfolders"
result += [descr]
from operator import itemgetter
return sorted(result, key=itemgetter("name"))
def getfolders(self, user, unseen_messages=True):
md_mailboxes = [{"name" : "INBOX", "class" : "inbox"},
@@ -314,11 +351,8 @@ class IMAPconnector(object):
msg = email.message_from_string(data[0][1] + data[1][1])
return msg
def fetch(self, start=None, stop=None, folder=None, all=False, **kwargs):
if not start and not stop:
return []
result = []
self.m.select(self._encodefolder(folder), True)
def fetch(self, start, stop=None, folder=None, all=False, **kwargs):
self.select_mailbox(folder, False)
if start and stop:
submessages = self.messages[start - 1:stop]
range = ",".join(submessages)
@@ -326,27 +360,19 @@ class IMAPconnector(object):
submessages = [start]
range = start
if not all:
query = '(FLAGS BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)])'
query = '(FLAGS BODYSTRUCTURE BODY.PEEK[HEADER.FIELDS (DATE FROM TO CC SUBJECT)])'
else:
query = '(RFC822)'
typ, data = self.m.fetch(range, query)
if not folder:
folder = "INBOX"
tmpdict = {}
for response_part in data:
if isinstance(response_part, tuple):
imapid = response_part[0].split()[0]
flags = imaplib.ParseFlags(response_part[0])
msg = email.message_from_string(response_part[1])
msg["imapid"] = imapid
if not "\\Seen" in flags:
msg["class"] = "unseen"
if "\\Answered" in flags:
msg["img_flags"] = static_url("pics/answered.png")
tmpdict[imapid] = msg
for id in submessages:
result += [tmpdict[id]]
data = self._cmd("FETCH", range, query)
result = []
for uid in submessages:
msg = email.message_from_string(data[int(uid)]['BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)]'])
msg['imapid'] = uid
if not r'\Seen' in data[int(uid)]['FLAGS']:
msg['class'] = 'unseen'
if r'\Answered' in data[int(uid)]['FLAGS']:
msg['img_flags'] = static_url('pics/answered.png')
result += [msg]
return result
def get_imapconnector(request):
+1 -1
View File
@@ -127,7 +127,7 @@ def print_folders(folders, selected=None, withunseen=False, withmenu=False):
if selected == name:
cssclass += " selected"
result += "<li name='%s' class='droppable %s'>\n" % (name, cssclass)
if fd.has_key("sub") and len(fd["sub"]):
if fd.has_key("sub"):
if selected is not None and selected != name and selected.count(name):
ul_state = "visible"
div_state = "expanded"
+4
View File
@@ -207,6 +207,10 @@ var AnchorNavigation = new Class({
url: query,
noCache : true,
onSuccess: function(resp) {
if (resp.status == "ko") {
infobox.error(resp.respmsg);
return;
}
var callback = ($defined(resp.callback)) ? resp.callback : "default";
this.callbacks[callback](resp);
infobox.info(gettext("Done"));