This patch changes how the notmuch vim client supports attachments:

- For each message part a 'Part <number>: <filename>' is added
  to the header.
- You can then use 'e' to extract the attachment under the cursor
  or use it elsewhere to extract all attachments (the prior behavior)
- You can use 'v' to 'view' the attachment/part using xdg-open by default.
- If the message is 'text/html' we include a 'Part:' for the body of the
  message so you can easily view it in a web browser if you so choose.

    Ian
---
 vim/notmuch.txt |  8 +++++-
 vim/notmuch.vim | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/vim/notmuch.txt b/vim/notmuch.txt
index 4374102..838a904 100644
--- a/vim/notmuch.txt
+++ b/vim/notmuch.txt
@@ -72,6 +72,9 @@ q     Quit view
 A      Archive (-inbox -unread)
 I      Mark as read (-unread)
 t      Tag (prompted)
+e       Extract attachment on the current 'Attachment' line or all
+       attachments if the cursor is elsewhere.
+v       View attachment on the current 'Attachment' line.
 s      Search
 p      Save patches
 r      Reply
@@ -148,6 +151,9 @@ You can also configure your externail mail reader and 
sendemail program:
 >
        let g:notmuch_reader = 'mutt -f %s'
        let g:notmuch_sendmail = 'sendmail'
-<
+
+You can also configure what probram is used to view attachments:
+
+       let g:notmuch_view_attachment = 'xdg-open'

 vim:tw=78:ts=8:noet:ft=help:
diff --git a/vim/notmuch.vim b/vim/notmuch.vim
index 331e930..5f73dce 100644
--- a/vim/notmuch.vim
+++ b/vim/notmuch.vim
@@ -35,6 +35,7 @@ let g:notmuch_show_maps = {
        \ 't':          'show_tag("")',
        \ 'o':          'show_open_msg()',
        \ 'e':          'show_extract_msg()',
+       \ '<Enter>':    'show_view_attachment()',
        \ 's':          'show_save_msg()',
        \ 'p':          'show_save_patches()',
        \ 'r':          'show_reply()',
@@ -58,6 +59,8 @@ let s:notmuch_date_format_default = '%d.%m.%y'
 let s:notmuch_datetime_format_default = '%d.%m.%y %H:%M:%S'
 let s:notmuch_reader_default = 'mutt -f %s'
 let s:notmuch_sendmail_default = 'sendmail'
+let s:notmuch_view_attachment_default = 'xdg-open'
+let s:notmuch_attachment_tmpdir_default = '~/.notmuch/tmp'
 let s:notmuch_folders_count_threads_default = 0

 function! s:new_file_buffer(type, fname)
@@ -147,13 +150,72 @@ function! s:show_info()
        ruby vim_puts get_message.inspect
 endfunction

+function! s:show_view_attachment()
+       let line = getline(".")
+ruby << EOF
+       m = get_message
+       line = VIM::evaluate('line')
+
+       match = line.match(/^Part (\d*):/)
+       if match and match.length == 2
+               # Set up the tmpdir
+               tmpdir = VIM::evaluate('g:notmuch_attachment_tmpdir')
+               tmpdir = File.expand_path(tmpdir)
+               Dir.mkdir(tmpdir) unless Dir.exists?(tmpdir)
+
+               p = m.mail.parts[match[1].to_i - 1]
+               if p == nil
+                       # Not a multipart message, use the message itself.
+                       p = m.mail
+               end
+               if p.filename and p.filename.length > 0
+                       filename = p.filename
+               else
+                       suffix = ''
+                       if p.mime_type == 'text/html'
+                               suffix = '.html'
+                       end
+                       filename = "part-#{match[1]}#{suffix}"
+               end
+
+               # Sanitize just in case..
+               filename.gsub!(/[^0-9A-Za-z.\-]/, '_')
+
+               fullpath = File.expand_path("#{tmpdir}/#{filename}")
+               vim_puts "Viewing attachment #{fullpath}"
+               File.open(fullpath, 'w') do |f|
+                       f.write p.body.decoded
+                       cmd = VIM::evaluate('g:notmuch_view_attachment')
+                       system(cmd, fullpath)
+               end
+       else
+               vim_puts "No attachment on this line."
+       end
+EOF
+endfunction
+
 function! s:show_extract_msg()
+       let line = getline(".")
 ruby << EOF
        m = get_message
-       m.mail.attachments.each do |a|
+       line = VIM::evaluate('line')
+
+       # If the user is on a line that has an 'Part'
+       # line, we just extract the one attachment.
+       match = line.match(/^Part (\d*):/)
+       if match and match.length == 2
+               a = m.mail.parts[match[1].to_i - 1]
                File.open(a.filename, 'w') do |f|
                        f.write a.body.decoded
-                       print "Extracted '#{a.filename}'"
+                       vim_puts "Extracted #{a.filename}"
+               end
+       else
+               # Extract them all..
+               m.mail.attachments.each do |a|
+                       File.open(a.filename, 'w') do |f|
+                               f.write a.body.decoded
+                               vim_puts "Extracted #{a.filename}"
+                       end
                end
        end
 EOF
@@ -326,6 +388,16 @@ ruby << EOF
                        b << "To: %s" % msg['to']
                        b << "Cc: %s" % msg['cc']
                        b << "Date: %s" % msg['date']
+                       cnt = 0
+                       m.parts.each do |p|
+                               cnt += 1
+                               b << "Part %d: %s (%s)" % [cnt, p.mime_type, 
p.filename]
+                       end
+                       # Add a special case for text/html messages.  Here we 
show the
+                       # only 'part' so that we can view it in a web browser 
if we want.
+                       if m.parts.length == 0 and part.mime_type == 'text/html'
+                               b << "Part 1: text/html"
+                       end
                        nm_m.body_start = b.count
                        b << "--- %s ---" % part.mime_type
                        part.convert.each_line do |l|
@@ -420,6 +492,14 @@ function! s:set_defaults()
                endif
        endif

+       if !exists('g:notmuch_attachment_tmpdir')
+               let g:notmuch_attachment_tmpdir = 
s:notmuch_attachment_tmpdir_default
+       endif
+
+       if !exists('g:notmuch_view_attachment')
+               let g:notmuch_view_attachment = 
s:notmuch_view_attachment_default
+       endif
+
        if !exists('g:notmuch_folders_count_threads')
                if exists('g:notmuch_rb_count_threads')
                        let g:notmuch_count_threads = g:notmuch_rb_count_threads
-- 
1.9.3

Reply via email to