diff options
-rw-r--r-- | mail/src/leap/mail/imap/mailbox.py | 39 | ||||
-rw-r--r-- | mail/src/leap/mail/incoming/service.py | 14 | ||||
-rw-r--r-- | mail/src/leap/mail/mail.py | 77 |
3 files changed, 66 insertions, 64 deletions
diff --git a/mail/src/leap/mail/imap/mailbox.py b/mail/src/leap/mail/imap/mailbox.py index 3769a3ed..c5016146 100644 --- a/mail/src/leap/mail/imap/mailbox.py +++ b/mail/src/leap/mail/imap/mailbox.py @@ -20,8 +20,12 @@ IMAP Mailbox. import re import logging import os +import cStringIO +import StringIO +import time from collections import defaultdict +from email.utils import formatdate from twisted.internet import defer from twisted.internet import reactor @@ -31,6 +35,7 @@ from twisted.mail import imap4 from zope.interface import implements from leap.common.check import leap_assert +from leap.common.check import leap_assert_type from leap.mail.constants import INBOX_NAME, MessageFlags from leap.mail.imap.messages import IMAPMessage @@ -50,7 +55,6 @@ NOTIFY_NEW = not os.environ.get('LEAP_SKIPNOTIFY', False) PROFILE_CMD = os.environ.get('LEAP_PROFILE_IMAPCMD', False) if PROFILE_CMD: - import time def _debugProfiling(result, cmdname, start): took = (time.time() - start) * 1000 @@ -315,12 +319,41 @@ class IMAPMailbox(object): :type flags: list of str :param date: timestamp - :type date: str + :type date: str, or None :return: a deferred that will be triggered with the UID of the added message. """ - return self.collection.add_raw_message(message, flags, date) + # TODO should raise ReadOnlyMailbox if not rw. + # TODO have a look at the cases for internal date in the rfc + # XXX we could treat the message as an IMessage from here + + if isinstance(message, (cStringIO.OutputType, StringIO.StringIO)): + message = message.getvalue() + + leap_assert_type(message, basestring) + + if flags is None: + flags = tuple() + else: + flags = tuple(str(flag) for flag in flags) + + if date is None: + date = formatdate(time.time()) + + # notify_just_mdoc=True: feels HACKY, but improves a *lot* the + # responsiveness of the APPENDS: we just need to be notified when the + # mdoc is saved, and let's hope that the other parts are doing just + # fine. This will not catch any errors when the inserts of the other + # parts fail, but on the other hand allows us to return very quickly, + # which seems a good compromise given that we have to serialize the + # appends. + # A better solution will probably involve implementing MULTIAPPEND + # extension or patching imap server to support pipelining. + + # TODO add notify_new as a callback here... + return self.collection.add_msg(message, flags, date, + notify_just_mdoc=True) def notify_new(self, *args): """ diff --git a/mail/src/leap/mail/incoming/service.py b/mail/src/leap/mail/incoming/service.py index 8b5c3713..ea790fe8 100644 --- a/mail/src/leap/mail/incoming/service.py +++ b/mail/src/leap/mail/incoming/service.py @@ -27,6 +27,7 @@ import warnings from email.parser import Parser from email.generator import Generator from email.utils import parseaddr +from email.utils import formatdate from StringIO import StringIO from urlparse import urlparse @@ -117,7 +118,8 @@ class IncomingMail(Service): :param soledad: a soledad instance :type soledad: Soledad - :param inbox: the inbox where the new emails will be stored + :param inbox: the collection for the inbox where the new emails will be + stored :type inbox: MessageCollection :param check_period: the period to fetch new mail, in seconds. @@ -132,7 +134,7 @@ class IncomingMail(Service): self._keymanager = keymanager self._soledad = soledad - self._inbox = inbox + self._inbox_collection = inbox self._userid = userid self._listeners = [] @@ -266,7 +268,7 @@ class IncomingMail(Service): Sends unread event to ui. """ leap_events.signal( - IMAP_UNREAD_MAIL, str(self._inbox.count_unseen())) + IMAP_UNREAD_MAIL, str(self._inbox_collection.count_unseen())) # process incoming mail. @@ -710,7 +712,8 @@ class IncomingMail(Service): :return: A Deferred that will be fired when the messages is stored :rtype: Defferred """ - doc, data = msgtuple + doc, raw_data = msgtuple + insertion_date = formatdate(time.time()) log.msg('adding message %s to local db' % (doc.doc_id,)) def msgSavedCallback(result): @@ -729,7 +732,8 @@ class IncomingMail(Service): d.addCallback(signal_deleted) return d - d = self._inbox.add_raw_message(data, (self.RECENT_FLAG,)) + d = self._inbox_collection.add_msg( + raw_data, (self.RECENT_FLAG,), date=insertion_date) d.addCallbacks(msgSavedCallback, self._errback) return d diff --git a/mail/src/leap/mail/mail.py b/mail/src/leap/mail/mail.py index 3127ef5e..f9e99f00 100644 --- a/mail/src/leap/mail/mail.py +++ b/mail/src/leap/mail/mail.py @@ -20,10 +20,6 @@ Generic Access to Mail objects: Public LEAP Mail API. import uuid import logging import StringIO -import cStringIO -import time - -from email.utils import formatdate from twisted.internet import defer from leap.common.check import leap_assert_type @@ -521,6 +517,15 @@ class MessageCollection(object): """ Add a message to this collection. + :param raw_message: the raw message + :param flags: tuple of flags for this message + :param tags: tuple of tags for this message + :param date: + formatted date, it will be used to retrieve the internal + date for this message. According to the spec, this is NOT the date + and time in the RFC-822 header, but rather a date and time that + reflects when the message was received. + :type date: str :param notify_just_mdoc: boolean passed to the wrapper.create method, to indicate whether we're interested in being notified when only @@ -533,7 +538,11 @@ class MessageCollection(object): message. :rtype: deferred """ + # TODO watch out if the use of this method in IMAP COPY/APPEND is + # passing the right date. + # XXX mdoc ref is a leaky abstraction here. generalize. + leap_assert_type(flags, tuple) leap_assert_type(date, str) @@ -558,66 +567,22 @@ class MessageCollection(object): d = wrapper.create(self.store, notify_just_mdoc=notify_just_mdoc) d.addCallback(insert_mdoc_id, wrapper) d.addErrback(lambda f: f.printTraceback()) - return d - - def add_raw_message(self, message, flags, date=None): - """ - Adds a message to this collection. - - :param message: the raw message - :type message: str - - :param flags: flag list - :type flags: list of str - - :param date: timestamp - :type date: str - - :return: a deferred that will be triggered with the UID of the added - message. - """ - # TODO should raise ReadOnlyMailbox if not rw. - # TODO have a look at the cases for internal date in the rfc - if isinstance(message, (cStringIO.OutputType, StringIO.StringIO)): - message = message.getvalue() - - # XXX we could treat the message as an IMessage from here - leap_assert_type(message, basestring) - - if flags is None: - flags = tuple() - else: - flags = tuple(str(flag) for flag in flags) - - if date is None: - date = formatdate(time.time()) - - # A better place for this would be the COPY/APPEND dispatcher - # if PROFILE_CMD: - # do_profile_cmd(d, "APPEND") - - # just_mdoc=True: feels HACKY, but improves a *lot* the responsiveness - # of the APPENDS: we just need to be notified when the mdoc - # is saved, and let's hope that the other parts are doing just fine. - # This will not catch any errors when the inserts of the other parts - # fail, but on the other hand allows us to return very quickly, which - # seems a good compromise given that we have to serialize the appends. - # A better solution will probably involve implementing MULTIAPPEND - # or patching imap server to support pipelining. - - d = self.add_msg(message, flags=flags, date=date, - notify_just_mdoc=True) - d.addErrback(lambda f: logger.warning(f.getTraceback())) d.addCallback(self.cb_signal_unread_to_ui) return d def cb_signal_unread_to_ui(self, result): """ - Sends unread event to ui. + Sends an unread event to ui, passing *only* the number of unread + messages if *this* is the inbox. This event is catched, for instance, + in the Bitmask client that displays a message with the number of unread + mails in the INBOX. + Used as a callback in several commands. :param result: ignored """ + # TODO it might make sense to modify the event so that + # it receives both the mailbox name AND the number of unread messages. if self.mbox_name.lower() == "inbox": d = defer.maybeDeferred(self.count_unseen) d.addCallback(self.__cb_signal_unread_to_ui) @@ -629,7 +594,7 @@ class MessageCollection(object): :param unseen: number of unseen messages. :type unseen: int """ - # TODO change name of the signal, non-imap now. + # TODO change name of the signal, independent from imap now. leap_events.signal(IMAP_UNREAD_MAIL, str(unseen)) def copy_msg(self, msg, new_mbox_uuid): |