From d95bbd9628954d7d8a5d5ebbea5f5bcf0ce6880b Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 20 Oct 2021 00:54:00 +0100 Subject: [PATCH 1/5] db: message: Implement get_subject Provide a method to get the subject of a given message. The subject is cached by not-much in the database, and is efficient to access directly through the notmuch2.msg object. Store the subject in our Message representation so it can be used efficiently when parsing and displaying mail threads. Signed-off-by: Kieran Bingham --- Fix no subject mails --- alot/db/message.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/alot/db/message.py b/alot/db/message.py index 6b1a3d9b8..cf21c3316 100644 --- a/alot/db/message.py +++ b/alot/db/message.py @@ -50,6 +50,11 @@ def __init__(self, dbman, msg, thread=None): self._mime_tree = None # will be read upon first use self._tags = msg.tags + try: + self._subject = decode_header(msg.header('subject')) + except LookupError: # No Subject on Email + self._subject = '' + self._session_keys = [ value for _, value in msg.properties.getall(prefix="session-key", exact=True) @@ -118,6 +123,10 @@ def get_filename(self): """returns absolute path of message files location""" return self._filename + def get_subject(self): + """returns Subject header (str)""" + return self._subject + def get_message_id(self): """returns messages id (str)""" return self._id From 512bfdce5b64a79b9f4eaf2a1324378b0a9672b6 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 21 Oct 2021 17:22:09 +0100 Subject: [PATCH 2/5] db: message: allow initialisation with a parent reference Allow Message instances to be created with a reference to their parent Message object. Add a get_parent() helper to return the parent of a message, or None if it is a top level message. Signed-off-by: Kieran Bingham --- alot/db/message.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/alot/db/message.py b/alot/db/message.py index cf21c3316..e86dabf78 100644 --- a/alot/db/message.py +++ b/alot/db/message.py @@ -26,7 +26,7 @@ class Message: It it uses a :class:`~alot.db.DBManager` for cached manipulation and lazy lookups. """ - def __init__(self, dbman, msg, thread=None): + def __init__(self, dbman, msg, thread=None, parent=None): """ :param dbman: db manager that is used for further lookups :type dbman: alot.db.DBManager @@ -34,11 +34,15 @@ def __init__(self, dbman, msg, thread=None): :type msg: notmuch2.Message :param thread: this messages thread (will be looked up later if `None`) :type thread: :class:`~alot.db.Thread` or `None` + :param parent: this message's parent (if it was a reply, and we have the + message it was a reply to) + :type parent: :class:`~alot.db.Message` or `None` """ self._dbman = dbman self._id = msg.messageid self._thread_id = msg.threadid self._thread = thread + self._parent = parent try: self._datetime = datetime.fromtimestamp(msg.date) except ValueError: @@ -115,6 +119,10 @@ def get_email(self): warning, policy=email.policy.SMTP) return self._email + def get_parent(self): + """returns parent Message if this is a reply or None otherwise""" + return self._parent + def get_date(self): """returns Date header value as :class:`~datetime.datetime`""" return self._datetime From 57b8c0323647003d7f85fc41f9de75f29015153d Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 21 Oct 2021 17:55:09 +0100 Subject: [PATCH 3/5] db: thread: Initialise Messages with their parent Provide a reference to the parent of any Message when it is initialised. Signed-off-by: Kieran Bingham --- alot/db/thread.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alot/db/thread.py b/alot/db/thread.py index be91cdf12..56b6d0d04 100644 --- a/alot/db/thread.py +++ b/alot/db/thread.py @@ -236,11 +236,11 @@ def get_messages(self): if not self._messages: # if not already cached with self._dbman._with_notmuch_thread(self._id) as thread: - def accumulate(acc, msg): - M = Message(self._dbman, msg, thread=self) + def accumulate(acc, msg, parent=None): + M = Message(self._dbman, msg, thread=self, parent=parent) acc[M] = [] for m in msg.replies(): - acc[M].append(accumulate(acc, m)) + acc[M].append(accumulate(acc, m, M)) return M self._messages = {} From 46e7581f8f0156ffbb58973d3a633597cc36f390 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 20 Oct 2021 00:55:54 +0100 Subject: [PATCH 4/5] widgets: thread: Include Subject in MessageSummary Replies to a parent message are not shown to avoid filling the buffer with noisy repeating content. Signed-off-by: Kieran Bingham --- alot/widgets/thread.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/alot/widgets/thread.py b/alot/widgets/thread.py index c5276df83..b5244fffd 100644 --- a/alot/widgets/thread.py +++ b/alot/widgets/thread.py @@ -78,9 +78,21 @@ def _render_wrap(size, focus=False): def __str__(self): author, address = self.message.get_author() date = self.message.get_datestring() + subject = self.message.get_subject() rep = author if author != '' else address if date is not None: rep += " (%s)" % date + + # Hide Subjects which are replies to the parent message. + # This allows threads containing multiple messages with distinct + # subjects to be displayed without adding noise to the replies. + parent = self.message.get_parent() + if parent: + psubject = parent.get_subject() + subject = subject.replace(psubject, "...") + + rep += ": " + subject + return rep def selectable(self): From f7bb7b69844688849c0231e3408511e02ef37875 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 15 Nov 2021 14:51:05 +0000 Subject: [PATCH 5/5] db: thread: Fix LookupError when no header(subject) Threads that do not have a subject will cause a LookupError() when retrieving the header. Catch this exception and set the subject to a null string. Signed-off-by: Kieran Bingham --- alot/db/thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alot/db/thread.py b/alot/db/thread.py index 56b6d0d04..ed9bcb0ed 100644 --- a/alot/db/thread.py +++ b/alot/db/thread.py @@ -49,7 +49,7 @@ def _refresh(self, thread): try: first_msg = list(thread.toplevel())[0] subject = first_msg.header('subject') - except IndexError: + except (IndexError, LookupError): subject = '' self._subject = subject