“================================================= ” File: vmail.vim “ Description: Vmail is a Vim interface to Gmail. ” Author: Daniel Choi “ ================================================

if exists(“g:loaded_vmail”) || &cp

finish

endif let g:loaded_vmail = 1

if !exists(“g:vmail_flagged_color”)

let g:vmail_flagged_color = "ctermfg=green guifg=green guibg=grey"

endif let s:mailbox = $VMAIL_MAILBOX let s:query = $VMAIL_QUERY let s:browser_command = $VMAIL_BROWSER let s:append_file = ''

let s:drb_uri = $DRB_URI

let s:client_script = “vmail_client ” . shellescape(s:drb_uri) . “ ” let s:set_window_width_command = s:client_script . “window_width= ” let s:list_mailboxes_command = s:client_script . “list_mailboxes ” let s:show_message_command = s:client_script . “show_message ” let s:update_command = s:client_script . “update” let s:fetch_headers_command = s:client_script . “fetch_headers ” let s:select_mailbox_command = s:client_script . “select_mailbox ” let s:search_command = s:client_script . “search ” let s:more_messages_command = s:client_script . “more_messages ” let s:flag_command = s:client_script . “flag ” let s:append_to_file_command = s:client_script . “append_to_file ” let s:move_to_command = s:client_script . “move_to ” let s:copy_to_command = s:client_script . “copy_to ” let s:new_message_template_command = s:client_script . “new_message_template ” let s:reply_template_command = s:client_script . “reply_template ” let s:forward_template_command = s:client_script . “forward_template ” let s:deliver_command = s:client_script . “deliver ” let s:save_attachments_command = s:client_script . “save_attachments ” let s:open_html_part_command = s:client_script . “open_html_part ” let s:show_help_command = s:client_script . “show_help”

let s:message_bufname = “current_message.txt”

function! VmailStatusLine()

return "%<%f\ " . s:mailbox . " " . s:query . "%r%=%-14.(%l,%c%V%)\ %Y %P"

endfunction

function! s:create_list_window()

setlocal nomodifiable
setlocal noswapfile
setlocal nowrap
setlocal nonumber
setlocal foldcolumn=0
setlocal nospell
setlocal textwidth=0
setlocal noreadonly
setlocal ft=vmailMessageList

" let user set this
" setlocal cursorline
" we need the bufnr to find the window later
let s:listbufnr = bufnr('%')
let s:listbufname = bufname('%')
setlocal statusline=%!VmailStatusLine()
call s:message_list_window_mappings()
autocmd BufNewFile,BufRead *.txt setlocal modifiable

endfunction

“ the message display buffer window function! s:create_message_window()

exec "split " . s:message_bufname
setlocal modifiable
setlocal buftype=nofile
let s:message_window_bufnr = bufnr('%')
call s:message_window_mappings()
setlocal ft=mail
close

endfunction

function! s:system_with_error_handling(command)

let res = system(a:command)
if res =~ 'VMAIL_ERROR'
  echoe "ERROR" res
  return ""
else
  return res
end

endfunction

function! s:show_message(stay_in_message_list)

let line = getline(line("."))
if match(line, '^>  Load') != -1
  setlocal modifiable
  delete
  call s:more_messages()
  return
endif
let s:uid = shellescape(matchstr(line, '\S\+$'))
if s:uid == ""
  return
end
" mark as read
let newline = substitute(line, '^\V*+', '* ', '')
let newline = substitute(newline, '^\V+ ', '  ', '')
setlocal modifiable
call setline(line('.'), newline)
setlocal nomodifiable
write
" this just clears the command line and prevents the screen from
" moving up when the next echo statement executes:
" call feedkeys(":\<cr>")
" redraw
let command = s:show_message_command . s:uid
echom "Loading message ". s:uid .". Please wait..."
redrawstatus
let res = s:system_with_error_handling(command)
call s:focus_message_window()
set modifiable
1,$delete
put =res
" critical: don't call execute 'normal \<cr>'
" call feedkeys("<cr>")
1delete
normal 1Gjk
set nomodifiable
if a:stay_in_message_list
  call s:focus_list_window()
end
redraw

endfunction

function! s:show_large_message()

call <SID>show_message(0)
wincmd o
3split
execute 'b'. s:listbufnr
wincmd p

endfunction

“ from message window function! s:show_next_message()

let fullscreen = (bufwinnr(s:listbufnr) == -1) " we're in full screen message mode
if fullscreen
  3split
  exec 'b'. s:listbufnr
else
  call s:focus_list_window()
end
normal j
call s:show_message(1)
normal zz
wincmd p
redraw

endfunction

function! s:show_previous_message()

let fullscreen = (bufwinnr(s:listbufnr) == -1) " we're in full screen message mode
if fullscreen
  3split
  exec 'b'. s:listbufnr
else
  call s:focus_list_window()
end
normal k
if line('.') != line('$')
  call s:show_message(1)
endif
normal zz
wincmd p
redraw

endfunction

“ from message list window function! s:show_next_message_in_list()

if line('.') != line('$')
  normal j
  call s:show_message(1)
endif

endfunction

function! s:show_previous_message_in_list()

if line('.') != 1
  normal k
  call s:show_message(1)
endif

endfunction

