Mercurial > index.cgi > dotfiles
comparison .vim/plugin/gnupg.vim @ 92:fa4f783acc35
New version of gnupg.vim
author | Steve Huston <huston@srhuston.net> |
---|---|
date | Tue, 30 Jul 2013 17:17:32 -0400 |
parents | 2bea356b1032 |
children | ab30008c9e93 |
comparison
equal
deleted
inserted
replaced
91:9d5fcbb36232 | 92:fa4f783acc35 |
---|---|
1 " Name: gnupg.vim | 1 " Name: gnupg.vim |
2 " Version: $Id: gnupg.vim 3026 2010-01-27 08:18:04Z mbr $ | 2 " Last Change: 2012 May 31 |
3 " Author: Markus Braun <markus.braun@krawel.de> | 3 " Maintainer: James McCoy <vega.james@gmail.com> |
4 " Original Author: Markus Braun <markus.braun@krawel.de> | |
4 " Summary: Vim plugin for transparent editing of gpg encrypted files. | 5 " Summary: Vim plugin for transparent editing of gpg encrypted files. |
5 " Licence: This program is free software; you can redistribute it and/or | 6 " License: This program is free software; you can redistribute it and/or |
6 " modify it under the terms of the GNU General Public License. | 7 " modify it under the terms of the GNU General Public License |
7 " See http://www.gnu.org/copyleft/gpl.txt | 8 " as published by the Free Software Foundation; either version |
9 " 2 of the License, or (at your option) any later version. | |
10 " See http://www.gnu.org/copyleft/gpl-2.0.txt | |
8 " | 11 " |
9 " Section: Documentation {{{1 | 12 " Section: Documentation {{{1 |
10 " | 13 " |
11 " Description: {{{2 | 14 " Description: {{{2 |
12 " | 15 " |
13 " This script implements transparent editing of gpg encrypted files. The | 16 " This script implements transparent editing of gpg encrypted files. The |
14 " filename must have a ".gpg", ".pgp" or ".asc" suffix. When opening such | 17 " filename must have a ".gpg", ".pgp" or ".asc" suffix. When opening such |
15 " a file the content is decrypted, when opening a new file the script will | 18 " a file the content is decrypted, when opening a new file the script will |
16 " ask for the recipients of the encrypted file. The file content will be | 19 " ask for the recipients of the encrypted file. The file content will be |
17 " encrypted to all recipients before it is written. The script turns off | 20 " encrypted to all recipients before it is written. The script turns off |
18 " viminfo and swapfile to increase security. | 21 " viminfo, swapfile, and undofile to increase security. |
19 " | 22 " |
20 " Installation: {{{2 | 23 " Installation: {{{2 |
21 " | 24 " |
22 " Copy the gnupg.vim file to the $HOME/.vim/plugin directory. | 25 " Copy the gnupg.vim file to the $HOME/.vim/plugin directory. |
23 " Refer to ':help add-plugin', ':help add-global-plugin' and ':help | 26 " Refer to ':help add-plugin', ':help add-global-plugin' and ':help |
69 " | 72 " |
70 " g:GPGPreferSymmetric | 73 " g:GPGPreferSymmetric |
71 " If set to 1 symmetric encryption is preferred for new files. Defaults to 0. | 74 " If set to 1 symmetric encryption is preferred for new files. Defaults to 0. |
72 " | 75 " |
73 " g:GPGPreferArmor | 76 " g:GPGPreferArmor |
74 " If set to 1 armored data is preferred for new files. Defaults to 0. | 77 " If set to 1 armored data is preferred for new files. Defaults to 0 |
78 " unless a "*.asc" file is being edited. | |
75 " | 79 " |
76 " g:GPGPreferSign | 80 " g:GPGPreferSign |
77 " If set to 1 signed data is preferred for new files. Defaults to 0. | 81 " If set to 1 signed data is preferred for new files. Defaults to 0. |
78 " | 82 " |
79 " g:GPGDefaultRecipients | 83 " g:GPGDefaultRecipients |
80 " If set, these recipients are used as defaults when no other recipient is | 84 " If set, these recipients are used as defaults when no other recipient is |
81 " defined. This variable is a Vim list. Default is unset. | 85 " defined. This variable is a Vim list. Default is unset. |
82 " | 86 " |
87 " g:GPGUsePipes | |
88 " If set to 1, use pipes instead of temporary files when interacting with | |
89 " gnupg. When set to 1, this can cause terminal-based gpg agents to not | |
90 " display correctly when prompting for passwords. Defaults to 0. | |
91 " | |
92 " g:GPGHomedir | |
93 " If set, specifies the directory that will be used for GPG's homedir. | |
94 " This corresponds to gpg's --homedir option. This variable is a Vim | |
95 " string. | |
96 " | |
83 " Known Issues: {{{2 | 97 " Known Issues: {{{2 |
84 " | 98 " |
85 " In some cases gvim can't decryt files | 99 " In some cases gvim can't decrypt files |
86 | 100 |
87 " This is caused by the fact that a running gvim has no TTY and thus gpg is | 101 " This is caused by the fact that a running gvim has no TTY and thus gpg is |
88 " not able to ask for the passphrase by itself. This is a problem for Windows | 102 " not able to ask for the passphrase by itself. This is a problem for Windows |
89 " and Linux versions of gvim and could not be solved unless a "terminal | 103 " and Linux versions of gvim and could not be solved unless a "terminal |
90 " emulation" is implemented for gvim. To circumvent this you have to use any | 104 " emulation" is implemented for gvim. To circumvent this you have to use any |
107 " - Mathieu Clabaut for inspirations through his vimspell.vim script. | 121 " - Mathieu Clabaut for inspirations through his vimspell.vim script. |
108 " - Richard Bronosky for patch to enable ".pgp" suffix. | 122 " - Richard Bronosky for patch to enable ".pgp" suffix. |
109 " - Erik Remmelzwaal for patch to enable windows support and patient beta | 123 " - Erik Remmelzwaal for patch to enable windows support and patient beta |
110 " testing. | 124 " testing. |
111 " - Lars Becker for patch to make gpg2 working. | 125 " - Lars Becker for patch to make gpg2 working. |
112 " - Thomas Arendsen Hein for patch to convert encoding of gpg output | 126 " - Thomas Arendsen Hein for patch to convert encoding of gpg output. |
113 " - Karl-Heinz Ruskowski for patch to fix unknown recipients and trust model | 127 " - Karl-Heinz Ruskowski for patch to fix unknown recipients and trust model |
114 " and patient beta testing. | 128 " and patient beta testing. |
115 " - Giel van Schijndel for patch to get GPG_TTY dynamically. | 129 " - Giel van Schijndel for patch to get GPG_TTY dynamically. |
116 " - Sebastian Luettich for patch to fix issue with symmetric encryption an set | 130 " - Sebastian Luettich for patch to fix issue with symmetric encryption an set |
117 " recipients. | 131 " recipients. |
118 " - Tim Swast for patch to generate signed files | 132 " - Tim Swast for patch to generate signed files. |
133 " - James Vega for patches for better '*.asc' handling, better filename | |
134 " escaping and better handling of multiple keyrings. | |
119 " | 135 " |
120 " Section: Plugin header {{{1 | 136 " Section: Plugin header {{{1 |
121 | 137 |
122 " guard against multiple loads {{{2 | 138 " guard against multiple loads {{{2 |
123 if (exists("g:loaded_gnupg") || &cp || exists("#BufReadPre#*.\(gpg\|asc\|pgp\)")) | 139 if (exists("g:loaded_gnupg") || &cp || exists("#GnuPG")) |
124 finish | 140 finish |
125 endif | 141 endif |
126 let g:loaded_gnupg = "$Revision: 3026 $" | 142 let g:loaded_gnupg = '2.5' |
143 let s:GPGInitRun = 0 | |
127 | 144 |
128 " check for correct vim version {{{2 | 145 " check for correct vim version {{{2 |
129 if (v:version < 700) | 146 if (v:version < 702) |
130 echohl ErrorMsg | echo 'plugin gnupg.vim requires Vim version >= 7.0' | echohl None | 147 echohl ErrorMsg | echo 'plugin gnupg.vim requires Vim version >= 7.2' | echohl None |
131 finish | 148 finish |
132 endif | 149 endif |
133 | 150 |
134 " Section: Autocmd setup {{{1 | 151 " Section: Autocmd setup {{{1 |
135 | 152 |
136 augroup GnuPG | 153 augroup GnuPG |
137 autocmd! | 154 autocmd! |
138 | 155 |
139 " initialize the internal variables | |
140 autocmd BufNewFile,BufReadPre,FileReadPre *.\(gpg\|asc\|pgp\) call s:GPGInit() | |
141 " force the user to edit the recipient list if he opens a new file and public | |
142 " keys are preferred | |
143 autocmd BufNewFile *.\(gpg\|asc\|pgp\) if (exists("g:GPGPreferSymmetric") && g:GPGPreferSymmetric == 0) | call s:GPGEditRecipients() | endif | |
144 " do the decryption | 156 " do the decryption |
145 autocmd BufReadPost,FileReadPost *.\(gpg\|asc\|pgp\) call s:GPGDecrypt() | 157 autocmd BufReadCmd *.\(gpg\|asc\|pgp\) call s:GPGInit(1) |
158 autocmd BufReadCmd *.\(gpg\|asc\|pgp\) call s:GPGDecrypt(1) | |
159 autocmd BufReadCmd *.\(gpg\|asc\|pgp\) call s:GPGBufReadPost() | |
160 autocmd FileReadCmd *.\(gpg\|asc\|pgp\) call s:GPGInit(0) | |
161 autocmd FileReadCmd *.\(gpg\|asc\|pgp\) call s:GPGDecrypt(0) | |
146 | 162 |
147 " convert all text to encrypted text before writing | 163 " convert all text to encrypted text before writing |
148 autocmd BufWritePre,FileWritePre *.\(gpg\|asc\|pgp\) call s:GPGEncrypt() | 164 autocmd BufWriteCmd *.\(gpg\|asc\|pgp\) call s:GPGBufWritePre() |
149 " undo the encryption so we are back in the normal text, directly | 165 autocmd BufWriteCmd,FileWriteCmd *.\(gpg\|asc\|pgp\) call s:GPGInit(0) |
150 " after the file has been written. | 166 autocmd BufWriteCmd,FileWriteCmd *.\(gpg\|asc\|pgp\) call s:GPGEncrypt() |
151 autocmd BufWritePost,FileWritePost *.\(gpg\|asc\|pgp\) call s:GPGEncryptPost() | |
152 | 167 |
153 " cleanup on leaving vim | 168 " cleanup on leaving vim |
154 autocmd VimLeave *.\(gpg\|asc\|pgp\) call s:GPGCleanup() | 169 autocmd VimLeave *.\(gpg\|asc\|pgp\) call s:GPGCleanup() |
155 augroup END | 170 augroup END |
156 | 171 |
157 " Section: Constants {{{1 | 172 " Section: Constants {{{1 |
158 | 173 |
159 let s:GPGMagicString = "\t \t" | 174 let s:GPGMagicString = "\t \t" |
175 let s:keyPattern = '\%(0x\)\=[[:xdigit:]]\{8,16}' | |
160 | 176 |
161 " Section: Highlight setup {{{1 | 177 " Section: Highlight setup {{{1 |
162 | 178 |
163 highlight default link GPGWarning WarningMsg | 179 highlight default link GPGWarning WarningMsg |
164 highlight default link GPGError ErrorMsg | 180 highlight default link GPGError ErrorMsg |
165 highlight default link GPGHighlightUnknownRecipient ErrorMsg | 181 highlight default link GPGHighlightUnknownRecipient ErrorMsg |
166 | 182 |
167 " Section: Functions {{{1 | 183 " Section: Functions {{{1 |
168 | 184 |
169 " Function: s:GPGInit() {{{2 | 185 " Function: s:GPGInit(bufread) {{{2 |
170 " | 186 " |
171 " initialize the plugin | 187 " initialize the plugin |
172 " | 188 " The bufread argument specifies whether this was called due to BufReadCmd |
173 function s:GPGInit() | 189 " |
174 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGInit()") | 190 function s:GPGInit(bufread) |
175 | 191 call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGInit(%d)", a:bufread)) |
176 " first make sure nothing is written to ~/.viminfo while editing | 192 |
177 " an encrypted file. | 193 " For FileReadCmd, we're reading the contents into another buffer. If that |
178 set viminfo= | 194 " buffer is also destined to be encrypted, then these settings will have |
179 | 195 " already been set, otherwise don't set them since it limits the |
180 " we don't want a swap file, as it writes unencrypted data to disk | 196 " functionality of the cleartext buffer. |
181 set noswapfile | 197 if a:bufread |
198 " we don't want a swap file, as it writes unencrypted data to disk | |
199 setl noswapfile | |
200 | |
201 " if persistent undo is present, disable it for this buffer | |
202 if exists('+undofile') | |
203 setl noundofile | |
204 endif | |
205 | |
206 " first make sure nothing is written to ~/.viminfo while editing | |
207 " an encrypted file. | |
208 set viminfo= | |
209 endif | |
210 | |
211 " the rest only has to be run once | |
212 if s:GPGInitRun | |
213 return | |
214 endif | |
182 | 215 |
183 " check what gpg command to use | 216 " check what gpg command to use |
184 if (!exists("g:GPGExecutable")) | 217 if (!exists("g:GPGExecutable")) |
185 let g:GPGExecutable = "gpg --trust-model always" | 218 let g:GPGExecutable = "gpg --trust-model always" |
186 endif | 219 endif |
195 let g:GPGPreferSymmetric = 0 | 228 let g:GPGPreferSymmetric = 0 |
196 endif | 229 endif |
197 | 230 |
198 " check if armored files are preferred | 231 " check if armored files are preferred |
199 if (!exists("g:GPGPreferArmor")) | 232 if (!exists("g:GPGPreferArmor")) |
200 let g:GPGPreferArmor = 0 | 233 " .asc files should be armored as that's what the extension is used for |
234 if expand('<afile>') =~ '\.asc$' | |
235 let g:GPGPreferArmor = 1 | |
236 else | |
237 let g:GPGPreferArmor = 0 | |
238 endif | |
201 endif | 239 endif |
202 | 240 |
203 " check if signed files are preferred | 241 " check if signed files are preferred |
204 if (!exists("g:GPGPreferSign")) | 242 if (!exists("g:GPGPreferSign")) |
205 let g:GPGPreferSign = 0 | 243 let g:GPGPreferSign = 0 |
206 endif | 244 endif |
207 | 245 |
208 " start with empty default recipients if none is defined so far | 246 " start with empty default recipients if none is defined so far |
209 if (!exists("g:GPGDefaultRecipients")) | 247 if (!exists("g:GPGDefaultRecipients")) |
210 let g:GPGDefaultRecipients = [] | 248 let g:GPGDefaultRecipients = [] |
249 endif | |
250 | |
251 " prefer not to use pipes since it can garble gpg agent display | |
252 if (!exists("g:GPGUsePipes")) | |
253 let g:GPGUsePipes = 0 | |
254 endif | |
255 | |
256 " allow alternate gnupg homedir | |
257 if (!exists('g:GPGHomedir')) | |
258 let g:GPGHomedir = '' | |
211 endif | 259 endif |
212 | 260 |
213 " print version | 261 " print version |
214 call s:GPGDebug(1, "gnupg.vim ". g:loaded_gnupg) | 262 call s:GPGDebug(1, "gnupg.vim ". g:loaded_gnupg) |
215 | 263 |
228 let s:GPGCommand = g:GPGExecutable . " --use-agent" | 276 let s:GPGCommand = g:GPGExecutable . " --use-agent" |
229 else | 277 else |
230 let s:GPGCommand = g:GPGExecutable . " --no-use-agent" | 278 let s:GPGCommand = g:GPGExecutable . " --no-use-agent" |
231 endif | 279 endif |
232 | 280 |
233 " don't use tty in gvim | 281 " don't use tty in gvim except for windows: we get their a tty for free. |
234 " FIXME find a better way to avoid an error. | 282 " FIXME find a better way to avoid an error. |
235 " with this solution only --use-agent will work | 283 " with this solution only --use-agent will work |
236 if (has("gui_running")) | 284 if (has("gui_running") && !has("gui_win32")) |
237 let s:GPGCommand = s:GPGCommand . " --no-tty" | 285 let s:GPGCommand = s:GPGCommand . " --no-tty" |
238 endif | 286 endif |
239 | 287 |
240 " setup shell environment for unix and windows | 288 " setup shell environment for unix and windows |
241 let s:shellredirsave = &shellredir | 289 let s:shellredirsave = &shellredir |
242 let s:shellsave = &shell | 290 let s:shellsave = &shell |
291 let s:shelltempsave = &shelltemp | |
292 " noshelltemp isn't currently supported on Windows, but it doesn't cause any | |
293 " errors and this future proofs us against requiring changes if Windows | |
294 " gains noshelltemp functionality | |
295 let s:shelltemp = !g:GPGUsePipes | |
243 if (has("unix")) | 296 if (has("unix")) |
244 " unix specific settings | 297 " unix specific settings |
245 let s:shellredir = ">%s 2>&1" | 298 let s:shellredir = ">%s 2>&1" |
246 let s:shell = '/bin/sh' | 299 let s:shell = '/bin/sh' |
247 let s:stderrredirnull = '2>/dev/null' | 300 let s:stderrredirnull = '2>/dev/null' |
253 let s:stderrredirnull = '2>nul' | 306 let s:stderrredirnull = '2>nul' |
254 endif | 307 endif |
255 | 308 |
256 call s:GPGDebug(3, "shellredirsave: " . s:shellredirsave) | 309 call s:GPGDebug(3, "shellredirsave: " . s:shellredirsave) |
257 call s:GPGDebug(3, "shellsave: " . s:shellsave) | 310 call s:GPGDebug(3, "shellsave: " . s:shellsave) |
311 call s:GPGDebug(3, "shelltempsave: " . s:shelltempsave) | |
258 | 312 |
259 call s:GPGDebug(3, "shell: " . s:shell) | 313 call s:GPGDebug(3, "shell: " . s:shell) |
260 call s:GPGDebug(3, "shellcmdflag: " . &shellcmdflag) | 314 call s:GPGDebug(3, "shellcmdflag: " . &shellcmdflag) |
261 call s:GPGDebug(3, "shellxquote: " . &shellxquote) | 315 call s:GPGDebug(3, "shellxquote: " . &shellxquote) |
262 call s:GPGDebug(3, "shellredir: " . s:shellredir) | 316 call s:GPGDebug(3, "shellredir: " . s:shellredir) |
263 call s:GPGDebug(3, "stderrredirnull: " . s:stderrredirnull) | 317 call s:GPGDebug(3, "stderrredirnull: " . s:stderrredirnull) |
264 | 318 |
265 call s:GPGDebug(3, "shell implementation: " . resolve(s:shell)) | 319 call s:GPGDebug(3, "shell implementation: " . resolve(s:shell)) |
266 | 320 |
267 " find the supported algorithms | 321 " find the supported algorithms |
268 let commandline = s:GPGCommand . " --version" | 322 let output = s:GPGSystem({ 'level': 2, 'args': '--version' }) |
269 call s:GPGDebug(2, "command: ". commandline) | |
270 let &shellredir = s:shellredir | |
271 let &shell = s:shell | |
272 let output = system(commandline) | |
273 let &shellredir = s:shellredirsave | |
274 let &shell = s:shellsave | |
275 call s:GPGDebug(2, "output: ". output) | |
276 | 323 |
277 let s:GPGPubkey = substitute(output, ".*Pubkey: \\(.\\{-}\\)\n.*", "\\1", "") | 324 let s:GPGPubkey = substitute(output, ".*Pubkey: \\(.\\{-}\\)\n.*", "\\1", "") |
278 let s:GPGCipher = substitute(output, ".*Cipher: \\(.\\{-}\\)\n.*", "\\1", "") | 325 let s:GPGCipher = substitute(output, ".*Cipher: \\(.\\{-}\\)\n.*", "\\1", "") |
279 let s:GPGHash = substitute(output, ".*Hash: \\(.\\{-}\\)\n.*", "\\1", "") | 326 let s:GPGHash = substitute(output, ".*Hash: \\(.\\{-}\\)\n.*", "\\1", "") |
280 let s:GPGCompress = substitute(output, ".*Compress.\\{-}: \\(.\\{-}\\)\n.*", "\\1", "") | 327 let s:GPGCompress = substitute(output, ".*Compress.\\{-}: \\(.\\{-}\\)\n.*", "\\1", "") |
282 call s:GPGDebug(2, "public key algorithms: " . s:GPGPubkey) | 329 call s:GPGDebug(2, "public key algorithms: " . s:GPGPubkey) |
283 call s:GPGDebug(2, "cipher algorithms: " . s:GPGCipher) | 330 call s:GPGDebug(2, "cipher algorithms: " . s:GPGCipher) |
284 call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash) | 331 call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash) |
285 call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress) | 332 call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress) |
286 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()") | 333 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()") |
334 let s:GPGInitRun = 1 | |
287 endfunction | 335 endfunction |
288 | 336 |
289 " Function: s:GPGCleanup() {{{2 | 337 " Function: s:GPGCleanup() {{{2 |
290 " | 338 " |
291 " cleanup on leaving vim | 339 " cleanup on leaving vim |
298 redraw! | 346 redraw! |
299 | 347 |
300 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGCleanup()") | 348 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGCleanup()") |
301 endfunction | 349 endfunction |
302 | 350 |
303 " Function: s:GPGDecrypt() {{{2 | 351 " Function: s:GPGDecrypt(bufread) {{{2 |
304 " | 352 " |
305 " decrypt the buffer and find all recipients of the encrypted file | 353 " decrypt the buffer and find all recipients of the encrypted file |
306 " | 354 " The bufread argument specifies whether this was called due to BufReadCmd |
307 function s:GPGDecrypt() | 355 " |
308 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGDecrypt()") | 356 function s:GPGDecrypt(bufread) |
309 | 357 call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGDecrypt(%d)", a:bufread)) |
310 " switch to binary mode to read the encrypted file | |
311 set bin | |
312 | 358 |
313 " get the filename of the current buffer | 359 " get the filename of the current buffer |
314 let filename = escape(expand("%:p"), '\"') | 360 let filename = expand("<afile>:p") |
315 | 361 |
316 " clear GPGEncrypted, GPGRecipients and GPGOptions | 362 " clear GPGRecipients and GPGOptions |
363 let b:GPGRecipients = g:GPGDefaultRecipients | |
364 let b:GPGOptions = [] | |
365 | |
366 " File doesn't exist yet, so nothing to decrypt | |
367 if empty(glob(filename)) | |
368 return | |
369 endif | |
370 | |
371 " Only let this if the file actually exists, otherwise GPG functionality | |
372 " will be disabled when editing a buffer that doesn't yet have a backing | |
373 " file | |
317 let b:GPGEncrypted = 0 | 374 let b:GPGEncrypted = 0 |
318 let b:GPGRecipients = [] | |
319 let b:GPGOptions = [] | |
320 | 375 |
321 " find the recipients of the file | 376 " find the recipients of the file |
322 let commandline = s:GPGCommand . " --verbose --decrypt --list-only --dry-run --batch --no-use-agent --logger-fd 1 \"" . filename . "\"" | 377 let cmd = { 'level': 3 } |
323 call s:GPGDebug(3, "command: " . commandline) | 378 let cmd.args = '--verbose --decrypt --list-only --dry-run --batch --no-use-agent --logger-fd 1 ' . shellescape(filename) |
324 let &shellredir = s:shellredir | 379 let output = s:GPGSystem(cmd) |
325 let &shell = s:shell | 380 |
326 let output = system(commandline) | 381 " Suppress the "N more lines" message when editing a file, not when reading |
327 let &shellredir = s:shellredirsave | 382 " the contents of a file into a buffer |
328 let &shell = s:shellsave | 383 let silent = a:bufread ? 'silent ' : '' |
329 call s:GPGDebug(3, "output: ". output) | 384 |
330 | 385 let asymmPattern = 'gpg: public key is ' . s:keyPattern |
331 " check if the file is symmetric/asymmetric encrypted | 386 " check if the file is symmetric/asymmetric encrypted |
332 if (match(output, "gpg: encrypted with [[:digit:]]\\+ passphrase") >= 0) | 387 if (match(output, "gpg: encrypted with [[:digit:]]\\+ passphrase") >= 0) |
333 " file is symmetric encrypted | 388 " file is symmetric encrypted |
334 let b:GPGEncrypted = 1 | 389 let b:GPGEncrypted = 1 |
335 call s:GPGDebug(1, "this file is symmetric encrypted") | 390 call s:GPGDebug(1, "this file is symmetric encrypted") |
345 echohl GPGWarning | 400 echohl GPGWarning |
346 echom "The cipher " . cipher . " is not known by the local gpg command. Using default!" | 401 echom "The cipher " . cipher . " is not known by the local gpg command. Using default!" |
347 echo | 402 echo |
348 echohl None | 403 echohl None |
349 endif | 404 endif |
350 elseif (match(output, "gpg: public key is [[:xdigit:]]\\{8}") >= 0) | 405 elseif (match(output, asymmPattern) >= 0) |
351 " file is asymmetric encrypted | 406 " file is asymmetric encrypted |
352 let b:GPGEncrypted = 1 | 407 let b:GPGEncrypted = 1 |
353 call s:GPGDebug(1, "this file is asymmetric encrypted") | 408 call s:GPGDebug(1, "this file is asymmetric encrypted") |
354 | 409 |
355 let b:GPGOptions += ["encrypt"] | 410 let b:GPGOptions += ["encrypt"] |
356 | 411 |
357 " find the used public keys | 412 " find the used public keys |
358 let start = match(output, "gpg: public key is [[:xdigit:]]\\{8}") | 413 let start = match(output, asymmPattern) |
359 while (start >= 0) | 414 while (start >= 0) |
360 let start = start + strlen("gpg: public key is ") | 415 let start = start + strlen("gpg: public key is ") |
361 let recipient = strpart(output, start, 8) | 416 let recipient = matchstr(output, s:keyPattern, start) |
362 call s:GPGDebug(1, "recipient is " . recipient) | 417 call s:GPGDebug(1, "recipient is " . recipient) |
363 let name = s:GPGNameToID(recipient) | 418 let name = s:GPGNameToID(recipient) |
364 if (strlen(name) > 0) | 419 if (strlen(name) > 0) |
365 let b:GPGRecipients += [name] | 420 let b:GPGRecipients += [name] |
366 call s:GPGDebug(1, "name of recipient is " . name) | 421 call s:GPGDebug(1, "name of recipient is " . name) |
368 let b:GPGRecipients += [recipient] | 423 let b:GPGRecipients += [recipient] |
369 echohl GPGWarning | 424 echohl GPGWarning |
370 echom "The recipient \"" . recipient . "\" is not in your public keyring!" | 425 echom "The recipient \"" . recipient . "\" is not in your public keyring!" |
371 echohl None | 426 echohl None |
372 end | 427 end |
373 let start = match(output, "gpg: public key is [[:xdigit:]]\\{8}", start) | 428 let start = match(output, asymmPattern, start) |
374 endwhile | 429 endwhile |
375 else | 430 else |
376 " file is not encrypted | 431 " file is not encrypted |
377 let b:GPGEncrypted = 0 | 432 let b:GPGEncrypted = 0 |
378 call s:GPGDebug(1, "this file is not encrypted") | 433 call s:GPGDebug(1, "this file is not encrypted") |
379 echohl GPGWarning | 434 echohl GPGWarning |
380 echom "File is not encrypted, all GPG functions disabled!" | 435 echom "File is not encrypted, all GPG functions disabled!" |
381 echohl None | 436 echohl None |
382 set nobin | 437 exe printf('%sr %s', silent, fnameescape(filename)) |
383 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") | 438 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") |
384 return | 439 return |
385 endif | 440 endif |
386 | 441 |
387 " check if the message is armored | 442 " check if the message is armored |
392 | 447 |
393 " finally decrypt the buffer content | 448 " finally decrypt the buffer content |
394 " since even with the --quiet option passphrase typos will be reported, | 449 " since even with the --quiet option passphrase typos will be reported, |
395 " we must redirect stderr (using shell temporarily) | 450 " we must redirect stderr (using shell temporarily) |
396 call s:GPGDebug(1, "decrypting file") | 451 call s:GPGDebug(1, "decrypting file") |
397 let commandline = "'[,']!" . s:GPGCommand . " --quiet --decrypt " . s:stderrredirnull | 452 let cmd = { 'level': 1, 'ex': silent . 'r !' } |
398 call s:GPGDebug(1, "command: " . commandline) | 453 let cmd.args = '--quiet --decrypt ' . shellescape(filename, 1) |
399 let &shellredir = s:shellredir | 454 call s:GPGExecute(cmd) |
400 let &shell = s:shell | 455 |
401 execute commandline | |
402 let &shellredir = s:shellredirsave | |
403 let &shell = s:shellsave | |
404 if (v:shell_error) " message could not be decrypted | 456 if (v:shell_error) " message could not be decrypted |
405 silent u | |
406 echohl GPGError | 457 echohl GPGError |
407 let blackhole = input("Message could not be decrypted! (Press ENTER)") | 458 let blackhole = input("Message could not be decrypted! (Press ENTER)") |
408 echohl None | 459 echohl None |
409 bwipeout | 460 " Only wipeout the buffer if we were creating one to start with. |
410 set nobin | 461 " FileReadCmd just reads the content into the existing buffer |
462 if a:bufread | |
463 silent bwipeout! | |
464 endif | |
411 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") | 465 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") |
412 return | 466 return |
413 endif | 467 endif |
414 | 468 |
415 " turn off binary mode | |
416 set nobin | |
417 | |
418 " call the autocommand for the file minus .gpg$ | |
419 execute ":doautocmd BufReadPost " . escape(expand("%:r"), ' *?\"'."'") | |
420 call s:GPGDebug(2, "called autocommand for " . escape(expand("%:r"), ' *?\"'."'")) | |
421 | |
422 " refresh screen | 469 " refresh screen |
423 redraw! | 470 redraw! |
424 | 471 |
425 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") | 472 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()") |
426 endfunction | 473 endfunction |
427 | 474 |
475 " Function: s:GPGBufReadPost() {{{2 | |
476 " | |
477 " Handle functionality specific to opening a file for reading rather than | |
478 " reading the contents of a file into a buffer | |
479 " | |
480 function s:GPGBufReadPost() | |
481 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGBufReadPost()") | |
482 " In order to make :undo a no-op immediately after the buffer is read, | |
483 " we need to do this dance with 'undolevels'. Actually discarding the undo | |
484 " history requires performing a change after setting 'undolevels' to -1 and, | |
485 " luckily, we have one we need to do (delete the extra line from the :r | |
486 " command) | |
487 let levels = &undolevels | |
488 set undolevels=-1 | |
489 silent 1delete | |
490 let &undolevels = levels | |
491 " call the autocommand for the file minus .gpg$ | |
492 silent execute ':doautocmd BufReadPost ' . fnameescape(expand('<afile>:r')) | |
493 call s:GPGDebug(2, 'called autocommand for ' . fnameescape(expand('<afile>:r'))) | |
494 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGBufReadPost()") | |
495 endfunction | |
496 | |
497 " Function: s:GPGBufWritePre() {{{2 | |
498 " | |
499 " Handle functionality specific to saving an entire buffer to a file rather | |
500 " than saving a partial buffer | |
501 " | |
502 function s:GPGBufWritePre() | |
503 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGBufWritePre()") | |
504 " call the autocommand for the file minus .gpg$ | |
505 silent execute ':doautocmd BufWritePre ' . fnameescape(expand('<afile>:r')) | |
506 call s:GPGDebug(2, 'called autocommand for ' . fnameescape(expand('<afile>:r'))) | |
507 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGBufWritePre()") | |
508 endfunction | |
509 | |
428 " Function: s:GPGEncrypt() {{{2 | 510 " Function: s:GPGEncrypt() {{{2 |
429 " | 511 " |
430 " encrypts the buffer to all previous recipients | 512 " encrypts the buffer to all previous recipients |
431 " | 513 " |
432 function s:GPGEncrypt() | 514 function s:GPGEncrypt() |
433 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncrypt()") | 515 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncrypt()") |
434 | |
435 " save window view | |
436 let s:GPGWindowView = winsaveview() | |
437 call s:GPGDebug(2, "saved window view " . string(s:GPGWindowView)) | |
438 | 516 |
439 " store encoding and switch to a safe one | 517 " store encoding and switch to a safe one |
440 if (&fileencoding != &encoding) | 518 if (&fileencoding != &encoding) |
441 let s:GPGEncoding = &encoding | 519 let s:GPGEncoding = &encoding |
442 let &encoding = &fileencoding | 520 let &encoding = &fileencoding |
444 else | 522 else |
445 let s:GPGEncoding = "" | 523 let s:GPGEncoding = "" |
446 call s:GPGDebug(2, "encoding and fileencoding are the same (\"" . &encoding . "\"), not switching") | 524 call s:GPGDebug(2, "encoding and fileencoding are the same (\"" . &encoding . "\"), not switching") |
447 endif | 525 endif |
448 | 526 |
449 " switch buffer to binary mode | |
450 set bin | |
451 | |
452 " guard for unencrypted files | 527 " guard for unencrypted files |
453 if (!exists("b:GPGEncrypted") || b:GPGEncrypted == 0) | 528 if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0) |
454 echohl GPGError | 529 echohl GPGError |
455 let blackhole = input("Message could not be encrypted! File might be empty! (Press ENTER)") | 530 let blackhole = input("Message could not be encrypted! (Press ENTER)") |
456 echohl None | 531 echohl None |
457 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") | 532 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") |
458 return | 533 return |
459 endif | 534 endif |
460 | 535 |
480 let options = "" | 555 let options = "" |
481 for option in b:GPGOptions | 556 for option in b:GPGOptions |
482 let options = options . " --" . option . " " | 557 let options = options . " --" . option . " " |
483 endfor | 558 endfor |
484 | 559 |
560 if (!exists('b:GPGRecipients')) | |
561 let b:GPGRecipients = [] | |
562 endif | |
563 | |
485 " check here again if all recipients are available in the keyring | 564 " check here again if all recipients are available in the keyring |
486 let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients) | 565 let [ recipients, unknownrecipients ] = s:GPGCheckRecipients(b:GPGRecipients) |
487 | 566 |
488 " check if there are unknown recipients and warn | 567 " check if there are unknown recipients and warn |
489 if (len(unknownrecipients) > 0) | 568 if (len(unknownrecipients) > 0) |
499 " built list of recipients | 578 " built list of recipients |
500 if (len(recipients) > 0) | 579 if (len(recipients) > 0) |
501 for gpgid in recipients | 580 for gpgid in recipients |
502 let options = options . " -r " . gpgid | 581 let options = options . " -r " . gpgid |
503 endfor | 582 endfor |
504 else | |
505 if (match(b:GPGOptions, "encrypt") >= 0) | |
506 echohl GPGError | |
507 echom "There are no recipients!!" | |
508 echom "Please use GPGEditRecipients to correct!!" | |
509 echo | |
510 echohl None | |
511 endif | |
512 endif | 583 endif |
513 | 584 |
514 " encrypt the buffer | 585 " encrypt the buffer |
515 let commandline = "'[,']!" . s:GPGCommand . " --quiet --no-encrypt-to " . options . " " . s:stderrredirnull | 586 let destfile = tempname() |
516 call s:GPGDebug(1, "command: " . commandline) | 587 let cmd = { 'level': 1, 'ex': "'[,']w !" } |
517 let &shellredir = s:shellredir | 588 let cmd.args = '--quiet --no-encrypt-to ' . options |
518 let &shell = s:shell | 589 let cmd.redirect = '>' . shellescape(destfile, 1) |
519 silent execute commandline | 590 call s:GPGExecute(cmd) |
520 let &shellredir = s:shellredirsave | |
521 let &shell = s:shellsave | |
522 if (v:shell_error) " message could not be encrypted | |
523 " delete content of the buffer to be sure no data is written unencrypted | |
524 " content will be recovered in GPGEncryptPost() | |
525 silent normal! 1GdG | |
526 | |
527 echohl GPGError | |
528 let blackhole = input("Message could not be encrypted! File might be empty! (Press ENTER)") | |
529 echohl None | |
530 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") | |
531 return | |
532 endif | |
533 | |
534 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") | |
535 endfunction | |
536 | |
537 " Function: s:GPGEncryptPost() {{{2 | |
538 " | |
539 " undo changes don by encrypt, after writing | |
540 " | |
541 function s:GPGEncryptPost() | |
542 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncryptPost()") | |
543 | |
544 " guard for unencrypted files | |
545 if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0) | |
546 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncryptPost()") | |
547 return | |
548 endif | |
549 | |
550 " undo encryption of buffer content | |
551 silent u | |
552 | |
553 " switch back from binary mode | |
554 set nobin | |
555 | 591 |
556 " restore encoding | 592 " restore encoding |
557 if (s:GPGEncoding != "") | 593 if (s:GPGEncoding != "") |
558 let &encoding = s:GPGEncoding | 594 let &encoding = s:GPGEncoding |
559 call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"") | 595 call s:GPGDebug(2, "restored encoding \"" . &encoding . "\"") |
560 endif | 596 endif |
561 | 597 |
562 " restore window view | 598 if (v:shell_error) " message could not be encrypted |
563 call winrestview(s:GPGWindowView) | 599 " Command failed, so clean up the tempfile |
564 call s:GPGDebug(2, "restored window view" . string(s:GPGWindowView)) | 600 call delete(destfile) |
565 | 601 echohl GPGError |
566 " refresh screen | 602 let blackhole = input("Message could not be encrypted! (Press ENTER)") |
567 redraw! | 603 echohl None |
568 | 604 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") |
569 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncryptPost()") | 605 return |
606 endif | |
607 | |
608 call rename(destfile, resolve(expand('<afile>'))) | |
609 setl nomodified | |
610 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()") | |
570 endfunction | 611 endfunction |
571 | 612 |
572 " Function: s:GPGViewRecipients() {{{2 | 613 " Function: s:GPGViewRecipients() {{{2 |
573 " | 614 " |
574 " echo the recipients | 615 " echo the recipients |
636 let editbuffername = "GPGRecipients_" . buffername | 677 let editbuffername = "GPGRecipients_" . buffername |
637 | 678 |
638 " check if this buffer exists | 679 " check if this buffer exists |
639 if (!bufexists(editbuffername)) | 680 if (!bufexists(editbuffername)) |
640 " create scratch buffer | 681 " create scratch buffer |
641 execute 'silent! split ' . escape(editbuffername, ' *?\"'."'") | 682 execute 'silent! split ' . fnameescape(editbuffername) |
642 | 683 |
643 " add a autocommand to regenerate the recipients after a write | 684 " add a autocommand to regenerate the recipients after a write |
644 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() | 685 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() |
645 else | 686 else |
646 if (bufwinnr(editbuffername) >= 0) | 687 if (bufwinnr(editbuffername) >= 0) |
647 " switch to scratch buffer window | 688 " switch to scratch buffer window |
648 execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" | 689 execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" |
649 else | 690 else |
650 " split scratch buffer window | 691 " split scratch buffer window |
651 execute 'silent! sbuffer ' . escape(editbuffername, ' *?\"'."'") | 692 execute 'silent! sbuffer ' . fnameescape(editbuffername) |
652 | 693 |
653 " add a autocommand to regenerate the recipients after a write | 694 " add a autocommand to regenerate the recipients after a write |
654 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() | 695 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishRecipientsBuffer() |
655 endif | 696 endif |
656 | 697 |
657 " empty the buffer | 698 " empty the buffer |
658 silent normal! 1GdG | 699 silent %delete |
659 endif | 700 endif |
660 | 701 |
661 " Mark the buffer as a scratch buffer | 702 " Mark the buffer as a scratch buffer |
662 setlocal buftype=acwrite | 703 setlocal buftype=acwrite |
663 setlocal bufhidden=hide | 704 setlocal bufhidden=hide |
700 | 741 |
701 " put the unknown recipients in the scratch buffer | 742 " put the unknown recipients in the scratch buffer |
702 let syntaxPattern = "\\(nonexxistinwordinthisbuffer" | 743 let syntaxPattern = "\\(nonexxistinwordinthisbuffer" |
703 for name in unknownrecipients | 744 for name in unknownrecipients |
704 let name = "!" . name | 745 let name = "!" . name |
705 let syntaxPattern = syntaxPattern . "\\|" . name | 746 let syntaxPattern = syntaxPattern . "\\|" . fnameescape(name) |
706 silent put =name | 747 silent put =name |
707 endfor | 748 endfor |
708 let syntaxPattern = syntaxPattern . "\\)" | 749 let syntaxPattern = syntaxPattern . "\\)" |
709 | 750 |
710 " define highlight | 751 " define highlight |
718 highlight clear GPGComment | 759 highlight clear GPGComment |
719 highlight link GPGComment Comment | 760 highlight link GPGComment Comment |
720 endif | 761 endif |
721 | 762 |
722 " delete the empty first line | 763 " delete the empty first line |
723 silent normal! 1Gdd | 764 silent 1delete |
724 | 765 |
725 " jump to the first recipient | 766 " jump to the first recipient |
726 silent normal! G | 767 silent $ |
727 | 768 |
728 endif | 769 endif |
729 | 770 |
730 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditRecipients()") | 771 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditRecipients()") |
731 endfunction | 772 endfunction |
753 endif | 794 endif |
754 | 795 |
755 " delete the autocommand | 796 " delete the autocommand |
756 autocmd! * <buffer> | 797 autocmd! * <buffer> |
757 | 798 |
758 | |
759 " get the recipients from the scratch buffer | 799 " get the recipients from the scratch buffer |
760 let recipients = [] | 800 let recipients = [] |
761 let lines = getline(1,"$") | 801 let lines = getline(1,"$") |
762 for recipient in lines | 802 for recipient in lines |
763 " delete all text after magic string | 803 let matches = matchlist(recipient, '^\(.\{-}\)\%(' . s:GPGMagicString . '(ID:\s\+\(' . s:keyPattern . '\)\s\+.*\)\=$') |
764 let recipient = substitute(recipient, s:GPGMagicString . ".*$", "", "") | 804 |
805 let recipient = matches[2] ? matches[2] : matches[1] | |
765 | 806 |
766 " delete all spaces at beginning and end of the recipient | 807 " delete all spaces at beginning and end of the recipient |
767 " also delete a '!' at the beginning of the recipient | 808 " also delete a '!' at the beginning of the recipient |
768 let recipient = substitute(recipient, "^[[:space:]!]*\\(.\\{-}\\)[[:space:]]*$", "\\1", "") | 809 let recipient = substitute(recipient, "^[[:space:]!]*\\(.\\{-}\\)[[:space:]]*$", "\\1", "") |
769 | 810 |
800 echom 'There are no known recipients!' | 841 echom 'There are no known recipients!' |
801 echohl None | 842 echohl None |
802 endif | 843 endif |
803 | 844 |
804 " reset modified flag | 845 " reset modified flag |
805 set nomodified | 846 setl nomodified |
806 | 847 |
807 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()") | 848 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()") |
808 endfunction | 849 endfunction |
809 | 850 |
810 " Function: s:GPGViewOptions() {{{2 | 851 " Function: s:GPGViewOptions() {{{2 |
858 let editbuffername = "GPGOptions_" . buffername | 899 let editbuffername = "GPGOptions_" . buffername |
859 | 900 |
860 " check if this buffer exists | 901 " check if this buffer exists |
861 if (!bufexists(editbuffername)) | 902 if (!bufexists(editbuffername)) |
862 " create scratch buffer | 903 " create scratch buffer |
863 execute 'silent! split ' . escape(editbuffername, ' *?\"'."'") | 904 execute 'silent! split ' . fnameescape(editbuffername) |
864 | 905 |
865 " add a autocommand to regenerate the options after a write | 906 " add a autocommand to regenerate the options after a write |
866 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() | 907 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() |
867 else | 908 else |
868 if (bufwinnr(editbuffername) >= 0) | 909 if (bufwinnr(editbuffername) >= 0) |
869 " switch to scratch buffer window | 910 " switch to scratch buffer window |
870 execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" | 911 execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w" |
871 else | 912 else |
872 " split scratch buffer window | 913 " split scratch buffer window |
873 execute 'silent! sbuffer ' . escape(editbuffername, ' *?\"'."'") | 914 execute 'silent! sbuffer ' . fnameescape(editbuffername) |
874 | 915 |
875 " add a autocommand to regenerate the options after a write | 916 " add a autocommand to regenerate the options after a write |
876 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() | 917 autocmd BufHidden,BufUnload,BufWriteCmd <buffer> call s:GPGFinishOptionsBuffer() |
877 endif | 918 endif |
878 | 919 |
879 " empty the buffer | 920 " empty the buffer |
880 silent normal! 1GdG | 921 silent %delete |
881 endif | 922 endif |
882 | 923 |
883 " Mark the buffer as a scratch buffer | 924 " Mark the buffer as a scratch buffer |
884 setlocal buftype=nofile | 925 setlocal buftype=nofile |
885 setlocal noswapfile | 926 setlocal noswapfile |
907 for option in options | 948 for option in options |
908 silent put =option | 949 silent put =option |
909 endfor | 950 endfor |
910 | 951 |
911 " delete the empty first line | 952 " delete the empty first line |
912 silent normal! 1Gdd | 953 silent 1delete |
913 | 954 |
914 " jump to the first option | 955 " jump to the first option |
915 silent normal! G | 956 silent $ |
916 | 957 |
917 " define highlight | 958 " define highlight |
918 if (has("syntax") && exists("g:syntax_on")) | 959 if (has("syntax") && exists("g:syntax_on")) |
919 syntax match GPGComment "^GPG:.*$" | 960 syntax match GPGComment "^GPG:.*$" |
920 highlight clear GPGComment | 961 highlight clear GPGComment |
973 " as modified | 1014 " as modified |
974 call setbufvar(b:GPGCorrespondingTo, "GPGOptions", options) | 1015 call setbufvar(b:GPGCorrespondingTo, "GPGOptions", options) |
975 call setbufvar(b:GPGCorrespondingTo, "&mod", 1) | 1016 call setbufvar(b:GPGCorrespondingTo, "&mod", 1) |
976 | 1017 |
977 " reset modified flag | 1018 " reset modified flag |
978 set nomodified | 1019 setl nomodified |
979 | 1020 |
980 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()") | 1021 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()") |
981 endfunction | 1022 endfunction |
982 | 1023 |
983 " Function: s:GPGCheckRecipients(tocheck) {{{2 | 1024 " Function: s:GPGCheckRecipients(tocheck) {{{2 |
1023 " | 1064 " |
1024 function s:GPGNameToID(name) | 1065 function s:GPGNameToID(name) |
1025 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGNameToID()") | 1066 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGNameToID()") |
1026 | 1067 |
1027 " ask gpg for the id for a name | 1068 " ask gpg for the id for a name |
1028 let commandline = s:GPGCommand . " --quiet --with-colons --fixed-list-mode --list-keys \"" . a:name . "\"" | 1069 let cmd = { 'level': 2 } |
1029 call s:GPGDebug(2, "command: ". commandline) | 1070 let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . shellescape(a:name) |
1030 let &shellredir = s:shellredir | 1071 let output = s:GPGSystem(cmd) |
1031 let &shell = s:shell | |
1032 let output = system(commandline) | |
1033 let &shellredir = s:shellredirsave | |
1034 let &shell = s:shellsave | |
1035 call s:GPGDebug(2, "output: ". output) | |
1036 | 1072 |
1037 " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, | 1073 " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, |
1038 " so convert it, if necessary | 1074 " so convert it, if necessary |
1039 if (&encoding != "utf-8") | 1075 if (&encoding != "utf-8") |
1040 let output = iconv(output, "utf-8", &encoding) | 1076 let output = iconv(output, "utf-8", &encoding) |
1043 | 1079 |
1044 " parse the output of gpg | 1080 " parse the output of gpg |
1045 let pubseen = 0 | 1081 let pubseen = 0 |
1046 let counter = 0 | 1082 let counter = 0 |
1047 let gpgids = [] | 1083 let gpgids = [] |
1084 let duplicates = {} | |
1048 let choices = "The name \"" . a:name . "\" is ambiguous. Please select the correct key:\n" | 1085 let choices = "The name \"" . a:name . "\" is ambiguous. Please select the correct key:\n" |
1049 for line in lines | 1086 for line in lines |
1050 let fields = split(line, ":") | 1087 |
1051 " search for the next uid | 1088 " check if this line has already been processed |
1052 if (pubseen == 1) | 1089 if !has_key(duplicates, line) |
1053 if (fields[0] == "uid") | 1090 let duplicates[line] = 1 |
1054 let choices = choices . " " . fields[9] . "\n" | 1091 |
1092 let fields = split(line, ":") | |
1093 | |
1094 " search for the next uid | |
1095 if pubseen | |
1096 if (fields[0] == "uid") | |
1097 let choices = choices . " " . fields[9] . "\n" | |
1098 else | |
1099 let pubseen = 0 | |
1100 endif | |
1101 " search for the next pub | |
1055 else | 1102 else |
1056 let pubseen = 0 | 1103 if (fields[0] == "pub") |
1057 endif | 1104 " Ignore keys which are not usable for encryption |
1058 endif | 1105 if fields[11] !~? 'e' |
1059 | 1106 continue |
1060 " search for the next pub | 1107 endif |
1061 if (pubseen == 0) | 1108 |
1062 if (fields[0] == "pub") | 1109 let identity = fields[4] |
1063 let identity = fields[4] | 1110 let gpgids += [identity] |
1064 let gpgids += [identity] | 1111 if exists("*strftime") |
1065 if exists("*strftime") | 1112 let choices = choices . counter . ": ID: 0x" . identity . " created at " . strftime("%c", fields[5]) . "\n" |
1066 let choices = choices . counter . ": ID: 0x" . identity . " created at " . strftime("%c", fields[5]) . "\n" | 1113 else |
1067 else | 1114 let choices = choices . counter . ": ID: 0x" . identity . "\n" |
1068 let choices = choices . counter . ": ID: 0x" . identity . "\n" | 1115 endif |
1116 let counter = counter+1 | |
1117 let pubseen = 1 | |
1069 endif | 1118 endif |
1070 let counter = counter+1 | |
1071 let pubseen = 1 | |
1072 endif | 1119 endif |
1073 endif | 1120 endif |
1074 | 1121 |
1075 endfor | 1122 endfor |
1076 | 1123 |
1082 while (answer == "") | 1129 while (answer == "") |
1083 let answer = input("Enter number: ", "0") | 1130 let answer = input("Enter number: ", "0") |
1084 endwhile | 1131 endwhile |
1085 endif | 1132 endif |
1086 | 1133 |
1087 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGIDToName()") | 1134 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGNameToID()") |
1088 return get(gpgids, answer, "") | 1135 return get(gpgids, answer, "") |
1089 endfunction | 1136 endfunction |
1090 | 1137 |
1091 " Function: s:GPGIDToName(identity) {{{2 | 1138 " Function: s:GPGIDToName(identity) {{{2 |
1092 " | 1139 " |
1097 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGIDToName()") | 1144 call s:GPGDebug(3, ">>>>>>>> Entering s:GPGIDToName()") |
1098 | 1145 |
1099 " TODO is the encryption subkey really unique? | 1146 " TODO is the encryption subkey really unique? |
1100 | 1147 |
1101 " ask gpg for the id for a name | 1148 " ask gpg for the id for a name |
1102 let commandline = s:GPGCommand . " --quiet --with-colons --fixed-list-mode --list-keys " . a:identity | 1149 let cmd = { 'level': 2 } |
1103 call s:GPGDebug(2, "command: ". commandline) | 1150 let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . a:identity |
1104 let &shellredir = s:shellredir | 1151 let output = s:GPGSystem(cmd) |
1105 let &shell = s:shell | |
1106 let output = system(commandline) | |
1107 let &shellredir = s:shellredirsave | |
1108 let &shell = s:shellsave | |
1109 call s:GPGDebug(2, "output: ". output) | |
1110 | 1152 |
1111 " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, | 1153 " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8, |
1112 " so convert it, if necessary | 1154 " so convert it, if necessary |
1113 if (&encoding != "utf-8") | 1155 if (&encoding != "utf-8") |
1114 let output = iconv(output, "utf-8", &encoding) | 1156 let output = iconv(output, "utf-8", &encoding) |
1118 " parse the output of gpg | 1160 " parse the output of gpg |
1119 let pubseen = 0 | 1161 let pubseen = 0 |
1120 let uid = "" | 1162 let uid = "" |
1121 for line in lines | 1163 for line in lines |
1122 let fields = split(line, ":") | 1164 let fields = split(line, ":") |
1123 if (pubseen == 0) " search for the next pub | 1165 |
1166 if !pubseen " search for the next pub | |
1124 if (fields[0] == "pub") | 1167 if (fields[0] == "pub") |
1168 " Ignore keys which are not usable for encryption | |
1169 if fields[11] !~? 'e' | |
1170 continue | |
1171 endif | |
1172 | |
1125 let pubseen = 1 | 1173 let pubseen = 1 |
1126 endif | 1174 endif |
1127 else " search for the next uid | 1175 else " search for the next uid |
1128 if (fields[0] == "uid") | 1176 if (fields[0] == "uid") |
1129 let pubseen = 0 | 1177 let pubseen = 0 |
1139 | 1187 |
1140 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGIDToName()") | 1188 call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGIDToName()") |
1141 return uid | 1189 return uid |
1142 endfunction | 1190 endfunction |
1143 | 1191 |
1192 function s:GPGPreCmd() | |
1193 let &shellredir = s:shellredir | |
1194 let &shell = s:shell | |
1195 let &shelltemp = s:shelltemp | |
1196 endfunction | |
1197 | |
1198 function s:GPGPostCmd() | |
1199 let &shellredir = s:shellredirsave | |
1200 let &shell = s:shellsave | |
1201 let &shelltemp = s:shelltempsave | |
1202 endfunction | |
1203 | |
1204 " Function: s:GPGSystem(dict) {{{2 | |
1205 " | |
1206 " run g:GPGCommand using system(), logging the commandline and output | |
1207 " Recognized keys are: | |
1208 " level - Debug level at which the commandline and output will be logged | |
1209 " args - Arguments to be given to g:GPGCommand | |
1210 " | |
1211 " Returns: command output | |
1212 " | |
1213 function s:GPGSystem(dict) | |
1214 let commandline = printf('%s %s', s:GPGCommand, a:dict.args) | |
1215 if (!empty(g:GPGHomedir)) | |
1216 let commandline .= ' --homedir ' . shellescape(g:GPGHomedir) | |
1217 endif | |
1218 let commandline .= ' ' . s:stderrredirnull | |
1219 call s:GPGDebug(a:dict.level, "command: ". commandline) | |
1220 | |
1221 call s:GPGPreCmd() | |
1222 let output = system(commandline) | |
1223 call s:GPGPostCmd() | |
1224 | |
1225 call s:GPGDebug(a:dict.level, "output: ". output) | |
1226 return output | |
1227 endfunction | |
1228 | |
1229 " Function: s:GPGExecute(dict) {{{2 | |
1230 " | |
1231 " run g:GPGCommand using :execute, logging the commandline | |
1232 " Recognized keys are: | |
1233 " level - Debug level at which the commandline will be logged | |
1234 " args - Arguments to be given to g:GPGCommand | |
1235 " ex - Ex command which will be :executed | |
1236 " redirect - Shell redirect to use, if needed | |
1237 " | |
1238 function s:GPGExecute(dict) | |
1239 let commandline = printf('%s%s %s', a:dict.ex, s:GPGCommand, a:dict.args) | |
1240 if (!empty(g:GPGHomedir)) | |
1241 let commandline .= ' --homedir ' . shellescape(g:GPGHomedir, 1) | |
1242 endif | |
1243 if (has_key(a:dict, 'redirect')) | |
1244 let commandline .= ' ' . a:dict.redirect | |
1245 endif | |
1246 let commandline .= ' ' . s:stderrredirnull | |
1247 call s:GPGDebug(a:dict.level, "command: " . commandline) | |
1248 | |
1249 call s:GPGPreCmd() | |
1250 execute commandline | |
1251 call s:GPGPostCmd() | |
1252 endfunction | |
1253 | |
1144 " Function: s:GPGDebug(level, text) {{{2 | 1254 " Function: s:GPGDebug(level, text) {{{2 |
1145 " | 1255 " |
1146 " output debug message, if this message has high enough importance | 1256 " output debug message, if this message has high enough importance |
1147 " only define function if GPGDebugLevel set at all | 1257 " only define function if GPGDebugLevel set at all |
1148 " | 1258 " |
1149 function s:GPGDebug(level, text) | 1259 function s:GPGDebug(level, text) |
1150 if exists("g:GPGDebugLevel") && g:GPGDebugLevel >= a:level | 1260 if exists("g:GPGDebugLevel") && g:GPGDebugLevel >= a:level |
1151 if exists("g:GPGDebugLog") | 1261 if exists("g:GPGDebugLog") |
1152 execute "redir >> " . g:GPGDebugLog | 1262 execute "redir >> " . g:GPGDebugLog |
1153 echom "GnuPG: " . a:text | 1263 silent echom "GnuPG: " . a:text |
1154 redir END | 1264 redir END |
1155 else | 1265 else |
1156 echom "GnuPG: " . a:text | 1266 echom "GnuPG: " . a:text |
1157 endif | 1267 endif |
1158 endif | 1268 endif |