summaryrefslogtreecommitdiffstats
path: root/lib/notmuch.py
diff options
context:
space:
mode:
authortoshio <toshio@mm3test.fedoraproject.org>2012-03-12 23:27:56 +0000
committertoshio <toshio@mm3test.fedoraproject.org>2012-03-12 23:27:56 +0000
commit1c4f1cb5a0332a1fcc4d2fa8cf908f029cf23594 (patch)
tree53779390ff498842d2b919da62182fe582d4d0ca /lib/notmuch.py
downloadhyperkitty-1c4f1cb5a0332a1fcc4d2fa8cf908f029cf23594.tar.gz
hyperkitty-1c4f1cb5a0332a1fcc4d2fa8cf908f029cf23594.tar.xz
hyperkitty-1c4f1cb5a0332a1fcc4d2fa8cf908f029cf23594.zip
Import the initial version of the hyperkitty archiver
Diffstat (limited to 'lib/notmuch.py')
-rw-r--r--lib/notmuch.py105
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/notmuch.py b/lib/notmuch.py
new file mode 100644
index 0000000..848adea
--- /dev/null
+++ b/lib/notmuch.py
@@ -0,0 +1,105 @@
+#-*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+
+from calendar import timegm
+from datetime import datetime, timedelta
+import json
+import os
+
+import bunch
+import notmuch
+
+from mm_app.lib import gravatar_url
+
+# Used to remove tags that notmuch added automatically that we don't want
+IGNORED_TAGS = (u'inbox', u'unread', u'signed')
+
+def get_ro_db(path):
+ # Instead of throwing an exception, notmuch bindings tend to segfault if
+ # the database path doesn't exist.
+
+ # Does the notmuch db exist?
+ actual_db_dir = os.path.join(path, '.notmuch')
+ if os.access(actual_db_dir, os.W_OK|os.X_OK) and os.path.isdir(actual_db_dir):
+ return notmuch.Database(path,
+ mode=notmuch.Database.MODE.READ_ONLY)
+
+ raise IOError('Notmuch database not present in %(path)s' %
+ {'path': path})
+
+def get_thread_info(thread):
+ thread_info = bunch.Bunch()
+
+ #
+ # Get information about the first email of a thread
+ #
+
+ first_email = tuple(thread.get_toplevel_messages())[0]
+ for tag in (tg for tg in first_email.get_tags() if tg.startswith('=msgid=')):
+ thread_info.email_id = tag.split('=msgid=', 1)[-1]
+ break
+ first_email_data = json.loads(first_email.format_message_as_json())
+
+ # Python-3.3 has ''.rsplit(maxsplit=1) (keyword arg). Until then, we need
+ # rsplit(None, 1) to get the desired behaviour
+ author = first_email_data['headers']['From'].rsplit(None, 1)
+ if author[-1].startswith('<'):
+ author[-1] = author[-1][1:]
+ if author[-1].endswith('>'):
+ author[-1] = author[-1][:-1]
+ # This accounts for From lines without a real name, just email address
+ name = author[0]
+ email = author[-1]
+ thread_info.author = name
+ thread_info.avatar = gravatar_url(email)
+
+ for body_part in first_email_data['body']:
+ try:
+ # The body may have many parts. We only want the part that we
+ # can guess is the actual text of an email message.
+ # For this prototype, that is defined as
+ # has a content-type and content keys. and the content-type
+ # is text/plain. When this is not a prototype, the heuristic
+ # should be more advanced
+ if body_part['content-type'] == u'text/plain':
+ thread_info.body = body_part['content']
+ break
+ except KeyError:
+ continue
+
+ #
+ # Get meta info about the thread itself
+ #
+
+ # Used for sorting threads
+ thread_info.most_recent = thread.get_newest_date()
+ date_as_offset = timegm(datetime.utcnow().timetuple()) - thread_info.most_recent
+ thread_info.age = str(timedelta(seconds=date_as_offset))
+ thread_info.title = thread.get_subject()
+ # Because notmuch doesn't allow us to extend the schema, everything is
+ # in a tag. Extract those tags that have special meaning to us
+ thread_info.tags = []
+ thread_info.answers = []
+ thread_info.liked = 0
+ for tag in thread.get_tags():
+ if tag.startswith('=msgid='):
+ msgid = tag.split('=msgid=', 1)[-1]
+ # The first email doesn't count as a reply :-)
+ if msgid != thread_info.email_id:
+ thread_info.answers.append(tag.split('=msgid=', 1)[-1])
+ elif tag.startswith('=threadlike='):
+ thread_info.liked = int(tag.split('=threadlike=', 1)[-1])
+ elif tag.startswith('=topic='):
+ thread_info.category = tag.split('=topic=', 1)[-1]
+ print thread_info.category
+ elif tag in IGNORED_TAGS:
+ continue
+ else:
+ thread_info.tags.append(tag)
+ # notmuch has this nice method call to give us the info but it returns
+ # it as a string instead of a list
+ thread_info.participants = set(thread.get_authors().replace(u'| ', u', ', 1).split(u', '))
+
+
+ return thread_info