“ invoked from withint message window function! s:show_raw()

let command = s:show_message_command . s:uid . ' raw'
echo command
setlocal modifiable
1,$delete
let res = s:system_with_error_handling(command)
put =res
1delete
normal 1G
setlocal nomodifiable

endfunction

function! s:focus_list_window()

if bufwinnr(s:listbufnr) == winnr()
  return
end
let winnr = bufwinnr(s:listbufnr)
if winnr == -1
  " create window
  split
  exec "buffer" . s:listbufnr
else
  exec winnr . "wincmd w"
endif
call s:set_list_colors()
" call feedkeys("\<c-l>") " prevents screen artifacts when user presses return too fast
" turn this off though, because it causes an annoying flash

endfunction

function! s:focus_message_window()

let winnr = bufwinnr(s:message_window_bufnr)
if winnr == -1
  " create window
  exec "rightbelow split " . s:message_bufname
else
  exec winnr . "wincmd w"
endif

endfunction

func! s:close_message_window()

if winnr('$') > 1
  close!
else
  call s:focus_list_window()
  wincmd p
  close!
  normal z.
endif

endfunc

“ gets new messages since last update function! s:update()

let command = s:update_command
echo "Checking for new messages. Please wait..."
let res = s:system_with_error_handling(command)
let lines = split(res, '\n')
if len(lines) > 0
  setlocal modifiable
  call append(0, lines)
  setlocal nomodifiable
  write!
  let num = len(lines)
  call cursor(num, 0)
  normal z.
  redraw
  echom "You have " . num . " new message" . (num == 1 ? '' : 's') . "!"
else
  redraw
  echom "No new messages"
endif

endfunction

“ function argument a:read: Represents the next state ” 0 means unread, 1 means read. function! s:mark_as_read_unread(read) range

let uid_set = s:collect_uids(a:firstline, a:lastline)
let nummsgs = len(uid_set)
" decide whether to set messages to SEEN or UNSEEN
let action = (a:read ? " +" : " -") . "FLAGS"
" construct the imap command
let command = s:flag_command . shellescape(join(uid_set, ',')) . action . " SEEN"
" do the real imap flagging
let res = s:system_with_error_handling(command)
setlocal modifiable
let lnum = a:firstline
while lnum <= a:lastline
  let line = getline(lnum)
  if action ==# " +FLAGS"
    let newline = substitute(line, '^*+', '* ', '')
    let newline = substitute(newline, '^+ ', '  ', '')
  else
    let newline = substitute(line, '^ ', '+', '')
    let newline = substitute(newline, '^\* ', '*+', '')
  endif
  call setline(lnum, newline)
  let lnum += 1
endwhile
setlocal nomodifiable
write
redraw
echom nummsgs  ." conversation(s) have been marked as " . (a:read ? "read" : "unread") . "."

endfunction

function! s:toggle_star() range

let uid_set = s:collect_uids(a:firstline, a:lastline)
let nummsgs = len(uid_set)
let flag_symbol = "^*"
" check if starred already
let action = " +FLAGS"
if (match(getline(a:firstline), flag_symbol) != -1)
  let action = " -FLAGS"
endif
let command = s:flag_command . shellescape(join(uid_set, ',')) . action . " Flagged"
if nummsgs == 1
  echom "Toggling flag on message"
else
  echom "Toggling flags on " . nummsgs . " messages"
endif
" toggle * on lines
let res = s:system_with_error_handling(command)
setlocal modifiable
let lnum = a:firstline
while lnum <= a:lastline
  let line = getline(lnum)
  if action == " +FLAGS"
    let newline = substitute(line, '^ ', '*', '')
    let newline = substitute(newline, '^+ ', '*+', '')
  else
    let newline = substitute(line, '^*+', '+ ', '')
    let newline = substitute(newline, '^* ', '  ', '')
  endif
  call setline(lnum, newline)
  let lnum += 1
endwhile
setlocal nomodifiable
write
redraw
if nummsgs == 1
  echom "Toggled flag on message"
else
  echom "Toggled flags on " . nummsgs . " messages"
endif

endfunction

“ flag can be Deleted or spam func! s:delete_messages(flag) range

let uid_set = s:collect_uids(a:firstline, a:lastline)
let nummsgs = len(uid_set)
let command = s:flag_command . shellescape(join(uid_set, ',')) . " +FLAGS " . a:flag
if nummsgs == 1
  echom "Deleting message"
else
  echom "Deleting " . nummsgs . " messages"
endif
let res = s:system_with_error_handling(command)
setlocal modifiable
exec "silent " . a:firstline . "," . a:lastline . "delete"
setlocal nomodifiable
write
redraw
echo nummsgs .  " message" . (nummsgs == 1 ? '' : 's') . " marked " . a:flag

endfunc

func! s:archive_messages() range

let uid_set = s:collect_uids(a:firstline, a:lastline)
let nummsgs = len(uid_set)
let command = s:move_to_command . shellescape(join(uid_set, ',')) . ' ' . "all"
echo "Archiving message" . (nummsgs == 1 ? '' : 's')
let res = s:system_with_error_handling(command)
setlocal modifiable
exec "silent " . a:firstline . "," . a:lastline . "delete"
setlocal nomodifiable
write
redraw
echo nummsgs . " message" . (nummsgs == 1 ? '' : 's') . " archived"

