Hello community, here is the log from the commit of package vim-plugins for openSUSE:Factory checked in at 2016-06-29 15:10:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/vim-plugins (Old) and /work/SRC/openSUSE:Factory/.vim-plugins.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "vim-plugins" Changes: -------- --- /work/SRC/openSUSE:Factory/vim-plugins/vim-plugins.changes 2016-06-03 16:38:26.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.vim-plugins.new/vim-plugins.changes 2016-06-29 15:10:51.000000000 +0200 @@ -1,0 +2,5 @@ +Sat Jun 25 13:41:30 UTC 2016 - sebix+novell.com@sebix.at + +- Update vim-plugin-gnupg to upstream version 2.6 + +------------------------------------------------------------------- Old: ---- vimplugin-gnupg-3026.tar.bz2 New: ---- vimplugin-gnupg-2.6.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ vim-plugins.spec ++++++ --- /var/tmp/diff_new_pack.UEt6ch/_old 2016-06-29 15:10:53.000000000 +0200 +++ /var/tmp/diff_new_pack.UEt6ch/_new 2016-06-29 15:10:53.000000000 +0200 @@ -43,7 +43,7 @@ %define latex_version 20120125 %define quilt_version 0.9.7 %define vimwiki_version 2.1 -%define gnupg_version 3026 +%define gnupg_version 2.6 %define gitdiff_version 2 %define snipmate_version 0.83 %define rails_version 4.4 @@ -484,6 +484,7 @@ Summary: Plugin for transparent editing of gpg encrypted files License: GPL-1.0+ Group: Productivity/Text/Editors +Url: https://github.com/jamessan/vim-gnupg Requires: gpg2 %description -n vim-plugin-gnupg @@ -491,8 +492,8 @@ must have a ".gpg", ".pgp" or ".asc" suffix. When opening such a file the content is decrypted, when opening a new file the script will ask for the recipients of the encrypted file. The file content will be encrypted to all -recipients before it is written. The script turns off viminfo and swapfile to -increase security. +recipients before it is written. The script turns off viminfo, swapfile, and +undofile to increase security. %package -n vim-plugin-gitdiff ++++++ vimplugin-gnupg-3026.tar.bz2 -> vimplugin-gnupg-2.6.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vimplugin-gnupg-3026/plugin/gnupg.vim new/vimplugin-gnupg-2.6/plugin/gnupg.vim --- old/vimplugin-gnupg-3026/plugin/gnupg.vim 2010-03-31 16:37:48.000000000 +0200 +++ new/vimplugin-gnupg-2.6/plugin/gnupg.vim 2016-04-25 05:27:34.000000000 +0200 @@ -1,10 +1,13 @@ " Name: gnupg.vim -" Version: $Id: gnupg.vim 3026 2010-01-27 08:18:04Z mbr $ -" Author: Markus Braun <markus.braun@krawel.de> +" Last Change: 2016 Apr 24 +" Maintainer: James McCoy <jamessan@jamessan.com> +" Original Author: Markus Braun <markus.braun@krawel.de> " Summary: Vim plugin for transparent editing of gpg encrypted files. -" Licence: This program is free software; you can redistribute it and/or -" modify it under the terms of the GNU General Public License. -" See http://www.gnu.org/copyleft/gpl.txt +" License: This program is free software; you can redistribute it and/or +" modify it under the terms of the GNU General Public License +" as published by the Free Software Foundation; either version +" 2 of the License, or (at your option) any later version. +" See http://www.gnu.org/copyleft/gpl-2.0.txt " " Section: Documentation {{{1 " @@ -15,7 +18,7 @@ " a file the content is decrypted, when opening a new file the script will " ask for the recipients of the encrypted file. The file content will be " encrypted to all recipients before it is written. The script turns off -" viminfo and swapfile to increase security. +" viminfo, swapfile, and undofile to increase security. " " Installation: {{{2 " @@ -39,6 +42,17 @@ " Most distributions provide software to ease handling of gpg and gpg-agent. " Examples are keychain or seahorse. " +" If there are specific actions that should take place when editing a +" GnuPG-managed buffer, an autocmd for the User event and GnuPG pattern can +" be defined. For example, the following will set 'textwidth' to 72 for all +" GnuPG-encrypted buffers: +" +" autocmd User GnuPG setl textwidth=72 +" +" This will be triggered before any BufRead or BufNewFile autocmds, and +" therefore will not take precedence over settings specific to any filetype +" that may get set. +" " Commands: {{{2 " " :GPGEditRecipients @@ -61,8 +75,9 @@ " Variables: {{{2 " " g:GPGExecutable -" If set used as gpg executable, otherwise the system chooses what is run -" when "gpg" is called. Defaults to "gpg". +" If set used as gpg executable. If unset, defaults to +" "gpg --trust-model always" if "gpg" is available, falling back to +" "gpg2 --trust-model always" if not. " " g:GPGUseAgent " If set to 0 a possible available gpg-agent won't be used. Defaults to 1. @@ -71,7 +86,8 @@ " If set to 1 symmetric encryption is preferred for new files. Defaults to 0. " " g:GPGPreferArmor -" If set to 1 armored data is preferred for new files. Defaults to 0. +" If set to 1 armored data is preferred for new files. Defaults to 0 +" unless a "*.asc" file is being edited. " " g:GPGPreferSign " If set to 1 signed data is preferred for new files. Defaults to 0. @@ -80,9 +96,36 @@ " If set, these recipients are used as defaults when no other recipient is " defined. This variable is a Vim list. Default is unset. " +" g:GPGPossibleRecipients +" If set, these contents are loaded into the recipients dialog. This +" allows to add commented lines with possible recipients to the list, +" which can be uncommented to select the actual recipients. Default is +" unset. Example: +" +" let g:GPGPossibleRecipients=[ +" \"Example User <example@example.com>", +" \"Other User <otherexample@example.com>" +" \] +" +" +" g:GPGUsePipes +" If set to 1, use pipes instead of temporary files when interacting with +" gnupg. When set to 1, this can cause terminal-based gpg agents to not +" display correctly when prompting for passwords. Defaults to 0. +" +" g:GPGHomedir +" If set, specifies the directory that will be used for GPG's homedir. +" This corresponds to gpg's --homedir option. This variable is a Vim +" string. Default is unset. +" +" g:GPGFilePattern +" If set, overrides the default set of file patterns that determine +" whether this plugin will be activated. Defaults to +" '*.\(gpg\|asc\|pgp\)'. +" " Known Issues: {{{2 " -" In some cases gvim can't decryt files +" In some cases gvim can't decrypt files " This is caused by the fact that a running gvim has no TTY and thus gpg is " not able to ask for the passphrase by itself. This is a problem for Windows @@ -102,6 +145,13 @@ " you will get a popup window the first time you open a file that " needs to be decrypted. " +" If you're using Vim <7.4.959, after the plugin runs any external command, +" Vim will no longer be able to yank to/paste from the X clipboard or +" primary selections. This is caused by a workaround for a different bug +" where Vim no longer recognizes the key codes for keys such as the arrow +" keys after running GnuPG. See the discussion at +" https://github.com/jamessan/vim-gnupg/issues/36 for more details. +" " Credits: {{{2 " " - Mathieu Clabaut for inspirations through his vimspell.vim script. @@ -109,54 +159,61 @@ " - Erik Remmelzwaal for patch to enable windows support and patient beta " testing. " - Lars Becker for patch to make gpg2 working. -" - Thomas Arendsen Hein for patch to convert encoding of gpg output +" - Thomas Arendsen Hein for patch to convert encoding of gpg output. " - Karl-Heinz Ruskowski for patch to fix unknown recipients and trust model " and patient beta testing. " - Giel van Schijndel for patch to get GPG_TTY dynamically. " - Sebastian Luettich for patch to fix issue with symmetric encryption an set " recipients. -" - Tim Swast for patch to generate signed files +" - Tim Swast for patch to generate signed files. +" - James Vega for patches for better '*.asc' handling, better filename +" escaping and better handling of multiple keyrings. " " Section: Plugin header {{{1 " guard against multiple loads {{{2 -if (exists("g:loaded_gnupg") || &cp || exists("#BufReadPre#*.\(gpg\|asc\|pgp\)")) +if (exists("g:loaded_gnupg") || &cp || exists("#GnuPG")) finish endif -let g:loaded_gnupg = "$Revision: 3026 $" +let g:loaded_gnupg = '2.6' +let s:GPGInitRun = 0 " check for correct vim version {{{2 -if (v:version < 700) - echohl ErrorMsg | echo 'plugin gnupg.vim requires Vim version >= 7.0' | echohl None +if (v:version < 702) + echohl ErrorMsg | echo 'plugin gnupg.vim requires Vim version >= 7.2' | echohl None finish endif " Section: Autocmd setup {{{1 +if (!exists("g:GPGFilePattern")) + let g:GPGFilePattern = '*.\(gpg\|asc\|pgp\)' +endif + augroup GnuPG 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 - autocmd BufReadPost,FileReadPost *.\(gpg\|asc\|pgp\) call s:GPGDecrypt() + exe "autocmd BufReadCmd " . g:GPGFilePattern . " call s:GPGInit(1) |" . + \ " call s:GPGDecrypt(1)" + exe "autocmd FileReadCmd " . g:GPGFilePattern . " call s:GPGInit(0) |" . + \ " call s:GPGDecrypt(0)" " convert all text to encrypted text before writing - autocmd BufWritePre,FileWritePre *.\(gpg\|asc\|pgp\) call s:GPGEncrypt() - " undo the encryption so we are back in the normal text, directly - " after the file has been written. - autocmd BufWritePost,FileWritePost *.\(gpg\|asc\|pgp\) call s:GPGEncryptPost() + " We check for GPGCorrespondingTo to avoid triggering on writes in GPG Options/Recipient windows + exe "autocmd BufWriteCmd,FileWriteCmd " . g:GPGFilePattern . " if !exists('b:GPGCorrespondingTo') |" . + \ " call s:GPGInit(0) |" . + \ " call s:GPGEncrypt() |" . + \ " endif" " cleanup on leaving vim - autocmd VimLeave *.\(gpg\|asc\|pgp\) call s:GPGCleanup() + exe "autocmd VimLeave " . g:GPGFilePattern . " call s:GPGCleanup()" augroup END " Section: Constants {{{1 let s:GPGMagicString = "\t \t" +let s:keyPattern = '\%(0x\)\=[[:xdigit:]]\{8,16}' " Section: Highlight setup {{{1 @@ -166,23 +223,67 @@ " Section: Functions {{{1 -" Function: s:GPGInit() {{{2 +" Function: s:shellescape(s[, special]) {{{2 +" +" Calls shellescape(), also taking into account 'shellslash' +" when on Windows and using $COMSPEC as the shell. +" +" Returns: shellescaped string +" +function s:shellescape(s, ...) + let special = a:0 ? a:1 : 0 + if exists('+shellslash') && &shell == $COMSPEC + let ssl = &shellslash + set noshellslash + + let escaped = shellescape(a:s, special) + + let &shellslash = ssl + else + let escaped = shellescape(a:s, special) + endif + + return escaped +endfunction + +" Function: s:GPGInit(bufread) {{{2 " " initialize the plugin +" The bufread argument specifies whether this was called due to BufReadCmd " -function s:GPGInit() - call s:GPGDebug(3, ">>>>>>>> Entering s:GPGInit()") +function s:GPGInit(bufread) + call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGInit(%d)", a:bufread)) - " first make sure nothing is written to ~/.viminfo while editing - " an encrypted file. - set viminfo= + " For FileReadCmd, we're reading the contents into another buffer. If that + " buffer is also destined to be encrypted, then these settings will have + " already been set, otherwise don't set them since it limits the + " functionality of the cleartext buffer. + if a:bufread + " we don't want a swap file, as it writes unencrypted data to disk + setl noswapfile + + " if persistent undo is present, disable it for this buffer + if exists('+undofile') + setl noundofile + endif - " we don't want a swap file, as it writes unencrypted data to disk - set noswapfile + " first make sure nothing is written to ~/.viminfo while editing + " an encrypted file. + set viminfo= + endif + + " the rest only has to be run once + if s:GPGInitRun + return + endif " check what gpg command to use if (!exists("g:GPGExecutable")) - let g:GPGExecutable = "gpg --trust-model always" + if executable("gpg") + let g:GPGExecutable = "gpg --trust-model always" + else + let g:GPGExecutable = "gpg2 --trust-model always" + endif endif " check if gpg-agent is allowed @@ -195,11 +296,6 @@ let g:GPGPreferSymmetric = 0 endif - " check if armored files are preferred - if (!exists("g:GPGPreferArmor")) - let g:GPGPreferArmor = 0 - endif - " check if signed files are preferred if (!exists("g:GPGPreferSign")) let g:GPGPreferSign = 0 @@ -210,42 +306,46 @@ let g:GPGDefaultRecipients = [] endif + if (!exists("g:GPGPossibleRecipients")) + let g:GPGPossibleRecipients = [] + endif + + + " prefer not to use pipes since it can garble gpg agent display + if (!exists("g:GPGUsePipes")) + let g:GPGUsePipes = 0 + endif + + " allow alternate gnupg homedir + if (!exists('g:GPGHomedir')) + let g:GPGHomedir = '' + endif + " print version call s:GPGDebug(1, "gnupg.vim ". g:loaded_gnupg) - " determine if gnupg can use the gpg-agent - if (exists("$GPG_AGENT_INFO") && g:GPGUseAgent == 1) - if (!exists("$GPG_TTY") && !has("gui_running")) - let $GPG_TTY = system("tty") - if (v:shell_error) - let $GPG_TTY = "" - echohl GPGError - echom "The GPG_TTY is not set and no TTY could be found using the `tty` command!" - echom "gpg-agent might not work." - echohl None - endif - endif - let s:GPGCommand = g:GPGExecutable . " --use-agent" - else - let s:GPGCommand = g:GPGExecutable . " --no-use-agent" - endif + let s:GPGCommand = g:GPGExecutable - " don't use tty in gvim + " don't use tty in gvim except for windows: we get their a tty for free. " FIXME find a better way to avoid an error. " with this solution only --use-agent will work - if (has("gui_running")) - let s:GPGCommand = s:GPGCommand . " --no-tty" + if (has("gui_running") && !has("gui_win32")) + let s:GPGCommand .= " --no-tty" endif " setup shell environment for unix and windows let s:shellredirsave = &shellredir let s:shellsave = &shell + let s:shelltempsave = &shelltemp + " noshelltemp isn't currently supported on Windows, but it doesn't cause any + " errors and this future proofs us against requiring changes if Windows + " gains noshelltemp functionality + let s:shelltemp = !g:GPGUsePipes if (has("unix")) " unix specific settings let s:shellredir = ">%s 2>&1" let s:shell = '/bin/sh' let s:stderrredirnull = '2>/dev/null' - let s:GPGCommand = "LANG=C LC_ALL=C " . s:GPGCommand else " windows specific settings let s:shellredir = '>%s' @@ -255,6 +355,7 @@ call s:GPGDebug(3, "shellredirsave: " . s:shellredirsave) call s:GPGDebug(3, "shellsave: " . s:shellsave) + call s:GPGDebug(3, "shelltempsave: " . s:shelltempsave) call s:GPGDebug(3, "shell: " . s:shell) call s:GPGDebug(3, "shellcmdflag: " . &shellcmdflag) @@ -265,25 +366,51 @@ call s:GPGDebug(3, "shell implementation: " . resolve(s:shell)) " find the supported algorithms - let commandline = s:GPGCommand . " --version" - call s:GPGDebug(2, "command: ". commandline) - let &shellredir = s:shellredir - let &shell = s:shell - let output = system(commandline) - let &shellredir = s:shellredirsave - let &shell = s:shellsave - call s:GPGDebug(2, "output: ". output) + let output = s:GPGSystem({ 'level': 2, 'args': '--version' }) + let gpgversion = substitute(output, '^gpg (GnuPG) \([0-9]\+\.\d\+\).*', '\1', '') let s:GPGPubkey = substitute(output, ".*Pubkey: \\(.\\{-}\\)\n.*", "\\1", "") let s:GPGCipher = substitute(output, ".*Cipher: \\(.\\{-}\\)\n.*", "\\1", "") let s:GPGHash = substitute(output, ".*Hash: \\(.\\{-}\\)\n.*", "\\1", "") let s:GPGCompress = substitute(output, ".*Compress.\\{-}: \\(.\\{-}\\)\n.*", "\\1", "") + " determine if gnupg can use the gpg-agent + if (str2float(gpgversion) >= 2.1 || (exists("$GPG_AGENT_INFO") && g:GPGUseAgent == 1)) + if (!exists("$GPG_TTY") && !has("gui_running")) + " Need to determine the associated tty by running a command in the + " shell. We can't use system() here because that doesn't run in a shell + " connected to a tty, so it's rather useless. + " + " Save/restore &modified so the buffer isn't incorrectly marked as + " modified just by detecting the correct tty value. + " Do the &undolevels dance so the :read and :delete don't get added into + " the undo tree, as the user needn't be aware of these. + let [mod, levels] = [&l:modified, &undolevels] + set undolevels=-1 + silent read !tty + let $GPG_TTY = getline('.') + silent delete + let [&l:modified, &undolevels] = [mod, levels] + " redraw is needed since we're using silent to run !tty, c.f. :help :! + redraw! + if (v:shell_error) + let $GPG_TTY = "" + echohl GPGWarning + echom "$GPG_TTY is not set and the `tty` command failed! gpg-agent might not work." + echohl None + endif + endif + let s:GPGCommand .= " --use-agent" + else + let s:GPGCommand .= " --no-use-agent" + endif + call s:GPGDebug(2, "public key algorithms: " . s:GPGPubkey) call s:GPGDebug(2, "cipher algorithms: " . s:GPGCipher) call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash) call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress) call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()") + let s:GPGInitRun = 1 endfunction " Function: s:GPGCleanup() {{{2 @@ -300,34 +427,63 @@ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGCleanup()") endfunction -" Function: s:GPGDecrypt() {{{2 +" Function: s:GPGDecrypt(bufread) {{{2 " " decrypt the buffer and find all recipients of the encrypted file +" The bufread argument specifies whether this was called due to BufReadCmd " -function s:GPGDecrypt() - call s:GPGDebug(3, ">>>>>>>> Entering s:GPGDecrypt()") - - " switch to binary mode to read the encrypted file - set bin +function s:GPGDecrypt(bufread) + call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGDecrypt(%d)", a:bufread)) " get the filename of the current buffer - let filename = escape(expand("%:p"), '\"') + let filename = expand("<afile>:p") - " clear GPGEncrypted, GPGRecipients and GPGOptions - let b:GPGEncrypted = 0 - let b:GPGRecipients = [] + " clear GPGRecipients and GPGOptions + if type(g:GPGDefaultRecipients) == type([]) + let b:GPGRecipients = copy(g:GPGDefaultRecipients) + else + let b:GPGRecipients = [] + echohl GPGWarning + echom "g:GPGDefaultRecipients is not a Vim list, please correct this in your vimrc!" + echohl None + endif let b:GPGOptions = [] + " file name minus extension + let autocmd_filename = fnameescape(expand('<afile>:r')) + + " File doesn't exist yet, so nothing to decrypt + if !filereadable(filename) + " Allow the user to define actions for GnuPG buffers + silent doautocmd User GnuPG + " call the autocommand for the file minus .gpg$ + silent execute ':doautocmd BufNewFile ' . autocmd_filename + call s:GPGDebug(2, 'called BufNewFile autocommand for ' . autocmd_filename) + + " This is a new file, so force the user to edit the recipient list if + " they open a new file and public keys are preferred + if (g:GPGPreferSymmetric == 0) + call s:GPGEditRecipients() + endif + + return + endif + + " Only let this if the file actually exists, otherwise GPG functionality + " will be disabled when editing a buffer that doesn't yet have a backing + " file + let b:GPGEncrypted = 0 + " find the recipients of the file - let commandline = s:GPGCommand . " --verbose --decrypt --list-only --dry-run --batch --no-use-agent --logger-fd 1 \"" . filename . "\"" - call s:GPGDebug(3, "command: " . commandline) - let &shellredir = s:shellredir - let &shell = s:shell - let output = system(commandline) - let &shellredir = s:shellredirsave - let &shell = s:shellsave - call s:GPGDebug(3, "output: ". output) + let cmd = { 'level': 3 } + let cmd.args = '--verbose --decrypt --list-only --dry-run --no-use-agent --logger-fd 1 ' . s:shellescape(filename) + let output = s:GPGSystem(cmd) + + " Suppress the "N more lines" message when editing a file, not when reading + " the contents of a file into a buffer + let silent = a:bufread ? 'silent ' : '' + let asymmPattern = 'gpg: public key is ' . s:keyPattern " check if the file is symmetric/asymmetric encrypted if (match(output, "gpg: encrypted with [[:digit:]]\\+ passphrase") >= 0) " file is symmetric encrypted @@ -347,7 +503,7 @@ echo echohl None endif - elseif (match(output, "gpg: public key is [[:xdigit:]]\\{8}") >= 0) + elseif (match(output, asymmPattern) >= 0) " file is asymmetric encrypted let b:GPGEncrypted = 1 call s:GPGDebug(1, "this file is asymmetric encrypted") @@ -355,22 +511,32 @@ let b:GPGOptions += ["encrypt"] " find the used public keys - let start = match(output, "gpg: public key is [[:xdigit:]]\\{8}") + let start = match(output, asymmPattern) while (start >= 0) let start = start + strlen("gpg: public key is ") - let recipient = strpart(output, start, 8) + let recipient = matchstr(output, s:keyPattern, start) call s:GPGDebug(1, "recipient is " . recipient) - let name = s:GPGNameToID(recipient) - if (strlen(name) > 0) - let b:GPGRecipients += [name] - call s:GPGDebug(1, "name of recipient is " . name) - else - let b:GPGRecipients += [recipient] - echohl GPGWarning - echom "The recipient \"" . recipient . "\" is not in your public keyring!" - echohl None + " In order to support anonymous communication, GnuPG allows eliding + " information in the encryption metadata specifying what keys the file + " was encrypted to (c.f., --throw-keyids and --hidden-recipient). In + " that case, the recipient(s) will be listed as having used a key of all + " zeroes. + " Since this will obviously never actually be in a keyring, only try to + " convert to an ID or add to the recipients list if it's not a hidden + " recipient. + if recipient !~? '^0x0\+$' + let name = s:GPGNameToID(recipient) + if !empty(name) + let b:GPGRecipients += [name] + call s:GPGDebug(1, "name of recipient is " . name) + else + let b:GPGRecipients += [recipient] + echohl GPGWarning + echom "The recipient \"" . recipient . "\" is not in your public keyring!" + echohl None + end end - let start = match(output, "gpg: public key is [[:xdigit:]]\\{8}", start) + let start = match(output, asymmPattern, start) endwhile else " file is not encrypted @@ -379,11 +545,19 @@ echohl GPGWarning echom "File is not encrypted, all GPG functions disabled!" echohl None - set nobin + exe printf('%sr %s', silent, fnameescape(filename)) call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") return endif + if a:bufread + silent execute ':doautocmd BufReadPre ' . autocmd_filename + call s:GPGDebug(2, 'called BufReadPre autocommand for ' . autocmd_filename) + else + silent execute ':doautocmd FileReadPre ' . autocmd_filename + call s:GPGDebug(2, 'called FileReadPre autocommand for ' . autocmd_filename) + endif + " check if the message is armored if (match(output, "gpg: armor header") >= 0) call s:GPGDebug(1, "this file is armored") @@ -394,30 +568,49 @@ " since even with the --quiet option passphrase typos will be reported, " we must redirect stderr (using shell temporarily) call s:GPGDebug(1, "decrypting file") - let commandline = "'[,']!" . s:GPGCommand . " --quiet --decrypt " . s:stderrredirnull - call s:GPGDebug(1, "command: " . commandline) - let &shellredir = s:shellredir - let &shell = s:shell - execute commandline - let &shellredir = s:shellredirsave - let &shell = s:shellsave + let cmd = { 'level': 1, 'ex': silent . 'r !' } + let cmd.args = '--quiet --decrypt ' . s:shellescape(filename, 1) + call s:GPGExecute(cmd) + if (v:shell_error) " message could not be decrypted - silent u echohl GPGError let blackhole = input("Message could not be decrypted! (Press ENTER)") echohl None - bwipeout - set nobin + " Only wipeout the buffer if we were creating one to start with. + " FileReadCmd just reads the content into the existing buffer + if a:bufread + silent bwipeout! + endif call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") return endif - " turn off binary mode - set nobin + if a:bufread + " In order to make :undo a no-op immediately after the buffer is read, + " we need to do this dance with 'undolevels'. Actually discarding the undo + " history requires performing a change after setting 'undolevels' to -1 and, + " luckily, we have one we need to do (delete the extra line from the :r + " command) + let levels = &undolevels + set undolevels=-1 + " :lockmarks doesn't actually prevent '[,'] from being overwritten, so we + " need to manually set them ourselves instead + silent 1delete + 1mark [ + $mark ] + let &undolevels = levels + let &readonly = filereadable(filename) && filewritable(filename) == 0 + " call the autocommand for the file minus .gpg$ + silent execute ':doautocmd BufReadPost ' . autocmd_filename + call s:GPGDebug(2, 'called BufReadPost autocommand for ' . autocmd_filename) + else + " call the autocommand for the file minus .gpg$ + silent execute ':doautocmd FileReadPost ' . autocmd_filename + call s:GPGDebug(2, 'called FileReadPost autocommand for ' . autocmd_filename) + endif - " call the autocommand for the file minus .gpg$ - execute ":doautocmd BufReadPost " . escape(expand("%:r"), ' *?\"'."'") - call s:GPGDebug(2, "called autocommand for " . escape(expand("%:r"), ' *?\"'."'")) + " Allow the user to define actions for GnuPG buffers + silent doautocmd User GnuPG " refresh screen redraw! @@ -432,9 +625,21 @@ function 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)) + " FileWriteCmd is only called when a portion of a buffer is being written to + " disk. Since Vim always sets the '[,'] marks to the part of a buffer that + " is being written, that can be used to determine whether BufWriteCmd or + " FileWriteCmd triggered us. + if [line("'["), line("']")] == [1, line('$')] + let auType = 'BufWrite' + else + let auType = 'FileWrite' + endif + + " file name minus extension + let autocmd_filename = fnameescape(expand('<afile>:r')) + + silent exe ':doautocmd '. auType .'Pre '. autocmd_filename + call s:GPGDebug(2, 'called '. auType .'Pre autocommand for ' . autocmd_filename) " store encoding and switch to a safe one if (&fileencoding != &encoding) @@ -446,20 +651,18 @@ call s:GPGDebug(2, "encoding and fileencoding are the same (\"" . &encoding . "\"), not switching") endif - " switch buffer to binary mode - set bin - " guard for unencrypted files - if (!exists("b:GPGEncrypted") || b:GPGEncrypted == 0) + if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0) 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 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") return endif + let filename = resolve(expand('<afile>')) " initialize GPGOptions if not happened before - if (!exists("b:GPGOptions") || len(b:GPGOptions) == 0) + if (!exists("b:GPGOptions") || empty(b:GPGOptions)) let b:GPGOptions = [] if (exists("g:GPGPreferSymmetric") && g:GPGPreferSymmetric == 1) let b:GPGOptions += ["symmetric"] @@ -467,7 +670,10 @@ else let b:GPGOptions += ["encrypt"] endif - if (exists("g:GPGPreferArmor") && g:GPGPreferArmor == 1) + " Fallback to preference by filename if the user didn't indicate + " their preference. + let preferArmor = get(g:, 'GPGPreferArmor', -1) + if (preferArmor >= 0 && preferArmor) || filename =~ '\.asc$' let b:GPGOptions += ["armor"] endif if (exists("g:GPGPreferSign") && g:GPGPreferSign == 1) @@ -482,11 +688,15 @@ let options = options . " --" . option . " " endfor + if (!exists('b:GPGRecipients')) + let b:GPGRecipients = [] + endif + " check here again if all recipients are available in the keyring - let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients) + let recipients = s:GPGCheckRecipients(b:GPGRecipients) " check if there are unknown recipients and warn - if (len(unknownrecipients) > 0) + if !empty(recipients.unknown) echohl GPGWarning echom "Please use GPGEditRecipients to correct!!" echo @@ -497,76 +707,49 @@ endif " built list of recipients - if (len(recipients) > 0) - for gpgid in recipients - let options = options . " -r " . gpgid - 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 + let options .= ' ' . join(map(recipients.valid, '"-r ".v:val'), ' ') " encrypt the buffer - let commandline = "'[,']!" . s:GPGCommand . " --quiet --no-encrypt-to " . options . " " . s:stderrredirnull - call s:GPGDebug(1, "command: " . commandline) - let &shellredir = s:shellredir - let &shell = s:shell - silent execute commandline - let &shellredir = s:shellredirsave - 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 + let destfile = tempname() + let cmd = { 'level': 1, 'ex': "'[,']w !" } + let cmd.args = '--quiet --no-encrypt-to ' . options + let cmd.redirect = '>' . s:shellescape(destfile, 1) + silent call s:GPGExecute(cmd) + + " restore encoding + if (s:GPGEncoding != "") + let &encoding = s:GPGEncoding + call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"") + endif + if (v:shell_error) " message could not be encrypted + " Command failed, so clean up the tempfile + call delete(destfile) 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 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()") + if rename(destfile, filename) + " Rename failed, so clean up the tempfile + call delete(destfile) + echohl GPGError + echom printf("\"%s\" E212: Can't open file for writing", filename) + echohl None return endif - " undo encryption of buffer content - silent u - - " switch back from binary mode - set nobin - - " restore encoding - if (s:GPGEncoding != "") - let &encoding = s:GPGEncoding - call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"") + if auType == 'BufWrite' + setl nomodified + let &readonly = filereadable(filename) && filewritable(filename) == 0 endif - " restore window view - call winrestview(s:GPGWindowView) - call s:GPGDebug(2, "restored window view" . string(s:GPGWindowView)) + silent exe ':doautocmd '. auType .'Post '. autocmd_filename + call s:GPGDebug(2, 'called '. auType .'Post autocommand for ' . autocmd_filename) - " refresh screen - redraw! - - call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncryptPost()") + call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") endfunction " Function: s:GPGViewRecipients() {{{2 @@ -585,25 +768,25 @@ return endif - let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients) + let recipients = s:GPGCheckRecipients(b:GPGRecipients) echo 'This file has following recipients (Unknown recipients have a prepended "!"):' " echo the recipients - for name in recipients + for name in recipients.valid let name = s:GPGIDToName(name) echo name endfor " echo the unknown recipients echohl GPGWarning - for name in unknownrecipients + for name in recipients.unknown let name = "!" . name echo name endfor echohl None " check if there is any known recipient - if (len(recipients) == 0) + if empty(recipients.valid) echohl GPGError echom 'There are no known recipients!' echohl None @@ -638,7 +821,7 @@ " check if this buffer exists if (!bufexists(editbuffername)) " create scratch buffer - execute 'silent! split ' . escape(editbuffername, ' *?\"'."'") + execute 'silent! split ' . fnameescape(editbuffername) " add a autocommand to regenerate the recipients after a write autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() @@ -648,14 +831,14 @@ execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" else " split scratch buffer window - execute 'silent! sbuffer ' . escape(editbuffername, ' *?\"'."'") + execute 'silent! sbuffer ' . fnameescape(editbuffername) " add a autocommand to regenerate the recipients after a write autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() endif " empty the buffer - silent normal! 1GdG + silent %delete endif " Mark the buffer as a scratch buffer @@ -679,12 +862,12 @@ silent put ='GPG: ----------------------------------------------------------------------' " get the recipients - let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(getbufvar(b:GPGCorrespondingTo, "GPGRecipients")) + let recipients = s:GPGCheckRecipients(getbufvar(b:GPGCorrespondingTo, "GPGRecipients")) " if there are no known or unknown recipients, use the default ones - if (len(recipients) == 0 && len(unknownrecipients) == 0) + if (empty(recipients.valid) && empty(recipients.unknown)) if (type(g:GPGDefaultRecipients) == type([])) - let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(g:GPGDefaultRecipients) + let recipients = s:GPGCheckRecipients(g:GPGDefaultRecipients) else echohl GPGWarning echom "g:GPGDefaultRecipients is not a Vim list, please correct this in your vimrc!" @@ -693,25 +876,30 @@ endif " put the recipients in the scratch buffer - for name in recipients + for name in recipients.valid let name = s:GPGIDToName(name) silent put =name endfor " put the unknown recipients in the scratch buffer - let syntaxPattern = "\\(nonexxistinwordinthisbuffer" - for name in unknownrecipients - let name = "!" . name - let syntaxPattern = syntaxPattern . "\\|" . name - silent put =name + let syntaxPattern = '' + if !empty(recipients.unknown) + let flaggedNames = map(recipients.unknown, '"!".v:val') + call append('$', flaggedNames) + let syntaxPattern = '\(' . join(flaggedNames, '\|') . '\)' + endif + + for line in g:GPGPossibleRecipients + silent put ='GPG: '.line endfor - let syntaxPattern = syntaxPattern . "\\)" " define highlight if (has("syntax") && exists("g:syntax_on")) - execute 'syntax match GPGUnknownRecipient "' . syntaxPattern . '"' highlight clear GPGUnknownRecipient - highlight link GPGUnknownRecipient GPGHighlightUnknownRecipient + if !empty(syntaxPattern) + execute 'syntax match GPGUnknownRecipient "' . syntaxPattern . '"' + highlight link GPGUnknownRecipient GPGHighlightUnknownRecipient + endif syntax match GPGComment "^GPG:.*$" execute 'syntax match GPGComment "' . s:GPGMagicString . '.*$"' @@ -720,10 +908,10 @@ endif " delete the empty first line - silent normal! 1Gdd + silent 1delete " jump to the first recipient - silent normal! G + silent $ endif @@ -755,13 +943,13 @@ " delete the autocommand autocmd! * <buffer> - " get the recipients from the scratch buffer let recipients = [] let lines = getline(1,"$") for recipient in lines - " delete all text after magic string - let recipient = substitute(recipient, s:GPGMagicString . ".*$", "", "") + let matches = matchlist(recipient, '^\(.\{-}\)\%(' . s:GPGMagicString . '(ID:\s\+\(' . s:keyPattern . '\)\s\+.*\)\=$') + + let recipient = matches[2] ? matches[2] : matches[1] " delete all spaces at beginning and end of the recipient " also delete a '!' at the beginning of the recipient @@ -771,9 +959,9 @@ let recipient = substitute(recipient, "^GPG:.*$", "", "") " only do this if the line is not empty - if (strlen(recipient) > 0) + if !empty(recipient) let gpgid = s:GPGNameToID(recipient) - if (strlen(gpgid) > 0) + if !empty(gpgid) if (match(recipients, gpgid) < 0) let recipients += [gpgid] endif @@ -789,20 +977,20 @@ endfor " write back the new recipient list to the corresponding buffer and mark it - " as modified. Buffer is now for sure a encrypted buffer. + " as modified. Buffer is now for sure an encrypted buffer. call setbufvar(b:GPGCorrespondingTo, "GPGRecipients", recipients) call setbufvar(b:GPGCorrespondingTo, "&mod", 1) call setbufvar(b:GPGCorrespondingTo, "GPGEncrypted", 1) " check if there is any known recipient - if (len(recipients) == 0) + if empty(recipients) echohl GPGError echom 'There are no known recipients!' echohl None endif " reset modified flag - set nomodified + setl nomodified call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()") endfunction @@ -860,7 +1048,7 @@ " check if this buffer exists if (!bufexists(editbuffername)) " create scratch buffer - execute 'silent! split ' . escape(editbuffername, ' *?\"'."'") + execute 'silent! split ' . fnameescape(editbuffername) " add a autocommand to regenerate the options after a write autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() @@ -870,14 +1058,14 @@ execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" else " split scratch buffer window - execute 'silent! sbuffer ' . escape(editbuffername, ' *?\"'."'") + execute 'silent! sbuffer ' . fnameescape(editbuffername) " add a autocommand to regenerate the options after a write autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() endif " empty the buffer - silent normal! 1GdG + silent %delete endif " Mark the buffer as a scratch buffer @@ -909,10 +1097,10 @@ endfor " delete the empty first line - silent normal! 1Gdd + silent 1delete " jump to the first option - silent normal! G + silent $ " define highlight if (has("syntax") && exists("g:syntax_on")) @@ -964,7 +1152,7 @@ let option = substitute(option, "^GPG:.*$", "", "") " only do this if the line is not empty - if (strlen(option) > 0 && match(options, option) < 0) + if (!empty(option) && match(options, option) < 0) let options += [option] endif endfor @@ -975,7 +1163,7 @@ call setbufvar(b:GPGCorrespondingTo, "&mod", 1) " reset modified flag - set nomodified + setl nomodified call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()") endfunction @@ -983,24 +1171,23 @@ " Function: s:GPGCheckRecipients(tocheck) {{{2 " " check if recipients are known -" Returns: two lists recipients and unknownrecipients +" Returns: dictionary of recipients, {'valid': [], 'unknown': []} " function s:GPGCheckRecipients(tocheck) call s:GPGDebug(3, ">>>>>>>> Entering s:GPGCheckRecipients()") - let recipients = [] - let unknownrecipients = [] + let recipients = {'valid': [], 'unknown': []} if (type(a:tocheck) == type([])) for recipient in a:tocheck let gpgid = s:GPGNameToID(recipient) - if (strlen(gpgid) > 0) - if (match(recipients, gpgid) < 0) - let recipients += [gpgid] + if !empty(gpgid) + if (match(recipients.valid, gpgid) < 0) + call add(recipients.valid, gpgid) endif else - if (match(unknownrecipients, recipient) < 0) - let unknownrecipients += [recipient] + if (match(recipients.unknown, recipient) < 0) + call add(recipients.unknown, recipient) echohl GPGWarning echom "The recipient \"" . recipient . "\" is not in your public keyring!" echohl None @@ -1009,11 +1196,11 @@ endfor endif - call s:GPGDebug(2, "recipients are: " . string(recipients)) - call s:GPGDebug(2, "unknown recipients are: " . string(unknownrecipients)) + call s:GPGDebug(2, "recipients are: " . string(recipients.valid)) + call s:GPGDebug(2, "unknown recipients are: " . string(recipients.unknown)) call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGCheckRecipients()") - return [ recipients, unknownrecipients ] + return recipients endfunction " Function: s:GPGNameToID(name) {{{2 @@ -1025,14 +1212,9 @@ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGNameToID()") " ask gpg for the id for a name - let commandline = s:GPGCommand . " --quiet --with-colons --fixed-list-mode --list-keys \"" . a:name . "\"" - call s:GPGDebug(2, "command: ". commandline) - let &shellredir = s:shellredir - let &shell = s:shell - let output = system(commandline) - let &shellredir = s:shellredirsave - let &shell = s:shellsave - call s:GPGDebug(2, "output: ". output) + let cmd = { 'level': 2 } + let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . s:shellescape(a:name) + let output = s:GPGSystem(cmd) " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, " so convert it, if necessary @@ -1045,31 +1227,41 @@ let pubseen = 0 let counter = 0 let gpgids = [] + let seen_keys = {} + let skip_key = 0 + let has_strftime = exists('*strftime') let choices = "The name \"" . a:name . "\" is ambiguous. Please select the correct key:\n" for line in lines + let fields = split(line, ":") - " search for the next uid - if (pubseen == 1) - if (fields[0] == "uid") - let choices = choices . " " . fields[9] . "\n" - else - let pubseen = 0 - endif - endif " search for the next pub - if (pubseen == 0) - if (fields[0] == "pub") - let identity = fields[4] - let gpgids += [identity] - if exists("*strftime") - let choices = choices . counter . ": ID: 0x" . identity . " created at " . strftime("%c", fields[5]) . "\n" - else - let choices = choices . counter . ": ID: 0x" . identity . "\n" - endif - let counter = counter+1 - let pubseen = 1 + if (fields[0] == "pub") + " check if this key has already been processed + if has_key(seen_keys, fields[4]) + let skip_key = 1 + continue + endif + let skip_key = 0 + let seen_keys[fields[4]] = 1 + + " Ignore keys which are not usable for encryption + if fields[11] !~? 'e' + continue + endif + + let identity = fields[4] + let gpgids += [identity] + if has_strftime + let choices = choices . counter . ": ID: 0x" . identity . " created at " . strftime("%c", fields[5]) . "\n" + else + let choices = choices . counter . ": ID: 0x" . identity . "\n" endif + let counter = counter+1 + let pubseen = 1 + " search for the next uid + elseif (!skip_key && fields[0] == "uid") + let choices = choices . " " . fields[9] . "\n" endif endfor @@ -1084,7 +1276,7 @@ endwhile endif - call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGIDToName()") + call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGNameToID()") return get(gpgids, answer, "") endfunction @@ -1099,14 +1291,9 @@ " TODO is the encryption subkey really unique? " ask gpg for the id for a name - let commandline = s:GPGCommand . " --quiet --with-colons --fixed-list-mode --list-keys " . a:identity - call s:GPGDebug(2, "command: ". commandline) - let &shellredir = s:shellredir - let &shell = s:shell - let output = system(commandline) - let &shellredir = s:shellredirsave - let &shell = s:shellsave - call s:GPGDebug(2, "output: ". output) + let cmd = { 'level': 2 } + let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . a:identity + let output = s:GPGSystem(cmd) " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, " so convert it, if necessary @@ -1120,8 +1307,14 @@ let uid = "" for line in lines let fields = split(line, ":") - if (pubseen == 0) " search for the next pub + + if !pubseen " search for the next pub if (fields[0] == "pub") + " Ignore keys which are not usable for encryption + if fields[11] !~? 'e' + continue + endif + let pubseen = 1 endif else " search for the next uid @@ -1141,6 +1334,93 @@ return uid endfunction +" Function: s:GPGPreCmd() {{{2 +" +" Setup the environment for running the gpg command +" +function s:GPGPreCmd() + let &shellredir = s:shellredir + let &shell = s:shell + let &shelltemp = s:shelltemp + " Force C locale so GPG output is consistent + let s:messages = v:lang + language messages C +endfunction + + +" Function: s:GPGPostCmd() {{{2 +" +" Restore the user's environment after running the gpg command +" +function s:GPGPostCmd() + let &shellredir = s:shellredirsave + let &shell = s:shellsave + let &shelltemp = s:shelltempsave + execute 'language messages' s:messages + " Workaround a bug in the interaction between console vim and + " pinentry-curses by forcing Vim to re-detect and setup its terminal + " settings + let &term = &term + silent doautocmd TermChanged +endfunction + +" Function: s:GPGSystem(dict) {{{2 +" +" run g:GPGCommand using system(), logging the commandline and output. This +" uses temp files (regardless of how 'shelltemp' is set) to hold the output of +" the command, so it must not be used for sensitive commands. +" Recognized keys are: +" level - Debug level at which the commandline and output will be logged +" args - Arguments to be given to g:GPGCommand +" +" Returns: command output +" +function s:GPGSystem(dict) + let commandline = s:GPGCommand + if (!empty(g:GPGHomedir)) + let commandline .= ' --homedir ' . s:shellescape(g:GPGHomedir) + endif + let commandline .= ' ' . a:dict.args + let commandline .= ' ' . s:stderrredirnull + call s:GPGDebug(a:dict.level, "command: ". commandline) + + call s:GPGPreCmd() + let output = system(commandline) + call s:GPGPostCmd() + + call s:GPGDebug(a:dict.level, "rc: ". v:shell_error) + call s:GPGDebug(a:dict.level, "output: ". output) + return output +endfunction + +" Function: s:GPGExecute(dict) {{{2 +" +" run g:GPGCommand using :execute, logging the commandline +" Recognized keys are: +" level - Debug level at which the commandline will be logged +" args - Arguments to be given to g:GPGCommand +" ex - Ex command which will be :executed +" redirect - Shell redirect to use, if needed +" +function s:GPGExecute(dict) + let commandline = printf('%s%s', a:dict.ex, s:GPGCommand) + if (!empty(g:GPGHomedir)) + let commandline .= ' --homedir ' . s:shellescape(g:GPGHomedir, 1) + endif + let commandline .= ' ' . a:dict.args + if (has_key(a:dict, 'redirect')) + let commandline .= ' ' . a:dict.redirect + endif + let commandline .= ' ' . s:stderrredirnull + call s:GPGDebug(a:dict.level, "command: " . commandline) + + call s:GPGPreCmd() + execute commandline + call s:GPGPostCmd() + + call s:GPGDebug(a:dict.level, "rc: ". v:shell_error) +endfunction + " Function: s:GPGDebug(level, text) {{{2 " " output debug message, if this message has high enough importance @@ -1150,7 +1430,7 @@ if exists("g:GPGDebugLevel") && g:GPGDebugLevel >= a:level if exists("g:GPGDebugLog") execute "redir >> " . g:GPGDebugLog - echom "GnuPG: " . a:text + silent echom "GnuPG: " . a:text redir END else echom "GnuPG: " . a:text