pazz / alot

Terminal-based Mail User Agent
GNU General Public License v3.0
695 stars 164 forks source link

Unable to open e-mails without Content-Type header #1512

Closed mmartin closed 4 years ago

mmartin commented 4 years ago

Describe the bug After b1c93c4d0c1eeacd64a195f16861bcb73910e739 I'm no longer able to open e-mails without Content-Type header.

Software Versions

To Reproduce Steps to reproduce the behaviour:

  1. try to open an e-mail without Content-Type header;
  2. see error.

Error Log

DEBUG:thread:matching lines None...
DEBUG:thread:MT expand
DEBUG:utils:Content-Transfer-Encoding: "7bit"
DEBUG:utils:assuming Content-Transfer-Encoding: 7bit
ERROR:ui:Traceback (most recent call last):
  File "/home/martins/.local/lib/python3.7/site-packages/alot/ui.py", line 723, in apply_command
    cmd.apply(self)
  File "/home/martins/.local/lib/python3.7/site-packages/alot/commands/thread.py", line 613, in apply
    mt.expand(mt.root)
  File "/home/martins/.local/lib/python3.7/site-packages/alot/widgets/thread.py", line 215, in expand
    self.reassemble()
  File "/home/martins/.local/lib/python3.7/site-packages/alot/widgets/thread.py", line 189, in reassemble
    self._maintree._treelist = self._assemble_structure()
  File "/home/martins/.local/lib/python3.7/site-packages/alot/widgets/thread.py", line 235, in _assemble_structure
    bodytree = self._get_body()
  File "/home/martins/.local/lib/python3.7/site-packages/alot/widgets/thread.py", line 269, in _get_body
    bodytxt = self._message.get_body_text()
  File "/home/martins/.local/lib/python3.7/site-packages/alot/db/message.py", line 280, in get_body_text
    return extract_body_part(self.mime_part)
  File "/home/martins/.local/lib/python3.7/site-packages/alot/db/utils.py", line 504, in extract_body_part
    else {})
  File "/home/martins/.local/lib/python3.7/site-packages/alot/db/utils.py", line 368, in render_part
    parms = tuple('='.join(p) for p in part.get_params())
TypeError: 'NoneType' object is not iterable

Additional info https://github.com/pazz/alot/blob/dff3ae0e46719c8261ba819d71734c5591988694/alot/db/utils.py#L368 get_params() returns None, if the e-mail doesn't have Content-Type header.

Proposed patch:

--- a/alot/db/utils.py
+++ b/alot/db/utils.py
@@ -365,7 +365,7 @@ def render_part(part, field_key='copiousoutput'):
             stdin = raw_payload

         # read parameter, create handler command
-        parms = tuple('='.join(p) for p in part.get_params())
+        parms = tuple('='.join(p) for p in part.get_params([]))

         # create and call external command
         cmd = mailcap.subst(entry['view'], ctype,
pazz commented 4 years ago

Would you mind adding a test case similar to 6bb18fa97c78b3cb1fcb60ce5d850602b55e358f for this?

mmartin commented 4 years ago

Something like this?

@mock.patch('alot.db.utils.settings.mailcap_find_match',
            mock.Mock(return_value=(None, {'view': 'cat "%s"'})))
def test_plaintext_mailcap_wo_content_type(self):
    mailstring = '\n'.join([
        'From: me@localhost'
        'To: you@localhost'
        'Subject: test subject'
        '\n'
        'test body'])
    mail = email.message_from_string(mailstring,
            _class=email.message.EmailMessage)
    body_part = utils.get_body_part(mail)
    actual = utils.extract_body_part(body_part)
    expected = 'test body'
    self.assertEqual(actual, expected)
pazz commented 4 years ago

Yes that looks great. Perhaps put the mail string into a separate file under tests/static/mail or simply re-use one of the mails already in that corpus? It'd great if you could send a PR with this test and your proposed patch (with an explanation why the extra empty list parameter fixes the issue). Thanks for making alot better :)