endfunc

“ ——————————————————————————–

“ append text bodies of a set of messages to a file func! s:append_messages_to_file() range

let uid_set = s:collect_uids(a:firstline, a:lastline)
let nummsgs = len(uid_set)
let append_file = input("print messages to file: ", s:append_file)
if append_file == ''
  echom "Canceled"
  return
endif
let s:append_file = append_file
let command = s:append_to_file_command . shellescape(join(uid_set, ',')) . ' ' . s:append_file
echo "Appending " . nummsgs . " message" . (nummsgs == 1 ? '' : 's') . " to " . s:append_file . ". Please wait..."
let res = s:system_with_error_handling(command)
echo res
redraw

endfunc

“ ——————————————————————————– ” move to another mailbox function! s:move_to_mailbox(copy) range

let s:copy_to_mailbox = a:copy
let uid_set = s:collect_uids(a:firstline, a:lastline)
let s:nummsgs = len(uid_set)
let s:uid_set = shellescape(join(uid_set, ','))
" now prompt use to select mailbox
if !exists("s:mailboxes")
  call s:get_mailbox_list()
endif
leftabove split MailboxSelect
setlocal buftype=nofile
setlocal noswapfile
setlocal modifiable
resize 1
let prompt = "select mailbox to " . (a:copy ? 'copy' : 'move') . " to: "
call setline(1, prompt)
normal $
inoremap <silent> <buffer> <cr> <Esc>:call <SID>complete_move_to_mailbox()<CR>
inoremap <silent> <buffer> <esc> <Esc>:q<cr>
setlocal completefunc=CompleteMoveMailbox
" c-p clears the line
let s:firstline = a:firstline
let s:lastline = a:lastline
call feedkeys("a\<c-x>\<c-u>\<c-p>", 't')
" save these in script scope to delete the lines when move completes

endfunction

function! s:complete_move_to_mailbox()

let mailbox = get(split(getline(line('.')), ": "), 1)
close
if s:copy_to_mailbox
  let command = s:copy_to_command . s:uid_set . ' ' . shellescape(mailbox)
else
  let command = s:move_to_command . s:uid_set . ' ' . shellescape(mailbox)
endif
redraw
echo "Moving uids ". s:uid_set . " to mailbox " . mailbox
let res = s:system_with_error_handling(command)
setlocal modifiable
if !s:copy_to_mailbox
  exec "silent " . s:firstline . "," . s:lastline . "delete"
end
setlocal nomodifiable
write
redraw
echo s:nummsgs .  " message" . (s:nummsgs == 1 ? '' : 's') . ' ' . (s:copy_to_mailbox ? 'copied' : 'moved') . ' to ' . mailbox

endfunction

function! CompleteMoveMailbox(findstart, base)

if !exists("s:mailboxes")
  call s:get_mailbox_list()
endif
if a:findstart
  " locate the start of the word
  let line = getline('.')
  let start = col('.') - 1
  while start > 0 && line[start - 1] =~ '\a'
    let start -= 1
  endwhile
  return start
else
  " find months matching with "a:base"
  let res = []
  for m in s:mailboxes
    if m == s:mailbox
      continue
    endif
    if m =~ '^' . a:base
      call add(res, m)
    endif
  endfor
  return res
endif

endfun “ ——————————————————————————–

function! s:get_mailbox_list()

let command = s:list_mailboxes_command
redraw
echo command
let res = s:system_with_error_handling(command)
let s:mailboxes = split(res, "\n", '')

endfunction

“ ——————————————————————————- ” select mailbox

function! s:mailbox_window()

call s:get_mailbox_list()
leftabove split MailboxSelect
setlocal buftype=nofile
setlocal noswapfile
setlocal modifiable
resize 1
inoremap <silent> <buffer> <cr> <Esc>:call <SID>select_mailbox()<CR>
inoremap <silent> <buffer> <esc> <Esc>:q<cr>
setlocal completefunc=CompleteMailbox
" c-p clears the line
call setline(1, "select mailbox to switch to: ")
normal $
call feedkeys("a\<c-x>\<c-u>\<c-p>", 't')

endfunction

function! CompleteMailbox(findstart, base)

if !exists("s:mailboxes")
  call s:get_mailbox_list()
endif
if a:findstart
  " locate the start of the word
  let line = getline('.')
  let start = col('.') - 1
  while start > 0 && line[start - 1] =~ '\a'
    let start -= 1
  endwhile
  return start
else
  " find mailboxes matching with "a:base"
  let res = []
  for m in s:mailboxes
    if m =~ '^' . a:base
      call add(res, m)
    endif
  endfor
  return res
endif

endfun

function! s:select_mailbox()

let mailbox = get(split(getline(line('.')), ": "), 1)
close
call s:focus_message_window()
close
" check if mailbox is a real mailbox
if (index(s:mailboxes, mailbox) == -1)
  return
