summaryrefslogtreecommitdiff
path: root/src/leap/mail/imap/messages.py
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2014-01-13 13:20:00 -0400
committerKali Kaneko <kali@leap.se>2014-01-13 13:20:00 -0400
commit51eaab77deedf0c923fe40cf3d346fa879bf2ae3 (patch)
tree6650583e59baf09ceca794ecc6ba080d6c7aaa62 /src/leap/mail/imap/messages.py
parent2d77a64c7cf3e70070e25af4ef75af7de7a3a5b1 (diff)
Add check for uniqueness when adding mails.
Check by mbox + content-hash
Diffstat (limited to 'src/leap/mail/imap/messages.py')
-rw-r--r--src/leap/mail/imap/messages.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/leap/mail/imap/messages.py b/src/leap/mail/imap/messages.py
index 37e4311..a3fcd87 100644
--- a/src/leap/mail/imap/messages.py
+++ b/src/leap/mail/imap/messages.py
@@ -1064,10 +1064,27 @@ class MessageCollection(WithMsgFields, IndexedDB, MailParser, MBoxParser):
hd[self.DATE_KEY] = date
return hd
+ def _fdoc_already_exists(self, chash):
+ """
+ Check whether we can find a flags doc for this mailbox with the
+ given content-hash. It enforces that we can only have the same maessage
+ listed once for a a given mailbox.
+
+ :param chash: the content-hash to check about.
+ :type chash: basestring
+ :return: False, if it does not exist, or UID.
+ """
+ exist = self._get_fdoc_from_chash(chash)
+ if exist:
+ return exist.content.get(fields.UID_KEY, "unknown-uid")
+ else:
+ return False
+
@deferred
def add_msg(self, raw, subject=None, flags=None, date=None, uid=1):
"""
Creates a new message document.
+ Here lives the magic of the leap mail. Well, in soledad, really.
:param raw: the raw message
:type raw: str
@@ -1097,6 +1114,14 @@ class MessageCollection(WithMsgFields, IndexedDB, MailParser, MBoxParser):
# parse
msg, chash, size, multi = self._do_parse(raw)
+ # check for uniqueness.
+ if self._fdoc_already_exists(chash):
+ logger.warning("We already have that message in this mailbox.")
+ # note that this operation will leave holes in the UID sequence,
+ # but we're gonna change that all the same for a local-only table.
+ # so not touch it by the moment.
+ return False
+
fd = self._populate_flags(flags, uid, chash, size, multi)
hd = self._populate_headr(msg, chash, subject, date)
@@ -1156,6 +1181,31 @@ class MessageCollection(WithMsgFields, IndexedDB, MailParser, MBoxParser):
# getters
+ def _get_fdoc_from_chash(self, chash):
+ """
+ Return a flags document for this mailbox with a given chash.
+
+ :return: A SoledadDocument containing the Flags Document, or None if
+ the query failed.
+ :rtype: SoledadDocument or None.
+ """
+ try:
+ query = self._soledad.get_from_index(
+ fields.TYPE_MBOX_C_HASH_IDX,
+ fields.TYPE_FLAGS_VAL, self.mbox, chash)
+ if query:
+ if len(query) > 1:
+ logger.warning(
+ "More than one fdoc found for this chash, "
+ "we got a duplicate!!")
+ # XXX we could take action, like trigger a background
+ # process to kill dupes.
+ return query.pop()
+ else:
+ return None
+ except Exception as exc:
+ logger.exception("Unhandled error %r" % exc)
+
def get_msg_by_uid(self, uid):
"""
Retrieves a LeapMessage by UID.