From aa7c770e6a88b7d9dc43e7446ea79e5e705586b8 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 26 Jan 2015 23:41:52 -0400 Subject: save drafts: search by msg-id --- src/leap/mail/adaptors/soledad.py | 24 +++++++++++++++++ src/leap/mail/imap/mailbox.py | 13 +++++---- src/leap/mail/imap/server.py | 57 ++++++++++++++++++++++++++++++++++----- src/leap/mail/mail.py | 19 +++++++++++++ src/leap/mail/mailbox_indexer.py | 2 +- 5 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/leap/mail/adaptors/soledad.py b/src/leap/mail/adaptors/soledad.py index 542ad94..4dc02a1 100644 --- a/src/leap/mail/adaptors/soledad.py +++ b/src/leap/mail/adaptors/soledad.py @@ -966,6 +966,30 @@ class SoledadMailAdaptor(SoledadIndexMixin): d.addErrback(self._errback) return d + # search api + + def get_mdoc_id_from_msgid(self, store, mbox_uuid, msgid): + """ + Get the UID for a message with the passed msgid (the one in the headers + msg-id). + This is used by the MUA to retrieve the recently saved draft. + """ + type_ = HeaderDocWrapper.model.type_ + uuid = mbox_uuid.replace('-', '_') + + msgid_index = indexes.TYPE_MSGID_IDX + + def get_mdoc_id(hdoc): + if not hdoc: + return None + hdoc = hdoc[0] + mdoc_id = hdoc.doc_id.replace("H-", "M-%s-" % uuid) + return mdoc_id + + d = store.get_from_index(msgid_index, type_, msgid) + d.addCallback(get_mdoc_id) + return d + # Mailbox handling def get_or_create_mbox(self, store, name): diff --git a/src/leap/mail/imap/mailbox.py b/src/leap/mail/imap/mailbox.py index c826e86..be7f70c 100644 --- a/src/leap/mail/imap/mailbox.py +++ b/src/leap/mail/imap/mailbox.py @@ -842,18 +842,17 @@ class IMAPMailbox(object): # '52D44F11.9060107@dev.bitmask.net'] # TODO hardcoding for now! -- we'll support generic queries later on - # but doing a quickfix for avoiding duplicat saves in the draft folder. - # See issue #4209 + # but doing a quickfix for avoiding duplicate saves in the draft + # folder. # See issue #4209 if len(query) > 2: if query[1] == 'HEADER' and query[2].lower() == "message-id": msgid = str(query[3]).strip() logger.debug("Searching for %s" % (msgid,)) - d = self.messages._get_uid_from_msgid(str(msgid)) - # XXX remove gatherResults - d1 = defer.gatherResults([d]) - # we want a list, so return it all the same - return d1 + + d = self.collection.get_uid_from_msgid(str(msgid)) + d.addCallback(lambda result: [result]) + return d # nothing implemented for any other query logger.warning("Cannot process query: %s" % (query,)) diff --git a/src/leap/mail/imap/server.py b/src/leap/mail/imap/server.py index 027fd7a..abe16be 100644 --- a/src/leap/mail/imap/server.py +++ b/src/leap/mail/imap/server.py @@ -199,8 +199,7 @@ class LEAPIMAPServer(imap4.IMAP4Server): a deferred, the client will only be informed of success (or failure) when the deferred's callback (or errback) is invoked. """ - # TODO return the output of _memstore.is_writing - # XXX and that should return a deferred! + # TODO implement a collection of ongoing deferreds? return None ############################################################# @@ -499,6 +498,50 @@ class LEAPIMAPServer(imap4.IMAP4Server): auth_DELETE = (do_DELETE, arg_astring) select_DELETE = auth_DELETE + # ----------------------------------------------------------------------- + # Patched just to allow __cbAppend to receive a deferred from messageCount + # TODO format and send upstream. + def do_APPEND(self, tag, mailbox, flags, date, message): + mailbox = self._parseMbox(mailbox) + maybeDeferred(self.account.select, mailbox).addCallback( + self._cbAppendGotMailbox, tag, flags, date, message).addErrback( + self._ebAppendGotMailbox, tag) + + def __ebAppend(self, failure, tag): + self.sendBadResponse(tag, 'APPEND failed: ' + str(failure.value)) + + def _cbAppendGotMailbox(self, mbox, tag, flags, date, message): + if not mbox: + self.sendNegativeResponse(tag, '[TRYCREATE] No such mailbox') + return + + d = mbox.addMessage(message, flags, date) + d.addCallback(self.__cbAppend, tag, mbox) + d.addErrback(self.__ebAppend, tag) + + def _ebAppendGotMailbox(self, failure, tag): + self.sendBadResponse( + tag, "Server error encountered while opening mailbox.") + log.err(failure) + + def __cbAppend(self, result, tag, mbox): + + # XXX patched --------------------------------- + def send_response(count): + self.sendUntaggedResponse('%d EXISTS' % count) + self.sendPositiveResponse(tag, 'APPEND complete') + + d = mbox.getMessageCount() + d.addCallback(send_response) + return d + # XXX patched --------------------------------- + + # ----------------------------------------------------------------------- + + auth_APPEND = (do_APPEND, arg_astring, imap4.IMAP4Server.opt_plist, + imap4.IMAP4Server.opt_datetime, arg_literal) + select_APPEND = auth_APPEND + # Need to override the command table after patching # arg_astring and arg_literal, except on the methods that we are already # overriding. @@ -511,10 +554,10 @@ class LEAPIMAPServer(imap4.IMAP4Server): # do_RENAME = imap4.IMAP4Server.do_RENAME # do_SUBSCRIBE = imap4.IMAP4Server.do_SUBSCRIBE # do_UNSUBSCRIBE = imap4.IMAP4Server.do_UNSUBSCRIBE + # do_APPEND = imap4.IMAP4Server.do_APPEND # ------------------------------------------------- do_LOGIN = imap4.IMAP4Server.do_LOGIN do_STATUS = imap4.IMAP4Server.do_STATUS - do_APPEND = imap4.IMAP4Server.do_APPEND do_COPY = imap4.IMAP4Server.do_COPY _selectWork = imap4.IMAP4Server._selectWork @@ -539,6 +582,10 @@ class LEAPIMAPServer(imap4.IMAP4Server): # re-add if we stop overriding DELETE # auth_DELETE = (do_DELETE, arg_astring) # select_DELETE = auth_DELETE + # auth_APPEND = (do_APPEND, arg_astring, opt_plist, opt_datetime, + # arg_literal) + # select_APPEND = auth_APPEND + # ---------------------------------------------------- auth_RENAME = (do_RENAME, arg_astring, arg_astring) @@ -559,10 +606,6 @@ class LEAPIMAPServer(imap4.IMAP4Server): auth_STATUS = (do_STATUS, arg_astring, arg_plist) select_STATUS = auth_STATUS - auth_APPEND = (do_APPEND, arg_astring, opt_plist, opt_datetime, - arg_literal) - select_APPEND = auth_APPEND - select_COPY = (do_COPY, arg_seqset, arg_astring) ############################################################# diff --git a/src/leap/mail/mail.py b/src/leap/mail/mail.py index d986f59..2766524 100644 --- a/src/leap/mail/mail.py +++ b/src/leap/mail/mail.py @@ -460,6 +460,25 @@ class MessageCollection(object): """ return self.mbox_indexer.all_uid_iter(self.mbox_uuid) + def get_uid_from_msgid(self, msgid): + """ + Return the UID(s) of the matching msg-ids for this mailbox collection. + """ + if not self.is_mailbox_collection(): + raise NotImplementedError() + + def get_uid(mdoc_id): + if not mdoc_id: + return None + d = self.mbox_indexer.get_uid_from_doc_id( + self.mbox_uuid, mdoc_id) + return d + + d = self.adaptor.get_mdoc_id_from_msgid( + self.store, self.mbox_uuid, msgid) + d.addCallback(get_uid) + return d + # Manipulate messages def add_msg(self, raw_msg, flags=tuple(), tags=tuple(), date=""): diff --git a/src/leap/mail/mailbox_indexer.py b/src/leap/mail/mailbox_indexer.py index 4eb0fa8..3bec41e 100644 --- a/src/leap/mail/mailbox_indexer.py +++ b/src/leap/mail/mailbox_indexer.py @@ -120,7 +120,7 @@ class MailboxIndexer(object): The doc_id must be in the format: - M++ + M-- :param mailbox: the mailbox name :type mailbox: str -- cgit v1.2.3