endif
let s:mailbox = mailbox
let s:query = "all"
let command = s:select_mailbox_command . shellescape(s:mailbox)
redraw
echom "Selecting mailbox: ". s:mailbox . ". Please wait..."
call s:system_with_error_handling(command)
redraw
" reset window width now
call s:system_with_error_handling(s:set_window_width_command . winwidth(1))
" now get latest 100 messages
call s:focus_list_window()
setlocal modifiable
let command = s:search_command . shellescape("all")
echo "Loading messages..."
let res = s:system_with_error_handling(command)
silent 1,$delete
silent! put! =res
execute "normal Gdd\<c-y>"
setlocal nomodifiable
write
normal gg
redraw
echom "Current mailbox: ". s:mailbox

endfunction

func! s:search_query()

if !exists("s:query")
  let s:query = ""
endif
let s:query = input("search query: ", s:query)
call s:do_search()

endfunc

function! s:do_search()

" empty query
if match(s:query, '^\s*$') != -1
  return
endif
" close message window if open
call s:focus_message_window()
close
let command = s:search_command . shellescape(s:query)
redraw
call s:focus_list_window()
setlocal modifiable
echo "Running query on " . s:mailbox . ": " . s:query . ". Please wait..."
let res = s:system_with_error_handling(command)
silent! 1,$delete
silent! put! =res
execute "silent normal Gdd\<c-y>"
setlocal nomodifiable
write
normal gg

endfunction

function! s:more_messages()

let command = s:more_messages_command
echo "Fetching more messages. Please wait..."
let res = s:system_with_error_handling(command)
setlocal modifiable
let lines =  split(res, "\n")
call append(line('$'), lines)
" execute "normal Gdd\<c-y>"
setlocal nomodifiable
normal j
redraw
echo "Done"

endfunction

“ ——————————————————————————– ” compose reply, compose, forward, save draft

function! s:compose_reply(all)

let command = s:reply_template_command
if a:all
  let command = command . ' 1'
endif
call s:open_compose_window(command)
" cursor after headers
normal 1G}

endfunction

function! s:compose_message()

let command = s:new_message_template_command
call s:open_compose_window(command)
" position cursor after to:

“ call search(”^to:“) ” normal A endfunction

function! s:compose_forward()

let command = s:forward_template_command
call s:open_compose_window(command)

“ call search(”^to:“) ” normal A endfunction

func! s:open_compose_window(command)

redraw
echo a:command
let res = s:system_with_error_handling(a:command)
let previous_winnr = winnr()
only
split compose_message.txt
setlocal modifiable
wincmd p
close!
silent! 1,$delete
silent! put! =res
redraw
"call feedkeys("\<cr>")
call s:compose_window_mappings()
setlocal completefunc=CompleteContact
setlocal ft=mail
normal 1G

endfunc

func! s:turn_into_compose_window()

call s:compose_window_mappings()
setlocal completefunc=CompleteContact

endfunc

“ contacts.txt file should be generated. ” grep works well, does partial matches function! CompleteContact(findstart, base)

if !exists("s:mailboxes")
  call s:get_mailbox_list()
endif
if a:findstart
  " locate the start of the word
  let line = getline('.')
  let start = col('.') - 1
  while start > 0 && line[start - 1] =~ '\a'
    let start -= 1
  endwhile
  return start
else
  " find contacts
  " model regex: match at beginning of line, or inside < > wrapping
  " email addr
  "  '\(^ho\|<ho\)'
  " let regex = shellescape('\(^' . a:base . '\|<' . a:base . '\)')
  let regex = shellescape(a:base)
  let matches = s:system_with_error_handling("grep -i " . regex  . " " . $VMAIL_CONTACTS_FILE)
  return split(matches, "\n")
endif

endfun

func! s:close_and_focus_list_window()

call s:focus_list_window()
wincmd p
close!
normal z.

endfunc

function! s:send_message()

let mail = join(getline(1,'$'), "\n")
echo "Sending message"
let res = system(s:deliver_command, mail)
if match(res, '^Failed') == -1
  write!
  call s:close_and_focus_list_window()
endif
echom substitute(res, '[\s\r\n]\+$', '', '')
redraw

endfunction

“ ——————————————————————————– ” Update message list with new emails.

func! UPDATE_MESSAGE_LIST(filename)

if s:mailbox == 'INBOX'
  if bufnr('%') == s:listbufnr
    call s:update_and_redraw_message_list(a:filename)

  " If current_message is open with message list in another split.
  elseif bufname('%') == s:message_bufname && index(tabpagebuflist(), s:listbufnr) >= 0
    let message_bufnr = bufnr('%')

    " Switch to message list window and update it.
    while bufnr('%') != s:listbufnr | wincmd w | endwhile
    call s:update_and_redraw_message_list(a:filename)

    while bufnr('%') != message_bufnr | wincmd w | endwhile
  else
    call s:update_message_list(a:filename)
  endif
endif

endfunc

func! s:update_and_redraw_message_list(filename)

call s:update_message_list(a:filename)
edit!
redraw!

endfunc

func! s:update_message_list(filename)

let newer_contents = readfile(a:filename)
let older_contents = readfile(s:listbufname)
let updated_contents = extend(newer_contents, older_contents)
call writefile(updated_contents, s:listbufname)

endfunc

“ ——————————————————————————–

“ call from inside message window with <Leader>h func! s:open_html_part()

let command = s:open_html_part_command
" the command saves the html part to a local file
let outfile = s:system_with_error_handling(command)
" todo: allow user to change open in browser command?
exec "!" . s:browser_command . ' ' . outfile

