[RFC PATCH 1/7] vim: show: add mailcap filtering

Subject: [RFC PATCH 1/7] vim: show: add mailcap filtering

Date: Thu, 13 Oct 2016 14:13:50 -0600

To: notmuch@notmuchmail.org

Cc: nlhowell@gmail.com

From: Nick Howell


Add mailcap filters, which allow us to display multiple parts.

See http://packages.debian.org/unstable/net/mime-support for details on
run-mailcap, the mailcap program we default to; the TLDR is that mailcap
is a program which accepts a mimetype argument, looks up a translation
program based on this, and hooks up stdin/stdout to this program.

This is useful for inline display of html, pdfs, docx, images (through
caca), etc, as well as external display (by launching an image viewer).
The implementation here linearizes the part tree of the message
(treating all multipart pieces as multipart/mixed) and then popens a
mailcap process for each. If mailcap fails for some reason (e.g. no
display rule), the contents are listed as "unavailable."

A sample $HOME/.mailcap configuration file:

application/pdf; pdftotext -layout '%s' - | fmt; copiousoutput;
text/html; vilistextum -u '%s' -w 72 -; copiousoutput;
text/plain; fmt -s

Some suggested converters:
- antiword, antixls, vilistextum, docx2txt
---
 vim/notmuch.vim | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index ad8b7c8..c66c874 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -60,6 +60,7 @@ let s:notmuch_reader_default = 'mutt -f %s'
 let s:notmuch_sendmail_default = 'sendmail'
 let s:notmuch_folders_count_threads_default = 0
 let s:notmuch_compose_start_insert_default = 1
+let s:notmuch_mailcap_filter_default = "run-mailcap --action=view %s:-"
 
 function! s:new_file_buffer(type, fname)
 	exec printf('edit %s', a:fname)
@@ -320,9 +321,9 @@ ruby << EOF
 		msgs = q.search_messages
 		msgs.each do |msg|
 			m = Mail.read(msg.filename)
-			part = m.find_first_text
 			nm_m = Message.new(msg, m)
 			$messages << nm_m
+			mailcap = VIM::evaluate('g:notmuch_mailcap_filter')
 			date_fmt = VIM::evaluate('g:notmuch_datetime_format')
 			date = Time.at(msg.date).strftime(date_fmt)
 			nm_m.start = b.count
@@ -332,9 +333,31 @@ ruby << EOF
 			b << "Cc: %s" % msg['cc']
 			b << "Date: %s" % msg['date']
 			nm_m.body_start = b.count
-			b << "--- %s ---" % part.mime_type
-			part.convert.each_line do |l|
-				b << l.chomp
+			parts = [m]
+			while parts.any?(&:multipart?)
+				parts = parts.collect do |part|
+					if part.multipart?
+						part.parts
+					else
+						part
+					end
+				end.flatten
+			end
+
+			parts.each do |part|
+				b << "--- %s ---" % part.mime_type
+				begin
+					IO.popen(mailcap % part.mime_type, "r+b") do |io|
+						io.write(part.decoded)
+						io.close_write
+						io.each_line do |l|
+							b << l.chomp
+						end
+					end
+				rescue
+					b << "--- unavailable ---"
+				end
+				b << ""
 			end
 			b << ""
 			nm_m.end = b.count
@@ -393,6 +416,9 @@ endfunction
 "" root
 
 function! s:set_defaults()
+	if !exists('g:notmuch_mailcap_filter')
+		let g:notmuch_mailcap_filter = s:notmuch_mailcap_filter_default
+	endif
 	if !exists('g:notmuch_date_format')
 		if exists('g:notmuch_rb_date_format')
 			let g:notmuch_date_format = g:notmuch_rb_date_format
-- 
2.7.3


Thread: