Skip to content

Commit 3bd0793

Browse files
author
Felix Van der Jeugt
committed
allow selection of contenttype
1 parent 94d17f5 commit 3bd0793

File tree

3 files changed

+78
-20
lines changed

3 files changed

+78
-20
lines changed

alot/commands/thread.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,3 +1192,19 @@ def refresh_widgets():
11921192
# flush index
11931193
if self.flush:
11941194
ui.apply_command(FlushCommand())
1195+
1196+
@registerCommand(MODE, 'nextctype', help='display the next contenttype')
1197+
class NextCTypeCommand(Command):
1198+
1199+
"""display the next contenttype"""
1200+
repeatable = True
1201+
1202+
def __init__(self, **kwargs):
1203+
Command.__init__(self, **kwargs)
1204+
1205+
def apply(self, ui):
1206+
tbuffer = ui.current_buffer
1207+
message_tree = tbuffer.get_selected_messagetree()
1208+
message_tree.next_contenttype()
1209+
message_tree.reassemble()
1210+
tbuffer.refresh()

alot/db/utils.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,29 @@ def extract_body(mail, types=None, field_key='copiousoutput'):
313313
:returns: The combined text of any parts to be used
314314
:rtype: str
315315
"""
316-
317316
preferred = 'text/plain' if settings.get(
318317
'prefer_plaintext') else 'text/html'
319-
has_preferred = False
320318

321319
# see if the mail has our preferred type
322320
if types is None:
323-
has_preferred = list(typed_subpart_iterator(
324-
mail, *preferred.split('/')))
321+
types = list(typed_subpart_iterator(mail, *preferred.split('/')))
322+
323+
body_parts = extract_body_parts(mail, types=types, field_key=field_key)
324+
return u'\n\n'.join(text for ctype, text in body_parts)
325+
326+
327+
def extract_body_parts(mail, types=None, field_key='copiousoutput'):
328+
"""Returns a string view of each body part of a Message.
329+
330+
If no preferred types are specified, all types are returned.
331+
332+
:param mail: the mail to use
333+
:type mail: :class:`email.Message`
334+
:param types: mime content types to use for body string
335+
:type types: list[(str,str)]
336+
:returns: The type and text of any parts to be used
337+
:rtype: str
338+
"""
325339

326340
body_parts = []
327341
for part in mail.walk():
@@ -333,16 +347,12 @@ def extract_body(mail, types=None, field_key='copiousoutput'):
333347
cd = part.get('Content-Disposition', '')
334348
if cd.startswith('attachment'):
335349
continue
336-
# if the mail has our preferred type, we only keep this type
337-
# note that if types != None, has_preferred always stays False
338-
if has_preferred and ctype != preferred:
339-
continue
340350

341351
enc = part.get_content_charset() or 'ascii'
342352
raw_payload = part.get_payload(decode=True)
343353
if ctype == 'text/plain':
344354
raw_payload = string_decode(raw_payload, enc)
345-
body_parts.append(string_sanitize(raw_payload))
355+
body_parts.append((ctype, string_sanitize(raw_payload)))
346356
else:
347357
# get mime handler
348358
_, entry = settings.mailcap_find_match(ctype, key=field_key)
@@ -382,8 +392,8 @@ def extract_body(mail, types=None, field_key='copiousoutput'):
382392
os.unlink(tempfile_name)
383393

384394
if rendered_payload: # handler had output
385-
body_parts.append(string_sanitize(rendered_payload))
386-
return u'\n\n'.join(body_parts)
395+
body_parts.append((ctype, string_sanitize(rendered_payload)))
396+
return body_parts
387397

388398

389399
def decode_header(header, normalize=False):

alot/widgets/thread.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from .globals import AttachmentWidget
1515
from ..settings.const import settings
1616
from ..db.utils import decode_header, X_SIGNATURE_MESSAGE_HEADER
17-
from ..db.utils import extract_body
17+
from ..db.utils import extract_body_parts
1818

1919

2020
class MessageSummaryWidget(urwid.WidgetWrap):
@@ -73,6 +73,18 @@ def keypress(self, size, key):
7373
return key
7474

7575

76+
class ContenttypeWidget(urwid.WidgetWrap):
77+
def __init__(self, types, current):
78+
value_att = settings.get_theming_attribute('thread', 'header_value')
79+
80+
cols = []
81+
cols.append(urwid.Text("content-type: "))
82+
for i, ctype in enumerate(types):
83+
cols.append(urwid.Text((value_att if i == current else None, ctype)))
84+
cols = [('fixed', len(c.text), c) for c in cols]
85+
urwid.WidgetWrap.__init__(self, urwid.Columns(cols, dividechars=1))
86+
87+
7688
class FocusableText(urwid.WidgetWrap):
7789
"""Selectable Text used for nodes in our example"""
7890
def __init__(self, txt, att, att_focus):
@@ -172,6 +184,8 @@ def __init__(self, message, odd=True):
172184
self._default_headers_tree = None
173185
self.display_attachments = True
174186
self._attachments = None
187+
self._current_contenttype = 0
188+
self._content_parts = None
175189
self._maintree = SimpleTree(self._assemble_structure())
176190
CollapsibleTree.__init__(self, self._maintree)
177191

@@ -205,6 +219,10 @@ def _assemble_structure(self):
205219
if attachmenttree is not None:
206220
mainstruct.append((attachmenttree, None))
207221

222+
contenttype = self._get_contenttype()
223+
if contenttype is not None:
224+
mainstruct.append((contenttype, None))
225+
208226
bodytree = self._get_body()
209227
if bodytree is not None:
210228
mainstruct.append((bodytree, None))
@@ -236,15 +254,29 @@ def _get_source(self):
236254
self._sourcetree = TextlinesList(sourcetxt, att, att_focus)
237255
return self._sourcetree
238256

257+
def _get_content_parts(self):
258+
if self._content_parts is None:
259+
att = settings.get_theming_attribute('thread', 'body')
260+
att_focus = settings.get_theming_attribute(
261+
'thread', 'body_focus')
262+
263+
self._content_parts = [
264+
(ctype,
265+
TextlinesList(text, att, att_focus))
266+
for ctype, text
267+
in extract_body_parts(self._message.get_email())]
268+
269+
return self._content_parts
270+
239271
def _get_body(self):
240-
if self._bodytree is None:
241-
bodytxt = extract_body(self._message.get_email())
242-
if bodytxt:
243-
att = settings.get_theming_attribute('thread', 'body')
244-
att_focus = settings.get_theming_attribute(
245-
'thread', 'body_focus')
246-
self._bodytree = TextlinesList(bodytxt, att, att_focus)
247-
return self._bodytree
272+
return self._get_content_parts()[self._current_contenttype][1]
273+
274+
def _get_contenttype(self):
275+
return ContenttypeWidget([ctype for ctype, _ in self._get_content_parts()], self._current_contenttype)
276+
277+
def next_contenttype(self):
278+
self._current_contenttype += 1
279+
self._current_contenttype %= len(self._get_content_parts())
248280

249281
def _get_headers(self):
250282
if self.display_all_headers is True:

0 commit comments

Comments
 (0)