endfunc

func! s:save_attachments()

if !exists("s:savedir")
  let s:savedir = getcwd() . "/attachments"
end
let s:savedir = input("save attachments to directory: ", s:savedir, "dir")
let command = s:save_attachments_command . s:savedir
let res = s:system_with_error_handling(command)
echo res

endfunc

func! s:attach_file(file)

normal gg
normal }
let attach = "attach: " . a:file
put =attach

endfunc

“ ——————————————————————————–

func! s:toggle_maximize_window()

if winnr('$') > 1
  only
  " normal z.
elseif bufwinnr(s:listbufnr) == winnr()
  call s:show_message(1)
else " we're in the message window
  call s:focus_list_window()
  wincmd p
endif

endfunc

“ maybe not DRY enough, but fix that later ” also, come up with a more precise regex pattern for matching hyperlinks func! s:open_href(all) range

let pattern = 'https\?:[^ >)\]]\+'
let n = 0
" range version
if a:firstline < a:lastline
  let lnum = a:firstline
  while lnum <= a:lastline
    let href = matchstr(getline(lnum), pattern)
    if href != ""
      let command = s:browser_command ." ".shellescape(href)." &"
      call s:system_with_error_handling(command)
      let n += 1
    endif
    let lnum += 1
  endwhile
  echom 'opened '.n.' links'
  return
end
let line = search(pattern, 'cw')
if line && a:all
  while line
    let href = matchstr(getline(line('.')), pattern)
    let command = s:browser_command ." ".shellescape(href)." &"
    call s:system_with_error_handling(command)
    let n += 1
    let line = search('https\?:', 'W')
  endwhile
  echom 'opened '.n.' links'
else
  let href = matchstr(getline(line('.')), pattern)
  let command = s:browser_command ." ".shellescape(href)." &"
  call s:system_with_error_handling(command)
  echom 'opened '.href
endif

endfunc

“ ——————————————————————————– ” HELP func! s:show_help()

let command = s:browser_command . ' ' . shellescape('http://danielchoi.com/software/vmail.html')
call s:system_with_error_handling(command)
"let helpfile = s:system_with_error_handling(s:show_help_command)
"exec "split " . helpfile

endfunc

“ ——————————————————————————– ” CONVENIENCE FUNCS

function! s:collect_uids(startline, endline)

let uid_set = []
let lnum = a:startline
while lnum <= a:endline
  let uid = matchstr(getline(lnum), '\S\+$')
  call add(uid_set, uid)
  let lnum += 1
endwhile
return uid_set

endfunc

“ ——————————————————————————– ” MAPPINGS

func! s:message_window_mappings()

if !hasmapto('<Plug>VmailMessageWindow_FocusListWindow')
  nmap <buffer> <CR> <Plug>VmailMessageWindow_FocusListWindow
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_FocusListWindow <C-W>=:call <SID>focus_list_window()<CR>

if !hasmapto('<Plug>VmailMessageWindow_Reply')
  nmap <buffer> <leader>r <Plug>VmailMessageWindow_Reply
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Reply :call <SID>compose_reply(0)<CR>

if !hasmapto('<Plug>VmailMessageWindow_ReplyToAll')
  nmap <buffer> <leader>a <Plug>VmailMessageWindow_ReplyToAll
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ReplyToAll :call <SID>compose_reply(1)<CR>

if !hasmapto('<Plug>VmailMessageWindow_ShowRaw')
  nmap <buffer> <leader>R <Plug>VmailMessageWindow_ShowRaw
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowRaw :call <SID>show_raw()<CR>

if !hasmapto('<Plug>VmailMessageWindow_Forward')
  nmap <buffer> <leader>f <Plug>VmailMessageWindow_Forward
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Forward :call <SID>compose_forward()<CR>

if !hasmapto('<Plug>VmailMessageWindow_ShowNext')
  nmap <buffer> <C-j> <Plug>VmailMessageWindow_ShowNext
  nmap <buffer> <leader>j <Plug>VmailMessageWindow_ShowNext
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowNext :call <SID>show_next_message()<CR>

if !hasmapto('<Plug>VmailMessageWindow_ShowPrev')
  nmap <buffer> <C-k> <Plug>VmailMessageWindow_ShowPrev
  nmap <buffer> <leader>k <Plug>VmailMessageWindow_ShowPrev
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowPrev :call <SID>show_previous_message()<CR>

if !hasmapto('<Plug>VmailMessageWindow_ComposeMessage')
  nmap <buffer> <leader>c <Plug>VmailMessageWindow_ComposeMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ComposeMessage :call <SID>compose_message()<CR>

if !hasmapto('<Plug>VmailMessageWindow_OpenHTML')
  nmap <buffer> <leader>h <Plug>VmailMessageWindow_OpenHTML
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_OpenHTML :call <SID>open_html_part()<CR>

if !hasmapto('<Plug>VmailMessageWindow_CloseWindow')
  nmap <buffer> <leader>q <Plug>VmailMessageWindow_CloseWindow
  nmap <buffer> o <Plug>VmailMessageWindow_CloseWindow
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_CloseWindow :call <SID>close_message_window()<CR>

