Claws-Mail Plugin: Cat Into Tree
This is a Python plugin script for your .claws-mail/python-scripts/main folder, which you can then assign to a keystroke or toolbar button. Once activated, it opens a window with the senders, subjects and bodies of the current selected messages loaded into an expanding shallow tree widget.
# cat-into-tree.py - Copyright 2020 MJ Ray GPL-2+
from __future__ import print_function, unicode_literals
# import clawsmail
import email
import re
import sys
import textwrap
# The modern way is to import gi and then from gi.repository import Gtk
# but I suspect something else imports gtk which prevents that
import gtk
__author__ = "MJ Ray"
__copyright__ = "Copyright 2020 MJ Ray"
__license__ = "GPL-2+"
__version__ = "1.01"
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def make_window():
def dismiss_window(button, w):
w.destroy()
def show_window(texts):
win = gtk.Window()
win.set_title("Summary")
win.connect("destroy", gtk.main_quit)
table = gtk.Table(2, 1)
win.add(table)
textscroller = gtk.ScrolledWindow()
textfield = gtk.TreeView()
textfield.set_model(texts)
rendererText = gtk.CellRendererText()
rendererText.set_property('font', 'Serif 9')
column = gtk.TreeViewColumn("Messages")
column.pack_start(rendererText, True)
column.add_attribute(rendererText, 'text', 0)
textfield.append_column(column)
textfield.set_property('hover-expand', True)
# textfield.expand_all()
def click_row(treev, path, column):
if treev.row_expanded(path):
treev.collapse_row(path)
else:
treev.expand_row(path, True)
textfield.connect("row-activated", click_row)
textscroller.add(textfield)
table.attach(textscroller, 0, 1, 1, 2)
button = gtk.Button("Dismiss")
button.connect("clicked", dismiss_window, win)
button.connect("activate", dismiss_window, win)
button.set_flags(gtk.CAN_DEFAULT)
table.attach(button, 0, 1, 0, 1, yoptions=gtk.FILL)
win.set_default(button)
def parse_key(w, event):
if gtk.gdk.keyval_name(event.keyval) in ('q', 'Escape'):
win.destroy()
return True
elif gtk.gdk.keyval_name(event.keyval) == 'a':
visible = textfield.get_visible_rect()
textfield.scroll_to_point(-1, visible.y + visible.height - 10)
return True
elif gtk.gdk.keyval_name(event.keyval) == 'A':
visible = textfield.get_visible_rect()
textfield.scroll_to_point(-1, visible.y - visible.height + 10)
return True
return False
win.add_events(gtk.gdk.KEY_PRESS_MASK)
win.connect("key-press-event", parse_key)
win.show_all()
win.present()
gtk.main()
return True
alltexts = gtk.TreeStore(str)
# iterate over the whole selection
# TODO: can this be sorted into a better order?
messages = clawsmail.get_summaryview_selected_message_list()
messages.sort(cmp=lambda x, y: cmp(x.FilePath, y.FilePath))
for msginfo in messages:
file = open(msginfo.FilePath, "r")
msgfile = file.read()
file.close()
eprint("Got file "+msginfo.FilePath)
# parse the email file
# TODO: can we use what claws has already parsed?
msg = email.message_from_string(msgfile)
eprint("Decoded a file")
# extract the decoded plain text body parts
body = u''
if msg.is_multipart():
# body += 'multipart\n'
for part in msg.walk():
# body += part.get_content_type() + "\n\n"
if part.get_content_type() == 'text/plain':
if part.get_content_charset():
body += part.get_payload(
decode=True).decode(part.get_content_charset())
else:
body += part.get_payload(decode=True)
eprint("Extracted multipart body")
# body += msg.get_payload(0,decode=True)
else:
# body += 'unipart\n'
# body += msg.get_content_type() + "\n\n"
if msg.get_content_charset():
body += msg.get_payload(
decode=True).decode(msg.get_content_charset())
else:
body += msg.get_payload(decode=True)
eprint("Extracted unipart body")
body = re.sub(
r'A new comment on the post "[^"]*" .* approval.*\nhttp.*\n\n',
'',
body
)
# body = re.sub(r'^.*?\n\n','',msg.as_string(),count=1,flags=re.DOTALL)
# text += '----\n' + body + '----\n\n'
bodylines = body.splitlines()
body = ("\n".join(map(lambda(x): textwrap.fill(x, 72), bodylines))
+ "\n(On "
+ msg['Date']
+ ")")
def is_header_or_quote(x):
return (len(x) > 1
and x[0] not in ('-', '=', '>', ' ')
and x[-1] not in ('-', '=', ',', ':', '0'))
leaderwidth = 88
lg = textwrap.fill(
" ".join(filter(is_header_or_quote,
bodylines[0:min(len(bodylines), 50)])),
leaderwidth,
initial_indent=" ",
subsequent_indent=" ")
# Add to what we're going to display
text = (u""
+ email.utils.parseaddr(msg["From"])[0]
+ " > "
+ msg['Subject']
+ "\n"
+ lg[0:lg.rfind(' ', 0, min(len(lg), leaderwidth*2))])
message = alltexts.append(None, [text])
eprint("Added header")
alltexts.append(message, [body])
eprint("Added body")
msginfo.unread = False
# msginfo.new = False
eprint("Showing window")
show_window(alltexts)
make_window()