summaryrefslogtreecommitdiff
path: root/src/leap/mail/imap/mailbox.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/mail/imap/mailbox.py')
-rw-r--r--src/leap/mail/imap/mailbox.py130
1 files changed, 80 insertions, 50 deletions
diff --git a/src/leap/mail/imap/mailbox.py b/src/leap/mail/imap/mailbox.py
index cf09bc4..b186e75 100644
--- a/src/leap/mail/imap/mailbox.py
+++ b/src/leap/mail/imap/mailbox.py
@@ -398,18 +398,19 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
flags = tuple(str(flag) for flag in flags)
d = self._do_add_message(message, flags=flags, date=date, uid=uid_next)
- d.addCallback(self._notify_new)
return d
- @deferred
def _do_add_message(self, message, flags, date, uid):
"""
Calls to the messageCollection add_msg method (deferred to thread).
Invoked from addMessage.
"""
- self.messages.add_msg(message, flags=flags, date=date, uid=uid)
+ d = self.messages.add_msg(message, flags=flags, date=date, uid=uid)
+ # XXX notify after batch APPEND?
+ d.addCallback(self.notify_new)
+ return d
- def _notify_new(self, *args):
+ def notify_new(self, *args):
"""
Notify of new messages to all the listeners.
@@ -463,8 +464,12 @@ 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)
+ d.addCallback(self.messages.reset_last_uid)
+
+ # XXX DEBUG -------------------
+ # FIXME !!!
+ # XXX should remove the hdocset too!!!
return d
def _bound_seq(self, messages_asked):
@@ -480,7 +485,10 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
iter(messages_asked)
except TypeError:
# looks like we cannot iterate
- messages_asked.last = self.last_uid
+ try:
+ messages_asked.last = self.last_uid
+ except ValueError:
+ pass
return messages_asked
def _filter_msg_seq(self, messages_asked):
@@ -516,8 +524,6 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
:rtype: A tuple of two-tuples of message sequence numbers and
LeapMessage
"""
- from twisted.internet import reactor
-
# For the moment our UID is sequential, so we
# can treat them all the same.
# Change this to the flag that twisted expects when we
@@ -528,23 +534,14 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
messages_asked = self._bound_seq(messages_asked)
seq_messg = self._filter_msg_seq(messages_asked)
-
- def getmsg(msgid):
- if self.isWriteable():
- deferLater(reactor, 2, self._unset_recent_flag, messages_asked)
- return self.messages.get_msg_by_uid(msgid)
+ getmsg = lambda uid: self.messages.get_msg_by_uid(uid)
# for sequence numbers (uid = 0)
if sequence:
logger.debug("Getting msg by index: INEFFICIENT call!")
raise NotImplementedError
-
else:
result = ((msgid, getmsg(msgid)) for msgid in seq_messg)
-
- # this should really be called as a final callback of
- # the do_FETCH method...
- deferLater(reactor, 1, self._signal_unread_to_ui)
return result
@deferred
@@ -557,7 +554,7 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
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
- it's not bad to fetch all the flags doc at once.
+ it's not bad to fetch all the FLAGS docs at once.
:param messages_asked: IDs of the messages to retrieve information
about
@@ -592,36 +589,55 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
return result
@deferred
- def _unset_recent_flag(self, message_uid):
+ def fetch_headers(self, messages_asked, uid):
"""
- Unsets `Recent` flag from a tuple of messages.
- Called from fetch.
+ A fast method to fetch all headers, tricking just the
+ needed subset of the MIME interface that's needed to satisfy
+ a generic HEADERS query.
- From RFC, about `Recent`:
+ 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
+ **MAYBE** it's not too bad to fetch all the HEADERS docs at once.
- Message is "recently" arrived in this mailbox. This session
- is the first session to have been notified about this
- message; if the session is read-write, subsequent sessions
- will not see \Recent set for this message. This flag can not
- be altered by the client.
+ :param messages_asked: IDs of the messages to retrieve information
+ about
+ :type messages_asked: MessageSet
- 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.
+ :param uid: If true, the IDs are UIDs. They are message sequence IDs
+ otherwise.
+ :type uid: bool
- :param message_uids: the sequence of msg ids to update.
- :type message_uids: sequence
+ :return: A tuple of two-tuples of message sequence numbers and
+ headersPart, which is a only a partial implementation of
+ MessagePart.
+ :rtype: tuple
"""
- # XXX deprecate this!
- # move to a mailbox-level call, and do it in batches!
+ class headersPart(object):
+ def __init__(self, uid, headers):
+ self.uid = uid
+ self.headers = headers
- 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()
+ def getUID(self):
+ return self.uid
- @deferred
- def _signal_unread_to_ui(self):
+ def getHeaders(self, _):
+ return dict(
+ (str(key), str(value))
+ for key, value in
+ self.headers.items())
+
+ messages_asked = self._bound_seq(messages_asked)
+ seq_messg = self._filter_msg_seq(messages_asked)
+
+ all_chash = self.messages.all_flags_chash()
+ all_headers = self.messages.all_headers()
+ result = ((msgid, headersPart(
+ msgid, all_headers.get(all_chash.get(msgid, 'nil'), {})))
+ for msgid in seq_messg)
+ return result
+
+ def signal_unread_to_ui(self):
"""
Sends unread event to ui.
"""
@@ -658,7 +674,6 @@ 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),
@@ -686,8 +701,12 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
msg.setFlags(flags)
result[msg_id] = msg.getFlags()
+ # After changing flags, we want to signal again to the
+ # UI because the number of unread might have changed.
+ # Hoever, we should probably limit this to INBOX only?
# this should really be called as a final callback of
- # the do_FETCH method...
+ # the do_STORE method...
+ from twisted.internet import reactor
deferLater(reactor, 1, self._signal_unread_to_ui)
return result
@@ -741,6 +760,7 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
"""
Copy the given message object into this mailbox.
"""
+ from twisted.internet import reactor
uid_next = self.getUIDNext()
msg = messageObject
@@ -753,17 +773,20 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
new_fdoc = copy.deepcopy(fdoc.content)
new_fdoc[self.UID_KEY] = uid_next
new_fdoc[self.MBOX_KEY] = self.mbox
+ self._do_add_doc(new_fdoc)
- 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)
+ # XXX should use a public api instead
+ hdoc = msg._hdoc
+ self.messages.add_hdocset_docid(hdoc.doc_id)
+
+ deferLater(reactor, 1, self.notify_new)
- @deferred
def _do_add_doc(self, doc):
"""
- Defers the adding of a new doc.
+ Defer the adding of a new doc.
+
:param doc: document to be created in soledad.
+ :type doc: dict
"""
self._soledad.create_doc(doc)
@@ -771,12 +794,19 @@ class SoledadMailbox(WithMsgFields, MBoxParser):
def deleteAllDocs(self):
"""
- Deletes all docs in this mailbox
+ Delete all docs in this mailbox
"""
docs = self.messages.get_all_docs()
for doc in docs:
self.messages._soledad.delete_doc(doc)
+ def unset_recent_flags(self, uids):
+ """
+ Unset Recent flag for a sequence of UIDs.
+ """
+ seq_messg = self._bound_seq(uids)
+ self.messages.unset_recent_flags(seq_messg)
+
def __repr__(self):
"""
Representation string for this mailbox.