if !hasmapto('<Plug>VmailMessageWindow_DeleteMessage')
  nmap <buffer> <leader># <Plug>VmailMessageWindow_DeleteMessage
  nmap <buffer> <leader>3 <Plug>VmailMessageWindow_DeleteMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_DeleteMessage :close<cr>:call <SID>focus_list_window()<CR>:call <SID>delete_messages("Deleted")<CR>

if !hasmapto('<Plug>VmailMessageWindow_ToggleStar')
  nmap <buffer> <leader>* <Plug>VmailMessageWindow_ToggleStar
  nmap <buffer> <leader>8 <Plug>VmailMessageWindow_ToggleStar
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ToggleStar :call <SID>focus_list_window()<cr>:call <SID>toggle_star()<CR>

if !hasmapto('<Plug>VmailMessageWindow_MarkAsRead')
  nmap <buffer> I <Plug>VmailMessageWindow_MarkAsRead
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsRead :call <SID>focus_list_window()<cr>:call <SID>mark_as_read_unread(1)<CR>

if !hasmapto('<Plug>VmailMessageWindow_MarkAsUnread')
  nmap <buffer> U <Plug>VmailMessageWindow_MarkAsUnread
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsUnread :call <SID>focus_list_window()<cr>:call <SID>mark_as_read_unread(0)<CR>

if !hasmapto('<Plug>VmailMessageWindow_MarkAsSpam')
  nmap <buffer> <leader>! <Plug>VmailMessageWindow_MarkAsSpam
  nmap <buffer> <leader>1 <Plug>VmailMessageWindow_MarkAsSpam
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsSpam :close<cr>:call <SID>focus_list_window()<cr>:call <SID>delete_messages("spam")<CR>

if !hasmapto('<Plug>VmailMessageWindow_ArchiveMessage')
  nmap <buffer> <leader>e <Plug>VmailMessageWindow_ArchiveMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ArchiveMessage :call <SID>focus_list_window()<cr>:call <SID>archive_messages()<CR>

if !hasmapto('<Plug>VmailMessageWindow_MoveToMailbox')
  nmap <buffer> <leader>b <Plug>VmailMessageWindow_MoveToMailbox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MoveToMailbox :call <SID>focus_list_window()<cr>:call <SID>move_to_mailbox(0)<CR>

if !hasmapto('<Plug>VmailMessageWindow_CopyToMailbox')
  nmap <buffer> <leader>B <Plug>VmailMessageWindow_CopyToMailbox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_CopyToMailbox :call <SID>focus_list_window()<cr>:call <SID>move_to_mailbox(1)<CR>

if !hasmapto('<Plug>VmailMessageWindow_Update')
  nmap <buffer> <leader>u <Plug>VmailMessageWindow_Update
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Update :call <SID>focus_list_window()<cr>:call <SID>update()<CR>

if !hasmapto('<Plug>VmailMessageWindow_SwitchMailBox')
  nmap <buffer> <leader>m <Plug>VmailMessageWindow_SwitchMailBox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_SwitchMailBox :call <SID>focus_list_window()<cr>:call <SID>mailbox_window()<CR>

if !hasmapto('<Plug>VmailMessageWindow_SaveAttachment')
  nmap <buffer> <leader>A <Plug>VmailMessageWindow_SaveAttachment
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_SaveAttachment :call <SID>save_attachments()<CR>

if !hasmapto('<Plug>VmailMessageWindow_ToggleWindow')
  nmap <buffer> <Space> <Plug>VmailMessageWindow_ToggleWindow
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ToggleWindow :call <SID>toggle_maximize_window()<cr>

if !hasmapto('<Plug>VmailMessageWindow_AppendMessagesToFile')
  nmap <buffer> <leader>vp <Plug>VmailMessageWindow_AppendMessagesToFile
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_AppendMessagesToFile :call <SID>focus_list_window()<cr>:call <SID>append_messages_to_file()<CR>

if !hasmapto('<Plug>VmailMessageWindow_Search')
  nmap <buffer> <leader>s <Plug>VmailMessageWindow_Search
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Search :call <SID>focus_list_window()<cr>:call <SID>search_query()<cr>

endfunc

func! s:message_list_window_mappings()

if !hasmapto('<Plug>VmailOpenMessage')
  nmap <buffer> <CR> <Plug>VmailOpenMessage
  nmap <buffer> o <Plug>VmailOpenMessage
  nmap <buffer> <LeftMouse> <Plug>VmailOpenMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailOpenMessage :call <SID>show_message(0)<CR>

if !hasmapto('<Plug>VmailOpenLargeMessage')
  nmap <buffer> O <Plug>VmailOpenLargeMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailOpenLargeMessage :call <SID>show_large_message()<CR>

if !hasmapto('<Plug>VmailPreviewMessage')
  nmap <buffer> l <Plug>VmailPreviewMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailPreviewMessage :call <SID>show_message(1)<CR>

if !hasmapto('<Plug>VmailExit')
  nmap <buffer> <leader>q <Plug>VmailExit
endif
nnoremap <buffer> <unique> <script> <Plug>VmailExit :qall!<CR>

