From 6adb53df7bcd0460049dfeeafd0da03337466ec5 Mon Sep 17 00:00:00 2001 From: Wang Shidong Date: Sun, 24 Oct 2021 11:56:24 +0800 Subject: [PATCH] feat(mail): improve vim-mail plugin --- autoload/SpaceVim/api/data/quopri.vim | 17 ++++ autoload/SpaceVim/layers/mail.vim | 2 +- bundle/vim-mail/autoload/mail/client.vim | 91 ++++++++++--------- .../vim-mail/autoload/mail/client/logger.vim | 15 --- bundle/vim-mail/autoload/mail/client/win.vim | 78 +++++++++++----- 5 files changed, 120 insertions(+), 83 deletions(-) create mode 100644 autoload/SpaceVim/api/data/quopri.vim delete mode 100644 bundle/vim-mail/autoload/mail/client/logger.vim diff --git a/autoload/SpaceVim/api/data/quopri.vim b/autoload/SpaceVim/api/data/quopri.vim new file mode 100644 index 000000000..e37c5b6c5 --- /dev/null +++ b/autoload/SpaceVim/api/data/quopri.vim @@ -0,0 +1,17 @@ +let s:self = {} + + +function! s:self.decode(str) abort + +endfunction + +function! s:self.encode(str) abort + +endfunction + + +function! SpaceVim#api#data#quopri#get() abort + + return deepcopy(s:self) + +endfunction diff --git a/autoload/SpaceVim/layers/mail.vim b/autoload/SpaceVim/layers/mail.vim index 09db5dbbe..6ad820232 100644 --- a/autoload/SpaceVim/layers/mail.vim +++ b/autoload/SpaceVim/layers/mail.vim @@ -48,7 +48,7 @@ endfunction function! SpaceVim#layers#mail#config() abort call SpaceVim#mapping#space#def('nnoremap', ['a', 'm'], 'call mail#client#open()', 'Start mail client', 1) - let g:mail_imap_host = s:imap_port + let g:mail_imap_host = s:imap_host let g:mail_imap_port = s:imap_port let g:mail_imap_login = s:imap_login let g:mail_imap_password = s:imap_password diff --git a/bundle/vim-mail/autoload/mail/client.vim b/bundle/vim-mail/autoload/mail/client.vim index 01c2b6593..5b54cec12 100644 --- a/bundle/vim-mail/autoload/mail/client.vim +++ b/bundle/vim-mail/autoload/mail/client.vim @@ -4,15 +4,21 @@ let s:job_noop_timer = '' let s:JOB = SpaceVim#api#import('job') function! mail#client#connect(ip, port) - let argv = ['telnet', a:ip, a:port] - let s:job_id = s:JOB.start(argv, - \ { - \ 'on_stdout' : function('s:on_stdout'), - \ 'on_stderr' : function('s:on_stderr'), - \ 'on_exit' : function('s:on_exit'), - \ } - \ ) - call mail#client#logger#info('mail client job id:' . s:job_id) + if has('nvim') + let s:job_id = sockconnect('tcp', a:ip . ':' . a:port, + \ { + \ 'on_data' : function('s:on_stdout'), + \ } + \ ) + call mail#logger#info('mail client job id:' . s:job_id) + else + let s:job_channel = ch_open(a:ip . ':' . a:port, + \ { + \ 'callback' : function('s:data_handle'), + \ } + \ ) + call mail#logger#info('mail client job channel:' . s:job_channel) + endif endfunction " Wed, 06 Sep 2017 02:55:41 +0000 ===> 2017-09-06 @@ -37,44 +43,44 @@ let s:_mail_from = '' let s:_mail_subject = '' let s:mail_unseen = 0 -function! s:parser(data) abort - if type(a:data) == 3 - for data in a:data - call mail#client#logger#info('STDOUT: ' . data) - if data =~ '^\* \d\+ FETCH ' - let s:_mail_id = matchstr(data, '\d\+') - elseif data =~ '^From: ' - let s:_mail_from = substitute(data, '^From: ', '', 'g') - let s:_mail_from .= repeat(' ', 50 - len(s:_mail_from)) - elseif data =~ '^Date: ' - let s:_mail_date = s:convert(substitute(data, '^Date: ', '', 'g')) - elseif data =~ '^Subject: ' - let s:_mail_subject = substitute(data, '^Subject: ', '', 'g') - call mail#client#mailbox#updatedir(s:_mail_id, s:_mail_from, s:_mail_date, s:_mail_subject, mail#client#win#currentDir()) - elseif data =~ '* STATUS INBOX' - let s:mail_unseen = matchstr(data, '\d\+') - endif - endfor - else - echom a:data - endif +function! s:data_handle(...) abort + call s:on_stdout(1,1, [a:1]) endfunction function! s:on_stdout(id, data, event) abort - call mail#client#logger#info('STDOUT: ' . string(a:data)) - call s:parser(a:data) + for data in a:data + call mail#logger#info('STDOUT: ' . data) + if data =~ '^\* \d\+ FETCH ' + let s:_mail_id = matchstr(data, '\d\+') + elseif data =~ '^From: ' + let s:_mail_from = substitute(data, '^From: ', '', 'g') + let s:_mail_from .= repeat(' ', 50 - len(s:_mail_from)) + elseif data =~ '^Date: ' + let s:_mail_date = s:convert(substitute(data, '^Date: ', '', 'g')) + elseif data =~ '^Subject: ' + let s:_mail_subject = substitute(data, '^Subject: ', '', 'g') + call mail#client#mailbox#updatedir(s:_mail_id, s:_mail_from, s:_mail_date, s:_mail_subject, mail#client#win#currentDir()) + elseif data =~ '* STATUS INBOX' + let s:mail_unseen = matchstr(data, '\d\+') + elseif data =~# '* OK Coremail System IMap Server Ready' + call mail#client#send(mail#command#login(g:mail_imap_login, g:mail_imap_password)) + call mail#client#send(mail#command#select(mail#client#win#currentDir())) + call mail#client#send(mail#command#fetch('1:15', 'BODY[HEADER.FIELDS ("DATE" "FROM" "SUBJECT")]')) + call mail#client#send(mail#command#status('INBOX', '["RECENT"]')) + let s:job_noop_timer = timer_start(20000, function('s:noop'), {'repeat' : -1}) + endif + endfor endfunction function! s:on_stderr(id, data, event) abort for data in a:data - call mail#client#logger#error('STDERR: ' . data) + call mail#logger#error('STDERR: ' . data) endfor endfunction function! s:on_exit(id, data, event) abort - call s:parser(a:data) let s:job_id = 0 if !empty(s:job_noop_timer) call timer_stop(s:job_noop_timer) @@ -84,11 +90,15 @@ endfunction function! mail#client#send(command) - call mail#client#logger#info('Send command: ' . a:command) - if s:job_id >= 0 - call s:JOB.send(s:job_id, a:command) + call mail#logger#info('Send command: ' . a:command) + if has('nvim') + if s:job_id >= 0 + call chansend(s:job_id, [a:command, '']) + else + call mail#logger#info('skipped!, job id is:' . s:job_id) + endif else - call mail#client#logger#info('skipped!, job id is:' . s:job_id) + call ch_sendraw(s:job_channel, a:command . "\n") endif endfunction @@ -96,11 +106,6 @@ function! mail#client#open() if s:job_id == 0 if !empty(g:mail_imap_login) && !empty(g:mail_imap_password) call mail#client#connect(g:mail_imap_host, g:mail_imap_port) - call mail#client#send(mail#command#login(g:mail_imap_login, g:mail_imap_password)) - call mail#client#send(mail#command#select(mail#client#win#currentDir())) - call mail#client#send(mail#command#fetch('1:15', 'BODY[HEADER.FIELDS ("DATE" "FROM" "SUBJECT")]')) - call mail#client#send(mail#command#status('INBOX', '["RECENT"]')) - let s:job_noop_timer = timer_start(20000, function('s:noop'), {'repeat' : -1}) endif endif call mail#client#win#open() diff --git a/bundle/vim-mail/autoload/mail/client/logger.vim b/bundle/vim-mail/autoload/mail/client/logger.vim deleted file mode 100644 index f58e4b4d1..000000000 --- a/bundle/vim-mail/autoload/mail/client/logger.vim +++ /dev/null @@ -1,15 +0,0 @@ -let s:LOGGER =SpaceVim#logger#derive('mail') - -function! mail#client#logger#info(msg) - call s:LOGGER.info(a:msg) -endfunction - -function! mail#client#logger#error(msg) - call s:LOGGER.error(a:msg) -endfunction - -function! mail#client#logger#warn(msg) - - call s:LOGGER.warn(a:msg) - -endfunction diff --git a/bundle/vim-mail/autoload/mail/client/win.vim b/bundle/vim-mail/autoload/mail/client/win.vim index d5f31938f..b1b58d401 100644 --- a/bundle/vim-mail/autoload/mail/client/win.vim +++ b/bundle/vim-mail/autoload/mail/client/win.vim @@ -2,6 +2,9 @@ " let s:BUFFER = SpaceVim#api#import('vim#buffer') +let s:BASE64 = SpaceVim#api#import('data#base64') +let s:QUOPRI = SpaceVim#api#import('data#quopri') +let s:ICONV = SpaceVim#api#import('iconv') let s:bufnr = -1 @@ -10,40 +13,67 @@ let s:win_dir = 'INBOX' let s:win_unseen = {} function! mail#client#win#open() - if s:bufnr ==# -1 - split __VIM_MAIL__ - let s:bufnr = bufnr('%') - setlocal buftype=nofile nobuflisted nolist noswapfile nowrap cursorline nospell nomodifiable nowrap norelativenumber number - nnoremap :call refresh() - setfiletype VimMailClient - else - split - exe 'b' . s:bufnr - endif - call s:refresh() + if s:bufnr ==# -1 + split __VIM_MAIL__ + let s:bufnr = bufnr('%') + setlocal buftype=nofile nobuflisted nolist noswapfile nowrap cursorline nospell nomodifiable nowrap norelativenumber number + nnoremap :call refresh() + setfiletype VimMailClient + else + split + exe 'b' . s:bufnr + endif + call s:refresh() endfunction function! mail#client#win#currentDir() - return s:win_dir + return s:win_dir +endfunction + +" =????= +" '=?UTF-8?B?VGhpcyBpcyBhIGhvcnNleTog8J+Qjg==?=' +function! s:encode(str) abort + " line endings (^M), strip these characters. + let origin_str = substitute(a:str, '\r', '', 'g') + let target_str = '' + let id = 0 + while !empty(matchstr(origin_str, '^=?[^?]*?[^?]*?[^?]*?=')) + let id += 1 + let str = matchstr(origin_str, '^=?[^?]*?[^?]*?[^?]*?=') + let origin_str = substitute(origin_str, '^=?[^?]*?[^?]*?[^?]*?=', '', '') + let charset = matchstr(str, '^=?\zs[^?]*') + let encoding = matchstr(str, '^=?[^?]*?\zs[^?]*') + let text = matchstr(str, '^=?[^?]*?[^?]*?\zs[^?]*') + if encoding ==? 'b' + let text = s:BASE64.decode(text) + let target_str .= iconv(text, charset, 'utf-8') + elseif encoding ==? 'q' && 0 + let text = s:QUOPRI.decode(text) + let target_str .= text + else + let target_str .= str + endif + endwhile + return target_str . origin_str endfunction function! s:refresh() abort - let mails = mail#client#mailbox#get(s:win_dir) - let lines = ['DATA FROM SUBJECT'] - for id in keys(mails) - call add(lines, mails[id]['data'] . ' ' . mails[id]['from'] . ' ' . mails[id]['subject']) - endfor - call setbufvar(s:bufnr, '&modifiable', 1) - call s:BUFFER.buf_set_lines(s:bufnr, 0, len(lines), 0, lines) - call setbufvar(s:bufnr, '&modifiable', 0) + let mails = mail#client#mailbox#get(s:win_dir) + let lines = ['DATA FROM SUBJECT'] + for id in keys(mails) + call add(lines, mails[id]['data'] . ' ' . s:encode(mails[id]['from']) . ' ' . s:encode(mails[id]['subject'])) + endfor + call setbufvar(s:bufnr, '&modifiable', 1) + call s:BUFFER.buf_set_lines(s:bufnr, 0, len(lines), 0, lines) + call setbufvar(s:bufnr, '&modifiable', 0) endfunction function! mail#client#win#status() abort - return { - \ 'dir' : s:win_dir, - \ 'unseen' : get(s:win_unseen, 's:win_dir', 0), - \ } + return { + \ 'dir' : s:win_dir, + \ 'unseen' : get(s:win_unseen, 's:win_dir', 0), + \ } endfunction