Refactor to use *WriteCmd/*ReadCmd autocommands.

With this change, we're able to properly handle errors from shell commands.
This means no more overwriting the original file when an incorrect password is
entered or some other similar scenario.

Also, move the handling of entering recipients to gpg itself instead of
mimicking that in Vim itself.

Signed-off-by: James Vega <vega.james@gmail.com>
This commit is contained in:
James Vega 2010-10-28 01:30:47 -04:00 committed by James McCoy
parent a8838d0e86
commit bf67f5561a

View File

@ -127,6 +127,7 @@ if (exists("g:loaded_gnupg") || &cp || exists("#BufReadPre#*.\(gpg\|asc\|pgp\)")
finish finish
endif endif
let g:loaded_gnupg = "$Revision$" let g:loaded_gnupg = "$Revision$"
let s:GPGInitRun = 0
" check for correct vim version {{{2 " check for correct vim version {{{2
if (v:version < 700) if (v:version < 700)
@ -143,19 +144,14 @@ endif
augroup GnuPG augroup GnuPG
autocmd! autocmd!
" initialize the internal variables
autocmd BufNewFile,BufReadPre,FileReadPre *.\(gpg\|asc\|pgp\) call s:GPGInit()
" force the user to edit the recipient list if he opens a new file and public
" keys are preferred
autocmd BufNewFile *.\(gpg\|asc\|pgp\) if (exists("g:GPGPreferSymmetric") && g:GPGPreferSymmetric == 0) | call s:GPGEditRecipients() | endif
" do the decryption " do the decryption
autocmd BufReadPost,FileReadPost *.\(gpg\|asc\|pgp\) call s:GPGDecrypt() autocmd BufReadCmd,FileReadCmd *.\(gpg\|asc\|pgp\) call s:GPGInit()
autocmd BufReadCmd,FileReadCmd *.\(gpg\|asc\|pgp\) call s:GPGDecrypt()
autocmd BufReadCmd *.\(gpg\|asc\|pgp\) call s:GPGBufReadPost()
" convert all text to encrypted text before writing " convert all text to encrypted text before writing
autocmd BufWritePre,FileWritePre *.\(gpg\|asc\|pgp\) call s:GPGEncrypt() autocmd BufWriteCmd,FileWriteCmd *.\(gpg\|asc\|pgp\) call s:GPGInit()
" undo the encryption so we are back in the normal text, directly autocmd BufWriteCmd,FileWriteCmd *.\(gpg\|asc\|pgp\) call s:GPGEncrypt()
" after the file has been written.
autocmd BufWritePost,FileWritePost *.\(gpg\|asc\|pgp\) call s:GPGEncryptPost()
" cleanup on leaving vim " cleanup on leaving vim
autocmd VimLeave *.\(gpg\|asc\|pgp\) call s:GPGCleanup() autocmd VimLeave *.\(gpg\|asc\|pgp\) call s:GPGCleanup()
@ -178,6 +174,9 @@ highlight default link GPGHighlightUnknownRecipient ErrorMsg
" initialize the plugin " initialize the plugin
" "
function s:GPGInit() function s:GPGInit()
if s:GPGInitRun
return
endif
call s:GPGDebug(3, ">>>>>>>> Entering s:GPGInit()") call s:GPGDebug(3, ">>>>>>>> Entering s:GPGInit()")
" first make sure nothing is written to ~/.viminfo while editing " first make sure nothing is written to ~/.viminfo while editing
@ -185,7 +184,7 @@ function s:GPGInit()
set viminfo= set viminfo=
" we don't want a swap file, as it writes unencrypted data to disk " we don't want a swap file, as it writes unencrypted data to disk
set noswapfile setl noswapfile
" check what gpg command to use " check what gpg command to use
if (!exists("g:GPGExecutable")) if (!exists("g:GPGExecutable"))
@ -296,6 +295,7 @@ function s:GPGInit()
call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash) call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash)
call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress) call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress)
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()")
let s:GPGInitRun = 1
endfunction endfunction
" Function: s:GPGCleanup() {{{2 " Function: s:GPGCleanup() {{{2
@ -319,11 +319,13 @@ endfunction
function s:GPGDecrypt() function s:GPGDecrypt()
call s:GPGDebug(3, ">>>>>>>> Entering s:GPGDecrypt()") call s:GPGDebug(3, ">>>>>>>> Entering s:GPGDecrypt()")
" switch to binary mode to read the encrypted file
set bin
" get the filename of the current buffer " get the filename of the current buffer
let filename = expand("%:p") let filename = expand("<afile>:p")
" File doesn't exist yet, so force recipients
if empty(glob(filename))
return
endif
" clear GPGEncrypted, GPGRecipients and GPGOptions " clear GPGEncrypted, GPGRecipients and GPGOptions
let b:GPGEncrypted = 0 let b:GPGEncrypted = 0
@ -391,7 +393,7 @@ function s:GPGDecrypt()
echohl GPGWarning echohl GPGWarning
echom "File is not encrypted, all GPG functions disabled!" echom "File is not encrypted, all GPG functions disabled!"
echohl None echohl None
set nobin silent exe '.r ' . fnameescape(filename)
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()")
return return
endif endif
@ -406,7 +408,7 @@ function s:GPGDecrypt()
" since even with the --quiet option passphrase typos will be reported, " since even with the --quiet option passphrase typos will be reported,
" we must redirect stderr (using shell temporarily) " we must redirect stderr (using shell temporarily)
call s:GPGDebug(1, "decrypting file") call s:GPGDebug(1, "decrypting file")
let commandline = "'[,']!" . s:GPGCommand . " --quiet --decrypt " . s:stderrredirnull let commandline = "r !" . s:GPGCommand . ' --quiet --decrypt ' . shellescape(filename, 1) . ' ' . s:stderrredirnull
call s:GPGDebug(1, "command: " . commandline) call s:GPGDebug(1, "command: " . commandline)
let &shellredir = s:shellredir let &shellredir = s:shellredir
let &shell = s:shell let &shell = s:shell
@ -414,29 +416,29 @@ function s:GPGDecrypt()
let &shellredir = s:shellredirsave let &shellredir = s:shellredirsave
let &shell = s:shellsave let &shell = s:shellsave
if (v:shell_error) " message could not be decrypted if (v:shell_error) " message could not be decrypted
silent u
echohl GPGError echohl GPGError
let blackhole = input("Message could not be decrypted! (Press ENTER)") let blackhole = input("Message could not be decrypted! (Press ENTER)")
echohl None echohl None
bwipeout silent bwipeout!
set nobin
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()")
return return
endif endif
" turn off binary mode
set nobin
" call the autocommand for the file minus .gpg$
execute ":doautocmd BufReadPost " . fnameescape(expand("%:r"))
call s:GPGDebug(2, "called autocommand for " . fnameescape(expand("%:r")))
" refresh screen " refresh screen
redraw! redraw!
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()")
endfunction endfunction
function s:GPGBufReadPost()
call s:GPGDebug(3, ">>>>>>>> Entering s:GPGBufReadPost()")
silent 1delete
" call the autocommand for the file minus .gpg$
execute ':doautocmd BufReadPost ' . fnameescape(expand('<afile>:r'))
call s:GPGDebug(2, 'called autocommand for ' . fnameescape(expand('<afile>:r')))
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGBufReadPost()")
endfunction
" Function: s:GPGEncrypt() {{{2 " Function: s:GPGEncrypt() {{{2
" "
" encrypts the buffer to all previous recipients " encrypts the buffer to all previous recipients
@ -444,10 +446,6 @@ endfunction
function s:GPGEncrypt() function s:GPGEncrypt()
call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncrypt()") call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncrypt()")
" save window view
let s:GPGWindowView = winsaveview()
call s:GPGDebug(2, "saved window view " . string(s:GPGWindowView))
" store encoding and switch to a safe one " store encoding and switch to a safe one
if (&fileencoding != &encoding) if (&fileencoding != &encoding)
let s:GPGEncoding = &encoding let s:GPGEncoding = &encoding
@ -458,13 +456,10 @@ function s:GPGEncrypt()
call s:GPGDebug(2, "encoding and fileencoding are the same (\"" . &encoding . "\"), not switching") call s:GPGDebug(2, "encoding and fileencoding are the same (\"" . &encoding . "\"), not switching")
endif endif
" switch buffer to binary mode
set bin
" guard for unencrypted files " guard for unencrypted files
if (!exists("b:GPGEncrypted") || b:GPGEncrypted == 0) if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0)
echohl GPGError echohl GPGError
let blackhole = input("Message could not be encrypted! File might be empty! (Press ENTER)") let blackhole = input("Message could not be encrypted! (Press ENTER)")
echohl None echohl None
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
return return
@ -494,6 +489,10 @@ function s:GPGEncrypt()
let options = options . " --" . option . " " let options = options . " --" . option . " "
endfor endfor
if (!exists('b:GPGRecipients'))
let b:GPGRecipients = []
endif
" check here again if all recipients are available in the keyring " check here again if all recipients are available in the keyring
let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients) let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients)
@ -513,57 +512,17 @@ function s:GPGEncrypt()
for gpgid in recipients for gpgid in recipients
let options = options . " -r " . gpgid let options = options . " -r " . gpgid
endfor endfor
else
if (match(b:GPGOptions, "encrypt") >= 0)
echohl GPGError
echom "There are no recipients!!"
echom "Please use GPGEditRecipients to correct!!"
echo
echohl None
endif
endif endif
" encrypt the buffer " encrypt the buffer
let commandline = "'[,']!" . s:GPGCommand . " --quiet --no-encrypt-to " . options . " " . s:stderrredirnull let destfile = tempname()
let commandline = "'[,']w !" . s:GPGCommand . ' --quiet --no-encrypt-to ' . options . '>' . shellescape(destfile, 1) . ' ' . s:stderrredirnull
call s:GPGDebug(1, "command: " . commandline) call s:GPGDebug(1, "command: " . commandline)
let &shellredir = s:shellredir let &shellredir = s:shellredir
let &shell = s:shell let &shell = s:shell
silent execute commandline silent execute commandline
let &shellredir = s:shellredirsave let &shellredir = s:shellredirsave
let &shell = s:shellsave let &shell = s:shellsave
if (v:shell_error) " message could not be encrypted
" delete content of the buffer to be sure no data is written unencrypted
" content will be recovered in GPGEncryptPost()
silent normal! 1GdG
echohl GPGError
let blackhole = input("Message could not be encrypted! File might be empty! (Press ENTER)")
echohl None
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
return
endif
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
endfunction
" Function: s:GPGEncryptPost() {{{2
"
" undo changes don by encrypt, after writing
"
function s:GPGEncryptPost()
call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncryptPost()")
" guard for unencrypted files
if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0)
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncryptPost()")
return
endif
" undo encryption of buffer content
silent u
" switch back from binary mode
set nobin
" restore encoding " restore encoding
if (s:GPGEncoding != "") if (s:GPGEncoding != "")
@ -571,14 +530,19 @@ function s:GPGEncryptPost()
call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"") call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"")
endif endif
" restore window view if (v:shell_error) " message could not be encrypted
call winrestview(s:GPGWindowView) " Command failed, so clean up the tempfile
call s:GPGDebug(2, "restored window view" . string(s:GPGWindowView)) call delete(destfile)
echohl GPGError
let blackhole = input("Message could not be encrypted! (Press ENTER)")
echohl None
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
return
endif
" refresh screen call rename(destfile, expand('<afile>'))
redraw! setl nomodified
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncryptPost()")
endfunction endfunction
" Function: s:GPGViewRecipients() {{{2 " Function: s:GPGViewRecipients() {{{2
@ -667,7 +631,7 @@ function s:GPGEditRecipients()
endif endif
" empty the buffer " empty the buffer
silent normal! 1GdG silent %delete
endif endif
" Mark the buffer as a scratch buffer " Mark the buffer as a scratch buffer
@ -732,10 +696,10 @@ function s:GPGEditRecipients()
endif endif
" delete the empty first line " delete the empty first line
silent normal! 1Gdd silent 1delete
" jump to the first recipient " jump to the first recipient
silent normal! G silent $
endif endif
@ -814,7 +778,7 @@ function s:GPGFinishRecipientsBuffer()
endif endif
" reset modified flag " reset modified flag
set nomodified setl nomodified
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()")
endfunction endfunction
@ -889,7 +853,7 @@ function s:GPGEditOptions()
endif endif
" empty the buffer " empty the buffer
silent normal! 1GdG silent %delete
endif endif
" Mark the buffer as a scratch buffer " Mark the buffer as a scratch buffer
@ -921,10 +885,10 @@ function s:GPGEditOptions()
endfor endfor
" delete the empty first line " delete the empty first line
silent normal! 1Gdd silent 1delete
" jump to the first option " jump to the first option
silent normal! G silent $
" define highlight " define highlight
if (has("syntax") && exists("g:syntax_on")) if (has("syntax") && exists("g:syntax_on"))
@ -987,7 +951,7 @@ function s:GPGFinishOptionsBuffer()
call setbufvar(b:GPGCorrespondingTo, "&mod", 1) call setbufvar(b:GPGCorrespondingTo, "&mod", 1)
" reset modified flag " reset modified flag
set nomodified setl nomodified
call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()") call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()")
endfunction endfunction