if !hasmapto('<Plug>VmailToggleStar')
  nmap <buffer> <leader>* <Plug>VmailToggleStar
  xmap <buffer> <leader>* <Plug>VmailToggleStar
  nmap <buffer> <leader>8 <Plug>VmailToggleStar
  xmap <buffer> <leader>8 <Plug>VmailToggleStar
endif
nnoremap <buffer> <unique> <script> <Plug>VmailToggleStar :call <SID>toggle_star()<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailToggleStar :call <SID>toggle_star()<CR>

if !hasmapto('<Plug>VmailMarkAsUnread')
  nmap <buffer> U <Plug>VmailMarkAsUnread
  xmap <buffer> U <Plug>VmailMarkAsUnread
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsUnread :call <SID>mark_as_read_unread(0)<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsUnread :call <SID>mark_as_read_unread(0)<CR>

if !hasmapto('<Plug>VmailMarkAsRead')
  nmap <buffer> I <Plug>VmailMarkAsRead
  xmap <buffer> I <Plug>VmailMarkAsRead
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsRead :call <SID>mark_as_read_unread(1)<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsRead :call <SID>mark_as_read_unread(1)<CR>

if !hasmapto('<Plug>VmailDelete')
  nmap <buffer> <leader># <Plug>VmailDelete
  xmap <buffer> <leader># <Plug>VmailDelete
  nmap <buffer> <leader>3 <Plug>VmailDelete
  xmap <buffer> <leader>3 <Plug>VmailDelete
endif
nnoremap <buffer> <unique> <script> <Plug>VmailDelete :call <SID>delete_messages("Deleted")<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailDelete :call <SID>delete_messages("Deleted")<CR>

if !hasmapto('<Plug>VmailMarkAsSpam')
  nmap <buffer> <leader>! <Plug>VmailMarkAsSpam
  xmap <buffer> <leader>! <Plug>VmailMarkAsSpam
  nmap <buffer> <leader>1 <Plug>VmailMarkAsSpam
  xmap <buffer> <leader>1 <Plug>VmailMarkAsSpam
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsSpam :call <SID>delete_messages("spam")<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsSpam :call <SID>delete_messages("spam")<CR>

if !hasmapto('<Plug>VmailArchiveMessage')
  nmap <buffer> <leader>e <Plug>VmailArchiveMessage
  xmap <buffer> <leader>e <Plug>VmailArchiveMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailArchiveMessage :call <SID>archive_messages()<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailArchiveMessage :call <SID>archive_messages()<CR>

if !hasmapto('<Plug>VmailAppendMessagesToFile')
  nmap <buffer> <leader>vp <Plug>VmailAppendMessagesToFile
  xmap <buffer> <leader>vp <Plug>VmailAppendMessagesToFile
endif
nnoremap <buffer> <unique> <script> <Plug>VmailAppendMessagesToFile :call <SID>append_messages_to_file()<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailAppendMessagesToFile :call <SID>append_messages_to_file()<CR>

if !hasmapto('<Plug>VmailUpdate')
  nmap <buffer> u <Plug>VmailUpdate
  nmap <buffer> <leader>u <Plug>VmailUpdate
endif
nnoremap <buffer> <unique> <script> <Plug>VmailUpdate :call <SID>update()<CR>

if !hasmapto('<Plug>VmailSearch')
  nmap <buffer> <leader>s <Plug>VmailSearch
endif
nnoremap <buffer> <unique> <script> <Plug>VmailSearch :call <SID>search_query()<CR>

if !hasmapto('<Plug>VmailSwitchMailbox')
  nmap <buffer> <leader>m <Plug>VmailSwitchMailbox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailSwitchMailbox :call <SID>mailbox_window()<CR>

if !hasmapto('<Plug>VmailMoveToMailbox')
  nmap <buffer> <leader>b <Plug>VmailMoveToMailbox
  xmap <buffer> <leader>b <Plug>VmailMoveToMailbox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailMoveToMailbox :call <SID>move_to_mailbox(0)<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailMoveToMailbox :call <SID>move_to_mailbox(0)<CR>

if !hasmapto('<Plug>VmailCopyToMailbox')
  nmap <buffer> <leader>B <Plug>VmailCopyToMailbox
  xmap <buffer> <leader>B <Plug>VmailCopyToMailbox
endif
nnoremap <buffer> <unique> <script> <Plug>VmailCopyToMailbox :call <SID>move_to_mailbox(1)<CR>
xnoremap <buffer> <unique> <script> <Plug>VmailCopyToMailbox :call <SID>move_to_mailbox(1)<CR>

if !hasmapto('<Plug>VmailComposeNew')
  nmap <buffer> <leader>c <Plug>VmailComposeNew
endif
nnoremap <buffer> <unique> <script> <Plug>VmailComposeNew :call <SID>compose_message()<CR>

if !hasmapto('<Plug>VmailComposeReply')
  nmap <buffer> <Leader>r <Plug>VmailComposeReply
endif
nnoremap <buffer> <unique> <script> <Plug>VmailComposeReply :call <SID>show_message(0)<CR>:call <SID>compose_reply(0)<CR>

if !hasmapto('<Plug>VmailComposeReplyAll')
  nmap <buffer> <Leader>a <Plug>VmailComposeReplyAll
endif
nnoremap <buffer> <unique> <script> <Plug>VmailComposeReplyAll :call <SID>show_message(0)<CR>:call <SID>compose_reply(1)<CR>

