1if exists("g:loaded_notmuch") 2 finish 3endif 4 5if !has("ruby") || version < 700 6 finish 7endif 8 9let g:loaded_notmuch = "yep" 10 11let g:notmuch_folders_maps = { 12 \ '<Enter>': 'folders_show_search()', 13 \ 's': 'folders_search_prompt()', 14 \ '=': 'folders_refresh()', 15 \ 'c': 'compose()', 16 \ } 17 18let g:notmuch_search_maps = { 19 \ 'q': 'kill_this_buffer()', 20 \ '<Enter>': 'search_show_thread(1)', 21 \ '<Space>': 'search_show_thread(2)', 22 \ 'A': 'search_tag("-inbox -unread")', 23 \ 'I': 'search_tag("-unread")', 24 \ 't': 'search_tag("")', 25 \ 's': 'search_search_prompt()', 26 \ '=': 'search_refresh()', 27 \ '?': 'search_info()', 28 \ 'c': 'compose()', 29 \ } 30 31let g:notmuch_show_maps = { 32 \ 'q': 'kill_this_buffer()', 33 \ 'A': 'show_tag("-inbox -unread")', 34 \ 'I': 'show_tag("-unread")', 35 \ 't': 'show_tag("")', 36 \ 'o': 'show_open_msg()', 37 \ 'e': 'show_extract_msg()', 38 \ 's': 'show_save_msg()', 39 \ 'p': 'show_save_patches()', 40 \ 'r': 'show_reply()', 41 \ '?': 'show_info()', 42 \ '<Tab>': 'show_next_msg()', 43 \ 'c': 'compose()', 44 \ } 45 46let g:notmuch_compose_maps = { 47 \ ',s': 'compose_send()', 48 \ ',q': 'compose_quit()', 49 \ } 50 51let s:notmuch_folders_default = [ 52 \ [ 'new', 'tag:inbox and tag:unread' ], 53 \ [ 'inbox', 'tag:inbox' ], 54 \ [ 'unread', 'tag:unread' ], 55 \ ] 56 57let s:notmuch_date_format_default = '%d.%m.%y' 58let s:notmuch_datetime_format_default = '%d.%m.%y %H:%M:%S' 59let s:notmuch_reader_default = 'mutt -f %s' 60let s:notmuch_sendmail_default = 'sendmail' 61let s:notmuch_folders_count_threads_default = 0 62let s:notmuch_compose_start_insert_default = 1 63 64function! s:new_file_buffer(type, fname) 65 exec printf('edit %s', a:fname) 66 execute printf('set filetype=notmuch-%s', a:type) 67 execute printf('set syntax=notmuch-%s', a:type) 68 ruby $curbuf.init(VIM::evaluate('a:type')) 69endfunction 70 71function! s:on_compose_delete() 72 if b:compose_done 73 return 74 endif 75 if input('[s]end/[q]uit? ') =~ '^s' 76 call s:compose_send() 77 endif 78endfunction 79 80"" actions 81 82function! s:compose_quit() 83 let b:compose_done = 1 84 call s:kill_this_buffer() 85endfunction 86 87function! s:compose_send() 88 let b:compose_done = 1 89 let fname = expand('%') 90 let lines = getline(5, '$') 91 92ruby << EOF 93 # Generate proper mail to send 94 text = VIM::evaluate('lines').join("\n") 95 fname = VIM::evaluate('fname') 96 transport = Mail.new(text) 97 transport.message_id = generate_message_id 98 transport.charset = 'utf-8' 99 File.write(fname, transport.to_s) 100EOF 101 102 let cmdtxt = g:notmuch_sendmail . ' -t -f ' . s:reply_from . ' < ' . fname 103 let out = system(cmdtxt) 104 let err = v:shell_error 105 if err 106 echohl Error 107 echo 'Eeek! unable to send mail' 108 echo out 109 echohl None 110 return 111 endif 112 call delete(fname) 113 echo 'Mail sent successfully.' 114 call s:kill_this_buffer() 115endfunction 116 117function! s:show_next_msg() 118ruby << EOF 119 r, c = $curwin.cursor 120 n = $curbuf.line_number 121 i = $messages.index { |m| n >= m.start && n <= m.end } 122 m = $messages[i + 1] 123 if m 124 r = m.body_start + 1 125 VIM::command("normal #{m.start}zt") 126 $curwin.cursor = r, c 127 end 128EOF 129endfunction 130 131function! s:show_reply() 132 ruby open_reply get_message.mail 133 let b:compose_done = 0 134 call s:set_map(g:notmuch_compose_maps) 135 autocmd BufDelete <buffer> call s:on_compose_delete() 136 if g:notmuch_compose_start_insert 137 startinsert! 138 end 139endfunction 140 141function! s:compose() 142 ruby open_compose 143 let b:compose_done = 0 144 call s:set_map(g:notmuch_compose_maps) 145 autocmd BufDelete <buffer> call s:on_compose_delete() 146 if g:notmuch_compose_start_insert 147 startinsert! 148 end 149endfunction 150 151function! s:show_info() 152 ruby vim_puts get_message.inspect 153endfunction 154 155function! s:show_extract_msg() 156ruby << EOF 157 m = get_message 158 m.mail.attachments.each do |a| 159 File.open(a.filename, 'w') do |f| 160 f.write a.body.decoded 161 print "Extracted '#{a.filename}'" 162 end 163 end 164EOF 165endfunction 166 167function! s:show_open_msg() 168ruby << EOF 169 m = get_message 170 mbox = File.expand_path('~/.notmuch/vim_mbox') 171 cmd = VIM::evaluate('g:notmuch_reader') % mbox 172 system "notmuch show --format=mbox id:#{m.message_id} > #{mbox} && #{cmd}" 173EOF 174endfunction 175 176function! s:show_save_msg() 177 let file = input('File name: ') 178ruby << EOF 179 file = VIM::evaluate('file') 180 m = get_message 181 system "notmuch show --format=mbox id:#{m.message_id} > #{file}" 182EOF 183endfunction 184 185function! s:show_save_patches() 186ruby << EOF 187 q = $curbuf.query($cur_thread) 188 t = q.search_threads.first 189 n = 0 190 t.toplevel_messages.first.replies.each do |m| 191 next if not m['subject'] =~ /^\[PATCH.*\]/ 192 file = "%04d.patch" % [n += 1] 193 system "notmuch show --format=mbox id:#{m.message_id} > #{file}" 194 end 195 vim_puts "Saved #{n} patches" 196EOF 197endfunction 198 199function! s:show_tag(intags) 200 if empty(a:intags) 201 let tags = input('tags: ') 202 else 203 let tags = a:intags 204 endif 205 ruby do_tag(get_cur_view, VIM::evaluate('l:tags')) 206 call s:show_next_thread() 207endfunction 208 209function! s:search_search_prompt() 210 let text = input('Search: ') 211 if text == "" 212 return 213 endif 214 setlocal modifiable 215ruby << EOF 216 $cur_search = VIM::evaluate('text') 217 $curbuf.reopen 218 search_render($cur_search) 219EOF 220 setlocal nomodifiable 221endfunction 222 223function! s:search_info() 224 ruby vim_puts get_thread_id 225endfunction 226 227function! s:search_refresh() 228 setlocal modifiable 229 ruby $curbuf.reopen 230 ruby search_render($cur_search) 231 setlocal nomodifiable 232endfunction 233 234function! s:search_tag(intags) 235 if empty(a:intags) 236 let tags = input('tags: ') 237 else 238 let tags = a:intags 239 endif 240 ruby do_tag(get_thread_id, VIM::evaluate('l:tags')) 241 norm j 242endfunction 243 244function! s:folders_search_prompt() 245 let text = input('Search: ') 246 call s:search(text) 247endfunction 248 249function! s:folders_refresh() 250 setlocal modifiable 251 ruby $curbuf.reopen 252 ruby folders_render() 253 setlocal nomodifiable 254endfunction 255 256"" basic 257 258function! s:show_cursor_moved() 259ruby << EOF 260 if $render.is_ready? 261 VIM::command('setlocal modifiable') 262 $render.do_next 263 VIM::command('setlocal nomodifiable') 264 end 265EOF 266endfunction 267 268function! s:show_next_thread() 269 call s:kill_this_buffer() 270 if line('.') != line('$') 271 norm j 272 call s:search_show_thread(0) 273 else 274 echo 'No more messages.' 275 endif 276endfunction 277 278function! s:kill_this_buffer() 279ruby << EOF 280 $curbuf.close 281 VIM::command("bdelete!") 282EOF 283endfunction 284 285function! s:set_map(maps) 286 nmapclear <buffer> 287 for [key, code] in items(a:maps) 288 let cmd = printf(":call <SID>%s<CR>", code) 289 exec printf('nnoremap <buffer> %s %s', key, cmd) 290 endfor 291endfunction 292 293function! s:new_buffer(type) 294 enew 295 setlocal buftype=nofile bufhidden=hide 296 keepjumps 0d 297 execute printf('set filetype=notmuch-%s', a:type) 298 execute printf('set syntax=notmuch-%s', a:type) 299 ruby $curbuf.init(VIM::evaluate('a:type')) 300endfunction 301 302function! s:set_menu_buffer() 303 setlocal nomodifiable 304 setlocal cursorline 305 setlocal nowrap 306endfunction 307 308"" main 309 310function! s:show(thread_id) 311 call s:new_buffer('show') 312 setlocal modifiable 313ruby << EOF 314 thread_id = VIM::evaluate('a:thread_id') 315 $cur_thread = thread_id 316 $messages.clear 317 $curbuf.render do |b| 318 q = $curbuf.query(get_cur_view) 319 q.sort = Notmuch::SORT_OLDEST_FIRST 320 $exclude_tags.each { |t| 321 q.add_tag_exclude(t) 322 } 323 msgs = q.search_messages 324 msgs.each do |msg| 325 m = Mail.read(msg.filename) 326 part = m.find_first_text 327 nm_m = Message.new(msg, m) 328 $messages << nm_m 329 date_fmt = VIM::evaluate('g:notmuch_datetime_format') 330 date = Time.at(msg.date).strftime(date_fmt) 331 nm_m.start = b.count 332 b << "%s %s (%s)" % [msg['from'], date, msg.tags] 333 b << "Subject: %s" % [msg['subject']] 334 b << "To: %s" % msg['to'] 335 b << "Cc: %s" % msg['cc'] 336 b << "Date: %s" % msg['date'] 337 nm_m.body_start = b.count 338 b << "--- %s ---" % part.mime_type 339 part.convert.each_line do |l| 340 b << l.chomp 341 end 342 b << "" 343 nm_m.end = b.count 344 end 345 b.delete(b.count) 346 end 347 $messages.each_with_index do |msg, i| 348 VIM::command("syntax region nmShowMsg#{i}Desc start='\\%%%il' end='\\%%%il' contains=@nmShowMsgDesc" % [msg.start, msg.start + 1]) 349 VIM::command("syntax region nmShowMsg#{i}Head start='\\%%%il' end='\\%%%il' contains=@nmShowMsgHead" % [msg.start + 1, msg.body_start]) 350 VIM::command("syntax region nmShowMsg#{i}Body start='\\%%%il' end='\\%%%dl' contains=@nmShowMsgBody" % [msg.body_start, msg.end]) 351 end 352EOF 353 setlocal nomodifiable 354 call s:set_map(g:notmuch_show_maps) 355endfunction 356 357function! s:search_show_thread(mode) 358ruby << EOF 359 mode = VIM::evaluate('a:mode') 360 id = get_thread_id 361 case mode 362 when 0; 363 when 1; $cur_filter = nil 364 when 2; $cur_filter = $cur_search 365 end 366 VIM::command("call s:show('#{id}')") 367EOF 368endfunction 369 370function! s:search(search) 371 call s:new_buffer('search') 372ruby << EOF 373 $cur_search = VIM::evaluate('a:search') 374 search_render($cur_search) 375EOF 376 call s:set_menu_buffer() 377 call s:set_map(g:notmuch_search_maps) 378 autocmd CursorMoved <buffer> call s:show_cursor_moved() 379endfunction 380 381function! s:folders_show_search() 382ruby << EOF 383 n = $curbuf.line_number 384 s = $searches[n - 1] 385 VIM::command("call s:search('#{s}')") 386EOF 387endfunction 388 389function! s:folders() 390 call s:new_buffer('folders') 391 ruby folders_render() 392 call s:set_menu_buffer() 393 call s:set_map(g:notmuch_folders_maps) 394endfunction 395 396"" root 397 398function! s:set_defaults() 399 if !exists('g:notmuch_date_format') 400 if exists('g:notmuch_rb_date_format') 401 let g:notmuch_date_format = g:notmuch_rb_date_format 402 else 403 let g:notmuch_date_format = s:notmuch_date_format_default 404 endif 405 endif 406 407 if !exists('g:notmuch_datetime_format') 408 if exists('g:notmuch_rb_datetime_format') 409 let g:notmuch_datetime_format = g:notmuch_rb_datetime_format 410 else 411 let g:notmuch_datetime_format = s:notmuch_datetime_format_default 412 endif 413 endif 414 415 if !exists('g:notmuch_reader') 416 if exists('g:notmuch_rb_reader') 417 let g:notmuch_reader = g:notmuch_rb_reader 418 else 419 let g:notmuch_reader = s:notmuch_reader_default 420 endif 421 endif 422 423 if !exists('g:notmuch_sendmail') 424 if exists('g:notmuch_rb_sendmail') 425 let g:notmuch_sendmail = g:notmuch_rb_sendmail 426 else 427 let g:notmuch_sendmail = s:notmuch_sendmail_default 428 endif 429 endif 430 431 if !exists('g:notmuch_folders_count_threads') 432 if exists('g:notmuch_rb_count_threads') 433 let g:notmuch_count_threads = g:notmuch_rb_count_threads 434 else 435 let g:notmuch_folders_count_threads = s:notmuch_folders_count_threads_default 436 endif 437 endif 438 439 if !exists('g:notmuch_compose_start_insert') 440 let g:notmuch_compose_start_insert = s:notmuch_compose_start_insert_default 441 endif 442 443 if !exists('g:notmuch_custom_search_maps') && exists('g:notmuch_rb_custom_search_maps') 444 let g:notmuch_custom_search_maps = g:notmuch_rb_custom_search_maps 445 endif 446 447 if !exists('g:notmuch_custom_show_maps') && exists('g:notmuch_rb_custom_show_maps') 448 let g:notmuch_custom_show_maps = g:notmuch_rb_custom_show_maps 449 endif 450 451 if exists('g:notmuch_custom_search_maps') 452 call extend(g:notmuch_search_maps, g:notmuch_custom_search_maps) 453 endif 454 455 if exists('g:notmuch_custom_show_maps') 456 call extend(g:notmuch_show_maps, g:notmuch_custom_show_maps) 457 endif 458 459 if !exists('g:notmuch_folders') 460 if exists('g:notmuch_rb_folders') 461 let g:notmuch_folders = g:notmuch_rb_folders 462 else 463 let g:notmuch_folders = s:notmuch_folders_default 464 endif 465 endif 466endfunction 467 468function! s:NotMuch(...) 469 call s:set_defaults() 470 471ruby << EOF 472 require 'notmuch' 473 require 'rubygems' 474 require 'tempfile' 475 require 'socket' 476 begin 477 require 'mail' 478 rescue LoadError 479 end 480 481 $db_name = nil 482 $email = $email_name = $email_address = nil 483 $exclude_tags = [] 484 $searches = [] 485 $threads = [] 486 $messages = [] 487 $mail_installed = defined?(Mail) 488 489 def get_config_item(item) 490 result = '' 491 IO.popen(['notmuch', 'config', 'get', item]) { |out| 492 result = out.read 493 } 494 return result.rstrip 495 end 496 497 def get_config 498 $db_name = get_config_item('database.path') 499 $email_name = get_config_item('user.name') 500 $email_address = get_config_item('user.primary_email') 501 $email_name = get_config_item('user.name') 502 $email = "%s <%s>" % [$email_name, $email_address] 503 ignore_tags = get_config_item('search.exclude_tags') 504 $exclude_tags = ignore_tags.split("\n") 505 end 506 507 def vim_puts(s) 508 VIM::command("echo '#{s.to_s}'") 509 end 510 511 def vim_p(s) 512 VIM::command("echo '#{s.inspect}'") 513 end 514 515 def author_filter(a) 516 # TODO email format, aliases 517 a.strip! 518 a.gsub!(/[\.@].*/, '') 519 a.gsub!(/^ext /, '') 520 a.gsub!(/ \(.*\)/, '') 521 a 522 end 523 524 def get_thread_id 525 n = $curbuf.line_number - 1 526 return "thread:%s" % $threads[n] 527 end 528 529 def get_message 530 n = $curbuf.line_number 531 return $messages.find { |m| n >= m.start && n <= m.end } 532 end 533 534 def get_cur_view 535 if $cur_filter 536 return "#{$cur_thread} and (#{$cur_filter})" 537 else 538 return $cur_thread 539 end 540 end 541 542 def generate_message_id 543 t = Time.now 544 random_tag = sprintf('%x%x_%x%x%x', 545 t.to_i, t.tv_usec, 546 $$, Thread.current.object_id.abs, rand(255)) 547 return "<#{random_tag}@#{Socket.gethostname}.notmuch>" 548 end 549 550 def open_compose_helper(lines, cur) 551 help_lines = [ 552 'Notmuch-Help: Type in your message here; to help you use these bindings:', 553 'Notmuch-Help: ,s - send the message (Notmuch-Help lines will be removed)', 554 'Notmuch-Help: ,q - abort the message', 555 ] 556 557 dir = File.expand_path('~/.notmuch/compose') 558 FileUtils.mkdir_p(dir) 559 Tempfile.open(['nm-', '.mail'], dir) do |f| 560 f.puts(help_lines) 561 f.puts 562 f.puts(lines) 563 564 sig_file = File.expand_path('~/.signature') 565 if File.exists?(sig_file) 566 f.puts("-- ") 567 f.write(File.read(sig_file)) 568 end 569 570 f.flush 571 572 cur += help_lines.size + 1 573 574 VIM::command("let s:reply_from='%s'" % $email_address) 575 VIM::command("call s:new_file_buffer('compose', '#{f.path}')") 576 VIM::command("call cursor(#{cur}, 0)") 577 end 578 end 579 580 def open_reply(orig) 581 reply = orig.reply do |m| 582 # fix headers 583 if not m[:reply_to] 584 m.to = [orig[:from].to_s, orig[:to].to_s] 585 end 586 m.cc = orig[:cc] 587 m.from = $email 588 m.charset = 'utf-8' 589 end 590 591 lines = [] 592 593 body_lines = [] 594 if $mail_installed 595 addr = Mail::Address.new(orig[:from].value) 596 name = addr.name 597 name = addr.local + "@" if name.nil? && !addr.local.nil? 598 else 599 name = orig[:from] 600 end 601 name = "somebody" if name.nil? 602 603 body_lines << "%s wrote:" % name 604 part = orig.find_first_text 605 part.convert.each_line do |l| 606 body_lines << "> %s" % l.chomp 607 end 608 body_lines << "" 609 body_lines << "" 610 body_lines << "" 611 612 reply.body = body_lines.join("\n") 613 614 lines += reply.present.lines.map { |e| e.chomp } 615 lines << "" 616 617 cur = lines.count - 1 618 619 open_compose_helper(lines, cur) 620 end 621 622 def open_compose() 623 lines = [] 624 625 lines << "From: #{$email}" 626 lines << "To: " 627 cur = lines.count 628 629 lines << "Cc: " 630 lines << "Bcc: " 631 lines << "Subject: " 632 lines << "" 633 lines << "" 634 lines << "" 635 636 open_compose_helper(lines, cur) 637 end 638 639 def folders_render() 640 $curbuf.render do |b| 641 folders = VIM::evaluate('g:notmuch_folders') 642 count_threads = VIM::evaluate('g:notmuch_folders_count_threads') == 1 643 $searches.clear 644 folders.each do |name, search| 645 q = $curbuf.query(search) 646 $exclude_tags.each { |t| 647 q.add_tag_exclude(t) 648 } 649 $searches << search 650 count = count_threads ? q.count_threads : q.count_messages 651 b << "%9d %-20s (%s)" % [count, name, search] 652 end 653 end 654 end 655 656 def search_render(search) 657 date_fmt = VIM::evaluate('g:notmuch_date_format') 658 q = $curbuf.query(search) 659 q.sort = Notmuch::SORT_NEWEST_FIRST 660 $exclude_tags.each { |t| 661 q.add_tag_exclude(t) 662 } 663 $threads.clear 664 t = q.search_threads 665 666 $render = $curbuf.render_staged(t) do |b, items| 667 items.each do |e| 668 authors = e.authors.to_utf8.split(/[,|]/).map { |a| author_filter(a) }.join(",") 669 date = Time.at(e.newest_date).strftime(date_fmt) 670 subject = e.messages.first['subject'] 671 if $mail_installed 672 subject = Mail::Field.parse("Subject: " + subject).to_s 673 else 674 subject = subject.force_encoding('utf-8') 675 end 676 b << "%-12s %3s %-20.20s | %s (%s)" % [date, e.matched_messages, authors, subject, e.tags] 677 $threads << e.thread_id 678 end 679 end 680 end 681 682 def do_tag(filter, tags) 683 $curbuf.do_write do |db| 684 q = db.query(filter) 685 q.search_messages.each do |e| 686 e.freeze 687 tags.split.each do |t| 688 case t 689 when /^-(.*)/ 690 e.remove_tag($1) 691 when /^\+(.*)/ 692 e.add_tag($1) 693 when /^([^\+^-].*)/ 694 e.add_tag($1) 695 end 696 end 697 e.thaw 698 e.tags_to_maildir_flags 699 end 700 q.destroy! 701 end 702 end 703 704 module DbHelper 705 def init(name) 706 @name = name 707 @db = Notmuch::Database.new($db_name) 708 @queries = [] 709 end 710 711 def query(*args) 712 q = @db.query(*args) 713 @queries << q 714 q 715 end 716 717 def close 718 @queries.delete_if { |q| ! q.destroy! } 719 @db.close 720 end 721 722 def reopen 723 close if @db 724 @db = Notmuch::Database.new($db_name) 725 end 726 727 def do_write 728 db = Notmuch::Database.new($db_name, :mode => Notmuch::MODE_READ_WRITE) 729 begin 730 yield db 731 ensure 732 db.close 733 end 734 end 735 end 736 737 class Message 738 attr_accessor :start, :body_start, :end 739 attr_reader :message_id, :filename, :mail 740 741 def initialize(msg, mail) 742 @message_id = msg.message_id 743 @filename = msg.filename 744 @mail = mail 745 @start = 0 746 @end = 0 747 mail.import_headers(msg) if not $mail_installed 748 end 749 750 def to_s 751 "id:%s" % @message_id 752 end 753 754 def inspect 755 "id:%s, file:%s" % [@message_id, @filename] 756 end 757 end 758 759 class StagedRender 760 def initialize(buffer, enumerable, block) 761 @b = buffer 762 @enumerable = enumerable 763 @block = block 764 @last_render = 0 765 766 @b.render { do_next } 767 end 768 769 def is_ready? 770 @last_render - @b.line_number <= $curwin.height 771 end 772 773 def do_next 774 items = @enumerable.take($curwin.height * 2) 775 return if items.empty? 776 @block.call @b, items 777 @last_render = @b.count 778 end 779 end 780 781 class VIM::Buffer 782 include DbHelper 783 784 def <<(a) 785 append(count(), a) 786 end 787 788 def render_staged(enumerable, &block) 789 StagedRender.new(self, enumerable, block) 790 end 791 792 def render 793 old_count = count 794 yield self 795 (1..old_count).each do 796 delete(1) 797 end 798 end 799 end 800 801 class Notmuch::Tags 802 def to_s 803 to_a.join(" ") 804 end 805 end 806 807 class Notmuch::Message 808 def to_s 809 "id:%s" % message_id 810 end 811 end 812 813 # workaround for bug in vim's ruby 814 class Object 815 def flush 816 end 817 end 818 819 module SimpleMessage 820 class Header < Array 821 def self.parse(string) 822 return nil if string.empty? 823 return Header.new(string.split(/,\s+/)) 824 end 825 826 def to_s 827 self.join(', ') 828 end 829 end 830 831 def initialize(string = nil) 832 @raw_source = string 833 @body = nil 834 @headers = {} 835 836 return if not string 837 838 if string =~ /(.*?(\r\n|\n))\2/m 839 head, body = $1, $' || '', $2 840 else 841 head, body = string, '' 842 end 843 @body = body 844 end 845 846 def [](name) 847 @headers[name.to_sym] 848 end 849 850 def []=(name, value) 851 @headers[name.to_sym] = value 852 end 853 854 def format_header(value) 855 value.to_s.tr('_', '-').gsub(/(\w+)/) { $1.capitalize } 856 end 857 858 def to_s 859 buffer = '' 860 @headers.each do |key, value| 861 buffer << "%s: %s\r\n" % 862 [format_header(key), value] 863 end 864 buffer << "\r\n" 865 buffer << @body 866 buffer 867 end 868 869 def body=(value) 870 @body = value 871 end 872 873 def from 874 @headers[:from] 875 end 876 877 def decoded 878 @body 879 end 880 881 def mime_type 882 'text/plain' 883 end 884 885 def multipart? 886 false 887 end 888 889 def reply 890 r = Mail::Message.new 891 r[:from] = self[:to] 892 r[:to] = self[:from] 893 r[:cc] = self[:cc] 894 r[:in_reply_to] = self[:message_id] 895 r[:references] = self[:references] 896 r 897 end 898 899 HEADERS = [ :from, :to, :cc, :references, :in_reply_to, :reply_to, :message_id ] 900 901 def import_headers(m) 902 HEADERS.each do |e| 903 dashed = format_header(e) 904 @headers[e] = Header.parse(m[dashed]) 905 end 906 end 907 end 908 909 module Mail 910 911 if not $mail_installed 912 puts "WARNING: Install the 'mail' gem, without it support is limited" 913 914 def self.read(filename) 915 Message.new(File.open(filename, 'rb') { |f| f.read }) 916 end 917 918 class Message 919 include SimpleMessage 920 end 921 end 922 923 class Message 924 925 def find_first_text 926 return self if not multipart? 927 return text_part || html_part 928 end 929 930 def convert 931 if mime_type != "text/html" 932 text = decoded 933 else 934 IO.popen(VIM::evaluate('exists("g:notmuch_html_converter") ? ' + 935 'g:notmuch_html_converter : "elinks --dump"'), "w+") do |pipe| 936 pipe.write(decode_body) 937 pipe.close_write 938 text = pipe.read 939 end 940 end 941 text 942 end 943 944 def present 945 buffer = '' 946 header.fields.each do |f| 947 buffer << "%s: %s\r\n" % [f.name, f.to_s] 948 end 949 buffer << "\r\n" 950 buffer << body.to_s 951 buffer 952 end 953 end 954 end 955 956 class String 957 def to_utf8 958 RUBY_VERSION >= "1.9" ? force_encoding('utf-8') : self 959 end 960 end 961 962 get_config 963EOF 964 if a:0 965 call s:search(join(a:000)) 966 else 967 call s:folders() 968 endif 969endfunction 970 971command -nargs=* NotMuch call s:NotMuch(<f-args>) 972 973" vim: set noexpandtab: 974