summaryrefslogtreecommitdiff
path: root/src/leap/mail/imap/mailbox.py
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2014-01-16 18:55:22 -0300
committerTomás Touceda <chiiph@leap.se>2014-01-16 18:55:22 -0300
commite3692d50ca2fa4110ba37322b1f46d71d93ac135 (patch)
tree951497ce242b3ad165764c295fcd80fe4b253b82 /src/leap/mail/imap/mailbox.py
parent06eebf54ab572ebaf6730f2095a062cd9549f12e (diff)
parent6c7207a5667d8158572b2a900a3506e3c3ecc6e5 (diff)
Merge remote-tracking branch 'refs/remotes/kali/bug/fix-store-iteration' into develop
Diffstat (limited to 'src/leap/mail/imap/mailbox.py')
-rw-r--r--src/leap/mail/imap/mailbox.py105
1 files changed, 61 insertions, 44 deletions
diff --git a/src/leap/mail/imap/mailbox.py b/src/leap/mail/imap/mailbox.py
index 94070ac..cf09bc4 100644
--- a/src/leap/mail/imap/mailbox.py
+++ b/src/leap/mail/imap/mailbox.py
@@ -463,9 +463,40 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
if not self.isWriteable():
raise imap4.ReadOnlyMailbox
d = self.messages.remove_all_deleted()
+ d.addCallback(self.messages.reset_last_uid)
d.addCallback(self._expunge_cb)
return d
+ def _bound_seq(self, messages_asked):
+ """
+ Put an upper bound to a messages sequence if this is open.
+
+ :param messages_asked: IDs of the messages.
+ :type messages_asked: MessageSet
+ :rtype: MessageSet
+ """
+ if not messages_asked.last:
+ try:
+ iter(messages_asked)
+ except TypeError:
+ # looks like we cannot iterate
+ messages_asked.last = self.last_uid
+ return messages_asked
+
+ def _filter_msg_seq(self, messages_asked):
+ """
+ Filter a message sequence returning only the ones that do exist in the
+ collection.
+
+ :param messages_asked: IDs of the messages.
+ :type messages_asked: MessageSet
+ :rtype: set
+ """
+ set_asked = set(messages_asked)
+ set_exist = set(self.messages.all_uid_iter())
+ seq_messg = set_asked.intersection(set_exist)
+ return seq_messg
+
@deferred
def fetch(self, messages_asked, uid):
"""
@@ -495,17 +526,13 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
sequence = False
#sequence = True if uid == 0 else False
- if not messages_asked.last:
- try:
- iter(messages_asked)
- except TypeError:
- # looks like we cannot iterate
- messages_asked.last = self.last_uid
+ messages_asked = self._bound_seq(messages_asked)
+ seq_messg = self._filter_msg_seq(messages_asked)
- set_asked = set(messages_asked)
- set_exist = set(self.messages.all_uid_iter())
- seq_messg = set_asked.intersection(set_exist)
- getmsg = lambda msgid: self.messages.get_msg_by_uid(msgid)
+ def getmsg(msgid):
+ if self.isWriteable():
+ deferLater(reactor, 2, self._unset_recent_flag, messages_asked)
+ return self.messages.get_msg_by_uid(msgid)
# for sequence numbers (uid = 0)
if sequence:
@@ -515,12 +542,6 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
else:
result = ((msgid, getmsg(msgid)) for msgid in seq_messg)
- if self.isWriteable():
- deferLater(reactor, 30, self._unset_recent_flag)
- # XXX I should rewrite the scheduler so it handles a
- # set of queues with different priority.
- self._unset_recent_flag()
-
# this should really be called as a final callback of
# the do_FETCH method...
deferLater(reactor, 1, self._signal_unread_to_ui)
@@ -532,6 +553,7 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
A fast method to fetch all flags, tricking just the
needed subset of the MIME interface that's needed to satisfy
a generic FLAGS query.
+
Given how LEAP Mail is supposed to work without local cache,
this query is going to be quite common, and also we expect
it to be in the form 1:* at the beginning of a session, so
@@ -561,23 +583,16 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
def getFlags(self):
return map(str, self.flags)
- if not messages_asked.last:
- try:
- iter(messages_asked)
- except TypeError:
- # looks like we cannot iterate
- messages_asked.last = self.last_uid
+ messages_asked = self._bound_seq(messages_asked)
+ seq_messg = self._filter_msg_seq(messages_asked)
- set_asked = set(messages_asked)
- set_exist = set(self.messages.all_uid_iter())
- seq_messg = set_asked.intersection(set_exist)
all_flags = self.messages.all_flags()
result = ((msgid, flagsPart(
msgid, all_flags[msgid])) for msgid in seq_messg)
return result
@deferred
- def _unset_recent_flag(self):
+ def _unset_recent_flag(self, message_uid):
"""
Unsets `Recent` flag from a tuple of messages.
Called from fetch.
@@ -593,19 +608,16 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
If it is not possible to determine whether or not this
session is the first session to be notified about a message,
then that message SHOULD be considered recent.
- """
- # TODO this fucker, for the sake of correctness, is messing with
- # the whole collection of flag docs.
- # Possible ways of action:
- # 1. Ignore it, we want fun.
- # 2. Trigger it with a delay
- # 3. Route it through a queue with lesser priority than the
- # regularar writer.
+ :param message_uids: the sequence of msg ids to update.
+ :type message_uids: sequence
+ """
+ # XXX deprecate this!
+ # move to a mailbox-level call, and do it in batches!
- log.msg('unsetting recent flags...')
- for msg in self.messages.get_recent():
- msg.removeFlags((fields.RECENT_FLAG,))
+ log.msg('unsetting recent flag: %s' % message_uid)
+ msg = self.messages.get_msg_by_uid(message_uid)
+ msg.removeFlags((fields.RECENT_FLAG,))
self._signal_unread_to_ui()
@deferred
@@ -617,7 +629,7 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
leap_events.signal(IMAP_UNREAD_MAIL, str(unseen))
@deferred
- def store(self, messages, flags, mode, uid):
+ def store(self, messages_asked, flags, mode, uid):
"""
Sets the flags of one or more messages.
@@ -646,25 +658,26 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
:raise ReadOnlyMailbox: Raised if this mailbox is not open for
read-write.
"""
+ from twisted.internet import reactor
# XXX implement also sequence (uid = 0)
# XXX we should prevent cclient from setting Recent flag.
leap_assert(not isinstance(flags, basestring),
"flags cannot be a string")
flags = tuple(flags)
+ messages_asked = self._bound_seq(messages_asked)
+ seq_messg = self._filter_msg_seq(messages_asked)
+
if not self.isWriteable():
log.msg('read only mailbox!')
raise imap4.ReadOnlyMailbox
- if not messages.last:
- messages.last = self.messages.count()
-
result = {}
- for msg_id in messages:
+ for msg_id in seq_messg:
log.msg("MSG ID = %s" % msg_id)
msg = self.messages.get_msg_by_uid(msg_id)
if not msg:
- return result
+ continue
if mode == 1:
msg.addFlags(flags)
elif mode == -1:
@@ -673,7 +686,9 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
msg.setFlags(flags)
result[msg_id] = msg.getFlags()
- self._signal_unread_to_ui()
+ # this should really be called as a final callback of
+ # the do_FETCH method...
+ deferLater(reactor, 1, self._signal_unread_to_ui)
return result
# ISearchableMailbox
@@ -740,6 +755,8 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
new_fdoc[self.MBOX_KEY] = self.mbox
d = self._do_add_doc(new_fdoc)
+ # XXX notify should be done when all the
+ # copies in the batch are finished.
d.addCallback(self._notify_new)
@deferred