if !hasmapto('<Plug>VmailForward')
  nmap <buffer> <Leader>f <Plug>VmailForward
endif
nnoremap <buffer> <unique> <script> <Plug>VmailForward :call <SID>show_message(0)<CR>:call <SID>compose_forward()<CR>

if !hasmapto('<Plug>VmailShowNextMessage')
  nmap <buffer> <C-j> <Plug>VmailShowNextMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailShowNextMessage :call <SID>show_next_message_in_list()<CR>

if !hasmapto('<Plug>VmailShowPrevMessage')
  nmap <buffer> <C-k> <Plug>VmailShowPrevMessage
endif
nnoremap <buffer> <unique> <script> <Plug>VmailShowPrevMessage :call <SID>show_previous_message_in_list()<CR>

if !hasmapto('<Plug>VmailToggleWindow')
  nmap <buffer> <Space> <Plug>VmailToggleWindow
endif
nnoremap <buffer> <unique> <script> <Plug>VmailToggleWindow :call <SID>toggle_maximize_window()<cr>

autocmd CursorMoved <buffer> :redraw
autocmd BufEnter,BufWinEnter <buffer> :call <SID>set_list_colors()

endfunc

func! s:compose_window_mappings()

if !hasmapto('<Plug>VmailComposeWinClose')
  nmap <buffer> <leader>q <Plug>VmailComposeWinClose
endif
nnoremap <buffer>  <script> <Plug>VmailComposeWinClose :call <SID>close_and_focus_list_window()<CR>
setlocal ai
command! -bar -nargs=1 -complete=file VMAttach call s:attach_file(<f-args>)

endfunc

func! s:global_mappings()

" NOTE send_message is a global mapping, so user can load a saved
" message from a file and send it
nnoremap <silent> <leader>vs :call <SID>send_message()<CR>
noremap <silent> <leader>o :call <SID>open_href(0)<cr>
noremap <silent> <leader>O :call <SID>open_href(1)<cr>
noremap <silent> <leader>? :call <SID>show_help()<cr>
noremap <silent> <leader>qq :qal!<cr>

endfunc

func! s:set_list_colors()

if !exists("g:syntax_on")
  return
endif
syn clear
syn match vmailSizeCol /|\s\+\(< 1k\|\d*\(b\|k\|M\|G\)\)\s\+|/ contains=vmailSeperator contained
syn match vmailFirstCol /^.\{-}|/ nextgroup=vmailDateCol
syn match vmailFirstColAnswered /An/ contained containedin=vmailFirstCol
syn match vmailFirstColForward /\$F/ contained containedin=vmailFirstCol
syn match vmailFirstColNotJunk /No/ contained containedin=vmailFirstCol

" Examples matched by vmailDateCol:
" | Dec 15 11:59pm |
" | Dec 15 2008    |
" | 15.12 23:59 |
" | 15.12 2008  |
syn match vmailDateCol /\s\+\(... \d\d \(\(\d\d:\d\d..\)\|\(\d\{4}\)\)\)\|\(\d\d\.\d\d \(\(\d\d:\d\d\)\|\(\d\{4}\)\)\)\s\+|/ nextgroup=vmailFromCol contains=vmailSeperator

syn match vmailFromCol /\s.\{-}|\@=/ contained nextgroup=vmailFromSeperator
syn match vmailFromColEmail /<[^ ]*/ contained containedin=vmailFromCol
syn match vmailFromSeperator /|/ contained nextgroup=vmailSubject
syn match vmailSubject /.*\s\+/ contained contains=vmailSizeCol
syn match vmailSubjectRe /\cre:\|fwd\?:/ contained containedin=vmailSubject
syn match vmailSeperator /|/ contained
syn match vmailNewMessage /^\s*+.*/
syn match vmailStarredMessage /^\s*\*.*/
hi def link vmailFirstCol         Comment
hi def link vmailDateCol          Statement
hi def link vmailFromCol          Identifier
hi def link vmailSizeCol          Constant
hi def link vmailSeperator        Comment
hi def link vmailFromSeperator    vmailSeperator
hi def link vmailFromColEmail     Comment
hi def link vmailSubjectRe        Type
hi def link vmailFirstColSpec     Number
hi def link vmailFirstColAnswered vmailFirstColSpec
hi def link vmailFirstColForward  vmailFirstColSpec
hi def link vmailFirstColNotJunk  vmailFirstColSpec
hi def link vmailSpecialMsg       Special
hi def link vmailNewMessage       vmailSpecialMsg
hi def link vmailStarredMessage   vmailSpecialMsg
syn match VmailBufferFlagged /^*.*/hs=s
exec "hi def VmailBufferFlagged " . g:vmail_flagged_color

endfunc

“TODO see if using LocalLeader and maplocalleader makes more sense let mapleader = ”,“

call s:global_mappings()

call s:create_list_window()

call s:create_message_window()

call s:focus_list_window() “ to go list window

“ send window width call s:system_with_error_handling(s:set_window_width_command . winwidth(1))

autocmd bufreadpost *.txt call <SID>turn_into_compose_window() normal G call s:system_with_error_handling(s:select_mailbox_command . shellescape(s:mailbox)) call s:do_search()