diff options
| author | Michael Olson | 2008-02-08 06:54:27 +0000 |
|---|---|---|
| committer | Michael Olson | 2008-02-08 06:54:27 +0000 |
| commit | c154c0be0459b3ff6449be0b2993fd77d7fbb1c7 (patch) | |
| tree | e4108eded300caaf19456a1f5b385d6a59a7ecbf | |
| parent | 1752e20580918ecec926dd9a42d07647aaad60da (diff) | |
| download | emacs-c154c0be0459b3ff6449be0b2993fd77d7fbb1c7.tar.gz emacs-c154c0be0459b3ff6449be0b2993fd77d7fbb1c7.zip | |
EasyPG: Initial check-in.
| -rw-r--r-- | doc/misc/Makefile.in | 8 | ||||
| -rw-r--r-- | doc/misc/epa.texi | 393 | ||||
| -rw-r--r-- | etc/NEWS | 8 | ||||
| -rw-r--r-- | lisp/epa-dired.el | 87 | ||||
| -rw-r--r-- | lisp/epa-file.el | 318 | ||||
| -rw-r--r-- | lisp/epa-mail.el | 178 | ||||
| -rw-r--r-- | lisp/epa-setup.el | 39 | ||||
| -rw-r--r-- | lisp/epa.el | 1176 | ||||
| -rw-r--r-- | lisp/epg-config.el | 140 | ||||
| -rw-r--r-- | lisp/epg-package-info.el | 37 | ||||
| -rw-r--r-- | lisp/epg.el | 2654 |
11 files changed, 5038 insertions, 0 deletions
diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in index 3d14d9a78a6..4460b6f596c 100644 --- a/doc/misc/Makefile.in +++ b/doc/misc/Makefile.in | |||
| @@ -49,6 +49,7 @@ INFO_TARGETS = \ | |||
| 49 | $(infodir)/ebrowse \ | 49 | $(infodir)/ebrowse \ |
| 50 | $(infodir)/ediff \ | 50 | $(infodir)/ediff \ |
| 51 | $(infodir)/emacs-mime \ | 51 | $(infodir)/emacs-mime \ |
| 52 | $(infodir)/epa \ | ||
| 52 | $(infodir)/erc \ | 53 | $(infodir)/erc \ |
| 53 | $(infodir)/eshell \ | 54 | $(infodir)/eshell \ |
| 54 | $(infodir)/eudc \ | 55 | $(infodir)/eudc \ |
| @@ -91,6 +92,7 @@ DVI_TARGETS = \ | |||
| 91 | ebrowse.dvi \ | 92 | ebrowse.dvi \ |
| 92 | ediff.dvi \ | 93 | ediff.dvi \ |
| 93 | emacs-mime.dvi \ | 94 | emacs-mime.dvi \ |
| 95 | epa.dvi \ | ||
| 94 | erc.dvi \ | 96 | erc.dvi \ |
| 95 | eshell.dvi \ | 97 | eshell.dvi \ |
| 96 | eudc.dvi \ | 98 | eudc.dvi \ |
| @@ -207,6 +209,12 @@ $(infodir)/emacs-mime: emacs-mime.texi | |||
| 207 | emacs-mime.dvi: emacs-mime.texi | 209 | emacs-mime.dvi: emacs-mime.texi |
| 208 | $(ENVADD) $(TEXI2DVI) ${srcdir}/emacs-mime.texi | 210 | $(ENVADD) $(TEXI2DVI) ${srcdir}/emacs-mime.texi |
| 209 | 211 | ||
| 212 | epa : $(infodir)/epa | ||
| 213 | $(infodir)/epa: epa.texi | ||
| 214 | cd $(srcdir); $(MAKEINFO) epa.texi | ||
| 215 | epa.dvi: epa.texi | ||
| 216 | $(ENVADD) $(TEXI2DVI) ${srcdir}/epa.texi | ||
| 217 | |||
| 210 | erc : $(infodir)/erc | 218 | erc : $(infodir)/erc |
| 211 | $(infodir)/erc: erc.texi | 219 | $(infodir)/erc: erc.texi |
| 212 | cd $(srcdir); $(MAKEINFO) erc.texi | 220 | cd $(srcdir); $(MAKEINFO) erc.texi |
diff --git a/doc/misc/epa.texi b/doc/misc/epa.texi new file mode 100644 index 00000000000..8fb5877ca2f --- /dev/null +++ b/doc/misc/epa.texi | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | \input texinfo @c -*- mode: texinfo -*- | ||
| 2 | @c %**start of header | ||
| 3 | @setfilename ../../info/epa | ||
| 4 | @settitle EasyPG Assistant User's Manual | ||
| 5 | @c %**end of header | ||
| 6 | |||
| 7 | @set VERSION 1.0.0 | ||
| 8 | |||
| 9 | @copying | ||
| 10 | This file describes EasyPG Assistant. | ||
| 11 | |||
| 12 | Copyright @copyright{} 2007, 2008 Free Software Foundation, Inc. | ||
| 13 | |||
| 14 | @quotation | ||
| 15 | Permission is granted to copy, distribute and/or modify this document | ||
| 16 | under the terms of the GNU Free Documentation License, Version 1.2 or | ||
| 17 | any later version published by the Free Software Foundation; with no | ||
| 18 | Invariant Sections, with no Front-Cover Texts, and with no Back-Cover | ||
| 19 | Texts. A copy of the license is included in the section entitled "GNU | ||
| 20 | Free Documentation License". | ||
| 21 | @end quotation | ||
| 22 | @end copying | ||
| 23 | |||
| 24 | @dircategory Emacs | ||
| 25 | @direntry | ||
| 26 | * EasyPG Assistant: (epa). An Emacs user interface to GNU Privacy Guard. | ||
| 27 | @end direntry | ||
| 28 | |||
| 29 | |||
| 30 | @titlepage | ||
| 31 | @title EasyPG Assistant | ||
| 32 | |||
| 33 | @author by Daiki Ueno | ||
| 34 | @page | ||
| 35 | |||
| 36 | @vskip 0pt plus 1filll | ||
| 37 | @insertcopying | ||
| 38 | @end titlepage | ||
| 39 | @page | ||
| 40 | |||
| 41 | @c @summarycontents | ||
| 42 | @c @contents | ||
| 43 | |||
| 44 | @node Top | ||
| 45 | @top EasyPG Assistant user's manual | ||
| 46 | |||
| 47 | EasyPG Assistant is an Emacs user interface to GNU Privacy Guard | ||
| 48 | (GnuPG, @pxref{Top, , Top, gnupg, Using the GNU Privacy Guard}). | ||
| 49 | |||
| 50 | EasyPG Assistant is a part of the package called EasyPG, an all-in-one | ||
| 51 | GnuPG interface for Emacs. EasyPG also contains the library interface | ||
| 52 | called EasyPG Library. | ||
| 53 | |||
| 54 | @noindent | ||
| 55 | This manual covers EasyPG version @value{VERSION}. | ||
| 56 | |||
| 57 | @menu | ||
| 58 | * Overview:: | ||
| 59 | * Quick start:: | ||
| 60 | * Commands:: | ||
| 61 | @end menu | ||
| 62 | |||
| 63 | @node Overview | ||
| 64 | @chapter Overview | ||
| 65 | |||
| 66 | EasyPG Assistant provides the following features. | ||
| 67 | |||
| 68 | @itemize @bullet | ||
| 69 | @item Key manegement. | ||
| 70 | @item Cryptographic operations on regions. | ||
| 71 | @item Cryptographic operations on files. | ||
| 72 | @item Dired integration. | ||
| 73 | @item Mail-mode integration. | ||
| 74 | @item Automatic encryption/decryption of *.gpg files. | ||
| 75 | @end itemize | ||
| 76 | |||
| 77 | @node Quick start | ||
| 78 | @chapter Quick start | ||
| 79 | |||
| 80 | To install, just follow the standard CMMI installation instructions. | ||
| 81 | |||
| 82 | @cartouche | ||
| 83 | @example | ||
| 84 | $ ./configure | ||
| 85 | $ sudo make install | ||
| 86 | @end example | ||
| 87 | @end cartouche | ||
| 88 | |||
| 89 | @noindent | ||
| 90 | Then, add the following line to your @file{~/.emacs} | ||
| 91 | |||
| 92 | @cartouche | ||
| 93 | @lisp | ||
| 94 | (require 'epa-setup) | ||
| 95 | @end lisp | ||
| 96 | @end cartouche | ||
| 97 | |||
| 98 | @noindent | ||
| 99 | That's all. Restart emacs and type @kbd{M-x epa- @key{TAB}}, and you will see a | ||
| 100 | lot of commands available. For example, | ||
| 101 | |||
| 102 | @itemize @bullet | ||
| 103 | @item To browse your keyring, type @kbd{M-x epa-list-keys} | ||
| 104 | |||
| 105 | @item To create a cleartext signature of the region, type @kbd{M-x epa-sign-region} | ||
| 106 | @end itemize | ||
| 107 | |||
| 108 | @node Commands | ||
| 109 | @chapter Commands | ||
| 110 | |||
| 111 | This chapter introduces various commands for typical use cases. | ||
| 112 | |||
| 113 | @menu | ||
| 114 | * Key management:: | ||
| 115 | * Cryptographic operations on regions:: | ||
| 116 | * Cryptographic operations on files:: | ||
| 117 | * Dired integration:: | ||
| 118 | * Mail-mode integration:: | ||
| 119 | * Encrypting/decrypting *.gpg files:: | ||
| 120 | @end menu | ||
| 121 | |||
| 122 | @node Key management | ||
| 123 | @section Key management | ||
| 124 | Probably the first step of using EasyPG Assistant is to browse your | ||
| 125 | keyring. @kbd{M-x epa-list-keys} is corresponding to @samp{gpg | ||
| 126 | --list-keys} from the command line. | ||
| 127 | |||
| 128 | @deffn Command epa-list-keys name mode | ||
| 129 | Show all keys matched with @var{name} from the public keyring. | ||
| 130 | @end deffn | ||
| 131 | |||
| 132 | @noindent | ||
| 133 | The output looks as follows. | ||
| 134 | |||
| 135 | @example | ||
| 136 | u A5B6B2D4B15813FE Daiki Ueno <ueno@@unixuser.org> | ||
| 137 | @end example | ||
| 138 | |||
| 139 | @noindent | ||
| 140 | A character on the leftmost column indicates the trust level of the | ||
| 141 | key. If it is @samp{u}, the key is marked as ultimately trusted. The | ||
| 142 | second column is the key ID, and the rest is the user ID. | ||
| 143 | |||
| 144 | You can move over entries by @key{TAB}. If you type @key{RET} or | ||
| 145 | click button1 on an entry, you will see more detailed information | ||
| 146 | about the key you selected. | ||
| 147 | |||
| 148 | @example | ||
| 149 | u Daiki Ueno <ueno@@unixuser.org> | ||
| 150 | u A5B6B2D4B15813FE 1024bits DSA | ||
| 151 | Created: 2001-10-09 | ||
| 152 | Expires: 2007-09-04 | ||
| 153 | Capabilities: sign certify | ||
| 154 | Fingerprint: 8003 7CD0 0F1A 9400 03CA 50AA A5B6 B2D4 B158 13FE | ||
| 155 | u 4447461B2A9BEA2D 2048bits ELGAMAL_E | ||
| 156 | Created: 2001-10-09 | ||
| 157 | Expires: 2007-09-04 | ||
| 158 | Capabilities: encrypt | ||
| 159 | Fingerprint: 9003 D76B 73B7 4A8A E588 10AF 4447 461B 2A9B EA2D | ||
| 160 | @end example | ||
| 161 | |||
| 162 | @noindent | ||
| 163 | To browse your private keyring, use @kbd{M-x epa-list-secret-keys}. | ||
| 164 | |||
| 165 | @deffn Command epa-list-secret-keys name | ||
| 166 | Show all keys matched with @var{name} from the private keyring. | ||
| 167 | @end deffn | ||
| 168 | |||
| 169 | @noindent | ||
| 170 | In @samp{*Keys*} buffer, several commands are available. The common | ||
| 171 | use case is to export some keys to a file. To do that, type @kbd{m} | ||
| 172 | to select keys, type @kbd{o}, and then supply the filename. | ||
| 173 | |||
| 174 | Below are other commands related to key management. Some of them take | ||
| 175 | a file as input/output, and others take the current region. | ||
| 176 | |||
| 177 | @deffn Command epa-insert-keys keys | ||
| 178 | Insert selected @var{keys} after the point. It will let you select | ||
| 179 | keys before insertion. By default, it will encode keys in the OpenPGP | ||
| 180 | armor format. | ||
| 181 | @end deffn | ||
| 182 | |||
| 183 | @deffn Command epa-import-keys file | ||
| 184 | Import keys from @var{file} to your keyring. | ||
| 185 | @end deffn | ||
| 186 | |||
| 187 | @deffn Command epa-import-keys-region start end | ||
| 188 | Import keys from the current region between @var{start} and @var{end} | ||
| 189 | to your keyring. | ||
| 190 | @end deffn | ||
| 191 | |||
| 192 | @deffn Command epa-import-armor-in-region start end | ||
| 193 | Import keys in the OpenPGP armor format in the current region between | ||
| 194 | @var{start} and @var{end}. The difference from | ||
| 195 | @code{epa-import-keys-region} is that | ||
| 196 | @code{epa-import-armor-in-region} searches armors in the region and | ||
| 197 | applies @code{epa-import-keys-region} to each of them. | ||
| 198 | @end deffn | ||
| 199 | |||
| 200 | @deffn Command epa-delete-keys allow-secret | ||
| 201 | Delete selected keys. If @var{allow-secret} is non-@code{nil}, it | ||
| 202 | also delete the secret keys. | ||
| 203 | @end deffn | ||
| 204 | |||
| 205 | @node Cryptographic operations on regions | ||
| 206 | @section Cryptographic operations on regions | ||
| 207 | |||
| 208 | @deffn Command epa-decrypt-region start end | ||
| 209 | Decrypt the current region between @var{start} and @var{end}. It | ||
| 210 | replaces the region with the decrypted text. | ||
| 211 | @end deffn | ||
| 212 | |||
| 213 | @deffn Command epa-decrypt-armor-in-region start end | ||
| 214 | Decrypt OpenPGP armors in the current region between @var{start} and | ||
| 215 | @var{end}. The difference from @code{epa-decrypt-region} is that | ||
| 216 | @code{epa-decrypt-armor-in-region} searches armors in the region | ||
| 217 | and applies @code{epa-decrypt-region} to each of them. That is, this | ||
| 218 | command does not alter the original text around armors. | ||
| 219 | @end deffn | ||
| 220 | |||
| 221 | @deffn Command epa-verify-region start end | ||
| 222 | Verify the current region between @var{start} and @var{end}. It sends | ||
| 223 | the verification result to the minibuffer or a popup window. It | ||
| 224 | replaces the region with the signed text. | ||
| 225 | @end deffn | ||
| 226 | |||
| 227 | @deffn Command epa-verify-cleartext-in-region | ||
| 228 | Verify OpenPGP cleartext blocks in the current region between | ||
| 229 | @var{start} and @var{end}. The difference from | ||
| 230 | @code{epa-verify-region} is that @code{epa-verify-cleartext-in-region} | ||
| 231 | searches OpenPGP cleartext blocks in the region and applies | ||
| 232 | @code{epa-verify-region} to each of them. That is, this command does | ||
| 233 | not alter the original text around OpenPGP cleartext blocks. | ||
| 234 | @end deffn | ||
| 235 | |||
| 236 | @deffn Command epa-sign-region start end signers type | ||
| 237 | Sign the current region between @var{start} and @var{end}. By | ||
| 238 | default, it creates a cleartext signature. If a prefix argument is | ||
| 239 | given, it will let you select signing keys, and then a signature | ||
| 240 | type. | ||
| 241 | @end deffn | ||
| 242 | |||
| 243 | @deffn Command epa-encrypt-region start end recipients sign signers | ||
| 244 | Encrypt the current region between @var{start} and @var{end}. It will | ||
| 245 | let you select recipients. If a prefix argument is given, it will | ||
| 246 | also ask you whether or not to sign the text before encryption and if | ||
| 247 | you answered yes, it will let you select the signing keys. | ||
| 248 | @end deffn | ||
| 249 | |||
| 250 | @node Cryptographic operations on files | ||
| 251 | @section Cryptographic operations on files | ||
| 252 | |||
| 253 | @deffn Command epa-decrypt-file file | ||
| 254 | Decrypt @var{file}. | ||
| 255 | @end deffn | ||
| 256 | |||
| 257 | @deffn Command epa-verify-file file | ||
| 258 | Verify @var{file}. | ||
| 259 | @end deffn | ||
| 260 | |||
| 261 | @deffn Command epa-sign-file file signers type | ||
| 262 | Sign @var{file}. If a prefix argument is given, it will let you | ||
| 263 | select signing keys, and then a signature type. | ||
| 264 | @end deffn | ||
| 265 | |||
| 266 | @deffn Command epa-encrypt-file file recipients | ||
| 267 | Encrypt @var{file}. It will let you select recipients. | ||
| 268 | @end deffn | ||
| 269 | |||
| 270 | @node Dired integration | ||
| 271 | @section Dired integration | ||
| 272 | |||
| 273 | EasyPG Assistant extends Dired Mode for GNU Emacs to allow users to | ||
| 274 | easily do cryptographic operations on files. For example, | ||
| 275 | |||
| 276 | @example | ||
| 277 | M-x dired | ||
| 278 | (mark some files) | ||
| 279 | : e (or M-x epa-dired-do-encrypt) | ||
| 280 | (select recipients by 'm' and click [OK]) | ||
| 281 | @end example | ||
| 282 | |||
| 283 | @noindent | ||
| 284 | The following keys are assigned. | ||
| 285 | |||
| 286 | @table @kbd | ||
| 287 | @item : d | ||
| 288 | @kindex @kbd{: d} | ||
| 289 | @findex epa-dired-do-decrypt | ||
| 290 | Decrypt marked files. | ||
| 291 | |||
| 292 | @item : v | ||
| 293 | @kindex @kbd{: v} | ||
| 294 | @findex epa-dired-do-verify | ||
| 295 | Verify marked files. | ||
| 296 | |||
| 297 | @item : s | ||
| 298 | @kindex @kbd{: s} | ||
| 299 | @findex epa-dired-do-sign | ||
| 300 | Sign marked files. | ||
| 301 | |||
| 302 | @item : e | ||
| 303 | @kindex @kbd{: e} | ||
| 304 | @findex epa-dired-do-encrypt | ||
| 305 | Encrypt marked files. | ||
| 306 | |||
| 307 | @end table | ||
| 308 | |||
| 309 | @node Mail-mode integration | ||
| 310 | @section Mail-mode integration | ||
| 311 | |||
| 312 | EasyPG Assistant provides a minor mode to help user compose inline PGP | ||
| 313 | messages. Inline PGP is sending the OpenPGP blobs directly inside a | ||
| 314 | mail message and it is not recommended and you should consider to use | ||
| 315 | PGP/MIME. See | ||
| 316 | @uref{http://josefsson.org/inline-openpgp-considered-harmful.html, | ||
| 317 | Inline PGP in E-mail is bad, Mm'kay?}. | ||
| 318 | |||
| 319 | @noindent | ||
| 320 | The following keys are assigned. | ||
| 321 | |||
| 322 | @table @kbd | ||
| 323 | @item C-c C-e d | ||
| 324 | @kindex @kbd{C-c C-e d} | ||
| 325 | @findex epa-mail-decrypt | ||
| 326 | Decrypt OpenPGP armors in the current buffer. | ||
| 327 | |||
| 328 | @item C-c C-e v | ||
| 329 | @kindex @kbd{C-c C-e v} | ||
| 330 | @findex epa-mail-verify | ||
| 331 | Verify OpenPGP cleartext signed messages in the current buffer. | ||
| 332 | |||
| 333 | @item C-c C-e s | ||
| 334 | @kindex @kbd{C-c C-e s} | ||
| 335 | @findex epa-mail-sign | ||
| 336 | Compose a signed message from the current buffer. | ||
| 337 | |||
| 338 | @item C-c C-e e | ||
| 339 | @kindex @kbd{C-c C-e e} | ||
| 340 | @findex epa-mail-encrypt | ||
| 341 | Compose an encrypted message from the current buffer. | ||
| 342 | |||
| 343 | @end table | ||
| 344 | |||
| 345 | @node Encrypting/decrypting *.gpg files | ||
| 346 | @section Encrypting/decrypting *.gpg files | ||
| 347 | Once @code{epa-setup} is loaded, every file whose extension is | ||
| 348 | @samp{.gpg} will be treated as encrypted. That is, when you attempt | ||
| 349 | to open such a file which already exists, the decrypted text is | ||
| 350 | inserted in the buffer rather than encrypted one. On the other hand, | ||
| 351 | when you attempt to save the buffer to a file whose extension is | ||
| 352 | @samp{.gpg}, encrypted data is written. | ||
| 353 | |||
| 354 | If you want to temporarily disable this behavior, use @kbd{M-x | ||
| 355 | epa-file-disable}, and then to enable this behavior use @kbd{M-x | ||
| 356 | epa-file-enable}. | ||
| 357 | |||
| 358 | @deffn Command epa-file-disable | ||
| 359 | Disable automatic encryption/decryption of *.gpg files. | ||
| 360 | @end deffn | ||
| 361 | |||
| 362 | @deffn Command epa-file-enable | ||
| 363 | Enable automatic encryption/decryption of *.gpg files. | ||
| 364 | @end deffn | ||
| 365 | |||
| 366 | @noindent | ||
| 367 | @code{epa-file} will let you select recipients. If you want to | ||
| 368 | suppress this question, it might be a good idea to put the following | ||
| 369 | line on the first line of the text being encrypted. | ||
| 370 | @vindex epa-file-encrypt-to | ||
| 371 | |||
| 372 | @cartouche | ||
| 373 | @lisp | ||
| 374 | ;; -*- epa-file-encrypt-to: ("ueno@@unixuser.org") -*- | ||
| 375 | @end lisp | ||
| 376 | @end cartouche | ||
| 377 | |||
| 378 | Other variables which control the automatic encryption/decryption | ||
| 379 | behavior are below. | ||
| 380 | |||
| 381 | @defvar epa-file-cache-passphrase-for-symmetric-encryption | ||
| 382 | If non-@code{nil}, cache passphrase for symmetric encryption. The | ||
| 383 | default value is @code{nil}. | ||
| 384 | @end defvar | ||
| 385 | |||
| 386 | @defvar epa-file-inhibit-auto-save | ||
| 387 | If non-@code{nil}, disable auto-saving when opening an encrypted file. | ||
| 388 | The default value is @code{t}. | ||
| 389 | @end defvar | ||
| 390 | |||
| 391 | @bye | ||
| 392 | |||
| 393 | @c End: | ||
| @@ -229,6 +229,14 @@ consult the Remember Manual for usage details. | |||
| 229 | dbus.el and by extensions to the C modules of Emacs. D-Bus is an | 229 | dbus.el and by extensions to the C modules of Emacs. D-Bus is an |
| 230 | inter-process communication mechanism for applications residing on the | 230 | inter-process communication mechanism for applications residing on the |
| 231 | same host, based on messages. See the manual for further details. | 231 | same host, based on messages. See the manual for further details. |
| 232 | |||
| 233 | ** EasyPG is now part of the Emacs distribution. | ||
| 234 | EasyPG is an all-in-one GnuPG interface for Emacs. It consists of two | ||
| 235 | parts: EasyPG Assistant and EasyPG Library. | ||
| 236 | |||
| 237 | EasyPG Assistant is a set of convenient tools to use GnuPG from | ||
| 238 | Emacs. EasyPG Library is a sort of an elisp port of GPGME, a wrapper | ||
| 239 | library which provides API to access some of the GnuPG functions. | ||
| 232 | 240 | ||
| 233 | * Changes in Specialized Modes and Packages in Emacs 23.1 | 241 | * Changes in Specialized Modes and Packages in Emacs 23.1 |
| 234 | 242 | ||
diff --git a/lisp/epa-dired.el b/lisp/epa-dired.el new file mode 100644 index 00000000000..b20218b0ff3 --- /dev/null +++ b/lisp/epa-dired.el | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | ;;; epa-dired.el --- the EasyPG Assistant, dired extension | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'epa) | ||
| 27 | (require 'dired) | ||
| 28 | |||
| 29 | (defvar epa-dired-map | ||
| 30 | (let ((keymap (make-sparse-keymap))) | ||
| 31 | (define-key keymap "d" 'epa-dired-do-decrypt) | ||
| 32 | (define-key keymap "v" 'epa-dired-do-verify) | ||
| 33 | (define-key keymap "s" 'epa-dired-do-sign) | ||
| 34 | (define-key keymap "e" 'epa-dired-do-encrypt) | ||
| 35 | keymap)) | ||
| 36 | |||
| 37 | (fset 'epa-dired-prefix epa-dired-map) | ||
| 38 | |||
| 39 | (defun epa-dired-mode-hook () | ||
| 40 | (define-key dired-mode-map ":" 'epa-dired-prefix)) | ||
| 41 | |||
| 42 | (defun epa-dired-do-decrypt () | ||
| 43 | "Decrypt marked files." | ||
| 44 | (interactive) | ||
| 45 | (let ((file-list (dired-get-marked-files))) | ||
| 46 | (while file-list | ||
| 47 | (epa-decrypt-file (expand-file-name (car file-list))) | ||
| 48 | (setq file-list (cdr file-list))) | ||
| 49 | (revert-buffer))) | ||
| 50 | |||
| 51 | (defun epa-dired-do-verify () | ||
| 52 | "Verify marked files." | ||
| 53 | (interactive) | ||
| 54 | (let ((file-list (dired-get-marked-files))) | ||
| 55 | (while file-list | ||
| 56 | (epa-verify-file (expand-file-name (car file-list))) | ||
| 57 | (setq file-list (cdr file-list))))) | ||
| 58 | |||
| 59 | (defun epa-dired-do-sign () | ||
| 60 | "Sign marked files." | ||
| 61 | (interactive) | ||
| 62 | (let ((file-list (dired-get-marked-files))) | ||
| 63 | (while file-list | ||
| 64 | (epa-sign-file | ||
| 65 | (expand-file-name (car file-list)) | ||
| 66 | (epa-select-keys (epg-make-context) "Select keys for signing. | ||
| 67 | If no one is selected, default secret key is used. " | ||
| 68 | nil t) | ||
| 69 | (y-or-n-p "Make a detached signature? ")) | ||
| 70 | (setq file-list (cdr file-list))) | ||
| 71 | (revert-buffer))) | ||
| 72 | |||
| 73 | (defun epa-dired-do-encrypt () | ||
| 74 | "Encrypt marked files." | ||
| 75 | (interactive) | ||
| 76 | (let ((file-list (dired-get-marked-files))) | ||
| 77 | (while file-list | ||
| 78 | (epa-encrypt-file | ||
| 79 | (expand-file-name (car file-list)) | ||
| 80 | (epa-select-keys (epg-make-context) "Select recipents for encryption. | ||
| 81 | If no one is selected, symmetric encryption will be performed. ")) | ||
| 82 | (setq file-list (cdr file-list))) | ||
| 83 | (revert-buffer))) | ||
| 84 | |||
| 85 | (provide 'epa-dired) | ||
| 86 | |||
| 87 | ;;; epa-dired.el ends here | ||
diff --git a/lisp/epa-file.el b/lisp/epa-file.el new file mode 100644 index 00000000000..e6438295ae6 --- /dev/null +++ b/lisp/epa-file.el | |||
| @@ -0,0 +1,318 @@ | |||
| 1 | ;;; epa-file.el --- the EasyPG Assistant, transparent file encryption | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'epa) | ||
| 27 | |||
| 28 | (defgroup epa-file nil | ||
| 29 | "The EasyPG Assistant hooks for transparent file encryption" | ||
| 30 | :group 'epa) | ||
| 31 | |||
| 32 | (defun epa-file--file-name-regexp-set (variable value) | ||
| 33 | (set-default variable value) | ||
| 34 | (if (fboundp 'epa-file-name-regexp-update) | ||
| 35 | (epa-file-name-regexp-update))) | ||
| 36 | |||
| 37 | (defcustom epa-file-name-regexp "\\.gpg\\(~\\|\\.~[0-9]+~\\)?\\'" | ||
| 38 | "Regexp which matches filenames to be encrypted with GnuPG. | ||
| 39 | |||
| 40 | If you set this outside Custom while epa-file is already enabled, you | ||
| 41 | have to call `epa-file-name-regexp-update' after setting it to | ||
| 42 | properly update file-name-handler-alist. Setting this through Custom | ||
| 43 | does that automatically." | ||
| 44 | :type 'regexp | ||
| 45 | :group 'epa-file | ||
| 46 | :set 'epa-file--file-name-regexp-set) | ||
| 47 | |||
| 48 | (defcustom epa-file-cache-passphrase-for-symmetric-encryption nil | ||
| 49 | "If non-nil, cache passphrase for symmetric encryption." | ||
| 50 | :type 'boolean | ||
| 51 | :group 'epa-file) | ||
| 52 | |||
| 53 | (defcustom epa-file-inhibit-auto-save t | ||
| 54 | "If non-nil, disable auto-saving when opening an encrypted file." | ||
| 55 | :type 'boolean | ||
| 56 | :group 'epa-file) | ||
| 57 | |||
| 58 | (defcustom epa-file-select-keys nil | ||
| 59 | "If non-nil, always asks user to select recipients." | ||
| 60 | :type 'boolean | ||
| 61 | :group 'epa-file) | ||
| 62 | |||
| 63 | (defvar epa-file-encrypt-to nil | ||
| 64 | "*Recipient(s) used for encrypting files. | ||
| 65 | May either be a string or a list of strings.") | ||
| 66 | |||
| 67 | ;;;###autoload | ||
| 68 | (put 'epa-file-encrypt-to 'safe-local-variable | ||
| 69 | (lambda (val) | ||
| 70 | (or (stringp val) | ||
| 71 | (and (listp val) | ||
| 72 | (catch 'safe | ||
| 73 | (mapc (lambda (elt) | ||
| 74 | (unless (stringp elt) | ||
| 75 | (throw 'safe nil))) | ||
| 76 | val) | ||
| 77 | t))))) | ||
| 78 | |||
| 79 | ;;;###autoload | ||
| 80 | (put 'epa-file-encrypt-to 'permanent-local t) | ||
| 81 | |||
| 82 | (defvar epa-file-handler | ||
| 83 | (cons epa-file-name-regexp 'epa-file-handler)) | ||
| 84 | |||
| 85 | (defvar epa-file-auto-mode-alist-entry | ||
| 86 | (list epa-file-name-regexp nil 'epa-file)) | ||
| 87 | |||
| 88 | (defvar epa-file-passphrase-alist nil) | ||
| 89 | |||
| 90 | (eval-and-compile | ||
| 91 | (if (fboundp 'encode-coding-string) | ||
| 92 | (defalias 'epa-file--encode-coding-string 'encode-coding-string) | ||
| 93 | (defalias 'epa-file--encode-coding-string 'identity))) | ||
| 94 | |||
| 95 | (eval-and-compile | ||
| 96 | (if (fboundp 'decode-coding-string) | ||
| 97 | (defalias 'epa-file--decode-coding-string 'decode-coding-string) | ||
| 98 | (defalias 'epa-file--decode-coding-string 'identity))) | ||
| 99 | |||
| 100 | (defun epa-file-name-regexp-update () | ||
| 101 | (interactive) | ||
| 102 | (unless (equal (car epa-file-handler) epa-file-name-regexp) | ||
| 103 | (setcar epa-file-handler epa-file-name-regexp))) | ||
| 104 | |||
| 105 | (defun epa-file-passphrase-callback-function (context key-id file) | ||
| 106 | (if (and epa-file-cache-passphrase-for-symmetric-encryption | ||
| 107 | (eq key-id 'SYM)) | ||
| 108 | (progn | ||
| 109 | (setq file (file-truename file)) | ||
| 110 | (let ((entry (assoc file epa-file-passphrase-alist)) | ||
| 111 | passphrase) | ||
| 112 | (or (copy-sequence (cdr entry)) | ||
| 113 | (progn | ||
| 114 | (unless entry | ||
| 115 | (setq entry (list file) | ||
| 116 | epa-file-passphrase-alist | ||
| 117 | (cons entry | ||
| 118 | epa-file-passphrase-alist))) | ||
| 119 | (setq passphrase (epa-passphrase-callback-function context | ||
| 120 | key-id nil)) | ||
| 121 | (setcdr entry (copy-sequence passphrase)) | ||
| 122 | passphrase)))) | ||
| 123 | (epa-passphrase-callback-function context key-id nil))) | ||
| 124 | |||
| 125 | (defun epa-file-handler (operation &rest args) | ||
| 126 | (save-match-data | ||
| 127 | (let ((op (get operation 'epa-file))) | ||
| 128 | (if op | ||
| 129 | (apply op args) | ||
| 130 | (epa-file-run-real-handler operation args))))) | ||
| 131 | |||
| 132 | (defun epa-file-run-real-handler (operation args) | ||
| 133 | (let ((inhibit-file-name-handlers | ||
| 134 | (cons 'epa-file-handler | ||
| 135 | (and (eq inhibit-file-name-operation operation) | ||
| 136 | inhibit-file-name-handlers))) | ||
| 137 | (inhibit-file-name-operation operation)) | ||
| 138 | (apply operation args))) | ||
| 139 | |||
| 140 | (defun epa-file-decode-and-insert (string file visit beg end replace) | ||
| 141 | (if (fboundp 'decode-coding-inserted-region) | ||
| 142 | (save-restriction | ||
| 143 | (narrow-to-region (point) (point)) | ||
| 144 | (let ((multibyte enable-multibyte-characters)) | ||
| 145 | (set-buffer-multibyte nil) | ||
| 146 | (insert string) | ||
| 147 | (set-buffer-multibyte multibyte) | ||
| 148 | (decode-coding-inserted-region | ||
| 149 | (point-min) (point-max) | ||
| 150 | (substring file 0 (string-match epa-file-name-regexp file)) | ||
| 151 | visit beg end replace))) | ||
| 152 | (insert (epa-file--decode-coding-string string (or coding-system-for-read | ||
| 153 | 'undecided))))) | ||
| 154 | |||
| 155 | (defvar last-coding-system-used) | ||
| 156 | (defun epa-file-insert-file-contents (file &optional visit beg end replace) | ||
| 157 | (barf-if-buffer-read-only) | ||
| 158 | (if (and visit (or beg end)) | ||
| 159 | (error "Attempt to visit less than an entire file")) | ||
| 160 | (setq file (expand-file-name file)) | ||
| 161 | (let* ((local-copy | ||
| 162 | (condition-case inl | ||
| 163 | (epa-file-run-real-handler #'file-local-copy (list file)) | ||
| 164 | (error))) | ||
| 165 | (local-file (or local-copy file)) | ||
| 166 | (context (epg-make-context)) | ||
| 167 | string length entry) | ||
| 168 | (if visit | ||
| 169 | (setq buffer-file-name file)) | ||
| 170 | (epg-context-set-passphrase-callback | ||
| 171 | context | ||
| 172 | (cons #'epa-file-passphrase-callback-function | ||
| 173 | local-file)) | ||
| 174 | (epg-context-set-progress-callback context | ||
| 175 | #'epa-progress-callback-function) | ||
| 176 | (unwind-protect | ||
| 177 | (progn | ||
| 178 | (if replace | ||
| 179 | (goto-char (point-min))) | ||
| 180 | (condition-case error | ||
| 181 | (setq string (epg-decrypt-file context local-file nil)) | ||
| 182 | (error | ||
| 183 | (if (setq entry (assoc file epa-file-passphrase-alist)) | ||
| 184 | (setcdr entry nil)) | ||
| 185 | (signal 'file-error | ||
| 186 | (cons "Opening input file" (cdr error))))) | ||
| 187 | (make-local-variable 'epa-file-encrypt-to) | ||
| 188 | (setq epa-file-encrypt-to | ||
| 189 | (mapcar #'car (epg-context-result-for context 'encrypted-to))) | ||
| 190 | (if (or beg end) | ||
| 191 | (setq string (substring string (or beg 0) end))) | ||
| 192 | (save-excursion | ||
| 193 | (save-restriction | ||
| 194 | (narrow-to-region (point) (point)) | ||
| 195 | (epa-file-decode-and-insert string file visit beg end replace) | ||
| 196 | (setq length (- (point-max) (point-min)))) | ||
| 197 | (if replace | ||
| 198 | (delete-region (point) (point-max))))) | ||
| 199 | (if (and local-copy | ||
| 200 | (file-exists-p local-copy)) | ||
| 201 | (delete-file local-copy))) | ||
| 202 | (list file length))) | ||
| 203 | (put 'insert-file-contents 'epa-file 'epa-file-insert-file-contents) | ||
| 204 | |||
| 205 | (defun epa-file-write-region (start end file &optional append visit lockname | ||
| 206 | mustbenew) | ||
| 207 | (if append | ||
| 208 | (error "Can't append to the file.")) | ||
| 209 | (setq file (expand-file-name file)) | ||
| 210 | (let* ((coding-system (or coding-system-for-write | ||
| 211 | (if (fboundp 'select-safe-coding-system) | ||
| 212 | ;; This is needed since Emacs 22 has | ||
| 213 | ;; no-conversion setting for *.gpg in | ||
| 214 | ;; `auto-coding-alist'. | ||
| 215 | (let ((buffer-file-name | ||
| 216 | (file-name-sans-extension file))) | ||
| 217 | (select-safe-coding-system | ||
| 218 | (point-min) (point-max))) | ||
| 219 | buffer-file-coding-system))) | ||
| 220 | (context (epg-make-context)) | ||
| 221 | (coding-system-for-write 'binary) | ||
| 222 | string entry | ||
| 223 | (recipients | ||
| 224 | (cond | ||
| 225 | ((listp epa-file-encrypt-to) epa-file-encrypt-to) | ||
| 226 | ((stringp epa-file-encrypt-to) (list epa-file-encrypt-to))))) | ||
| 227 | (epg-context-set-passphrase-callback | ||
| 228 | context | ||
| 229 | (cons #'epa-file-passphrase-callback-function | ||
| 230 | file)) | ||
| 231 | (epg-context-set-progress-callback context | ||
| 232 | #'epa-progress-callback-function) | ||
| 233 | (epg-context-set-armor context epa-armor) | ||
| 234 | (condition-case error | ||
| 235 | (setq string | ||
| 236 | (epg-encrypt-string | ||
| 237 | context | ||
| 238 | (if (stringp start) | ||
| 239 | (epa-file--encode-coding-string start coding-system) | ||
| 240 | (epa-file--encode-coding-string (buffer-substring start end) | ||
| 241 | coding-system)) | ||
| 242 | (if (or epa-file-select-keys | ||
| 243 | (not (local-variable-p 'epa-file-encrypt-to | ||
| 244 | (current-buffer)))) | ||
| 245 | (epa-select-keys | ||
| 246 | context | ||
| 247 | "Select recipents for encryption. | ||
| 248 | If no one is selected, symmetric encryption will be performed. " | ||
| 249 | recipients) | ||
| 250 | (if epa-file-encrypt-to | ||
| 251 | (epg-list-keys context recipients))))) | ||
| 252 | (error | ||
| 253 | (if (setq entry (assoc file epa-file-passphrase-alist)) | ||
| 254 | (setcdr entry nil)) | ||
| 255 | (signal 'file-error (cons "Opening output file" (cdr error))))) | ||
| 256 | (epa-file-run-real-handler | ||
| 257 | #'write-region | ||
| 258 | (list string nil file append visit lockname mustbenew)) | ||
| 259 | (if (boundp 'last-coding-system-used) | ||
| 260 | (setq last-coding-system-used coding-system)) | ||
| 261 | (if (eq visit t) | ||
| 262 | (progn | ||
| 263 | (setq buffer-file-name file) | ||
| 264 | (set-visited-file-modtime)) | ||
| 265 | (if (stringp visit) | ||
| 266 | (progn | ||
| 267 | (set-visited-file-modtime) | ||
| 268 | (setq buffer-file-name visit)))) | ||
| 269 | (if (or (eq visit t) | ||
| 270 | (eq visit nil) | ||
| 271 | (stringp visit)) | ||
| 272 | (message "Wrote %s" buffer-file-name)))) | ||
| 273 | (put 'write-region 'epa-file 'epa-file-write-region) | ||
| 274 | |||
| 275 | (defun epa-file-find-file-hook () | ||
| 276 | (if (and buffer-file-name | ||
| 277 | (string-match epa-file-name-regexp buffer-file-name) | ||
| 278 | epa-file-inhibit-auto-save) | ||
| 279 | (auto-save-mode 0)) | ||
| 280 | (set-buffer-modified-p nil)) | ||
| 281 | |||
| 282 | (defun epa-file-select-keys () | ||
| 283 | "Select recipients for encryption." | ||
| 284 | (interactive) | ||
| 285 | (make-local-variable 'epa-file-encrypt-to) | ||
| 286 | (setq epa-file-encrypt-to | ||
| 287 | (epa-select-keys | ||
| 288 | (epg-make-context) | ||
| 289 | "Select recipents for encryption. | ||
| 290 | If no one is selected, symmetric encryption will be performed. "))) | ||
| 291 | |||
| 292 | ;;;###autoload | ||
| 293 | (defun epa-file-enable () | ||
| 294 | (interactive) | ||
| 295 | (if (memq epa-file-handler file-name-handler-alist) | ||
| 296 | (message "`epa-file' already enabled") | ||
| 297 | (setq file-name-handler-alist | ||
| 298 | (cons epa-file-handler file-name-handler-alist)) | ||
| 299 | (add-hook 'find-file-hooks 'epa-file-find-file-hook) | ||
| 300 | (setq auto-mode-alist (cons epa-file-auto-mode-alist-entry auto-mode-alist)) | ||
| 301 | (message "`epa-file' enabled"))) | ||
| 302 | |||
| 303 | ;;;###autoload | ||
| 304 | (defun epa-file-disable () | ||
| 305 | (interactive) | ||
| 306 | (if (memq epa-file-handler file-name-handler-alist) | ||
| 307 | (progn | ||
| 308 | (setq file-name-handler-alist | ||
| 309 | (delq epa-file-handler file-name-handler-alist)) | ||
| 310 | (remove-hook 'find-file-hooks 'epa-file-find-file-hook) | ||
| 311 | (setq auto-mode-alist (delq epa-file-auto-mode-alist-entry | ||
| 312 | auto-mode-alist)) | ||
| 313 | (message "`epa-file' disabled")) | ||
| 314 | (message "`epa-file' already disabled"))) | ||
| 315 | |||
| 316 | (provide 'epa-file) | ||
| 317 | |||
| 318 | ;;; epa-file.el ends here | ||
diff --git a/lisp/epa-mail.el b/lisp/epa-mail.el new file mode 100644 index 00000000000..f88a6f11b41 --- /dev/null +++ b/lisp/epa-mail.el | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | ;;; epa-mail.el --- the EasyPG Assistant, minor-mode for mail composer | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG, mail, message | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'epa) | ||
| 27 | (require 'mail-utils) | ||
| 28 | |||
| 29 | (defvar epa-mail-mode-map | ||
| 30 | (let ((keymap (make-sparse-keymap))) | ||
| 31 | (define-key keymap "\C-c\C-ed" 'epa-mail-decrypt) | ||
| 32 | (define-key keymap "\C-c\C-ev" 'epa-mail-verify) | ||
| 33 | (define-key keymap "\C-c\C-es" 'epa-mail-sign) | ||
| 34 | (define-key keymap "\C-c\C-ee" 'epa-mail-encrypt) | ||
| 35 | (define-key keymap "\C-c\C-ei" 'epa-mail-import-keys) | ||
| 36 | (define-key keymap "\C-c\C-eo" 'epa-insert-keys) | ||
| 37 | keymap)) | ||
| 38 | |||
| 39 | (defvar epa-mail-mode-hook nil) | ||
| 40 | (defvar epa-mail-mode-on-hook nil) | ||
| 41 | (defvar epa-mail-mode-off-hook nil) | ||
| 42 | |||
| 43 | (define-minor-mode epa-mail-mode | ||
| 44 | "A minor-mode for composing encrypted/clearsigned mails." | ||
| 45 | nil " epa-mail" epa-mail-mode-map) | ||
| 46 | |||
| 47 | (defun epa-mail--find-usable-key (keys usage) | ||
| 48 | "Find a usable key from KEYS for USAGE." | ||
| 49 | (catch 'found | ||
| 50 | (while keys | ||
| 51 | (let ((pointer (epg-key-sub-key-list (car keys)))) | ||
| 52 | (while pointer | ||
| 53 | (if (and (memq usage (epg-sub-key-capability (car pointer))) | ||
| 54 | (not (memq (epg-sub-key-validity (car pointer)) | ||
| 55 | '(revoked expired)))) | ||
| 56 | (throw 'found (car keys))) | ||
| 57 | (setq pointer (cdr pointer)))) | ||
| 58 | (setq keys (cdr keys))))) | ||
| 59 | |||
| 60 | ;;;###autoload | ||
| 61 | (defun epa-mail-decrypt () | ||
| 62 | "Decrypt OpenPGP armors in the current buffer. | ||
| 63 | The buffer is expected to contain a mail message. | ||
| 64 | |||
| 65 | Don't use this command in Lisp programs!" | ||
| 66 | (interactive) | ||
| 67 | (epa-decrypt-armor-in-region (point-min) (point-max))) | ||
| 68 | |||
| 69 | ;;;###autoload | ||
| 70 | (defun epa-mail-verify () | ||
| 71 | "Verify OpenPGP cleartext signed messages in the current buffer. | ||
| 72 | The buffer is expected to contain a mail message. | ||
| 73 | |||
| 74 | Don't use this command in Lisp programs!" | ||
| 75 | (interactive) | ||
| 76 | (epa-verify-cleartext-in-region (point-min) (point-max))) | ||
| 77 | |||
| 78 | ;;;###autoload | ||
| 79 | (defun epa-mail-sign (start end signers mode) | ||
| 80 | "Sign the current buffer. | ||
| 81 | The buffer is expected to contain a mail message. | ||
| 82 | |||
| 83 | Don't use this command in Lisp programs!" | ||
| 84 | (interactive | ||
| 85 | (save-excursion | ||
| 86 | (goto-char (point-min)) | ||
| 87 | (if (search-forward mail-header-separator nil t) | ||
| 88 | (forward-line)) | ||
| 89 | (setq epa-last-coding-system-specified | ||
| 90 | (or coding-system-for-write | ||
| 91 | (epa--select-safe-coding-system (point) (point-max)))) | ||
| 92 | (let ((verbose current-prefix-arg)) | ||
| 93 | (list (point) (point-max) | ||
| 94 | (if verbose | ||
| 95 | (epa-select-keys (epg-make-context epa-protocol) | ||
| 96 | "Select keys for signing. | ||
| 97 | If no one is selected, default secret key is used. " | ||
| 98 | nil t)) | ||
| 99 | (if verbose | ||
| 100 | (epa--read-signature-type) | ||
| 101 | 'clear))))) | ||
| 102 | (epa-sign-region start end signers mode)) | ||
| 103 | |||
| 104 | ;;;###autoload | ||
| 105 | (defun epa-mail-encrypt (start end recipients sign signers) | ||
| 106 | "Encrypt the current buffer. | ||
| 107 | The buffer is expected to contain a mail message. | ||
| 108 | |||
| 109 | Don't use this command in Lisp programs!" | ||
| 110 | (interactive | ||
| 111 | (save-excursion | ||
| 112 | (let ((verbose current-prefix-arg) | ||
| 113 | (context (epg-make-context epa-protocol)) | ||
| 114 | recipients recipient-key) | ||
| 115 | (goto-char (point-min)) | ||
| 116 | (save-restriction | ||
| 117 | (narrow-to-region (point) | ||
| 118 | (if (search-forward mail-header-separator nil 0) | ||
| 119 | (match-beginning 0) | ||
| 120 | (point))) | ||
| 121 | (setq recipients | ||
| 122 | (mail-strip-quoted-names | ||
| 123 | (mapconcat #'identity | ||
| 124 | (nconc (mail-fetch-field "to" nil nil t) | ||
| 125 | (mail-fetch-field "cc" nil nil t) | ||
| 126 | (mail-fetch-field "bcc" nil nil t)) | ||
| 127 | ",")))) | ||
| 128 | (if recipients | ||
| 129 | (setq recipients (delete "" | ||
| 130 | (split-string recipients "[ \t\n]+")))) | ||
| 131 | (goto-char (point-min)) | ||
| 132 | (if (search-forward mail-header-separator nil t) | ||
| 133 | (forward-line)) | ||
| 134 | (setq epa-last-coding-system-specified | ||
| 135 | (or coding-system-for-write | ||
| 136 | (epa--select-safe-coding-system (point) (point-max)))) | ||
| 137 | (list (point) (point-max) | ||
| 138 | (if verbose | ||
| 139 | (epa-select-keys | ||
| 140 | context | ||
| 141 | "Select recipients for encryption. | ||
| 142 | If no one is selected, symmetric encryption will be performed. " | ||
| 143 | recipients) | ||
| 144 | (if recipients | ||
| 145 | (mapcar | ||
| 146 | (lambda (recipient) | ||
| 147 | (setq recipient-key | ||
| 148 | (epa-mail--find-usable-key | ||
| 149 | (epg-list-keys | ||
| 150 | (epg-make-context epa-protocol) | ||
| 151 | (concat "<" recipient ">")) | ||
| 152 | 'encrypt)) | ||
| 153 | (unless (or recipient-key | ||
| 154 | (y-or-n-p | ||
| 155 | (format | ||
| 156 | "No public key for %s; skip it? " | ||
| 157 | recipient))) | ||
| 158 | (error "No public key for %s" recipient)) | ||
| 159 | recipient-key) | ||
| 160 | recipients))) | ||
| 161 | (setq sign (if verbose (y-or-n-p "Sign? "))) | ||
| 162 | (if sign | ||
| 163 | (epa-select-keys context | ||
| 164 | "Select keys for signing. ")))))) | ||
| 165 | (epa-encrypt-region start end recipients sign signers)) | ||
| 166 | |||
| 167 | ;;;###autoload | ||
| 168 | (defun epa-mail-import-keys () | ||
| 169 | "Import keys in the OpenPGP armor format in the current buffer. | ||
| 170 | The buffer is expected to contain a mail message. | ||
| 171 | |||
| 172 | Don't use this command in Lisp programs!" | ||
| 173 | (interactive) | ||
| 174 | (epa-import-armor-in-region (point-min) (point-max))) | ||
| 175 | |||
| 176 | (provide 'epa-mail) | ||
| 177 | |||
| 178 | ;;; epa-mail.el ends here | ||
diff --git a/lisp/epa-setup.el b/lisp/epa-setup.el new file mode 100644 index 00000000000..8737fed4a52 --- /dev/null +++ b/lisp/epa-setup.el | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | ;;; epa-setup.el --- setup routine for the EasyPG Assistant. | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (autoload 'epa-list-keys "epa") | ||
| 27 | |||
| 28 | (autoload 'epa-dired-mode-hook "epa-dired") | ||
| 29 | (add-hook 'dired-mode-hook 'epa-dired-mode-hook) | ||
| 30 | |||
| 31 | (require 'epa-file) | ||
| 32 | (epa-file-enable) | ||
| 33 | |||
| 34 | (autoload 'epa-mail-mode "epa-mail") | ||
| 35 | (add-hook 'mail-mode-hook 'epa-mail-mode) | ||
| 36 | |||
| 37 | (provide 'epa-setup) | ||
| 38 | |||
| 39 | ;;; epa-setup.el ends here | ||
diff --git a/lisp/epa.el b/lisp/epa.el new file mode 100644 index 00000000000..700a41f36f6 --- /dev/null +++ b/lisp/epa.el | |||
| @@ -0,0 +1,1176 @@ | |||
| 1 | ;;; epa.el --- the EasyPG Assistant | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'epg) | ||
| 27 | (require 'font-lock) | ||
| 28 | (require 'widget) | ||
| 29 | (eval-when-compile (require 'wid-edit)) | ||
| 30 | (require 'derived) | ||
| 31 | |||
| 32 | (defgroup epa nil | ||
| 33 | "The EasyPG Assistant" | ||
| 34 | :group 'epg) | ||
| 35 | |||
| 36 | (defcustom epa-popup-info-window t | ||
| 37 | "If non-nil, status information from epa commands is displayed on | ||
| 38 | the separate window." | ||
| 39 | :type 'boolean | ||
| 40 | :group 'epa) | ||
| 41 | |||
| 42 | (defcustom epa-info-window-height 5 | ||
| 43 | "Number of lines used to display status information." | ||
| 44 | :type 'integer | ||
| 45 | :group 'epa) | ||
| 46 | |||
| 47 | (defgroup epa-faces nil | ||
| 48 | "Faces for epa-mode." | ||
| 49 | :group 'epa) | ||
| 50 | |||
| 51 | (defface epa-validity-high | ||
| 52 | `((((class color) (background dark)) | ||
| 53 | (:foreground "PaleTurquoise" | ||
| 54 | ,@(if (assq ':weight custom-face-attributes) | ||
| 55 | '(:weight bold) | ||
| 56 | '(:bold t)))) | ||
| 57 | (t | ||
| 58 | (,@(if (assq ':weight custom-face-attributes) | ||
| 59 | '(:weight bold) | ||
| 60 | '(:bold t))))) | ||
| 61 | "Face used for displaying the high validity." | ||
| 62 | :group 'epa-faces) | ||
| 63 | |||
| 64 | (defface epa-validity-medium | ||
| 65 | `((((class color) (background dark)) | ||
| 66 | (:foreground "PaleTurquoise" | ||
| 67 | ,@(if (assq ':slant custom-face-attributes) | ||
| 68 | '(:slant italic) | ||
| 69 | '(:italic t)))) | ||
| 70 | (t | ||
| 71 | (,@(if (assq ':slant custom-face-attributes) | ||
| 72 | '(:slant italic) | ||
| 73 | '(:italic t))))) | ||
| 74 | "Face used for displaying the medium validity." | ||
| 75 | :group 'epa-faces) | ||
| 76 | |||
| 77 | (defface epa-validity-low | ||
| 78 | `((t | ||
| 79 | (,@(if (assq ':slant custom-face-attributes) | ||
| 80 | '(:slant italic) | ||
| 81 | '(:italic t))))) | ||
| 82 | "Face used for displaying the low validity." | ||
| 83 | :group 'epa-faces) | ||
| 84 | |||
| 85 | (defface epa-validity-disabled | ||
| 86 | `((t | ||
| 87 | (,@(if (assq ':slant custom-face-attributes) | ||
| 88 | '(:slant italic) | ||
| 89 | '(:italic t)) | ||
| 90 | :inverse-video t))) | ||
| 91 | "Face used for displaying the disabled validity." | ||
| 92 | :group 'epa-faces) | ||
| 93 | |||
| 94 | (defface epa-string | ||
| 95 | '((((class color) (background dark)) | ||
| 96 | (:foreground "lightyellow")) | ||
| 97 | (((class color) (background light)) | ||
| 98 | (:foreground "blue4"))) | ||
| 99 | "Face used for displaying the string." | ||
| 100 | :group 'epa-faces) | ||
| 101 | |||
| 102 | (defface epa-mark | ||
| 103 | `((((class color) (background dark)) | ||
| 104 | (:foreground "orange" | ||
| 105 | ,@(if (assq ':weight custom-face-attributes) | ||
| 106 | '(:weight bold) | ||
| 107 | '(:bold t)))) | ||
| 108 | (((class color) (background light)) | ||
| 109 | (:foreground "red" | ||
| 110 | ,@(if (assq ':weight custom-face-attributes) | ||
| 111 | '(:weight bold) | ||
| 112 | '(:bold t)))) | ||
| 113 | (t | ||
| 114 | (,@(if (assq ':weight custom-face-attributes) | ||
| 115 | '(:weight bold) | ||
| 116 | '(:bold t))))) | ||
| 117 | "Face used for displaying the high validity." | ||
| 118 | :group 'epa-faces) | ||
| 119 | |||
| 120 | (defface epa-field-name | ||
| 121 | `((((class color) (background dark)) | ||
| 122 | (:foreground "PaleTurquoise" | ||
| 123 | ,@(if (assq ':weight custom-face-attributes) | ||
| 124 | '(:weight bold) | ||
| 125 | '(:bold t)))) | ||
| 126 | (t | ||
| 127 | (,@(if (assq ':weight custom-face-attributes) | ||
| 128 | '(:weight bold) | ||
| 129 | '(:bold t))))) | ||
| 130 | "Face for the name of the attribute field." | ||
| 131 | :group 'epa) | ||
| 132 | |||
| 133 | (defface epa-field-body | ||
| 134 | `((((class color) (background dark)) | ||
| 135 | (:foreground "turquoise" | ||
| 136 | ,@(if (assq ':slant custom-face-attributes) | ||
| 137 | '(:slant italic) | ||
| 138 | '(:italic t)))) | ||
| 139 | (t | ||
| 140 | (,@(if (assq ':slant custom-face-attributes) | ||
| 141 | '(:slant italic) | ||
| 142 | '(:italic t))))) | ||
| 143 | "Face for the body of the attribute field." | ||
| 144 | :group 'epa) | ||
| 145 | |||
| 146 | (defcustom epa-validity-face-alist | ||
| 147 | '((unknown . epa-validity-disabled) | ||
| 148 | (invalid . epa-validity-disabled) | ||
| 149 | (disabled . epa-validity-disabled) | ||
| 150 | (revoked . epa-validity-disabled) | ||
| 151 | (expired . epa-validity-disabled) | ||
| 152 | (none . epa-validity-low) | ||
| 153 | (undefined . epa-validity-low) | ||
| 154 | (never . epa-validity-low) | ||
| 155 | (marginal . epa-validity-medium) | ||
| 156 | (full . epa-validity-high) | ||
| 157 | (ultimate . epa-validity-high)) | ||
| 158 | "An alist mapping validity values to faces." | ||
| 159 | :type '(repeat (cons symbol face)) | ||
| 160 | :group 'epa) | ||
| 161 | |||
| 162 | (defvar epa-font-lock-keywords | ||
| 163 | '(("^\\*" | ||
| 164 | (0 'epa-mark)) | ||
| 165 | ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$" | ||
| 166 | (1 'epa-field-name) | ||
| 167 | (2 'epa-field-body))) | ||
| 168 | "Default expressions to addon in epa-mode.") | ||
| 169 | |||
| 170 | (defconst epa-pubkey-algorithm-letter-alist | ||
| 171 | '((1 . ?R) | ||
| 172 | (2 . ?r) | ||
| 173 | (3 . ?s) | ||
| 174 | (16 . ?g) | ||
| 175 | (17 . ?D) | ||
| 176 | (20 . ?G))) | ||
| 177 | |||
| 178 | (defvar epa-protocol 'OpenPGP | ||
| 179 | "*The default protocol. | ||
| 180 | The value can be either OpenPGP or CMS. | ||
| 181 | |||
| 182 | You should bind this variable with `let', but do not set it globally.") | ||
| 183 | |||
| 184 | (defvar epa-armor nil | ||
| 185 | "*If non-nil, epa commands create ASCII armored output. | ||
| 186 | |||
| 187 | You should bind this variable with `let', but do not set it globally.") | ||
| 188 | |||
| 189 | (defvar epa-textmode nil | ||
| 190 | "*If non-nil, epa commands treat input files as text. | ||
| 191 | |||
| 192 | You should bind this variable with `let', but do not set it globally.") | ||
| 193 | |||
| 194 | (defvar epa-keys-buffer nil) | ||
| 195 | (defvar epa-key-buffer-alist nil) | ||
| 196 | (defvar epa-key nil) | ||
| 197 | (defvar epa-list-keys-arguments nil) | ||
| 198 | (defvar epa-info-buffer nil) | ||
| 199 | (defvar epa-last-coding-system-specified nil) | ||
| 200 | |||
| 201 | (defvar epa-key-list-mode-map | ||
| 202 | (let ((keymap (make-sparse-keymap))) | ||
| 203 | (define-key keymap "m" 'epa-mark-key) | ||
| 204 | (define-key keymap "u" 'epa-unmark-key) | ||
| 205 | (define-key keymap "d" 'epa-decrypt-file) | ||
| 206 | (define-key keymap "v" 'epa-verify-file) | ||
| 207 | (define-key keymap "s" 'epa-sign-file) | ||
| 208 | (define-key keymap "e" 'epa-encrypt-file) | ||
| 209 | (define-key keymap "r" 'epa-delete-keys) | ||
| 210 | (define-key keymap "i" 'epa-import-keys) | ||
| 211 | (define-key keymap "o" 'epa-export-keys) | ||
| 212 | (define-key keymap "g" 'revert-buffer) | ||
| 213 | (define-key keymap "n" 'next-line) | ||
| 214 | (define-key keymap "p" 'previous-line) | ||
| 215 | (define-key keymap " " 'scroll-up) | ||
| 216 | (define-key keymap [delete] 'scroll-down) | ||
| 217 | (define-key keymap "q" 'epa-exit-buffer) | ||
| 218 | keymap)) | ||
| 219 | |||
| 220 | (defvar epa-key-mode-map | ||
| 221 | (let ((keymap (make-sparse-keymap))) | ||
| 222 | (define-key keymap "q" 'epa-exit-buffer) | ||
| 223 | keymap)) | ||
| 224 | |||
| 225 | (defvar epa-info-mode-map | ||
| 226 | (let ((keymap (make-sparse-keymap))) | ||
| 227 | (define-key keymap "q" 'delete-window) | ||
| 228 | keymap)) | ||
| 229 | |||
| 230 | (defvar epa-exit-buffer-function #'bury-buffer) | ||
| 231 | |||
| 232 | (define-widget 'epa-key 'push-button | ||
| 233 | "Button for representing a epg-key object." | ||
| 234 | :format "%[%v%]" | ||
| 235 | :button-face-get 'epa--key-widget-button-face-get | ||
| 236 | :value-create 'epa--key-widget-value-create | ||
| 237 | :action 'epa--key-widget-action | ||
| 238 | :help-echo 'epa--key-widget-help-echo) | ||
| 239 | |||
| 240 | (defun epa--key-widget-action (widget &optional event) | ||
| 241 | (epa--show-key (widget-get widget :value))) | ||
| 242 | |||
| 243 | (defun epa--key-widget-value-create (widget) | ||
| 244 | (let* ((key (widget-get widget :value)) | ||
| 245 | (primary-sub-key (car (epg-key-sub-key-list key))) | ||
| 246 | (primary-user-id (car (epg-key-user-id-list key)))) | ||
| 247 | (insert (format "%c " | ||
| 248 | (if (epg-sub-key-validity primary-sub-key) | ||
| 249 | (car (rassq (epg-sub-key-validity primary-sub-key) | ||
| 250 | epg-key-validity-alist)) | ||
| 251 | ? )) | ||
| 252 | (epg-sub-key-id primary-sub-key) | ||
| 253 | " " | ||
| 254 | (if primary-user-id | ||
| 255 | (if (stringp (epg-user-id-string primary-user-id)) | ||
| 256 | (epg-user-id-string primary-user-id) | ||
| 257 | (epg-decode-dn (epg-user-id-string primary-user-id))) | ||
| 258 | "")))) | ||
| 259 | |||
| 260 | (defun epa--key-widget-button-face-get (widget) | ||
| 261 | (let ((validity (epg-sub-key-validity (car (epg-key-sub-key-list | ||
| 262 | (widget-get widget :value)))))) | ||
| 263 | (if validity | ||
| 264 | (cdr (assq validity epa-validity-face-alist)) | ||
| 265 | 'default))) | ||
| 266 | |||
| 267 | (defun epa--key-widget-help-echo (widget) | ||
| 268 | (format "Show %s" | ||
| 269 | (epg-sub-key-id (car (epg-key-sub-key-list | ||
| 270 | (widget-get widget :value)))))) | ||
| 271 | |||
| 272 | (eval-and-compile | ||
| 273 | (if (fboundp 'encode-coding-string) | ||
| 274 | (defalias 'epa--encode-coding-string 'encode-coding-string) | ||
| 275 | (defalias 'epa--encode-coding-string 'identity))) | ||
| 276 | |||
| 277 | (eval-and-compile | ||
| 278 | (if (fboundp 'decode-coding-string) | ||
| 279 | (defalias 'epa--decode-coding-string 'decode-coding-string) | ||
| 280 | (defalias 'epa--decode-coding-string 'identity))) | ||
| 281 | |||
| 282 | (defun epa-key-list-mode () | ||
| 283 | "Major mode for `epa-list-keys'." | ||
| 284 | (kill-all-local-variables) | ||
| 285 | (buffer-disable-undo) | ||
| 286 | (setq major-mode 'epa-key-list-mode | ||
| 287 | mode-name "Keys" | ||
| 288 | truncate-lines t | ||
| 289 | buffer-read-only t) | ||
| 290 | (use-local-map epa-key-list-mode-map) | ||
| 291 | (make-local-variable 'font-lock-defaults) | ||
| 292 | (setq font-lock-defaults '(epa-font-lock-keywords t)) | ||
| 293 | ;; In XEmacs, auto-initialization of font-lock is not effective | ||
| 294 | ;; if buffer-file-name is not set. | ||
| 295 | (font-lock-set-defaults) | ||
| 296 | (make-local-variable 'epa-exit-buffer-function) | ||
| 297 | (make-local-variable 'revert-buffer-function) | ||
| 298 | (setq revert-buffer-function 'epa--key-list-revert-buffer) | ||
| 299 | (run-hooks 'epa-key-list-mode-hook)) | ||
| 300 | |||
| 301 | (defun epa-key-mode () | ||
| 302 | "Major mode for a key description." | ||
| 303 | (kill-all-local-variables) | ||
| 304 | (buffer-disable-undo) | ||
| 305 | (setq major-mode 'epa-key-mode | ||
| 306 | mode-name "Key" | ||
| 307 | truncate-lines t | ||
| 308 | buffer-read-only t) | ||
| 309 | (use-local-map epa-key-mode-map) | ||
| 310 | (make-local-variable 'font-lock-defaults) | ||
| 311 | (setq font-lock-defaults '(epa-font-lock-keywords t)) | ||
| 312 | ;; In XEmacs, auto-initialization of font-lock is not effective | ||
| 313 | ;; if buffer-file-name is not set. | ||
| 314 | (font-lock-set-defaults) | ||
| 315 | (make-local-variable 'epa-exit-buffer-function) | ||
| 316 | (run-hooks 'epa-key-mode-hook)) | ||
| 317 | |||
| 318 | (defun epa-info-mode () | ||
| 319 | "Major mode for `epa-info-buffer'." | ||
| 320 | (kill-all-local-variables) | ||
| 321 | (buffer-disable-undo) | ||
| 322 | (setq major-mode 'epa-info-mode | ||
| 323 | mode-name "Info" | ||
| 324 | truncate-lines t | ||
| 325 | buffer-read-only t) | ||
| 326 | (use-local-map epa-info-mode-map) | ||
| 327 | (run-hooks 'epa-info-mode-hook)) | ||
| 328 | |||
| 329 | (defun epa-mark-key (&optional arg) | ||
| 330 | "Mark a key on the current line. | ||
| 331 | If ARG is non-nil, unmark the key." | ||
| 332 | (interactive "P") | ||
| 333 | (let ((inhibit-read-only t) | ||
| 334 | buffer-read-only | ||
| 335 | properties) | ||
| 336 | (beginning-of-line) | ||
| 337 | (unless (get-text-property (point) 'epa-key) | ||
| 338 | (error "No key on this line")) | ||
| 339 | (setq properties (text-properties-at (point))) | ||
| 340 | (delete-char 1) | ||
| 341 | (insert (if arg " " "*")) | ||
| 342 | (set-text-properties (1- (point)) (point) properties) | ||
| 343 | (forward-line))) | ||
| 344 | |||
| 345 | (defun epa-unmark-key (&optional arg) | ||
| 346 | "Unmark a key on the current line. | ||
| 347 | If ARG is non-nil, mark the key." | ||
| 348 | (interactive "P") | ||
| 349 | (epa-mark-key (not arg))) | ||
| 350 | |||
| 351 | (defun epa-exit-buffer () | ||
| 352 | "Exit the current buffer. | ||
| 353 | `epa-exit-buffer-function' is called if it is set." | ||
| 354 | (interactive) | ||
| 355 | (funcall epa-exit-buffer-function)) | ||
| 356 | |||
| 357 | (defun epa--insert-keys (keys) | ||
| 358 | (save-excursion | ||
| 359 | (save-restriction | ||
| 360 | (narrow-to-region (point) (point)) | ||
| 361 | (let (point) | ||
| 362 | (while keys | ||
| 363 | (setq point (point)) | ||
| 364 | (insert " ") | ||
| 365 | (add-text-properties point (point) | ||
| 366 | (list 'epa-key (car keys) | ||
| 367 | 'front-sticky nil | ||
| 368 | 'rear-nonsticky t | ||
| 369 | 'start-open t | ||
| 370 | 'end-open t)) | ||
| 371 | (widget-create 'epa-key :value (car keys)) | ||
| 372 | (insert "\n") | ||
| 373 | (setq keys (cdr keys)))) | ||
| 374 | (add-text-properties (point-min) (point-max) | ||
| 375 | (list 'epa-list-keys t | ||
| 376 | 'front-sticky nil | ||
| 377 | 'rear-nonsticky t | ||
| 378 | 'start-open t | ||
| 379 | 'end-open t))))) | ||
| 380 | |||
| 381 | (defun epa--list-keys (name secret) | ||
| 382 | (unless (and epa-keys-buffer | ||
| 383 | (buffer-live-p epa-keys-buffer)) | ||
| 384 | (setq epa-keys-buffer (generate-new-buffer "*Keys*"))) | ||
| 385 | (set-buffer epa-keys-buffer) | ||
| 386 | (epa-key-list-mode) | ||
| 387 | (let ((inhibit-read-only t) | ||
| 388 | buffer-read-only | ||
| 389 | (point (point-min)) | ||
| 390 | (context (epg-make-context epa-protocol))) | ||
| 391 | (unless (get-text-property point 'epa-list-keys) | ||
| 392 | (setq point (next-single-property-change point 'epa-list-keys))) | ||
| 393 | (when point | ||
| 394 | (delete-region point | ||
| 395 | (or (next-single-property-change point 'epa-list-keys) | ||
| 396 | (point-max))) | ||
| 397 | (goto-char point)) | ||
| 398 | (epa--insert-keys (epg-list-keys context name secret)) | ||
| 399 | (widget-setup) | ||
| 400 | (set-keymap-parent (current-local-map) widget-keymap)) | ||
| 401 | (make-local-variable 'epa-list-keys-arguments) | ||
| 402 | (setq epa-list-keys-arguments (list name secret)) | ||
| 403 | (goto-char (point-min)) | ||
| 404 | (pop-to-buffer (current-buffer))) | ||
| 405 | |||
| 406 | ;;;###autoload | ||
| 407 | (defun epa-list-keys (&optional name) | ||
| 408 | "List all keys matched with NAME from the public keyring." | ||
| 409 | (interactive | ||
| 410 | (if current-prefix-arg | ||
| 411 | (let ((name (read-string "Pattern: " | ||
| 412 | (if epa-list-keys-arguments | ||
| 413 | (car epa-list-keys-arguments))))) | ||
| 414 | (list (if (equal name "") nil name))) | ||
| 415 | (list nil))) | ||
| 416 | (epa--list-keys name nil)) | ||
| 417 | |||
| 418 | ;;;###autoload | ||
| 419 | (defun epa-list-secret-keys (&optional name) | ||
| 420 | "List all keys matched with NAME from the private keyring." | ||
| 421 | (interactive | ||
| 422 | (if current-prefix-arg | ||
| 423 | (let ((name (read-string "Pattern: " | ||
| 424 | (if epa-list-keys-arguments | ||
| 425 | (car epa-list-keys-arguments))))) | ||
| 426 | (list (if (equal name "") nil name))) | ||
| 427 | (list nil))) | ||
| 428 | (epa--list-keys name t)) | ||
| 429 | |||
| 430 | (defun epa--key-list-revert-buffer (&optional ignore-auto noconfirm) | ||
| 431 | (apply #'epa--list-keys epa-list-keys-arguments)) | ||
| 432 | |||
| 433 | (defun epa--marked-keys () | ||
| 434 | (or (save-excursion | ||
| 435 | (set-buffer epa-keys-buffer) | ||
| 436 | (goto-char (point-min)) | ||
| 437 | (let (keys key) | ||
| 438 | (while (re-search-forward "^\\*" nil t) | ||
| 439 | (if (setq key (get-text-property (match-beginning 0) | ||
| 440 | 'epa-key)) | ||
| 441 | (setq keys (cons key keys)))) | ||
| 442 | (nreverse keys))) | ||
| 443 | (save-excursion | ||
| 444 | (beginning-of-line) | ||
| 445 | (let ((key (get-text-property (point) 'epa-key))) | ||
| 446 | (if key | ||
| 447 | (list key)))))) | ||
| 448 | |||
| 449 | (defun epa--select-keys (prompt keys) | ||
| 450 | (save-excursion | ||
| 451 | (unless (and epa-keys-buffer | ||
| 452 | (buffer-live-p epa-keys-buffer)) | ||
| 453 | (setq epa-keys-buffer (generate-new-buffer "*Keys*"))) | ||
| 454 | (set-buffer epa-keys-buffer) | ||
| 455 | (epa-key-list-mode) | ||
| 456 | (let ((inhibit-read-only t) | ||
| 457 | buffer-read-only) | ||
| 458 | (erase-buffer) | ||
| 459 | (insert prompt "\n" | ||
| 460 | (substitute-command-keys "\ | ||
| 461 | - `\\[epa-mark-key]' to mark a key on the line | ||
| 462 | - `\\[epa-unmark-key]' to unmark a key on the line\n")) | ||
| 463 | (widget-create 'link | ||
| 464 | :notify (lambda (&rest ignore) (abort-recursive-edit)) | ||
| 465 | :help-echo | ||
| 466 | (substitute-command-keys | ||
| 467 | "Click here or \\[abort-recursive-edit] to cancel") | ||
| 468 | "Cancel") | ||
| 469 | (widget-create 'link | ||
| 470 | :notify (lambda (&rest ignore) (exit-recursive-edit)) | ||
| 471 | :help-echo | ||
| 472 | (substitute-command-keys | ||
| 473 | "Click here or \\[exit-recursive-edit] to finish") | ||
| 474 | "OK") | ||
| 475 | (insert "\n\n") | ||
| 476 | (epa--insert-keys keys) | ||
| 477 | (widget-setup) | ||
| 478 | (set-keymap-parent (current-local-map) widget-keymap) | ||
| 479 | (setq epa-exit-buffer-function #'abort-recursive-edit) | ||
| 480 | (goto-char (point-min)) | ||
| 481 | (pop-to-buffer (current-buffer))) | ||
| 482 | (unwind-protect | ||
| 483 | (progn | ||
| 484 | (recursive-edit) | ||
| 485 | (epa--marked-keys)) | ||
| 486 | (if (get-buffer-window epa-keys-buffer) | ||
| 487 | (delete-window (get-buffer-window epa-keys-buffer))) | ||
| 488 | (kill-buffer epa-keys-buffer)))) | ||
| 489 | |||
| 490 | ;;;###autoload | ||
| 491 | (defun epa-select-keys (context prompt &optional names secret) | ||
| 492 | "Display a user's keyring and ask him to select keys. | ||
| 493 | CONTEXT is an epg-context. | ||
| 494 | PROMPT is a string to prompt with. | ||
| 495 | NAMES is a list of strings to be matched with keys. If it is nil, all | ||
| 496 | the keys are listed. | ||
| 497 | If SECRET is non-nil, list secret keys instead of public keys." | ||
| 498 | (let ((keys (epg-list-keys context names secret))) | ||
| 499 | (if (> (length keys) 1) | ||
| 500 | (epa--select-keys prompt keys) | ||
| 501 | keys))) | ||
| 502 | |||
| 503 | (defun epa--show-key (key) | ||
| 504 | (let* ((primary-sub-key (car (epg-key-sub-key-list key))) | ||
| 505 | (entry (assoc (epg-sub-key-id primary-sub-key) | ||
| 506 | epa-key-buffer-alist)) | ||
| 507 | (inhibit-read-only t) | ||
| 508 | buffer-read-only | ||
| 509 | pointer) | ||
| 510 | (unless entry | ||
| 511 | (setq entry (cons (epg-sub-key-id primary-sub-key) nil) | ||
| 512 | epa-key-buffer-alist (cons entry epa-key-buffer-alist))) | ||
| 513 | (unless (and (cdr entry) | ||
| 514 | (buffer-live-p (cdr entry))) | ||
| 515 | (setcdr entry (generate-new-buffer | ||
| 516 | (format "*Key*%s" (epg-sub-key-id primary-sub-key))))) | ||
| 517 | (set-buffer (cdr entry)) | ||
| 518 | (epa-key-mode) | ||
| 519 | (make-local-variable 'epa-key) | ||
| 520 | (setq epa-key key) | ||
| 521 | (erase-buffer) | ||
| 522 | (setq pointer (epg-key-user-id-list key)) | ||
| 523 | (while pointer | ||
| 524 | (if (car pointer) | ||
| 525 | (insert " " | ||
| 526 | (if (epg-user-id-validity (car pointer)) | ||
| 527 | (char-to-string | ||
| 528 | (car (rassq (epg-user-id-validity (car pointer)) | ||
| 529 | epg-key-validity-alist))) | ||
| 530 | " ") | ||
| 531 | " " | ||
| 532 | (if (stringp (epg-user-id-string (car pointer))) | ||
| 533 | (epg-user-id-string (car pointer)) | ||
| 534 | (epg-decode-dn (epg-user-id-string (car pointer)))) | ||
| 535 | "\n")) | ||
| 536 | (setq pointer (cdr pointer))) | ||
| 537 | (setq pointer (epg-key-sub-key-list key)) | ||
| 538 | (while pointer | ||
| 539 | (insert " " | ||
| 540 | (if (epg-sub-key-validity (car pointer)) | ||
| 541 | (char-to-string | ||
| 542 | (car (rassq (epg-sub-key-validity (car pointer)) | ||
| 543 | epg-key-validity-alist))) | ||
| 544 | " ") | ||
| 545 | " " | ||
| 546 | (epg-sub-key-id (car pointer)) | ||
| 547 | " " | ||
| 548 | (format "%dbits" | ||
| 549 | (epg-sub-key-length (car pointer))) | ||
| 550 | " " | ||
| 551 | (cdr (assq (epg-sub-key-algorithm (car pointer)) | ||
| 552 | epg-pubkey-algorithm-alist)) | ||
| 553 | "\n\tCreated: " | ||
| 554 | (condition-case nil | ||
| 555 | (format-time-string "%Y-%m-%d" | ||
| 556 | (epg-sub-key-creation-time (car pointer))) | ||
| 557 | (error "????-??-??")) | ||
| 558 | (if (epg-sub-key-expiration-time (car pointer)) | ||
| 559 | (format "\n\tExpires: %s" | ||
| 560 | (condition-case nil | ||
| 561 | (format-time-string "%Y-%m-%d" | ||
| 562 | (epg-sub-key-expiration-time | ||
| 563 | (car pointer))) | ||
| 564 | (error "????-??-??"))) | ||
| 565 | "") | ||
| 566 | "\n\tCapabilities: " | ||
| 567 | (mapconcat #'symbol-name | ||
| 568 | (epg-sub-key-capability (car pointer)) | ||
| 569 | " ") | ||
| 570 | "\n\tFingerprint: " | ||
| 571 | (epg-sub-key-fingerprint (car pointer)) | ||
| 572 | "\n") | ||
| 573 | (setq pointer (cdr pointer))) | ||
| 574 | (goto-char (point-min)) | ||
| 575 | (pop-to-buffer (current-buffer)))) | ||
| 576 | |||
| 577 | (defun epa-display-info (info) | ||
| 578 | (if epa-popup-info-window | ||
| 579 | (save-selected-window | ||
| 580 | (unless (and epa-info-buffer (buffer-live-p epa-info-buffer)) | ||
| 581 | (setq epa-info-buffer (generate-new-buffer "*Info*"))) | ||
| 582 | (if (get-buffer-window epa-info-buffer) | ||
| 583 | (delete-window (get-buffer-window epa-info-buffer))) | ||
| 584 | (save-excursion | ||
| 585 | (set-buffer epa-info-buffer) | ||
| 586 | (let ((inhibit-read-only t) | ||
| 587 | buffer-read-only) | ||
| 588 | (erase-buffer) | ||
| 589 | (insert info)) | ||
| 590 | (epa-info-mode) | ||
| 591 | (goto-char (point-min))) | ||
| 592 | (if (> (window-height) | ||
| 593 | epa-info-window-height) | ||
| 594 | (set-window-buffer (split-window nil (- (window-height) | ||
| 595 | epa-info-window-height)) | ||
| 596 | epa-info-buffer) | ||
| 597 | (pop-to-buffer epa-info-buffer) | ||
| 598 | (if (> (window-height) epa-info-window-height) | ||
| 599 | (shrink-window (- (window-height) epa-info-window-height))))) | ||
| 600 | (message "%s" info))) | ||
| 601 | |||
| 602 | (defun epa-display-verify-result (verify-result) | ||
| 603 | (epa-display-info (epg-verify-result-to-string verify-result))) | ||
| 604 | (make-obsolete 'epa-display-verify-result 'epa-display-info) | ||
| 605 | |||
| 606 | (defun epa-passphrase-callback-function (context key-id handback) | ||
| 607 | (if (eq key-id 'SYM) | ||
| 608 | (read-passwd "Passphrase for symmetric encryption: " | ||
| 609 | (eq (epg-context-operation context) 'encrypt)) | ||
| 610 | (read-passwd | ||
| 611 | (if (eq key-id 'PIN) | ||
| 612 | "Passphrase for PIN: " | ||
| 613 | (let ((entry (assoc key-id epg-user-id-alist))) | ||
| 614 | (if entry | ||
| 615 | (format "Passphrase for %s %s: " key-id (cdr entry)) | ||
| 616 | (format "Passphrase for %s: " key-id))))))) | ||
| 617 | |||
| 618 | (defun epa-progress-callback-function (context what char current total | ||
| 619 | handback) | ||
| 620 | (message "%s%d%% (%d/%d)" (or handback | ||
| 621 | (concat what ": ")) | ||
| 622 | (if (> total 0) (floor (* (/ current (float total)) 100)) 0) | ||
| 623 | current total)) | ||
| 624 | |||
| 625 | ;;;###autoload | ||
| 626 | (defun epa-decrypt-file (file) | ||
| 627 | "Decrypt FILE." | ||
| 628 | (interactive "fFile: ") | ||
| 629 | (setq file (expand-file-name file)) | ||
| 630 | (let* ((default-name (file-name-sans-extension file)) | ||
| 631 | (plain (expand-file-name | ||
| 632 | (read-file-name | ||
| 633 | (concat "To file (default " | ||
| 634 | (file-name-nondirectory default-name) | ||
| 635 | ") ") | ||
| 636 | (file-name-directory default-name) | ||
| 637 | default-name))) | ||
| 638 | (context (epg-make-context epa-protocol))) | ||
| 639 | (epg-context-set-passphrase-callback context | ||
| 640 | #'epa-passphrase-callback-function) | ||
| 641 | (epg-context-set-progress-callback context | ||
| 642 | (cons | ||
| 643 | #'epa-progress-callback-function | ||
| 644 | (format "Decrypting %s..." | ||
| 645 | (file-name-nondirectory file)))) | ||
| 646 | (message "Decrypting %s..." (file-name-nondirectory file)) | ||
| 647 | (epg-decrypt-file context file plain) | ||
| 648 | (message "Decrypting %s...wrote %s" (file-name-nondirectory file) | ||
| 649 | (file-name-nondirectory plain)) | ||
| 650 | (if (epg-context-result-for context 'verify) | ||
| 651 | (epa-display-info (epg-verify-result-to-string | ||
| 652 | (epg-context-result-for context 'verify)))))) | ||
| 653 | |||
| 654 | ;;;###autoload | ||
| 655 | (defun epa-verify-file (file) | ||
| 656 | "Verify FILE." | ||
| 657 | (interactive "fFile: ") | ||
| 658 | (setq file (expand-file-name file)) | ||
| 659 | (let* ((context (epg-make-context epa-protocol)) | ||
| 660 | (plain (if (equal (file-name-extension file) "sig") | ||
| 661 | (file-name-sans-extension file)))) | ||
| 662 | (epg-context-set-progress-callback context | ||
| 663 | (cons | ||
| 664 | #'epa-progress-callback-function | ||
| 665 | (format "Verifying %s..." | ||
| 666 | (file-name-nondirectory file)))) | ||
| 667 | (message "Verifying %s..." (file-name-nondirectory file)) | ||
| 668 | (epg-verify-file context file plain) | ||
| 669 | (message "Verifying %s...done" (file-name-nondirectory file)) | ||
| 670 | (if (epg-context-result-for context 'verify) | ||
| 671 | (epa-display-info (epg-verify-result-to-string | ||
| 672 | (epg-context-result-for context 'verify)))))) | ||
| 673 | |||
| 674 | (defun epa--read-signature-type () | ||
| 675 | (let (type c) | ||
| 676 | (while (null type) | ||
| 677 | (message "Signature type (n,c,d,?) ") | ||
| 678 | (setq c (read-char)) | ||
| 679 | (cond ((eq c ?c) | ||
| 680 | (setq type 'clear)) | ||
| 681 | ((eq c ?d) | ||
| 682 | (setq type 'detached)) | ||
| 683 | ((eq c ??) | ||
| 684 | (with-output-to-temp-buffer "*Help*" | ||
| 685 | (save-excursion | ||
| 686 | (set-buffer standard-output) | ||
| 687 | (insert "\ | ||
| 688 | n - Create a normal signature | ||
| 689 | c - Create a cleartext signature | ||
| 690 | d - Create a detached signature | ||
| 691 | ? - Show this help | ||
| 692 | ")))) | ||
| 693 | (t | ||
| 694 | (setq type 'normal)))))) | ||
| 695 | |||
| 696 | ;;;###autoload | ||
| 697 | (defun epa-sign-file (file signers mode) | ||
| 698 | "Sign FILE by SIGNERS keys selected." | ||
| 699 | (interactive | ||
| 700 | (let ((verbose current-prefix-arg)) | ||
| 701 | (list (expand-file-name (read-file-name "File: ")) | ||
| 702 | (if verbose | ||
| 703 | (epa-select-keys (epg-make-context epa-protocol) | ||
| 704 | "Select keys for signing. | ||
| 705 | If no one is selected, default secret key is used. " | ||
| 706 | nil t)) | ||
| 707 | (if verbose | ||
| 708 | (epa--read-signature-type) | ||
| 709 | 'clear)))) | ||
| 710 | (let ((signature (concat file | ||
| 711 | (if (eq epa-protocol 'OpenPGP) | ||
| 712 | (if (or epa-armor | ||
| 713 | (not (memq mode | ||
| 714 | '(nil t normal detached)))) | ||
| 715 | ".asc" | ||
| 716 | (if (memq mode '(t detached)) | ||
| 717 | ".sig" | ||
| 718 | ".gpg")) | ||
| 719 | (if (memq mode '(t detached)) | ||
| 720 | ".p7s" | ||
| 721 | ".p7m")))) | ||
| 722 | (context (epg-make-context epa-protocol))) | ||
| 723 | (epg-context-set-armor context epa-armor) | ||
| 724 | (epg-context-set-textmode context epa-textmode) | ||
| 725 | (epg-context-set-signers context signers) | ||
| 726 | (epg-context-set-passphrase-callback context | ||
| 727 | #'epa-passphrase-callback-function) | ||
| 728 | (epg-context-set-progress-callback context | ||
| 729 | (cons | ||
| 730 | #'epa-progress-callback-function | ||
| 731 | (format "Signing %s..." | ||
| 732 | (file-name-nondirectory file)))) | ||
| 733 | (message "Signing %s..." (file-name-nondirectory file)) | ||
| 734 | (epg-sign-file context file signature mode) | ||
| 735 | (message "Signing %s...wrote %s" (file-name-nondirectory file) | ||
| 736 | (file-name-nondirectory signature)))) | ||
| 737 | |||
| 738 | ;;;###autoload | ||
| 739 | (defun epa-encrypt-file (file recipients) | ||
| 740 | "Encrypt FILE for RECIPIENTS." | ||
| 741 | (interactive | ||
| 742 | (list (expand-file-name (read-file-name "File: ")) | ||
| 743 | (epa-select-keys (epg-make-context epa-protocol) | ||
| 744 | "Select recipients for encryption. | ||
| 745 | If no one is selected, symmetric encryption will be performed. "))) | ||
| 746 | (let ((cipher (concat file (if (eq epa-protocol 'OpenPGP) | ||
| 747 | (if epa-armor ".asc" ".gpg") | ||
| 748 | ".p7m"))) | ||
| 749 | (context (epg-make-context epa-protocol))) | ||
| 750 | (epg-context-set-armor context epa-armor) | ||
| 751 | (epg-context-set-textmode context epa-textmode) | ||
| 752 | (epg-context-set-passphrase-callback context | ||
| 753 | #'epa-passphrase-callback-function) | ||
| 754 | (epg-context-set-progress-callback context | ||
| 755 | (cons | ||
| 756 | #'epa-progress-callback-function | ||
| 757 | (format "Encrypting %s..." | ||
| 758 | (file-name-nondirectory file)))) | ||
| 759 | (message "Encrypting %s..." (file-name-nondirectory file)) | ||
| 760 | (epg-encrypt-file context file recipients cipher) | ||
| 761 | (message "Encrypting %s...wrote %s" (file-name-nondirectory file) | ||
| 762 | (file-name-nondirectory cipher)))) | ||
| 763 | |||
| 764 | ;;;###autoload | ||
| 765 | (defun epa-decrypt-region (start end) | ||
| 766 | "Decrypt the current region between START and END. | ||
| 767 | |||
| 768 | Don't use this command in Lisp programs!" | ||
| 769 | (interactive "r") | ||
| 770 | (save-excursion | ||
| 771 | (let ((context (epg-make-context epa-protocol)) | ||
| 772 | plain) | ||
| 773 | (epg-context-set-passphrase-callback context | ||
| 774 | #'epa-passphrase-callback-function) | ||
| 775 | (epg-context-set-progress-callback context | ||
| 776 | (cons | ||
| 777 | #'epa-progress-callback-function | ||
| 778 | "Decrypting...")) | ||
| 779 | (message "Decrypting...") | ||
| 780 | (setq plain (epg-decrypt-string context (buffer-substring start end))) | ||
| 781 | (message "Decrypting...done") | ||
| 782 | (setq plain (epa--decode-coding-string | ||
| 783 | plain | ||
| 784 | (or coding-system-for-read | ||
| 785 | (get-text-property start 'epa-coding-system-used)))) | ||
| 786 | (if (y-or-n-p "Replace the original text? ") | ||
| 787 | (let ((inhibit-read-only t) | ||
| 788 | buffer-read-only) | ||
| 789 | (delete-region start end) | ||
| 790 | (goto-char start) | ||
| 791 | (insert plain)) | ||
| 792 | (with-output-to-temp-buffer "*Temp*" | ||
| 793 | (set-buffer standard-output) | ||
| 794 | (insert plain) | ||
| 795 | (epa-info-mode))) | ||
| 796 | (if (epg-context-result-for context 'verify) | ||
| 797 | (epa-display-info (epg-verify-result-to-string | ||
| 798 | (epg-context-result-for context 'verify))))))) | ||
| 799 | |||
| 800 | (defun epa--find-coding-system-for-mime-charset (mime-charset) | ||
| 801 | (if (featurep 'xemacs) | ||
| 802 | (if (fboundp 'find-coding-system) | ||
| 803 | (find-coding-system mime-charset)) | ||
| 804 | (let ((pointer (coding-system-list))) | ||
| 805 | (while (and pointer | ||
| 806 | (eq (coding-system-get (car pointer) 'mime-charset) | ||
| 807 | mime-charset)) | ||
| 808 | (setq pointer (cdr pointer))) | ||
| 809 | pointer))) | ||
| 810 | |||
| 811 | ;;;###autoload | ||
| 812 | (defun epa-decrypt-armor-in-region (start end) | ||
| 813 | "Decrypt OpenPGP armors in the current region between START and END. | ||
| 814 | |||
| 815 | Don't use this command in Lisp programs!" | ||
| 816 | (interactive "r") | ||
| 817 | (save-excursion | ||
| 818 | (save-restriction | ||
| 819 | (narrow-to-region start end) | ||
| 820 | (goto-char start) | ||
| 821 | (let (armor-start armor-end) | ||
| 822 | (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t) | ||
| 823 | (setq armor-start (match-beginning 0) | ||
| 824 | armor-end (re-search-forward "^-----END PGP MESSAGE-----$" | ||
| 825 | nil t)) | ||
| 826 | (unless armor-end | ||
| 827 | (error "No armor tail")) | ||
| 828 | (goto-char armor-start) | ||
| 829 | (let ((coding-system-for-read | ||
| 830 | (or coding-system-for-read | ||
| 831 | (if (re-search-forward "^Charset: \\(.*\\)" armor-end t) | ||
| 832 | (epa--find-coding-system-for-mime-charset | ||
| 833 | (intern (downcase (match-string 1)))))))) | ||
| 834 | (goto-char armor-end) | ||
| 835 | (epa-decrypt-region armor-start armor-end))))))) | ||
| 836 | |||
| 837 | ;;;###autoload | ||
| 838 | (defun epa-verify-region (start end) | ||
| 839 | "Verify the current region between START and END. | ||
| 840 | |||
| 841 | Don't use this command in Lisp programs!" | ||
| 842 | (interactive "r") | ||
| 843 | (let ((context (epg-make-context epa-protocol)) | ||
| 844 | plain) | ||
| 845 | (epg-context-set-progress-callback context | ||
| 846 | (cons | ||
| 847 | #'epa-progress-callback-function | ||
| 848 | "Verifying...")) | ||
| 849 | (message "Verifying...") | ||
| 850 | (setq plain (epg-verify-string | ||
| 851 | context | ||
| 852 | (epa--encode-coding-string | ||
| 853 | (buffer-substring start end) | ||
| 854 | (or coding-system-for-write | ||
| 855 | (get-text-property start 'epa-coding-system-used))))) | ||
| 856 | (message "Verifying...done") | ||
| 857 | (setq plain (epa--decode-coding-string | ||
| 858 | plain | ||
| 859 | (or coding-system-for-read | ||
| 860 | (get-text-property start 'epa-coding-system-used)))) | ||
| 861 | (if (y-or-n-p "Replace the original text? ") | ||
| 862 | (let ((inhibit-read-only t) | ||
| 863 | buffer-read-only) | ||
| 864 | (delete-region start end) | ||
| 865 | (goto-char start) | ||
| 866 | (insert plain)) | ||
| 867 | (with-output-to-temp-buffer "*Temp*" | ||
| 868 | (set-buffer standard-output) | ||
| 869 | (insert plain) | ||
| 870 | (epa-info-mode))) | ||
| 871 | (if (epg-context-result-for context 'verify) | ||
| 872 | (epa-display-info (epg-verify-result-to-string | ||
| 873 | (epg-context-result-for context 'verify)))))) | ||
| 874 | |||
| 875 | ;;;###autoload | ||
| 876 | (defun epa-verify-cleartext-in-region (start end) | ||
| 877 | "Verify OpenPGP cleartext signed messages in the current region | ||
| 878 | between START and END. | ||
| 879 | |||
| 880 | Don't use this command in Lisp programs!" | ||
| 881 | (interactive "r") | ||
| 882 | (save-excursion | ||
| 883 | (save-restriction | ||
| 884 | (narrow-to-region start end) | ||
| 885 | (goto-char start) | ||
| 886 | (let (cleartext-start cleartext-end) | ||
| 887 | (while (re-search-forward "-----BEGIN PGP SIGNED MESSAGE-----$" | ||
| 888 | nil t) | ||
| 889 | (setq cleartext-start (match-beginning 0)) | ||
| 890 | (unless (re-search-forward "^-----BEGIN PGP SIGNATURE-----$" | ||
| 891 | nil t) | ||
| 892 | (error "Invalid cleartext signed message")) | ||
| 893 | (setq cleartext-end (re-search-forward | ||
| 894 | "^-----END PGP SIGNATURE-----$" | ||
| 895 | nil t)) | ||
| 896 | (unless cleartext-end | ||
| 897 | (error "No cleartext tail")) | ||
| 898 | (epa-verify-region cleartext-start cleartext-end)))))) | ||
| 899 | |||
| 900 | (eval-and-compile | ||
| 901 | (if (fboundp 'select-safe-coding-system) | ||
| 902 | (defalias 'epa--select-safe-coding-system 'select-safe-coding-system) | ||
| 903 | (defun epa--select-safe-coding-system (from to) | ||
| 904 | buffer-file-coding-system))) | ||
| 905 | |||
| 906 | ;;;###autoload | ||
| 907 | (defun epa-sign-region (start end signers mode) | ||
| 908 | "Sign the current region between START and END by SIGNERS keys selected. | ||
| 909 | |||
| 910 | Don't use this command in Lisp programs!" | ||
| 911 | (interactive | ||
| 912 | (let ((verbose current-prefix-arg)) | ||
| 913 | (setq epa-last-coding-system-specified | ||
| 914 | (or coding-system-for-write | ||
| 915 | (epa--select-safe-coding-system | ||
| 916 | (region-beginning) (region-end)))) | ||
| 917 | (list (region-beginning) (region-end) | ||
| 918 | (if verbose | ||
| 919 | (epa-select-keys (epg-make-context epa-protocol) | ||
| 920 | "Select keys for signing. | ||
| 921 | If no one is selected, default secret key is used. " | ||
| 922 | nil t)) | ||
| 923 | (if verbose | ||
| 924 | (epa--read-signature-type) | ||
| 925 | 'clear)))) | ||
| 926 | (save-excursion | ||
| 927 | (let ((context (epg-make-context epa-protocol)) | ||
| 928 | signature) | ||
| 929 | ;;(epg-context-set-armor context epa-armor) | ||
| 930 | (epg-context-set-armor context t) | ||
| 931 | ;;(epg-context-set-textmode context epa-textmode) | ||
| 932 | (epg-context-set-textmode context t) | ||
| 933 | (epg-context-set-signers context signers) | ||
| 934 | (epg-context-set-passphrase-callback context | ||
| 935 | #'epa-passphrase-callback-function) | ||
| 936 | (epg-context-set-progress-callback context | ||
| 937 | (cons | ||
| 938 | #'epa-progress-callback-function | ||
| 939 | "Signing...")) | ||
| 940 | (message "Signing...") | ||
| 941 | (setq signature (epg-sign-string context | ||
| 942 | (epa--encode-coding-string | ||
| 943 | (buffer-substring start end) | ||
| 944 | epa-last-coding-system-specified) | ||
| 945 | mode)) | ||
| 946 | (message "Signing...done") | ||
| 947 | (delete-region start end) | ||
| 948 | (goto-char start) | ||
| 949 | (add-text-properties (point) | ||
| 950 | (progn | ||
| 951 | (insert (epa--decode-coding-string | ||
| 952 | signature | ||
| 953 | (or coding-system-for-read | ||
| 954 | epa-last-coding-system-specified))) | ||
| 955 | (point)) | ||
| 956 | (list 'epa-coding-system-used | ||
| 957 | epa-last-coding-system-specified | ||
| 958 | 'front-sticky nil | ||
| 959 | 'rear-nonsticky t | ||
| 960 | 'start-open t | ||
| 961 | 'end-open t))))) | ||
| 962 | |||
| 963 | (eval-and-compile | ||
| 964 | (if (fboundp 'derived-mode-p) | ||
| 965 | (defalias 'epa--derived-mode-p 'derived-mode-p) | ||
| 966 | (defun epa--derived-mode-p (&rest modes) | ||
| 967 | "Non-nil if the current major mode is derived from one of MODES. | ||
| 968 | Uses the `derived-mode-parent' property of the symbol to trace backwards." | ||
| 969 | (let ((parent major-mode)) | ||
| 970 | (while (and (not (memq parent modes)) | ||
| 971 | (setq parent (get parent 'derived-mode-parent)))) | ||
| 972 | parent)))) | ||
| 973 | |||
| 974 | ;;;###autoload | ||
| 975 | (defun epa-encrypt-region (start end recipients sign signers) | ||
| 976 | "Encrypt the current region between START and END for RECIPIENTS. | ||
| 977 | |||
| 978 | Don't use this command in Lisp programs!" | ||
| 979 | (interactive | ||
| 980 | (let ((verbose current-prefix-arg) | ||
| 981 | (context (epg-make-context epa-protocol)) | ||
| 982 | sign) | ||
| 983 | (setq epa-last-coding-system-specified | ||
| 984 | (or coding-system-for-write | ||
| 985 | (epa--select-safe-coding-system | ||
| 986 | (region-beginning) (region-end)))) | ||
| 987 | (list (region-beginning) (region-end) | ||
| 988 | (epa-select-keys context | ||
| 989 | "Select recipients for encryption. | ||
| 990 | If no one is selected, symmetric encryption will be performed. ") | ||
| 991 | (setq sign (if verbose (y-or-n-p "Sign? "))) | ||
| 992 | (if sign | ||
| 993 | (epa-select-keys context | ||
| 994 | "Select keys for signing. "))))) | ||
| 995 | (save-excursion | ||
| 996 | (let ((context (epg-make-context epa-protocol)) | ||
| 997 | cipher) | ||
| 998 | ;;(epg-context-set-armor context epa-armor) | ||
| 999 | (epg-context-set-armor context t) | ||
| 1000 | ;;(epg-context-set-textmode context epa-textmode) | ||
| 1001 | (epg-context-set-textmode context t) | ||
| 1002 | (if sign | ||
| 1003 | (epg-context-set-signers context signers)) | ||
| 1004 | (epg-context-set-passphrase-callback context | ||
| 1005 | #'epa-passphrase-callback-function) | ||
| 1006 | (epg-context-set-progress-callback context | ||
| 1007 | (cons | ||
| 1008 | #'epa-progress-callback-function | ||
| 1009 | "Encrypting...")) | ||
| 1010 | (message "Encrypting...") | ||
| 1011 | (setq cipher (epg-encrypt-string context | ||
| 1012 | (epa--encode-coding-string | ||
| 1013 | (buffer-substring start end) | ||
| 1014 | epa-last-coding-system-specified) | ||
| 1015 | recipients | ||
| 1016 | sign)) | ||
| 1017 | (message "Encrypting...done") | ||
| 1018 | (delete-region start end) | ||
| 1019 | (goto-char start) | ||
| 1020 | (add-text-properties (point) | ||
| 1021 | (progn | ||
| 1022 | (insert cipher) | ||
| 1023 | (point)) | ||
| 1024 | (list 'epa-coding-system-used | ||
| 1025 | epa-last-coding-system-specified | ||
| 1026 | 'front-sticky nil | ||
| 1027 | 'rear-nonsticky t | ||
| 1028 | 'start-open t | ||
| 1029 | 'end-open t))))) | ||
| 1030 | |||
| 1031 | ;;;###autoload | ||
| 1032 | (defun epa-delete-keys (keys &optional allow-secret) | ||
| 1033 | "Delete selected KEYS. | ||
| 1034 | |||
| 1035 | Don't use this command in Lisp programs!" | ||
| 1036 | (interactive | ||
| 1037 | (let ((keys (epa--marked-keys))) | ||
| 1038 | (unless keys | ||
| 1039 | (error "No keys selected")) | ||
| 1040 | (list keys | ||
| 1041 | (eq (nth 1 epa-list-keys-arguments) t)))) | ||
| 1042 | (let ((context (epg-make-context epa-protocol))) | ||
| 1043 | (message "Deleting...") | ||
| 1044 | (epg-delete-keys context keys allow-secret) | ||
| 1045 | (message "Deleting...done") | ||
| 1046 | (apply #'epa-list-keys epa-list-keys-arguments))) | ||
| 1047 | |||
| 1048 | ;;;###autoload | ||
| 1049 | (defun epa-import-keys (file) | ||
| 1050 | "Import keys from FILE. | ||
| 1051 | |||
| 1052 | Don't use this command in Lisp programs!" | ||
| 1053 | (interactive "fFile: ") | ||
| 1054 | (setq file (expand-file-name file)) | ||
| 1055 | (let ((context (epg-make-context epa-protocol))) | ||
| 1056 | (message "Importing %s..." (file-name-nondirectory file)) | ||
| 1057 | (condition-case nil | ||
| 1058 | (progn | ||
| 1059 | (epg-import-keys-from-file context file) | ||
| 1060 | (message "Importing %s...done" (file-name-nondirectory file))) | ||
| 1061 | (error | ||
| 1062 | (message "Importing %s...failed" (file-name-nondirectory file)))) | ||
| 1063 | (if (epg-context-result-for context 'import) | ||
| 1064 | (epa-display-info (epg-import-result-to-string | ||
| 1065 | (epg-context-result-for context 'import)))) | ||
| 1066 | (if (eq major-mode 'epa-key-list-mode) | ||
| 1067 | (apply #'epa-list-keys epa-list-keys-arguments)))) | ||
| 1068 | |||
| 1069 | ;;;###autoload | ||
| 1070 | (defun epa-import-keys-region (start end) | ||
| 1071 | "Import keys from the region. | ||
| 1072 | |||
| 1073 | Don't use this command in Lisp programs!" | ||
| 1074 | (interactive "r") | ||
| 1075 | (let ((context (epg-make-context epa-protocol))) | ||
| 1076 | (message "Importing...") | ||
| 1077 | (condition-case nil | ||
| 1078 | (progn | ||
| 1079 | (epg-import-keys-from-string context (buffer-substring start end)) | ||
| 1080 | (message "Importing...done")) | ||
| 1081 | (error | ||
| 1082 | (message "Importing...failed"))) | ||
| 1083 | (if (epg-context-result-for context 'import) | ||
| 1084 | (epa-display-info (epg-import-result-to-string | ||
| 1085 | (epg-context-result-for context 'import)))))) | ||
| 1086 | |||
| 1087 | ;;;###autoload | ||
| 1088 | (defun epa-import-armor-in-region (start end) | ||
| 1089 | "Import keys in the OpenPGP armor format in the current region | ||
| 1090 | between START and END. | ||
| 1091 | |||
| 1092 | Don't use this command in Lisp programs!" | ||
| 1093 | (interactive "r") | ||
| 1094 | (save-excursion | ||
| 1095 | (save-restriction | ||
| 1096 | (narrow-to-region start end) | ||
| 1097 | (goto-char start) | ||
| 1098 | (let (armor-start armor-end) | ||
| 1099 | (while (re-search-forward | ||
| 1100 | "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$" | ||
| 1101 | nil t) | ||
| 1102 | (setq armor-start (match-beginning 0) | ||
| 1103 | armor-end (re-search-forward | ||
| 1104 | (concat "^-----END " (match-string 1) "-----$") | ||
| 1105 | nil t)) | ||
| 1106 | (unless armor-end | ||
| 1107 | (error "No armor tail")) | ||
| 1108 | (epa-import-keys-region armor-start armor-end)))))) | ||
| 1109 | |||
| 1110 | ;;;###autoload | ||
| 1111 | (defun epa-export-keys (keys file) | ||
| 1112 | "Export selected KEYS to FILE. | ||
| 1113 | |||
| 1114 | Don't use this command in Lisp programs!" | ||
| 1115 | (interactive | ||
| 1116 | (let ((keys (epa--marked-keys)) | ||
| 1117 | default-name) | ||
| 1118 | (unless keys | ||
| 1119 | (error "No keys selected")) | ||
| 1120 | (setq default-name | ||
| 1121 | (expand-file-name | ||
| 1122 | (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys)))) | ||
| 1123 | (if epa-armor ".asc" ".gpg")) | ||
| 1124 | default-directory)) | ||
| 1125 | (list keys | ||
| 1126 | (expand-file-name | ||
| 1127 | (read-file-name | ||
| 1128 | (concat "To file (default " | ||
| 1129 | (file-name-nondirectory default-name) | ||
| 1130 | ") ") | ||
| 1131 | (file-name-directory default-name) | ||
| 1132 | default-name))))) | ||
| 1133 | (let ((context (epg-make-context epa-protocol))) | ||
| 1134 | (epg-context-set-armor context epa-armor) | ||
| 1135 | (message "Exporting to %s..." (file-name-nondirectory file)) | ||
| 1136 | (epg-export-keys-to-file context keys file) | ||
| 1137 | (message "Exporting to %s...done" (file-name-nondirectory file)))) | ||
| 1138 | |||
| 1139 | ;;;###autoload | ||
| 1140 | (defun epa-insert-keys (keys) | ||
| 1141 | "Insert selected KEYS after the point. | ||
| 1142 | |||
| 1143 | Don't use this command in Lisp programs!" | ||
| 1144 | (interactive | ||
| 1145 | (list (epa-select-keys (epg-make-context epa-protocol) | ||
| 1146 | "Select keys to export. "))) | ||
| 1147 | (let ((context (epg-make-context epa-protocol))) | ||
| 1148 | ;;(epg-context-set-armor context epa-armor) | ||
| 1149 | (epg-context-set-armor context t) | ||
| 1150 | (insert (epg-export-keys-to-string context keys)))) | ||
| 1151 | |||
| 1152 | ;; (defun epa-sign-keys (keys &optional local) | ||
| 1153 | ;; "Sign selected KEYS. | ||
| 1154 | ;; If a prefix-arg is specified, the signature is marked as non exportable. | ||
| 1155 | |||
| 1156 | ;; Don't use this command in Lisp programs!" | ||
| 1157 | ;; (interactive | ||
| 1158 | ;; (let ((keys (epa--marked-keys))) | ||
| 1159 | ;; (unless keys | ||
| 1160 | ;; (error "No keys selected")) | ||
| 1161 | ;; (list keys current-prefix-arg))) | ||
| 1162 | ;; (let ((context (epg-make-context epa-protocol))) | ||
| 1163 | ;; (epg-context-set-passphrase-callback context | ||
| 1164 | ;; #'epa-passphrase-callback-function) | ||
| 1165 | ;; (epg-context-set-progress-callback context | ||
| 1166 | ;; (cons | ||
| 1167 | ;; #'epa-progress-callback-function | ||
| 1168 | ;; "Signing keys...")) | ||
| 1169 | ;; (message "Signing keys...") | ||
| 1170 | ;; (epg-sign-keys context keys local) | ||
| 1171 | ;; (message "Signing keys...done"))) | ||
| 1172 | ;; (make-obsolete 'epa-sign-keys "Do not use.") | ||
| 1173 | |||
| 1174 | (provide 'epa) | ||
| 1175 | |||
| 1176 | ;;; epa.el ends here | ||
diff --git a/lisp/epg-config.el b/lisp/epg-config.el new file mode 100644 index 00000000000..6675cbc2eeb --- /dev/null +++ b/lisp/epg-config.el | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | ;;; epg-config.el --- configuration of the EasyPG Library | ||
| 2 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'epg-package-info) | ||
| 27 | |||
| 28 | (defgroup epg () | ||
| 29 | "The EasyPG Library" | ||
| 30 | :group 'emacs) | ||
| 31 | |||
| 32 | (defcustom epg-gpg-program "gpg" | ||
| 33 | "The `gpg' executable." | ||
| 34 | :group 'epg | ||
| 35 | :type 'string) | ||
| 36 | |||
| 37 | (defcustom epg-gpgsm-program "gpgsm" | ||
| 38 | "The `gpgsm' executable." | ||
| 39 | :group 'epg | ||
| 40 | :type 'string) | ||
| 41 | |||
| 42 | (defcustom epg-gpg-home-directory nil | ||
| 43 | "The directory which contains the configuration files of `epg-gpg-program'." | ||
| 44 | :group 'epg | ||
| 45 | :type '(choice (const :tag "Default" nil) directory)) | ||
| 46 | |||
| 47 | (defcustom epg-passphrase-coding-system nil | ||
| 48 | "Coding system to use with messages from `epg-gpg-program'." | ||
| 49 | :group 'epg | ||
| 50 | :type 'symbol) | ||
| 51 | |||
| 52 | (defcustom epg-debug nil | ||
| 53 | "If non-nil, debug output goes to the \" *epg-debug*\" buffer. | ||
| 54 | Note that the buffer name starts with a space." | ||
| 55 | :group 'epg | ||
| 56 | :type 'boolean) | ||
| 57 | |||
| 58 | (defconst epg-gpg-minimum-version "1.4.3") | ||
| 59 | |||
| 60 | ;;;###autoload | ||
| 61 | (defun epg-configuration () | ||
| 62 | "Return a list of internal configuration parameters of `epg-gpg-program'." | ||
| 63 | (let (config groups type args) | ||
| 64 | (with-temp-buffer | ||
| 65 | (apply #'call-process epg-gpg-program nil (list t nil) nil | ||
| 66 | (append (if epg-gpg-home-directory | ||
| 67 | (list "--homedir" epg-gpg-home-directory)) | ||
| 68 | '("--with-colons" "--list-config"))) | ||
| 69 | (goto-char (point-min)) | ||
| 70 | (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t) | ||
| 71 | (setq type (intern (match-string 1)) | ||
| 72 | args (match-string 2)) | ||
| 73 | (cond | ||
| 74 | ((eq type 'group) | ||
| 75 | (if (string-match "\\`\\([^:]+\\):" args) | ||
| 76 | (setq groups | ||
| 77 | (cons (cons (downcase (match-string 1 args)) | ||
| 78 | (delete "" (split-string | ||
| 79 | (substring args | ||
| 80 | (match-end 0)) | ||
| 81 | ";"))) | ||
| 82 | groups)) | ||
| 83 | (if epg-debug | ||
| 84 | (message "Invalid group configuration: %S" args)))) | ||
| 85 | ((memq type '(pubkey cipher digest compress)) | ||
| 86 | (if (string-match "\\`\\([0-9]+\\)\\(;[0-9]+\\)*" args) | ||
| 87 | (setq config | ||
| 88 | (cons (cons type | ||
| 89 | (mapcar #'string-to-number | ||
| 90 | (delete "" (split-string args ";")))) | ||
| 91 | config)) | ||
| 92 | (if epg-debug | ||
| 93 | (message "Invalid %S algorithm configuration: %S" | ||
| 94 | type args)))) | ||
| 95 | (t | ||
| 96 | (setq config (cons (cons type args) config)))))) | ||
| 97 | (if groups | ||
| 98 | (cons (cons 'groups groups) config) | ||
| 99 | config))) | ||
| 100 | |||
| 101 | (defun epg-config--parse-version (string) | ||
| 102 | (let ((index 0) | ||
| 103 | version) | ||
| 104 | (while (eq index (string-match "\\([0-9]+\\)\\.?" string index)) | ||
| 105 | (setq version (cons (string-to-number (match-string 1 string)) | ||
| 106 | version) | ||
| 107 | index (match-end 0))) | ||
| 108 | (nreverse version))) | ||
| 109 | |||
| 110 | (defun epg-config--compare-version (v1 v2) | ||
| 111 | (while (and v1 v2 (= (car v1) (car v2))) | ||
| 112 | (setq v1 (cdr v1) v2 (cdr v2))) | ||
| 113 | (- (or (car v1) 0) (or (car v2) 0))) | ||
| 114 | |||
| 115 | ;;;###autoload | ||
| 116 | (defun epg-check-configuration (config &optional minimum-version) | ||
| 117 | "Verify that a sufficient version of GnuPG is installed." | ||
| 118 | (let ((entry (assq 'version config)) | ||
| 119 | version) | ||
| 120 | (unless (and entry | ||
| 121 | (stringp (cdr entry))) | ||
| 122 | (error "Undetermined version: %S" entry)) | ||
| 123 | (setq version (epg-config--parse-version (cdr entry)) | ||
| 124 | minimum-version (epg-config--parse-version | ||
| 125 | (or minimum-version | ||
| 126 | epg-gpg-minimum-version))) | ||
| 127 | (unless (>= (epg-config--compare-version version minimum-version) 0) | ||
| 128 | (error "Unsupported version: %s" (cdr entry))))) | ||
| 129 | |||
| 130 | ;;;###autoload | ||
| 131 | (defun epg-expand-group (config group) | ||
| 132 | "Look at CONFIG and try to expand GROUP." | ||
| 133 | (let ((entry (assq 'groups config))) | ||
| 134 | (if (and entry | ||
| 135 | (setq entry (assoc (downcase group) (cdr entry)))) | ||
| 136 | (cdr entry)))) | ||
| 137 | |||
| 138 | (provide 'epg-config) | ||
| 139 | |||
| 140 | ;;; epg-config.el ends here | ||
diff --git a/lisp/epg-package-info.el b/lisp/epg-package-info.el new file mode 100644 index 00000000000..01709ee2a16 --- /dev/null +++ b/lisp/epg-package-info.el | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | ;;; epg-package-info.el --- package information about EasyPG | ||
| 2 | ;; Copyright (C) 2007, 2008 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 5 | ;; Keywords: PGP, GnuPG | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 12 | ;; any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 21 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | ;; Boston, MA 02110-1301, USA. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (defconst epg-package-name "epg" | ||
| 27 | "Name of this package.") | ||
| 28 | |||
| 29 | (defconst epg-version-number "1.0.0" | ||
| 30 | "Version number of this package.") | ||
| 31 | |||
| 32 | (defconst epg-bug-report-address "ueno@unixuser.org" | ||
| 33 | "Report bugs to this address.") | ||
| 34 | |||
| 35 | (provide 'epg-package-info) | ||
| 36 | |||
| 37 | ;;; epg-package-info.el ends here | ||
diff --git a/lisp/epg.el b/lisp/epg.el new file mode 100644 index 00000000000..d9c334d2f0f --- /dev/null +++ b/lisp/epg.el | |||
| @@ -0,0 +1,2654 @@ | |||
| 1 | ;;; epg.el --- the EasyPG Library | ||
| 2 | ;; Copyright (C) 1999, 2000, 2002, 2003, 2004, | ||
| 3 | ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 6 | ;; Keywords: PGP, GnuPG | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 23 | ;; Boston, MA 02110-1301, USA. | ||
| 24 | |||
| 25 | ;;; Code: | ||
| 26 | |||
| 27 | (require 'epg-config) | ||
| 28 | |||
| 29 | (defvar epg-user-id nil | ||
| 30 | "GnuPG ID of your default identity.") | ||
| 31 | |||
| 32 | (defvar epg-user-id-alist nil | ||
| 33 | "An alist mapping from key ID to user ID.") | ||
| 34 | |||
| 35 | (defvar epg-last-status nil) | ||
| 36 | (defvar epg-read-point nil) | ||
| 37 | (defvar epg-process-filter-running nil) | ||
| 38 | (defvar epg-pending-status-list nil) | ||
| 39 | (defvar epg-key-id nil) | ||
| 40 | (defvar epg-context nil) | ||
| 41 | (defvar epg-debug-buffer nil) | ||
| 42 | |||
| 43 | ;; from gnupg/include/cipher.h | ||
| 44 | (defconst epg-cipher-algorithm-alist | ||
| 45 | '((0 . "NONE") | ||
| 46 | (1 . "IDEA") | ||
| 47 | (2 . "3DES") | ||
| 48 | (3 . "CAST5") | ||
| 49 | (4 . "BLOWFISH") | ||
| 50 | (7 . "AES") | ||
| 51 | (8 . "AES192") | ||
| 52 | (9 . "AES256") | ||
| 53 | (10 . "TWOFISH") | ||
| 54 | (110 . "DUMMY"))) | ||
| 55 | |||
| 56 | ;; from gnupg/include/cipher.h | ||
| 57 | (defconst epg-pubkey-algorithm-alist | ||
| 58 | '((1 . "RSA") | ||
| 59 | (2 . "RSA_E") | ||
| 60 | (3 . "RSA_S") | ||
| 61 | (16 . "ELGAMAL_E") | ||
| 62 | (17 . "DSA") | ||
| 63 | (20 . "ELGAMAL"))) | ||
| 64 | |||
| 65 | ;; from gnupg/include/cipher.h | ||
| 66 | (defconst epg-digest-algorithm-alist | ||
| 67 | '((1 . "MD5") | ||
| 68 | (2 . "SHA1") | ||
| 69 | (3 . "RMD160") | ||
| 70 | (8 . "SHA256") | ||
| 71 | (9 . "SHA384") | ||
| 72 | (10 . "SHA512"))) | ||
| 73 | |||
| 74 | ;; from gnupg/include/cipher.h | ||
| 75 | (defconst epg-compress-algorithm-alist | ||
| 76 | '((0 . "NONE") | ||
| 77 | (1 . "ZIP") | ||
| 78 | (2 . "ZLIB") | ||
| 79 | (3 . "BZIP2"))) | ||
| 80 | |||
| 81 | (defconst epg-invalid-recipients-reason-alist | ||
| 82 | '((0 . "No specific reason given") | ||
| 83 | (1 . "Not Found") | ||
| 84 | (2 . "Ambigious specification") | ||
| 85 | (3 . "Wrong key usage") | ||
| 86 | (4 . "Key revoked") | ||
| 87 | (5 . "Key expired") | ||
| 88 | (6 . "No CRL known") | ||
| 89 | (7 . "CRL too old") | ||
| 90 | (8 . "Policy mismatch") | ||
| 91 | (9 . "Not a secret key") | ||
| 92 | (10 . "Key not trusted"))) | ||
| 93 | |||
| 94 | (defconst epg-delete-problem-reason-alist | ||
| 95 | '((1 . "No such key") | ||
| 96 | (2 . "Must delete secret key first") | ||
| 97 | (3 . "Ambigious specification"))) | ||
| 98 | |||
| 99 | (defconst epg-import-ok-reason-alist | ||
| 100 | '((0 . "Not actually changed") | ||
| 101 | (1 . "Entirely new key") | ||
| 102 | (2 . "New user IDs") | ||
| 103 | (4 . "New signatures") | ||
| 104 | (8 . "New subkeys") | ||
| 105 | (16 . "Contains private key"))) | ||
| 106 | |||
| 107 | (defconst epg-import-problem-reason-alist | ||
| 108 | '((0 . "No specific reason given") | ||
| 109 | (1 . "Invalid Certificate") | ||
| 110 | (2 . "Issuer Certificate missing") | ||
| 111 | (3 . "Certificate Chain too long") | ||
| 112 | (4 . "Error storing certificate"))) | ||
| 113 | |||
| 114 | (defconst epg-no-data-reason-alist | ||
| 115 | '((1 . "No armored data") | ||
| 116 | (2 . "Expected a packet but did not found one") | ||
| 117 | (3 . "Invalid packet found, this may indicate a non OpenPGP message") | ||
| 118 | (4 . "Signature expected but not found"))) | ||
| 119 | |||
| 120 | (defconst epg-unexpected-reason-alist nil) | ||
| 121 | |||
| 122 | (defvar epg-key-validity-alist | ||
| 123 | '((?o . unknown) | ||
| 124 | (?i . invalid) | ||
| 125 | (?d . disabled) | ||
| 126 | (?r . revoked) | ||
| 127 | (?e . expired) | ||
| 128 | (?- . none) | ||
| 129 | (?q . undefined) | ||
| 130 | (?n . never) | ||
| 131 | (?m . marginal) | ||
| 132 | (?f . full) | ||
| 133 | (?u . ultimate))) | ||
| 134 | |||
| 135 | (defvar epg-key-capablity-alist | ||
| 136 | '((?e . encrypt) | ||
| 137 | (?s . sign) | ||
| 138 | (?c . certify) | ||
| 139 | (?a . authentication))) | ||
| 140 | |||
| 141 | (defvar epg-new-signature-type-alist | ||
| 142 | '((?D . detached) | ||
| 143 | (?C . clear) | ||
| 144 | (?S . normal))) | ||
| 145 | |||
| 146 | (defvar epg-dn-type-alist | ||
| 147 | '(("1.2.840.113549.1.9.1" . "EMail") | ||
| 148 | ("2.5.4.12" . "T") | ||
| 149 | ("2.5.4.42" . "GN") | ||
| 150 | ("2.5.4.4" . "SN") | ||
| 151 | ("0.2.262.1.10.7.20" . "NameDistinguisher") | ||
| 152 | ("2.5.4.16" . "ADDR") | ||
| 153 | ("2.5.4.15" . "BC") | ||
| 154 | ("2.5.4.13" . "D") | ||
| 155 | ("2.5.4.17" . "PostalCode") | ||
| 156 | ("2.5.4.65" . "Pseudo") | ||
| 157 | ("2.5.4.5" . "SerialNumber"))) | ||
| 158 | |||
| 159 | (defvar epg-prompt-alist nil) | ||
| 160 | |||
| 161 | (put 'epg-error 'error-conditions '(epg-error error)) | ||
| 162 | |||
| 163 | (defun epg-make-data-from-file (file) | ||
| 164 | "Make a data object from FILE." | ||
| 165 | (cons 'epg-data (vector file nil))) | ||
| 166 | |||
| 167 | (defun epg-make-data-from-string (string) | ||
| 168 | "Make a data object from STRING." | ||
| 169 | (cons 'epg-data (vector nil string))) | ||
| 170 | |||
| 171 | (defun epg-data-file (data) | ||
| 172 | "Return the file of DATA." | ||
| 173 | (unless (eq (car-safe data) 'epg-data) | ||
| 174 | (signal 'wrong-type-argument (list 'epg-data-p data))) | ||
| 175 | (aref (cdr data) 0)) | ||
| 176 | |||
| 177 | (defun epg-data-string (data) | ||
| 178 | "Return the string of DATA." | ||
| 179 | (unless (eq (car-safe data) 'epg-data) | ||
| 180 | (signal 'wrong-type-argument (list 'epg-data-p data))) | ||
| 181 | (aref (cdr data) 1)) | ||
| 182 | |||
| 183 | (defun epg-make-context (&optional protocol armor textmode include-certs | ||
| 184 | cipher-algorithm digest-algorithm | ||
| 185 | compress-algorithm) | ||
| 186 | "Return a context object." | ||
| 187 | (cons 'epg-context | ||
| 188 | (vector (or protocol 'OpenPGP) armor textmode include-certs | ||
| 189 | cipher-algorithm digest-algorithm compress-algorithm | ||
| 190 | #'epg-passphrase-callback-function | ||
| 191 | nil | ||
| 192 | nil nil nil nil nil nil))) | ||
| 193 | |||
| 194 | (defun epg-context-protocol (context) | ||
| 195 | "Return the protocol used within CONTEXT." | ||
| 196 | (unless (eq (car-safe context) 'epg-context) | ||
| 197 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 198 | (aref (cdr context) 0)) | ||
| 199 | |||
| 200 | (defun epg-context-armor (context) | ||
| 201 | "Return t if the output shouled be ASCII armored in CONTEXT." | ||
| 202 | (unless (eq (car-safe context) 'epg-context) | ||
| 203 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 204 | (aref (cdr context) 1)) | ||
| 205 | |||
| 206 | (defun epg-context-textmode (context) | ||
| 207 | "Return t if canonical text mode should be used in CONTEXT." | ||
| 208 | (unless (eq (car-safe context) 'epg-context) | ||
| 209 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 210 | (aref (cdr context) 2)) | ||
| 211 | |||
| 212 | (defun epg-context-include-certs (context) | ||
| 213 | "Return how many certificates should be included in an S/MIME signed | ||
| 214 | message." | ||
| 215 | (unless (eq (car-safe context) 'epg-context) | ||
| 216 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 217 | (aref (cdr context) 3)) | ||
| 218 | |||
| 219 | (defun epg-context-cipher-algorithm (context) | ||
| 220 | "Return the cipher algorithm in CONTEXT." | ||
| 221 | (unless (eq (car-safe context) 'epg-context) | ||
| 222 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 223 | (aref (cdr context) 4)) | ||
| 224 | |||
| 225 | (defun epg-context-digest-algorithm (context) | ||
| 226 | "Return the digest algorithm in CONTEXT." | ||
| 227 | (unless (eq (car-safe context) 'epg-context) | ||
| 228 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 229 | (aref (cdr context) 5)) | ||
| 230 | |||
| 231 | (defun epg-context-compress-algorithm (context) | ||
| 232 | "Return the compress algorithm in CONTEXT." | ||
| 233 | (unless (eq (car-safe context) 'epg-context) | ||
| 234 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 235 | (aref (cdr context) 6)) | ||
| 236 | |||
| 237 | (defun epg-context-passphrase-callback (context) | ||
| 238 | "Return the function used to query passphrase." | ||
| 239 | (unless (eq (car-safe context) 'epg-context) | ||
| 240 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 241 | (aref (cdr context) 7)) | ||
| 242 | |||
| 243 | (defun epg-context-progress-callback (context) | ||
| 244 | "Return the function which handles progress update." | ||
| 245 | (unless (eq (car-safe context) 'epg-context) | ||
| 246 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 247 | (aref (cdr context) 8)) | ||
| 248 | |||
| 249 | (defun epg-context-signers (context) | ||
| 250 | "Return the list of key-id for singning." | ||
| 251 | (unless (eq (car-safe context) 'epg-context) | ||
| 252 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 253 | (aref (cdr context) 9)) | ||
| 254 | |||
| 255 | (defun epg-context-sig-notations (context) | ||
| 256 | "Return the list of notations for singning." | ||
| 257 | (unless (eq (car-safe context) 'epg-context) | ||
| 258 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 259 | (aref (cdr context) 10)) | ||
| 260 | |||
| 261 | (defun epg-context-process (context) | ||
| 262 | "Return the process object of `epg-gpg-program'. | ||
| 263 | This function is for internal use only." | ||
| 264 | (unless (eq (car-safe context) 'epg-context) | ||
| 265 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 266 | (aref (cdr context) 11)) | ||
| 267 | |||
| 268 | (defun epg-context-output-file (context) | ||
| 269 | "Return the output file of `epg-gpg-program'. | ||
| 270 | This function is for internal use only." | ||
| 271 | (unless (eq (car-safe context) 'epg-context) | ||
| 272 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 273 | (aref (cdr context) 12)) | ||
| 274 | |||
| 275 | (defun epg-context-result (context) | ||
| 276 | "Return the result of the previous cryptographic operation." | ||
| 277 | (unless (eq (car-safe context) 'epg-context) | ||
| 278 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 279 | (aref (cdr context) 13)) | ||
| 280 | |||
| 281 | (defun epg-context-operation (context) | ||
| 282 | "Return the name of the current cryptographic operation." | ||
| 283 | (unless (eq (car-safe context) 'epg-context) | ||
| 284 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 285 | (aref (cdr context) 14)) | ||
| 286 | |||
| 287 | (defun epg-context-set-protocol (context protocol) | ||
| 288 | "Set the protocol used within CONTEXT." | ||
| 289 | (unless (eq (car-safe context) 'epg-context) | ||
| 290 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 291 | (aset (cdr context) 0 protocol)) | ||
| 292 | |||
| 293 | (defun epg-context-set-armor (context armor) | ||
| 294 | "Specify if the output shouled be ASCII armored in CONTEXT." | ||
| 295 | (unless (eq (car-safe context) 'epg-context) | ||
| 296 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 297 | (aset (cdr context) 1 armor)) | ||
| 298 | |||
| 299 | (defun epg-context-set-textmode (context textmode) | ||
| 300 | "Specify if canonical text mode should be used in CONTEXT." | ||
| 301 | (unless (eq (car-safe context) 'epg-context) | ||
| 302 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 303 | (aset (cdr context) 2 textmode)) | ||
| 304 | |||
| 305 | (defun epg-context-set-include-certs (context include-certs) | ||
| 306 | "Set how many certificates should be included in an S/MIME signed message." | ||
| 307 | (unless (eq (car-safe context) 'epg-context) | ||
| 308 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 309 | (aset (cdr context) 3 include-certs)) | ||
| 310 | |||
| 311 | (defun epg-context-set-cipher-algorithm (context cipher-algorithm) | ||
| 312 | "Set the cipher algorithm in CONTEXT." | ||
| 313 | (unless (eq (car-safe context) 'epg-context) | ||
| 314 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 315 | (aset (cdr context) 4 cipher-algorithm)) | ||
| 316 | |||
| 317 | (defun epg-context-set-digest-algorithm (context digest-algorithm) | ||
| 318 | "Set the digest algorithm in CONTEXT." | ||
| 319 | (unless (eq (car-safe context) 'epg-context) | ||
| 320 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 321 | (aset (cdr context) 5 digest-algorithm)) | ||
| 322 | |||
| 323 | (defun epg-context-set-compress-algorithm (context compress-algorithm) | ||
| 324 | "Set the compress algorithm in CONTEXT." | ||
| 325 | (unless (eq (car-safe context) 'epg-context) | ||
| 326 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 327 | (aset (cdr context) 6 compress-algorithm)) | ||
| 328 | |||
| 329 | (defun epg-context-set-passphrase-callback (context | ||
| 330 | passphrase-callback) | ||
| 331 | "Set the function used to query passphrase." | ||
| 332 | (unless (eq (car-safe context) 'epg-context) | ||
| 333 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 334 | (aset (cdr context) 7 passphrase-callback)) | ||
| 335 | |||
| 336 | (defun epg-context-set-progress-callback (context | ||
| 337 | progress-callback) | ||
| 338 | "Set the function which handles progress update. | ||
| 339 | If optional argument HANDBACK is specified, it is passed to PROGRESS-CALLBACK." | ||
| 340 | (unless (eq (car-safe context) 'epg-context) | ||
| 341 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 342 | (aset (cdr context) 8 progress-callback)) | ||
| 343 | |||
| 344 | (defun epg-context-set-signers (context signers) | ||
| 345 | "Set the list of key-id for singning." | ||
| 346 | (unless (eq (car-safe context) 'epg-context) | ||
| 347 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 348 | (aset (cdr context) 9 signers)) | ||
| 349 | |||
| 350 | (defun epg-context-set-sig-notations (context notations) | ||
| 351 | "Set the list of notations for singning." | ||
| 352 | (unless (eq (car-safe context) 'epg-context) | ||
| 353 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 354 | (aset (cdr context) 10 notations)) | ||
| 355 | |||
| 356 | (defun epg-context-set-process (context process) | ||
| 357 | "Set the process object of `epg-gpg-program'. | ||
| 358 | This function is for internal use only." | ||
| 359 | (unless (eq (car-safe context) 'epg-context) | ||
| 360 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 361 | (aset (cdr context) 11 process)) | ||
| 362 | |||
| 363 | (defun epg-context-set-output-file (context output-file) | ||
| 364 | "Set the output file of `epg-gpg-program'. | ||
| 365 | This function is for internal use only." | ||
| 366 | (unless (eq (car-safe context) 'epg-context) | ||
| 367 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 368 | (aset (cdr context) 12 output-file)) | ||
| 369 | |||
| 370 | (defun epg-context-set-result (context result) | ||
| 371 | "Set the result of the previous cryptographic operation." | ||
| 372 | (unless (eq (car-safe context) 'epg-context) | ||
| 373 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 374 | (aset (cdr context) 13 result)) | ||
| 375 | |||
| 376 | (defun epg-context-set-operation (context operation) | ||
| 377 | "Set the name of the current cryptographic operation." | ||
| 378 | (unless (eq (car-safe context) 'epg-context) | ||
| 379 | (signal 'wrong-type-argument (list 'epg-context-p context))) | ||
| 380 | (aset (cdr context) 14 operation)) | ||
| 381 | |||
| 382 | (defun epg-make-signature (status &optional key-id) | ||
| 383 | "Return a signature object." | ||
| 384 | (cons 'epg-signature (vector status key-id nil nil nil nil nil nil nil nil | ||
| 385 | nil))) | ||
| 386 | |||
| 387 | (defun epg-signature-status (signature) | ||
| 388 | "Return the status code of SIGNATURE." | ||
| 389 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 390 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 391 | (aref (cdr signature) 0)) | ||
| 392 | |||
| 393 | (defun epg-signature-key-id (signature) | ||
| 394 | "Return the key-id of SIGNATURE." | ||
| 395 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 396 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 397 | (aref (cdr signature) 1)) | ||
| 398 | |||
| 399 | (defun epg-signature-validity (signature) | ||
| 400 | "Return the validity of SIGNATURE." | ||
| 401 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 402 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 403 | (aref (cdr signature) 2)) | ||
| 404 | |||
| 405 | (defun epg-signature-fingerprint (signature) | ||
| 406 | "Return the fingerprint of SIGNATURE." | ||
| 407 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 408 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 409 | (aref (cdr signature) 3)) | ||
| 410 | |||
| 411 | (defun epg-signature-creation-time (signature) | ||
| 412 | "Return the creation time of SIGNATURE." | ||
| 413 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 414 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 415 | (aref (cdr signature) 4)) | ||
| 416 | |||
| 417 | (defun epg-signature-expiration-time (signature) | ||
| 418 | "Return the expiration time of SIGNATURE." | ||
| 419 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 420 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 421 | (aref (cdr signature) 5)) | ||
| 422 | |||
| 423 | (defun epg-signature-pubkey-algorithm (signature) | ||
| 424 | "Return the public key algorithm of SIGNATURE." | ||
| 425 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 426 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 427 | (aref (cdr signature) 6)) | ||
| 428 | |||
| 429 | (defun epg-signature-digest-algorithm (signature) | ||
| 430 | "Return the digest algorithm of SIGNATURE." | ||
| 431 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 432 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 433 | (aref (cdr signature) 7)) | ||
| 434 | |||
| 435 | (defun epg-signature-class (signature) | ||
| 436 | "Return the class of SIGNATURE." | ||
| 437 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 438 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 439 | (aref (cdr signature) 8)) | ||
| 440 | |||
| 441 | (defun epg-signature-version (signature) | ||
| 442 | "Return the version of SIGNATURE." | ||
| 443 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 444 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 445 | (aref (cdr signature) 9)) | ||
| 446 | |||
| 447 | (defun epg-sig-notations (signature) | ||
| 448 | "Return the list of notations of SIGNATURE." | ||
| 449 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 450 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 451 | (aref (cdr signature) 10)) | ||
| 452 | |||
| 453 | (defun epg-signature-set-status (signature status) | ||
| 454 | "Set the status code of SIGNATURE." | ||
| 455 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 456 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 457 | (aset (cdr signature) 0 status)) | ||
| 458 | |||
| 459 | (defun epg-signature-set-key-id (signature key-id) | ||
| 460 | "Set the key-id of SIGNATURE." | ||
| 461 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 462 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 463 | (aset (cdr signature) 1 key-id)) | ||
| 464 | |||
| 465 | (defun epg-signature-set-validity (signature validity) | ||
| 466 | "Set the validity of SIGNATURE." | ||
| 467 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 468 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 469 | (aset (cdr signature) 2 validity)) | ||
| 470 | |||
| 471 | (defun epg-signature-set-fingerprint (signature fingerprint) | ||
| 472 | "Set the fingerprint of SIGNATURE." | ||
| 473 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 474 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 475 | (aset (cdr signature) 3 fingerprint)) | ||
| 476 | |||
| 477 | (defun epg-signature-set-creation-time (signature creation-time) | ||
| 478 | "Set the creation time of SIGNATURE." | ||
| 479 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 480 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 481 | (aset (cdr signature) 4 creation-time)) | ||
| 482 | |||
| 483 | (defun epg-signature-set-expiration-time (signature expiration-time) | ||
| 484 | "Set the expiration time of SIGNATURE." | ||
| 485 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 486 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 487 | (aset (cdr signature) 5 expiration-time)) | ||
| 488 | |||
| 489 | (defun epg-signature-set-pubkey-algorithm (signature pubkey-algorithm) | ||
| 490 | "Set the public key algorithm of SIGNATURE." | ||
| 491 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 492 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 493 | (aset (cdr signature) 6 pubkey-algorithm)) | ||
| 494 | |||
| 495 | (defun epg-signature-set-digest-algorithm (signature digest-algorithm) | ||
| 496 | "Set the digest algorithm of SIGNATURE." | ||
| 497 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 498 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 499 | (aset (cdr signature) 7 digest-algorithm)) | ||
| 500 | |||
| 501 | (defun epg-signature-set-class (signature class) | ||
| 502 | "Set the class of SIGNATURE." | ||
| 503 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 504 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 505 | (aset (cdr signature) 8 class)) | ||
| 506 | |||
| 507 | (defun epg-signature-set-version (signature version) | ||
| 508 | "Set the version of SIGNATURE." | ||
| 509 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 510 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 511 | (aset (cdr signature) 9 version)) | ||
| 512 | |||
| 513 | (defun epg-signature-set-notations (signature notations) | ||
| 514 | "Set the list of notations of SIGNATURE." | ||
| 515 | (unless (eq (car-safe signature) 'epg-signature) | ||
| 516 | (signal 'wrong-type-argument (list 'epg-signature-p signature))) | ||
| 517 | (aset (cdr signature) 10 notations)) | ||
| 518 | |||
| 519 | (defun epg-make-new-signature (type pubkey-algorithm digest-algorithm | ||
| 520 | class creation-time fingerprint) | ||
| 521 | "Return a new signature object." | ||
| 522 | (cons 'epg-new-signature (vector type pubkey-algorithm digest-algorithm | ||
| 523 | class creation-time fingerprint))) | ||
| 524 | |||
| 525 | (defun epg-new-signature-type (new-signature) | ||
| 526 | "Return the type of NEW-SIGNATURE." | ||
| 527 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 528 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 529 | (aref (cdr new-signature) 0)) | ||
| 530 | |||
| 531 | (defun epg-new-signature-pubkey-algorithm (new-signature) | ||
| 532 | "Return the public key algorithm of NEW-SIGNATURE." | ||
| 533 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 534 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 535 | (aref (cdr new-signature) 1)) | ||
| 536 | |||
| 537 | (defun epg-new-signature-digest-algorithm (new-signature) | ||
| 538 | "Return the digest algorithm of NEW-SIGNATURE." | ||
| 539 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 540 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 541 | (aref (cdr new-signature) 2)) | ||
| 542 | |||
| 543 | (defun epg-new-signature-class (new-signature) | ||
| 544 | "Return the class of NEW-SIGNATURE." | ||
| 545 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 546 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 547 | (aref (cdr new-signature) 3)) | ||
| 548 | |||
| 549 | (defun epg-new-signature-creation-time (new-signature) | ||
| 550 | "Return the creation time of NEW-SIGNATURE." | ||
| 551 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 552 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 553 | (aref (cdr new-signature) 4)) | ||
| 554 | |||
| 555 | (defun epg-new-signature-fingerprint (new-signature) | ||
| 556 | "Return the fingerprint of NEW-SIGNATURE." | ||
| 557 | (unless (eq (car-safe new-signature) 'epg-new-signature) | ||
| 558 | (signal 'wrong-type-argument (list 'epg-new-signature-p new-signature))) | ||
| 559 | (aref (cdr new-signature) 5)) | ||
| 560 | |||
| 561 | (defun epg-make-key (owner-trust) | ||
| 562 | "Return a key object." | ||
| 563 | (cons 'epg-key (vector owner-trust nil nil))) | ||
| 564 | |||
| 565 | (defun epg-key-owner-trust (key) | ||
| 566 | "Return the owner trust of KEY." | ||
| 567 | (unless (eq (car-safe key) 'epg-key) | ||
| 568 | (signal 'wrong-type-argument (list 'epg-key-p key))) | ||
| 569 | (aref (cdr key) 0)) | ||
| 570 | |||
| 571 | (defun epg-key-sub-key-list (key) | ||
| 572 | "Return the sub key list of KEY." | ||
| 573 | (unless (eq (car-safe key) 'epg-key) | ||
| 574 | (signal 'wrong-type-argument (list 'epg-key-p key))) | ||
| 575 | (aref (cdr key) 1)) | ||
| 576 | |||
| 577 | (defun epg-key-user-id-list (key) | ||
| 578 | "Return the user ID list of KEY." | ||
| 579 | (unless (eq (car-safe key) 'epg-key) | ||
| 580 | (signal 'wrong-type-argument (list 'epg-key-p key))) | ||
| 581 | (aref (cdr key) 2)) | ||
| 582 | |||
| 583 | (defun epg-key-set-sub-key-list (key sub-key-list) | ||
| 584 | "Set the sub key list of KEY." | ||
| 585 | (unless (eq (car-safe key) 'epg-key) | ||
| 586 | (signal 'wrong-type-argument (list 'epg-key-p key))) | ||
| 587 | (aset (cdr key) 1 sub-key-list)) | ||
| 588 | |||
| 589 | (defun epg-key-set-user-id-list (key user-id-list) | ||
| 590 | "Set the user ID list of KEY." | ||
| 591 | (unless (eq (car-safe key) 'epg-key) | ||
| 592 | (signal 'wrong-type-argument (list 'epg-key-p key))) | ||
| 593 | (aset (cdr key) 2 user-id-list)) | ||
| 594 | |||
| 595 | (defun epg-make-sub-key (validity capability secret-p algorithm length id | ||
| 596 | creation-time expiration-time) | ||
| 597 | "Return a sub key object." | ||
| 598 | (cons 'epg-sub-key | ||
| 599 | (vector validity capability secret-p algorithm length id creation-time | ||
| 600 | expiration-time nil))) | ||
| 601 | |||
| 602 | (defun epg-sub-key-validity (sub-key) | ||
| 603 | "Return the validity of SUB-KEY." | ||
| 604 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 605 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 606 | (aref (cdr sub-key) 0)) | ||
| 607 | |||
| 608 | (defun epg-sub-key-capability (sub-key) | ||
| 609 | "Return the capability of SUB-KEY." | ||
| 610 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 611 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 612 | (aref (cdr sub-key) 1)) | ||
| 613 | |||
| 614 | (defun epg-sub-key-secret-p (sub-key) | ||
| 615 | "Return non-nil if SUB-KEY is a secret key." | ||
| 616 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 617 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 618 | (aref (cdr sub-key) 2)) | ||
| 619 | |||
| 620 | (defun epg-sub-key-algorithm (sub-key) | ||
| 621 | "Return the algorithm of SUB-KEY." | ||
| 622 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 623 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 624 | (aref (cdr sub-key) 3)) | ||
| 625 | |||
| 626 | (defun epg-sub-key-length (sub-key) | ||
| 627 | "Return the length of SUB-KEY." | ||
| 628 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 629 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 630 | (aref (cdr sub-key) 4)) | ||
| 631 | |||
| 632 | (defun epg-sub-key-id (sub-key) | ||
| 633 | "Return the ID of SUB-KEY." | ||
| 634 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 635 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 636 | (aref (cdr sub-key) 5)) | ||
| 637 | |||
| 638 | (defun epg-sub-key-creation-time (sub-key) | ||
| 639 | "Return the creation time of SUB-KEY." | ||
| 640 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 641 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 642 | (aref (cdr sub-key) 6)) | ||
| 643 | |||
| 644 | (defun epg-sub-key-expiration-time (sub-key) | ||
| 645 | "Return the expiration time of SUB-KEY." | ||
| 646 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 647 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 648 | (aref (cdr sub-key) 7)) | ||
| 649 | |||
| 650 | (defun epg-sub-key-fingerprint (sub-key) | ||
| 651 | "Return the fingerprint of SUB-KEY." | ||
| 652 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 653 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 654 | (aref (cdr sub-key) 8)) | ||
| 655 | |||
| 656 | (defun epg-sub-key-set-fingerprint (sub-key fingerprint) | ||
| 657 | "Set the fingerprint of SUB-KEY. | ||
| 658 | This function is for internal use only." | ||
| 659 | (unless (eq (car-safe sub-key) 'epg-sub-key) | ||
| 660 | (signal 'wrong-type-argument (list 'epg-sub-key-p sub-key))) | ||
| 661 | (aset (cdr sub-key) 8 fingerprint)) | ||
| 662 | |||
| 663 | (defun epg-make-user-id (validity string) | ||
| 664 | "Return a user ID object." | ||
| 665 | (cons 'epg-user-id (vector validity string nil))) | ||
| 666 | |||
| 667 | (defun epg-user-id-validity (user-id) | ||
| 668 | "Return the validity of USER-ID." | ||
| 669 | (unless (eq (car-safe user-id) 'epg-user-id) | ||
| 670 | (signal 'wrong-type-argument (list 'epg-user-id-p user-id))) | ||
| 671 | (aref (cdr user-id) 0)) | ||
| 672 | |||
| 673 | (defun epg-user-id-string (user-id) | ||
| 674 | "Return the name of USER-ID." | ||
| 675 | (unless (eq (car-safe user-id) 'epg-user-id) | ||
| 676 | (signal 'wrong-type-argument (list 'epg-user-id-p user-id))) | ||
| 677 | (aref (cdr user-id) 1)) | ||
| 678 | |||
| 679 | (defun epg-user-id-signature-list (user-id) | ||
| 680 | "Return the signature list of USER-ID." | ||
| 681 | (unless (eq (car-safe user-id) 'epg-user-id) | ||
| 682 | (signal 'wrong-type-argument (list 'epg-user-id-p user-id))) | ||
| 683 | (aref (cdr user-id) 2)) | ||
| 684 | |||
| 685 | (defun epg-user-id-set-signature-list (user-id signature-list) | ||
| 686 | "Set the signature list of USER-ID." | ||
| 687 | (unless (eq (car-safe user-id) 'epg-user-id) | ||
| 688 | (signal 'wrong-type-argument (list 'epg-user-id-p user-id))) | ||
| 689 | (aset (cdr user-id) 2 signature-list)) | ||
| 690 | |||
| 691 | (defun epg-make-key-signature (validity pubkey-algorithm key-id creation-time | ||
| 692 | expiration-time user-id class | ||
| 693 | exportable-p) | ||
| 694 | "Return a key signature object." | ||
| 695 | (cons 'epg-key-signature | ||
| 696 | (vector validity pubkey-algorithm key-id creation-time expiration-time | ||
| 697 | user-id class exportable-p))) | ||
| 698 | |||
| 699 | (defun epg-key-signature-validity (key-signature) | ||
| 700 | "Return the validity of KEY-SIGNATURE." | ||
| 701 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 702 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 703 | (aref (cdr key-signature) 0)) | ||
| 704 | |||
| 705 | (defun epg-key-signature-pubkey-algorithm (key-signature) | ||
| 706 | "Return the public key algorithm of KEY-SIGNATURE." | ||
| 707 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 708 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 709 | (aref (cdr key-signature) 1)) | ||
| 710 | |||
| 711 | (defun epg-key-signature-key-id (key-signature) | ||
| 712 | "Return the key-id of KEY-SIGNATURE." | ||
| 713 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 714 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 715 | (aref (cdr key-signature) 2)) | ||
| 716 | |||
| 717 | (defun epg-key-signature-creation-time (key-signature) | ||
| 718 | "Return the creation time of KEY-SIGNATURE." | ||
| 719 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 720 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 721 | (aref (cdr key-signature) 3)) | ||
| 722 | |||
| 723 | (defun epg-key-signature-expiration-time (key-signature) | ||
| 724 | "Return the expiration time of KEY-SIGNATURE." | ||
| 725 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 726 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 727 | (aref (cdr key-signature) 4)) | ||
| 728 | |||
| 729 | (defun epg-key-signature-user-id (key-signature) | ||
| 730 | "Return the user-id of KEY-SIGNATURE." | ||
| 731 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 732 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 733 | (aref (cdr key-signature) 5)) | ||
| 734 | |||
| 735 | (defun epg-key-signature-class (key-signature) | ||
| 736 | "Return the class of KEY-SIGNATURE." | ||
| 737 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 738 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 739 | (aref (cdr key-signature) 6)) | ||
| 740 | |||
| 741 | (defun epg-key-signature-exportable-p (key-signature) | ||
| 742 | "Return t if KEY-SIGNATURE is exportable." | ||
| 743 | (unless (eq (car-safe key-signature) 'epg-key-signature) | ||
| 744 | (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature))) | ||
| 745 | (aref (cdr key-signature) 7)) | ||
| 746 | |||
| 747 | (defun epg-make-sig-notation (name value &optional human-readable | ||
| 748 | critical) | ||
| 749 | "Return a notation object." | ||
| 750 | (cons 'epg-sig-notation (vector name value human-readable critical))) | ||
| 751 | |||
| 752 | (defun epg-sig-notation-name (sig-notation) | ||
| 753 | "Return the name of SIG-NOTATION." | ||
| 754 | (unless (eq (car-safe sig-notation) 'epg-sig-notation) | ||
| 755 | (signal 'wrong-type-argument (list 'epg-sig-notation-p | ||
| 756 | sig-notation))) | ||
| 757 | (aref (cdr sig-notation) 0)) | ||
| 758 | |||
| 759 | (defun epg-sig-notation-value (sig-notation) | ||
| 760 | "Return the value of SIG-NOTATION." | ||
| 761 | (unless (eq (car-safe sig-notation) 'epg-sig-notation) | ||
| 762 | (signal 'wrong-type-argument (list 'epg-sig-notation-p | ||
| 763 | sig-notation))) | ||
| 764 | (aref (cdr sig-notation) 1)) | ||
| 765 | |||
| 766 | (defun epg-sig-notation-human-readable (sig-notation) | ||
| 767 | "Return the human-readable of SIG-NOTATION." | ||
| 768 | (unless (eq (car-safe sig-notation) 'epg-sig-notation) | ||
| 769 | (signal 'wrong-type-argument (list 'epg-sig-notation-p | ||
| 770 | sig-notation))) | ||
| 771 | (aref (cdr sig-notation) 2)) | ||
| 772 | |||
| 773 | (defun epg-sig-notation-critical (sig-notation) | ||
| 774 | "Return the critical of SIG-NOTATION." | ||
| 775 | (unless (eq (car-safe sig-notation) 'epg-sig-notation) | ||
| 776 | (signal 'wrong-type-argument (list 'epg-sig-notation-p | ||
| 777 | sig-notation))) | ||
| 778 | (aref (cdr sig-notation) 3)) | ||
| 779 | |||
| 780 | (defun epg-sig-notation-set-value (sig-notation value) | ||
| 781 | "Set the value of SIG-NOTATION." | ||
| 782 | (unless (eq (car-safe sig-notation) 'epg-sig-notation) | ||
| 783 | (signal 'wrong-type-argument (list 'epg-sig-notation-p | ||
| 784 | sig-notation))) | ||
| 785 | (aset (cdr sig-notation) 1 value)) | ||
| 786 | |||
| 787 | (defun epg-make-import-status (fingerprint &optional reason new user-id | ||
| 788 | signature sub-key secret) | ||
| 789 | "Return a import status object." | ||
| 790 | (cons 'epg-import-status (vector fingerprint reason new user-id signature | ||
| 791 | sub-key secret))) | ||
| 792 | |||
| 793 | (defun epg-import-status-fingerprint (import-status) | ||
| 794 | "Return the fingerprint of the key that was considered." | ||
| 795 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 796 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 797 | (aref (cdr import-status) 0)) | ||
| 798 | |||
| 799 | (defun epg-import-status-reason (import-status) | ||
| 800 | "Return the reason code for import failure." | ||
| 801 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 802 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 803 | (aref (cdr import-status) 1)) | ||
| 804 | |||
| 805 | (defun epg-import-status-new (import-status) | ||
| 806 | "Return t if the imported key was new." | ||
| 807 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 808 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 809 | (aref (cdr import-status) 2)) | ||
| 810 | |||
| 811 | (defun epg-import-status-user-id (import-status) | ||
| 812 | "Return t if the imported key contained new user IDs." | ||
| 813 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 814 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 815 | (aref (cdr import-status) 3)) | ||
| 816 | |||
| 817 | (defun epg-import-status-signature (import-status) | ||
| 818 | "Return t if the imported key contained new signatures." | ||
| 819 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 820 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 821 | (aref (cdr import-status) 4)) | ||
| 822 | |||
| 823 | (defun epg-import-status-sub-key (import-status) | ||
| 824 | "Return t if the imported key contained new sub keys." | ||
| 825 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 826 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 827 | (aref (cdr import-status) 5)) | ||
| 828 | |||
| 829 | (defun epg-import-status-secret (import-status) | ||
| 830 | "Return t if the imported key contained a secret key." | ||
| 831 | (unless (eq (car-safe import-status) 'epg-import-status) | ||
| 832 | (signal 'wrong-type-argument (list 'epg-import-status-p import-status))) | ||
| 833 | (aref (cdr import-status) 6)) | ||
| 834 | |||
| 835 | (defun epg-make-import-result (considered no-user-id imported imported-rsa | ||
| 836 | unchanged new-user-ids new-sub-keys | ||
| 837 | new-signatures new-revocations | ||
| 838 | secret-read secret-imported | ||
| 839 | secret-unchanged not-imported | ||
| 840 | imports) | ||
| 841 | "Return a import result object." | ||
| 842 | (cons 'epg-import-result (vector considered no-user-id imported imported-rsa | ||
| 843 | unchanged new-user-ids new-sub-keys | ||
| 844 | new-signatures new-revocations secret-read | ||
| 845 | secret-imported secret-unchanged | ||
| 846 | not-imported imports))) | ||
| 847 | |||
| 848 | (defun epg-import-result-considered (import-result) | ||
| 849 | "Return the total number of considered keys." | ||
| 850 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 851 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 852 | (aref (cdr import-result) 0)) | ||
| 853 | |||
| 854 | (defun epg-import-result-no-user-id (import-result) | ||
| 855 | "Return the number of keys without user ID." | ||
| 856 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 857 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 858 | (aref (cdr import-result) 1)) | ||
| 859 | |||
| 860 | (defun epg-import-result-imported (import-result) | ||
| 861 | "Return the number of imported keys." | ||
| 862 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 863 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 864 | (aref (cdr import-result) 2)) | ||
| 865 | |||
| 866 | (defun epg-import-result-imported-rsa (import-result) | ||
| 867 | "Return the number of imported RSA keys." | ||
| 868 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 869 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 870 | (aref (cdr import-result) 3)) | ||
| 871 | |||
| 872 | (defun epg-import-result-unchanged (import-result) | ||
| 873 | "Return the number of unchanged keys." | ||
| 874 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 875 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 876 | (aref (cdr import-result) 4)) | ||
| 877 | |||
| 878 | (defun epg-import-result-new-user-ids (import-result) | ||
| 879 | "Return the number of new user IDs." | ||
| 880 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 881 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 882 | (aref (cdr import-result) 5)) | ||
| 883 | |||
| 884 | (defun epg-import-result-new-sub-keys (import-result) | ||
| 885 | "Return the number of new sub keys." | ||
| 886 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 887 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 888 | (aref (cdr import-result) 6)) | ||
| 889 | |||
| 890 | (defun epg-import-result-new-signatures (import-result) | ||
| 891 | "Return the number of new signatures." | ||
| 892 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 893 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 894 | (aref (cdr import-result) 7)) | ||
| 895 | |||
| 896 | (defun epg-import-result-new-revocations (import-result) | ||
| 897 | "Return the number of new revocations." | ||
| 898 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 899 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 900 | (aref (cdr import-result) 8)) | ||
| 901 | |||
| 902 | (defun epg-import-result-secret-read (import-result) | ||
| 903 | "Return the total number of secret keys read." | ||
| 904 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 905 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 906 | (aref (cdr import-result) 9)) | ||
| 907 | |||
| 908 | (defun epg-import-result-secret-imported (import-result) | ||
| 909 | "Return the number of imported secret keys." | ||
| 910 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 911 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 912 | (aref (cdr import-result) 10)) | ||
| 913 | |||
| 914 | (defun epg-import-result-secret-unchanged (import-result) | ||
| 915 | "Return the number of unchanged secret keys." | ||
| 916 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 917 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 918 | (aref (cdr import-result) 11)) | ||
| 919 | |||
| 920 | (defun epg-import-result-not-imported (import-result) | ||
| 921 | "Return the number of keys not imported." | ||
| 922 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 923 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 924 | (aref (cdr import-result) 12)) | ||
| 925 | |||
| 926 | (defun epg-import-result-imports (import-result) | ||
| 927 | "Return the list of `epg-import-status' objects." | ||
| 928 | (unless (eq (car-safe import-result) 'epg-import-result) | ||
| 929 | (signal 'wrong-type-argument (list 'epg-import-result-p import-result))) | ||
| 930 | (aref (cdr import-result) 13)) | ||
| 931 | |||
| 932 | (defun epg-context-result-for (context name) | ||
| 933 | "Return the result of CONTEXT associated with NAME." | ||
| 934 | (cdr (assq name (epg-context-result context)))) | ||
| 935 | |||
| 936 | (defun epg-context-set-result-for (context name value) | ||
| 937 | "Set the result of CONTEXT associated with NAME to VALUE." | ||
| 938 | (let* ((result (epg-context-result context)) | ||
| 939 | (entry (assq name result))) | ||
| 940 | (if entry | ||
| 941 | (setcdr entry value) | ||
| 942 | (epg-context-set-result context (cons (cons name value) result))))) | ||
| 943 | |||
| 944 | (defun epg-signature-to-string (signature) | ||
| 945 | "Convert SIGNATURE to a human readable string." | ||
| 946 | (let* ((user-id (cdr (assoc (epg-signature-key-id signature) | ||
| 947 | epg-user-id-alist))) | ||
| 948 | (pubkey-algorithm (epg-signature-pubkey-algorithm signature))) | ||
| 949 | (concat | ||
| 950 | (cond ((eq (epg-signature-status signature) 'good) | ||
| 951 | "Good signature from ") | ||
| 952 | ((eq (epg-signature-status signature) 'bad) | ||
| 953 | "Bad signature from ") | ||
| 954 | ((eq (epg-signature-status signature) 'expired) | ||
| 955 | "Expired signature from ") | ||
| 956 | ((eq (epg-signature-status signature) 'expired-key) | ||
| 957 | "Signature made by expired key ") | ||
| 958 | ((eq (epg-signature-status signature) 'revoked-key) | ||
| 959 | "Signature made by revoked key ") | ||
| 960 | ((eq (epg-signature-status signature) 'no-pubkey) | ||
| 961 | "No public key for ")) | ||
| 962 | (epg-signature-key-id signature) | ||
| 963 | (if user-id | ||
| 964 | (concat " " | ||
| 965 | (if (stringp user-id) | ||
| 966 | user-id | ||
| 967 | (epg-decode-dn user-id))) | ||
| 968 | "") | ||
| 969 | (if (epg-signature-validity signature) | ||
| 970 | (format " (trust %s)" (epg-signature-validity signature)) | ||
| 971 | "") | ||
| 972 | (if (epg-signature-creation-time signature) | ||
| 973 | (format-time-string " created at %Y-%m-%dT%T%z" | ||
| 974 | (epg-signature-creation-time signature)) | ||
| 975 | "") | ||
| 976 | (if pubkey-algorithm | ||
| 977 | (concat " using " | ||
| 978 | (or (cdr (assq pubkey-algorithm epg-pubkey-algorithm-alist)) | ||
| 979 | (format "(unknown algorithm %d)" pubkey-algorithm))) | ||
| 980 | "")))) | ||
| 981 | |||
| 982 | (defun epg-verify-result-to-string (verify-result) | ||
| 983 | "Convert VERIFY-RESULT to a human readable string." | ||
| 984 | (mapconcat #'epg-signature-to-string verify-result "\n")) | ||
| 985 | |||
| 986 | (defun epg-new-signature-to-string (new-signature) | ||
| 987 | "Convert NEW-SIGNATURE to a human readable string." | ||
| 988 | (concat | ||
| 989 | (cond ((eq (epg-new-signature-type new-signature) 'detached) | ||
| 990 | "Detached signature ") | ||
| 991 | ((eq (epg-new-signature-type new-signature) 'clear) | ||
| 992 | "Cleartext signature ") | ||
| 993 | (t | ||
| 994 | "Signature ")) | ||
| 995 | (cdr (assq (epg-new-signature-pubkey-algorithm new-signature) | ||
| 996 | epg-pubkey-algorithm-alist)) | ||
| 997 | "/" | ||
| 998 | (cdr (assq (epg-new-signature-digest-algorithm new-signature) | ||
| 999 | epg-digest-algorithm-alist)) | ||
| 1000 | " " | ||
| 1001 | (format "%02X " (epg-new-signature-class new-signature)) | ||
| 1002 | (epg-new-signature-fingerprint new-signature))) | ||
| 1003 | |||
| 1004 | (defun epg-import-result-to-string (import-result) | ||
| 1005 | "Convert IMPORT-RESULT to a human readable string." | ||
| 1006 | (concat (format "Total number processed: %d\n" | ||
| 1007 | (epg-import-result-considered import-result)) | ||
| 1008 | (if (> (epg-import-result-not-imported import-result) 0) | ||
| 1009 | (format " skipped new keys: %d\n" | ||
| 1010 | (epg-import-result-not-imported import-result))) | ||
| 1011 | (if (> (epg-import-result-no-user-id import-result) 0) | ||
| 1012 | (format " w/o user IDs: %d\n" | ||
| 1013 | (epg-import-result-no-user-id import-result))) | ||
| 1014 | (if (> (epg-import-result-imported import-result) 0) | ||
| 1015 | (concat (format " imported: %d" | ||
| 1016 | (epg-import-result-imported import-result)) | ||
| 1017 | (if (> (epg-import-result-imported-rsa import-result) 0) | ||
| 1018 | (format " (RSA: %d)" | ||
| 1019 | (epg-import-result-imported-rsa | ||
| 1020 | import-result))) | ||
| 1021 | "\n")) | ||
| 1022 | (if (> (epg-import-result-unchanged import-result) 0) | ||
| 1023 | (format " unchanged: %d\n" | ||
| 1024 | (epg-import-result-unchanged import-result))) | ||
| 1025 | (if (> (epg-import-result-new-user-ids import-result) 0) | ||
| 1026 | (format " new user IDs: %d\n" | ||
| 1027 | (epg-import-result-new-user-ids import-result))) | ||
| 1028 | (if (> (epg-import-result-new-sub-keys import-result) 0) | ||
| 1029 | (format " new subkeys: %d\n" | ||
| 1030 | (epg-import-result-new-sub-keys import-result))) | ||
| 1031 | (if (> (epg-import-result-new-signatures import-result) 0) | ||
| 1032 | (format " new signatures: %d\n" | ||
| 1033 | (epg-import-result-new-signatures import-result))) | ||
| 1034 | (if (> (epg-import-result-new-revocations import-result) 0) | ||
| 1035 | (format " new key revocations: %d\n" | ||
| 1036 | (epg-import-result-new-revocations import-result))) | ||
| 1037 | (if (> (epg-import-result-secret-read import-result) 0) | ||
| 1038 | (format " secret keys read: %d\n" | ||
| 1039 | (epg-import-result-secret-read import-result))) | ||
| 1040 | (if (> (epg-import-result-secret-imported import-result) 0) | ||
| 1041 | (format " secret keys imported: %d\n" | ||
| 1042 | (epg-import-result-secret-imported import-result))) | ||
| 1043 | (if (> (epg-import-result-secret-unchanged import-result) 0) | ||
| 1044 | (format " secret keys unchanged: %d\n" | ||
| 1045 | (epg-import-result-secret-unchanged import-result))))) | ||
| 1046 | |||
| 1047 | (defun epg--start (context args) | ||
| 1048 | "Start `epg-gpg-program' in a subprocess with given ARGS." | ||
| 1049 | (if (and (epg-context-process context) | ||
| 1050 | (eq (process-status (epg-context-process context)) 'run)) | ||
| 1051 | (error "%s is already running in this context" | ||
| 1052 | (if (eq (epg-context-protocol context) 'CMS) | ||
| 1053 | epg-gpgsm-program | ||
| 1054 | epg-gpg-program))) | ||
| 1055 | (let* ((args (append (list "--no-tty" | ||
| 1056 | "--status-fd" "1" | ||
| 1057 | "--yes") | ||
| 1058 | (if (and (not (eq (epg-context-protocol context) 'CMS)) | ||
| 1059 | (string-match ":" (or (getenv "GPG_AGENT_INFO") | ||
| 1060 | ""))) | ||
| 1061 | '("--use-agent")) | ||
| 1062 | (if (and (not (eq (epg-context-protocol context) 'CMS)) | ||
| 1063 | (epg-context-progress-callback context)) | ||
| 1064 | '("--enable-progress-filter")) | ||
| 1065 | (if epg-gpg-home-directory | ||
| 1066 | (list "--homedir" epg-gpg-home-directory)) | ||
| 1067 | (unless (eq (epg-context-protocol context) 'CMS) | ||
| 1068 | '("--command-fd" "0")) | ||
| 1069 | (if (epg-context-armor context) '("--armor")) | ||
| 1070 | (if (epg-context-textmode context) '("--textmode")) | ||
| 1071 | (if (epg-context-output-file context) | ||
| 1072 | (list "--output" (epg-context-output-file context))) | ||
| 1073 | args)) | ||
| 1074 | (coding-system-for-write 'binary) | ||
| 1075 | (coding-system-for-read 'binary) | ||
| 1076 | process-connection-type | ||
| 1077 | (orig-mode (default-file-modes)) | ||
| 1078 | (buffer (generate-new-buffer " *epg*")) | ||
| 1079 | process) | ||
| 1080 | (if epg-debug | ||
| 1081 | (save-excursion | ||
| 1082 | (unless epg-debug-buffer | ||
| 1083 | (setq epg-debug-buffer (generate-new-buffer " *epg-debug*"))) | ||
| 1084 | (set-buffer epg-debug-buffer) | ||
| 1085 | (goto-char (point-max)) | ||
| 1086 | (insert (format "%s %s\n" | ||
| 1087 | (if (eq (epg-context-protocol context) 'CMS) | ||
| 1088 | epg-gpgsm-program | ||
| 1089 | epg-gpg-program) | ||
| 1090 | (mapconcat #'identity args " "))))) | ||
| 1091 | (with-current-buffer buffer | ||
| 1092 | (if (fboundp 'set-buffer-multibyte) | ||
| 1093 | (set-buffer-multibyte nil)) | ||
| 1094 | (make-local-variable 'epg-last-status) | ||
| 1095 | (setq epg-last-status nil) | ||
| 1096 | (make-local-variable 'epg-read-point) | ||
| 1097 | (setq epg-read-point (point-min)) | ||
| 1098 | (make-local-variable 'epg-process-filter-running) | ||
| 1099 | (setq epg-process-filter-running nil) | ||
| 1100 | (make-local-variable 'epg-pending-status-list) | ||
| 1101 | (setq epg-pending-status-list nil) | ||
| 1102 | (make-local-variable 'epg-key-id) | ||
| 1103 | (setq epg-key-id nil) | ||
| 1104 | (make-local-variable 'epg-context) | ||
| 1105 | (setq epg-context context)) | ||
| 1106 | (unwind-protect | ||
| 1107 | (progn | ||
| 1108 | (set-default-file-modes 448) | ||
| 1109 | (setq process | ||
| 1110 | (apply #'start-process "epg" buffer | ||
| 1111 | (if (eq (epg-context-protocol context) 'CMS) | ||
| 1112 | epg-gpgsm-program | ||
| 1113 | epg-gpg-program) | ||
| 1114 | args))) | ||
| 1115 | (set-default-file-modes orig-mode)) | ||
| 1116 | (set-process-filter process #'epg--process-filter) | ||
| 1117 | (epg-context-set-process context process))) | ||
| 1118 | |||
| 1119 | (defun epg--process-filter (process input) | ||
| 1120 | (if epg-debug | ||
| 1121 | (save-excursion | ||
| 1122 | (unless epg-debug-buffer | ||
| 1123 | (setq epg-debug-buffer (generate-new-buffer " *epg-debug*"))) | ||
| 1124 | (set-buffer epg-debug-buffer) | ||
| 1125 | (goto-char (point-max)) | ||
| 1126 | (insert input))) | ||
| 1127 | (if (buffer-live-p (process-buffer process)) | ||
| 1128 | (save-excursion | ||
| 1129 | (set-buffer (process-buffer process)) | ||
| 1130 | (goto-char (point-max)) | ||
| 1131 | (insert input) | ||
| 1132 | (unless epg-process-filter-running | ||
| 1133 | (unwind-protect | ||
| 1134 | (progn | ||
| 1135 | (setq epg-process-filter-running t) | ||
| 1136 | (goto-char epg-read-point) | ||
| 1137 | (beginning-of-line) | ||
| 1138 | (while (looking-at ".*\n") ;the input line finished | ||
| 1139 | (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)") | ||
| 1140 | (let* ((status (match-string 1)) | ||
| 1141 | (string (match-string 2)) | ||
| 1142 | (symbol (intern-soft (concat "epg--status-" | ||
| 1143 | status)))) | ||
| 1144 | (if (member status epg-pending-status-list) | ||
| 1145 | (setq epg-pending-status-list nil)) | ||
| 1146 | (if (and symbol | ||
| 1147 | (fboundp symbol)) | ||
| 1148 | (funcall symbol epg-context string)) | ||
| 1149 | (setq epg-last-status (cons status string)))) | ||
| 1150 | (forward-line) | ||
| 1151 | (setq epg-read-point (point)))) | ||
| 1152 | (setq epg-process-filter-running nil)))))) | ||
| 1153 | |||
| 1154 | (defun epg-read-output (context) | ||
| 1155 | "Read the output file CONTEXT and return the content as a string." | ||
| 1156 | (with-temp-buffer | ||
| 1157 | (if (fboundp 'set-buffer-multibyte) | ||
| 1158 | (set-buffer-multibyte nil)) | ||
| 1159 | (if (file-exists-p (epg-context-output-file context)) | ||
| 1160 | (let ((coding-system-for-read 'binary)) | ||
| 1161 | (insert-file-contents (epg-context-output-file context)) | ||
| 1162 | (buffer-string))))) | ||
| 1163 | |||
| 1164 | (defun epg-wait-for-status (context status-list) | ||
| 1165 | "Wait until one of elements in STATUS-LIST arrives." | ||
| 1166 | (with-current-buffer (process-buffer (epg-context-process context)) | ||
| 1167 | (setq epg-pending-status-list status-list) | ||
| 1168 | (while (and (eq (process-status (epg-context-process context)) 'run) | ||
| 1169 | epg-pending-status-list) | ||
| 1170 | (accept-process-output (epg-context-process context) 1)))) | ||
| 1171 | |||
| 1172 | (defun epg-wait-for-completion (context) | ||
| 1173 | "Wait until the `epg-gpg-program' process completes." | ||
| 1174 | (while (eq (process-status (epg-context-process context)) 'run) | ||
| 1175 | (accept-process-output (epg-context-process context) 1))) | ||
| 1176 | |||
| 1177 | (defun epg-reset (context) | ||
| 1178 | "Reset the CONTEXT." | ||
| 1179 | (if (and (epg-context-process context) | ||
| 1180 | (buffer-live-p (process-buffer (epg-context-process context)))) | ||
| 1181 | (kill-buffer (process-buffer (epg-context-process context)))) | ||
| 1182 | (epg-context-set-process context nil)) | ||
| 1183 | |||
| 1184 | (defun epg-delete-output-file (context) | ||
| 1185 | "Delete the output file of CONTEXT." | ||
| 1186 | (if (and (epg-context-output-file context) | ||
| 1187 | (file-exists-p (epg-context-output-file context))) | ||
| 1188 | (delete-file (epg-context-output-file context)))) | ||
| 1189 | |||
| 1190 | (eval-and-compile | ||
| 1191 | (if (fboundp 'decode-coding-string) | ||
| 1192 | (defalias 'epg--decode-coding-string 'decode-coding-string) | ||
| 1193 | (defalias 'epg--decode-coding-string 'identity))) | ||
| 1194 | |||
| 1195 | (defun epg--status-USERID_HINT (context string) | ||
| 1196 | (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string) | ||
| 1197 | (let* ((key-id (match-string 1 string)) | ||
| 1198 | (user-id (match-string 2 string)) | ||
| 1199 | (entry (assoc key-id epg-user-id-alist))) | ||
| 1200 | (condition-case nil | ||
| 1201 | (setq user-id (epg--decode-coding-string | ||
| 1202 | (epg--decode-percent-escape user-id) | ||
| 1203 | 'utf-8)) | ||
| 1204 | (error)) | ||
| 1205 | (if entry | ||
| 1206 | (setcdr entry user-id) | ||
| 1207 | (setq epg-user-id-alist (cons (cons key-id user-id) | ||
| 1208 | epg-user-id-alist)))))) | ||
| 1209 | |||
| 1210 | (defun epg--status-NEED_PASSPHRASE (context string) | ||
| 1211 | (if (string-match "\\`\\([^ ]+\\)" string) | ||
| 1212 | (setq epg-key-id (match-string 1 string)))) | ||
| 1213 | |||
| 1214 | (defun epg--status-NEED_PASSPHRASE_SYM (context string) | ||
| 1215 | (setq epg-key-id 'SYM)) | ||
| 1216 | |||
| 1217 | (defun epg--status-NEED_PASSPHRASE_PIN (context string) | ||
| 1218 | (setq epg-key-id 'PIN)) | ||
| 1219 | |||
| 1220 | (eval-and-compile | ||
| 1221 | (if (fboundp 'clear-string) | ||
| 1222 | (defalias 'epg--clear-string 'clear-string) | ||
| 1223 | (defun epg--clear-string (string) | ||
| 1224 | (fillarray string 0)))) | ||
| 1225 | |||
| 1226 | (eval-and-compile | ||
| 1227 | (if (fboundp 'encode-coding-string) | ||
| 1228 | (defalias 'epg--encode-coding-string 'encode-coding-string) | ||
| 1229 | (defalias 'epg--encode-coding-string 'identity))) | ||
| 1230 | |||
| 1231 | (defun epg--status-GET_HIDDEN (context string) | ||
| 1232 | (when (and epg-key-id | ||
| 1233 | (string-match "\\`passphrase\\." string)) | ||
| 1234 | (unless (epg-context-passphrase-callback context) | ||
| 1235 | (error "passphrase-callback not set")) | ||
| 1236 | (let (inhibit-quit | ||
| 1237 | passphrase | ||
| 1238 | passphrase-with-new-line | ||
| 1239 | encoded-passphrase-with-new-line) | ||
| 1240 | (unwind-protect | ||
| 1241 | (condition-case nil | ||
| 1242 | (progn | ||
| 1243 | (setq passphrase | ||
| 1244 | (funcall | ||
| 1245 | (if (consp (epg-context-passphrase-callback context)) | ||
| 1246 | (car (epg-context-passphrase-callback context)) | ||
| 1247 | (epg-context-passphrase-callback context)) | ||
| 1248 | context | ||
| 1249 | epg-key-id | ||
| 1250 | (if (consp (epg-context-passphrase-callback context)) | ||
| 1251 | (cdr (epg-context-passphrase-callback context))))) | ||
| 1252 | (when passphrase | ||
| 1253 | (setq passphrase-with-new-line (concat passphrase "\n")) | ||
| 1254 | (epg--clear-string passphrase) | ||
| 1255 | (setq passphrase nil) | ||
| 1256 | (if epg-passphrase-coding-system | ||
| 1257 | (progn | ||
| 1258 | (setq encoded-passphrase-with-new-line | ||
| 1259 | (epg--encode-coding-string | ||
| 1260 | passphrase-with-new-line | ||
| 1261 | (coding-system-change-eol-conversion | ||
| 1262 | epg-passphrase-coding-system 'unix))) | ||
| 1263 | (epg--clear-string passphrase-with-new-line) | ||
| 1264 | (setq passphrase-with-new-line nil)) | ||
| 1265 | (setq encoded-passphrase-with-new-line | ||
| 1266 | passphrase-with-new-line | ||
| 1267 | passphrase-with-new-line nil)) | ||
| 1268 | (process-send-string (epg-context-process context) | ||
| 1269 | encoded-passphrase-with-new-line))) | ||
| 1270 | (quit | ||
| 1271 | (epg-context-set-result-for | ||
| 1272 | context 'error | ||
| 1273 | (cons '(quit) | ||
| 1274 | (epg-context-result-for context 'error))) | ||
| 1275 | (delete-process (epg-context-process context)))) | ||
| 1276 | (if passphrase | ||
| 1277 | (epg--clear-string passphrase)) | ||
| 1278 | (if passphrase-with-new-line | ||
| 1279 | (epg--clear-string passphrase-with-new-line)) | ||
| 1280 | (if encoded-passphrase-with-new-line | ||
| 1281 | (epg--clear-string encoded-passphrase-with-new-line)))))) | ||
| 1282 | |||
| 1283 | (defun epg--prompt-GET_BOOL (context string) | ||
| 1284 | (let ((entry (assoc string epg-prompt-alist))) | ||
| 1285 | (y-or-n-p (if entry (cdr entry) (concat string "? "))))) | ||
| 1286 | |||
| 1287 | (defun epg--prompt-GET_BOOL-untrusted_key.override (context string) | ||
| 1288 | (y-or-n-p (if (and (equal (car epg-last-status) "USERID_HINT") | ||
| 1289 | (string-match "\\`\\([^ ]+\\) \\(.*\\)" | ||
| 1290 | (cdr epg-last-status))) | ||
| 1291 | (let* ((key-id (match-string 1 (cdr epg-last-status))) | ||
| 1292 | (user-id (match-string 2 (cdr epg-last-status))) | ||
| 1293 | (entry (assoc key-id epg-user-id-alist))) | ||
| 1294 | (if entry | ||
| 1295 | (setq user-id (cdr entry))) | ||
| 1296 | (format "Untrusted key %s %s. Use anyway? " key-id user-id)) | ||
| 1297 | "Use untrusted key anyway? "))) | ||
| 1298 | |||
| 1299 | (defun epg--status-GET_BOOL (context string) | ||
| 1300 | (let (inhibit-quit) | ||
| 1301 | (condition-case nil | ||
| 1302 | (if (funcall (or (intern-soft (concat "epg--prompt-GET_BOOL-" string)) | ||
| 1303 | #'epg--prompt-GET_BOOL) | ||
| 1304 | context string) | ||
| 1305 | (process-send-string (epg-context-process context) "y\n") | ||
| 1306 | (process-send-string (epg-context-process context) "n\n")) | ||
| 1307 | (quit | ||
| 1308 | (epg-context-set-result-for | ||
| 1309 | context 'error | ||
| 1310 | (cons '(quit) | ||
| 1311 | (epg-context-result-for context 'error))) | ||
| 1312 | (delete-process (epg-context-process context)))))) | ||
| 1313 | |||
| 1314 | (defun epg--status-GET_LINE (context string) | ||
| 1315 | (let ((entry (assoc string epg-prompt-alist)) | ||
| 1316 | inhibit-quit) | ||
| 1317 | (condition-case nil | ||
| 1318 | (process-send-string (epg-context-process context) | ||
| 1319 | (concat (read-string | ||
| 1320 | (if entry | ||
| 1321 | (cdr entry) | ||
| 1322 | (concat string ": "))) | ||
| 1323 | "\n")) | ||
| 1324 | (quit | ||
| 1325 | (epg-context-set-result-for | ||
| 1326 | context 'error | ||
| 1327 | (cons '(quit) | ||
| 1328 | (epg-context-result-for context 'error))) | ||
| 1329 | (delete-process (epg-context-process context)))))) | ||
| 1330 | |||
| 1331 | (defun epg--status-*SIG (context status string) | ||
| 1332 | (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string) | ||
| 1333 | (let* ((key-id (match-string 1 string)) | ||
| 1334 | (user-id (match-string 2 string)) | ||
| 1335 | (entry (assoc key-id epg-user-id-alist))) | ||
| 1336 | (epg-context-set-result-for | ||
| 1337 | context | ||
| 1338 | 'verify | ||
| 1339 | (cons (epg-make-signature status key-id) | ||
| 1340 | (epg-context-result-for context 'verify))) | ||
| 1341 | (condition-case nil | ||
| 1342 | (if (eq (epg-context-protocol context) 'CMS) | ||
| 1343 | (setq user-id (epg-dn-from-string user-id)) | ||
| 1344 | (setq user-id (epg--decode-coding-string | ||
| 1345 | (epg--decode-percent-escape user-id) | ||
| 1346 | 'utf-8))) | ||
| 1347 | (error)) | ||
| 1348 | (if entry | ||
| 1349 | (setcdr entry user-id) | ||
| 1350 | (setq epg-user-id-alist | ||
| 1351 | (cons (cons key-id user-id) epg-user-id-alist)))) | ||
| 1352 | (epg-context-set-result-for | ||
| 1353 | context | ||
| 1354 | 'verify | ||
| 1355 | (cons (epg-make-signature status) | ||
| 1356 | (epg-context-result-for context 'verify))))) | ||
| 1357 | |||
| 1358 | (defun epg--status-GOODSIG (context string) | ||
| 1359 | (epg--status-*SIG context 'good string)) | ||
| 1360 | |||
| 1361 | (defun epg--status-EXPSIG (context string) | ||
| 1362 | (epg--status-*SIG context 'expired string)) | ||
| 1363 | |||
| 1364 | (defun epg--status-EXPKEYSIG (context string) | ||
| 1365 | (epg--status-*SIG context 'expired-key string)) | ||
| 1366 | |||
| 1367 | (defun epg--status-REVKEYSIG (context string) | ||
| 1368 | (epg--status-*SIG context 'revoked-key string)) | ||
| 1369 | |||
| 1370 | (defun epg--status-BADSIG (context string) | ||
| 1371 | (epg--status-*SIG context 'bad string)) | ||
| 1372 | |||
| 1373 | (defun epg--status-NO_PUBKEY (context string) | ||
| 1374 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1375 | (if (and signature | ||
| 1376 | (eq (epg-signature-status signature) 'error) | ||
| 1377 | (equal (epg-signature-key-id signature) string)) | ||
| 1378 | (epg-signature-set-status signature 'no-pubkey)))) | ||
| 1379 | |||
| 1380 | (defun epg--time-from-seconds (seconds) | ||
| 1381 | (let ((number-seconds (string-to-number (concat seconds ".0")))) | ||
| 1382 | (cons (floor (/ number-seconds 65536)) | ||
| 1383 | (floor (mod number-seconds 65536))))) | ||
| 1384 | |||
| 1385 | (defun epg--status-ERRSIG (context string) | ||
| 1386 | (if (string-match "\\`\\([^ ]+\\) \\([0-9]+\\) \\([0-9]+\\) \ | ||
| 1387 | \\([0-9A-Fa-f][0-9A-Fa-f]\\) \\([^ ]+\\) \\([0-9]+\\)" | ||
| 1388 | string) | ||
| 1389 | (let ((signature (epg-make-signature 'error))) | ||
| 1390 | (epg-context-set-result-for | ||
| 1391 | context | ||
| 1392 | 'verify | ||
| 1393 | (cons signature | ||
| 1394 | (epg-context-result-for context 'verify))) | ||
| 1395 | (epg-signature-set-key-id | ||
| 1396 | signature | ||
| 1397 | (match-string 1 string)) | ||
| 1398 | (epg-signature-set-pubkey-algorithm | ||
| 1399 | signature | ||
| 1400 | (string-to-number (match-string 2 string))) | ||
| 1401 | (epg-signature-set-digest-algorithm | ||
| 1402 | signature | ||
| 1403 | (string-to-number (match-string 3 string))) | ||
| 1404 | (epg-signature-set-class | ||
| 1405 | signature | ||
| 1406 | (string-to-number (match-string 4 string) 16)) | ||
| 1407 | (epg-signature-set-creation-time | ||
| 1408 | signature | ||
| 1409 | (epg--time-from-seconds (match-string 5 string)))))) | ||
| 1410 | |||
| 1411 | (defun epg--status-VALIDSIG (context string) | ||
| 1412 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1413 | (when (and signature | ||
| 1414 | (eq (epg-signature-status signature) 'good) | ||
| 1415 | (string-match "\\`\\([^ ]+\\) [^ ]+ \\([^ ]+\\) \\([^ ]+\\) \ | ||
| 1416 | \\([0-9]+\\) [^ ]+ \\([0-9]+\\) \\([0-9]+\\) \\([0-9A-Fa-f][0-9A-Fa-f]\\) \ | ||
| 1417 | \\(.*\\)" | ||
| 1418 | string)) | ||
| 1419 | (epg-signature-set-fingerprint | ||
| 1420 | signature | ||
| 1421 | (match-string 1 string)) | ||
| 1422 | (epg-signature-set-creation-time | ||
| 1423 | signature | ||
| 1424 | (epg--time-from-seconds (match-string 2 string))) | ||
| 1425 | (unless (equal (match-string 3 string) "0") | ||
| 1426 | (epg-signature-set-expiration-time | ||
| 1427 | signature | ||
| 1428 | (epg--time-from-seconds (match-string 3 string)))) | ||
| 1429 | (epg-signature-set-version | ||
| 1430 | signature | ||
| 1431 | (string-to-number (match-string 4 string))) | ||
| 1432 | (epg-signature-set-pubkey-algorithm | ||
| 1433 | signature | ||
| 1434 | (string-to-number (match-string 5 string))) | ||
| 1435 | (epg-signature-set-digest-algorithm | ||
| 1436 | signature | ||
| 1437 | (string-to-number (match-string 6 string))) | ||
| 1438 | (epg-signature-set-class | ||
| 1439 | signature | ||
| 1440 | (string-to-number (match-string 7 string) 16))))) | ||
| 1441 | |||
| 1442 | (defun epg--status-TRUST_UNDEFINED (context string) | ||
| 1443 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1444 | (if (and signature | ||
| 1445 | (eq (epg-signature-status signature) 'good)) | ||
| 1446 | (epg-signature-set-validity signature 'undefined)))) | ||
| 1447 | |||
| 1448 | (defun epg--status-TRUST_NEVER (context string) | ||
| 1449 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1450 | (if (and signature | ||
| 1451 | (eq (epg-signature-status signature) 'good)) | ||
| 1452 | (epg-signature-set-validity signature 'never)))) | ||
| 1453 | |||
| 1454 | (defun epg--status-TRUST_MARGINAL (context string) | ||
| 1455 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1456 | (if (and signature | ||
| 1457 | (eq (epg-signature-status signature) 'marginal)) | ||
| 1458 | (epg-signature-set-validity signature 'marginal)))) | ||
| 1459 | |||
| 1460 | (defun epg--status-TRUST_FULLY (context string) | ||
| 1461 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1462 | (if (and signature | ||
| 1463 | (eq (epg-signature-status signature) 'good)) | ||
| 1464 | (epg-signature-set-validity signature 'full)))) | ||
| 1465 | |||
| 1466 | (defun epg--status-TRUST_ULTIMATE (context string) | ||
| 1467 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1468 | (if (and signature | ||
| 1469 | (eq (epg-signature-status signature) 'good)) | ||
| 1470 | (epg-signature-set-validity signature 'ultimate)))) | ||
| 1471 | |||
| 1472 | (defun epg--status-NOTATION_NAME (context string) | ||
| 1473 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1474 | (if signature | ||
| 1475 | (epg-signature-set-notations | ||
| 1476 | signature | ||
| 1477 | (cons (epg-make-sig-notation string nil t nil) | ||
| 1478 | (epg-sig-notations signature)))))) | ||
| 1479 | |||
| 1480 | (defun epg--status-NOTATION_DATA (context string) | ||
| 1481 | (let ((signature (car (epg-context-result-for context 'verify))) | ||
| 1482 | notation) | ||
| 1483 | (if (and signature | ||
| 1484 | (setq notation (car (epg-sig-notations signature)))) | ||
| 1485 | (epg-sig-notation-set-value notation string)))) | ||
| 1486 | |||
| 1487 | (defun epg--status-POLICY_URL (context string) | ||
| 1488 | (let ((signature (car (epg-context-result-for context 'verify)))) | ||
| 1489 | (if signature | ||
| 1490 | (epg-signature-set-notations | ||
| 1491 | signature | ||
| 1492 | (cons (epg-make-sig-notation nil string t nil) | ||
| 1493 | (epg-sig-notations signature)))))) | ||
| 1494 | |||
| 1495 | (defun epg--status-PROGRESS (context string) | ||
| 1496 | (if (and (epg-context-progress-callback context) | ||
| 1497 | (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)" | ||
| 1498 | string)) | ||
| 1499 | (funcall (if (consp (epg-context-progress-callback context)) | ||
| 1500 | (car (epg-context-progress-callback context)) | ||
| 1501 | (epg-context-progress-callback context)) | ||
| 1502 | context | ||
| 1503 | (match-string 1 string) | ||
| 1504 | (match-string 2 string) | ||
| 1505 | (string-to-number (match-string 3 string)) | ||
| 1506 | (string-to-number (match-string 4 string)) | ||
| 1507 | (if (consp (epg-context-progress-callback context)) | ||
| 1508 | (cdr (epg-context-progress-callback context)))))) | ||
| 1509 | |||
| 1510 | (defun epg--status-ENC_TO (context string) | ||
| 1511 | (if (string-match "\\`\\([0-9A-Za-z]+\\) \\([0-9]+\\) \\([0-9]+\\)" string) | ||
| 1512 | (epg-context-set-result-for | ||
| 1513 | context 'encrypted-to | ||
| 1514 | (cons (list (match-string 1 string) | ||
| 1515 | (string-to-number (match-string 2 string)) | ||
| 1516 | (string-to-number (match-string 3 string))) | ||
| 1517 | (epg-context-result-for context 'encrypted-to))))) | ||
| 1518 | |||
| 1519 | (defun epg--status-DECRYPTION_FAILED (context string) | ||
| 1520 | (epg-context-set-result-for context 'decryption-failed t)) | ||
| 1521 | |||
| 1522 | (defun epg--status-DECRYPTION_OKAY (context string) | ||
| 1523 | (epg-context-set-result-for context 'decryption-okay t)) | ||
| 1524 | |||
| 1525 | (defun epg--status-NODATA (context string) | ||
| 1526 | (epg-context-set-result-for | ||
| 1527 | context 'error | ||
| 1528 | (cons (cons 'no-data (string-to-number string)) | ||
| 1529 | (epg-context-result-for context 'error)))) | ||
| 1530 | |||
| 1531 | (defun epg--status-UNEXPECTED (context string) | ||
| 1532 | (epg-context-set-result-for | ||
| 1533 | context 'error | ||
| 1534 | (cons (cons 'unexpected (string-to-number string)) | ||
| 1535 | (epg-context-result-for context 'error)))) | ||
| 1536 | |||
| 1537 | (defun epg--status-KEYEXPIRED (context string) | ||
| 1538 | (epg-context-set-result-for | ||
| 1539 | context 'error | ||
| 1540 | (cons (list 'key-expired (cons 'expiration-time | ||
| 1541 | (epg--time-from-seconds string))) | ||
| 1542 | (epg-context-result-for context 'error)))) | ||
| 1543 | |||
| 1544 | (defun epg--status-KEYREVOKED (context string) | ||
| 1545 | (epg-context-set-result-for | ||
| 1546 | context 'error | ||
| 1547 | (cons '(key-revoked) | ||
| 1548 | (epg-context-result-for context 'error)))) | ||
| 1549 | |||
| 1550 | (defun epg--status-BADARMOR (context string) | ||
| 1551 | (epg-context-set-result-for | ||
| 1552 | context 'error | ||
| 1553 | (cons '(bad-armor) | ||
| 1554 | (epg-context-result-for context 'error)))) | ||
| 1555 | |||
| 1556 | (defun epg--status-INV_RECP (context string) | ||
| 1557 | (if (string-match "\\`\\([0-9]+\\) \\(.*\\)" string) | ||
| 1558 | (epg-context-set-result-for | ||
| 1559 | context 'error | ||
| 1560 | (cons (list 'invalid-recipient | ||
| 1561 | (cons 'reason | ||
| 1562 | (string-to-number (match-string 1 string))) | ||
| 1563 | (cons 'requested-recipient | ||
| 1564 | (match-string 2 string))) | ||
| 1565 | (epg-context-result-for context 'error))))) | ||
| 1566 | |||
| 1567 | (defun epg--status-NO_RECP (context string) | ||
| 1568 | (epg-context-set-result-for | ||
| 1569 | context 'error | ||
| 1570 | (cons '(no-recipients) | ||
| 1571 | (epg-context-result-for context 'error)))) | ||
| 1572 | |||
| 1573 | (defun epg--status-DELETE_PROBLEM (context string) | ||
| 1574 | (if (string-match "\\`\\([0-9]+\\)" string) | ||
| 1575 | (epg-context-set-result-for | ||
| 1576 | context 'error | ||
| 1577 | (cons (cons 'delete-problem | ||
| 1578 | (string-to-number (match-string 1 string))) | ||
| 1579 | (epg-context-result-for context 'error))))) | ||
| 1580 | |||
| 1581 | (defun epg--status-SIG_CREATED (context string) | ||
| 1582 | (if (string-match "\\`\\([DCS]\\) \\([0-9]+\\) \\([0-9]+\\) \ | ||
| 1583 | \\([0-9A-Fa-F][0-9A-Fa-F]\\) \\(.*\\) " string) | ||
| 1584 | (epg-context-set-result-for | ||
| 1585 | context 'sign | ||
| 1586 | (cons (epg-make-new-signature | ||
| 1587 | (cdr (assq (aref (match-string 1 string) 0) | ||
| 1588 | epg-new-signature-type-alist)) | ||
| 1589 | (string-to-number (match-string 2 string)) | ||
| 1590 | (string-to-number (match-string 3 string)) | ||
| 1591 | (string-to-number (match-string 4 string) 16) | ||
| 1592 | (epg--time-from-seconds (match-string 5 string)) | ||
| 1593 | (substring string (match-end 0))) | ||
| 1594 | (epg-context-result-for context 'sign))))) | ||
| 1595 | |||
| 1596 | (defun epg--status-KEY_CREATED (context string) | ||
| 1597 | (if (string-match "\\`\\([BPS]\\) \\([^ ]+\\)" string) | ||
| 1598 | (epg-context-set-result-for | ||
| 1599 | context 'generate-key | ||
| 1600 | (cons (list (cons 'type (string-to-char (match-string 1 string))) | ||
| 1601 | (cons 'fingerprint (match-string 2 string))) | ||
| 1602 | (epg-context-result-for context 'generate-key))))) | ||
| 1603 | |||
| 1604 | (defun epg--status-KEY_NOT_CREATED (context string) | ||
| 1605 | (epg-context-set-result-for | ||
| 1606 | context 'error | ||
| 1607 | (cons '(key-not-created) | ||
| 1608 | (epg-context-result-for context 'error)))) | ||
| 1609 | |||
| 1610 | (defun epg--status-IMPORTED (context string) | ||
| 1611 | (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string) | ||
| 1612 | (let* ((key-id (match-string 1 string)) | ||
| 1613 | (user-id (match-string 2 string)) | ||
| 1614 | (entry (assoc key-id epg-user-id-alist))) | ||
| 1615 | (condition-case nil | ||
| 1616 | (setq user-id (epg--decode-coding-string | ||
| 1617 | (epg--decode-percent-escape user-id) | ||
| 1618 | 'utf-8)) | ||
| 1619 | (error)) | ||
| 1620 | (if entry | ||
| 1621 | (setcdr entry user-id) | ||
| 1622 | (setq epg-user-id-alist (cons (cons key-id user-id) | ||
| 1623 | epg-user-id-alist)))))) | ||
| 1624 | |||
| 1625 | (defun epg--status-IMPORT_OK (context string) | ||
| 1626 | (if (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string) | ||
| 1627 | (let ((reason (string-to-number (match-string 1 string)))) | ||
| 1628 | (epg-context-set-result-for | ||
| 1629 | context 'import-status | ||
| 1630 | (cons (epg-make-import-status (if (match-beginning 2) | ||
| 1631 | (match-string 3 string)) | ||
| 1632 | nil | ||
| 1633 | (/= (logand reason 1) 0) | ||
| 1634 | (/= (logand reason 2) 0) | ||
| 1635 | (/= (logand reason 4) 0) | ||
| 1636 | (/= (logand reason 8) 0) | ||
| 1637 | (/= (logand reason 16) 0)) | ||
| 1638 | (epg-context-result-for context 'import-status)))))) | ||
| 1639 | |||
| 1640 | (defun epg--status-IMPORT_PROBLEM (context string) | ||
| 1641 | (if (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string) | ||
| 1642 | (epg-context-set-result-for | ||
| 1643 | context 'import-status | ||
| 1644 | (cons (epg-make-import-status | ||
| 1645 | (if (match-beginning 2) | ||
| 1646 | (match-string 3 string)) | ||
| 1647 | (string-to-number (match-string 1 string))) | ||
| 1648 | (epg-context-result-for context 'import-status))))) | ||
| 1649 | |||
| 1650 | (defun epg--status-IMPORT_RES (context string) | ||
| 1651 | (when (string-match "\\`\\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \ | ||
| 1652 | \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \ | ||
| 1653 | \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" string) | ||
| 1654 | (epg-context-set-result-for | ||
| 1655 | context 'import | ||
| 1656 | (epg-make-import-result (string-to-number (match-string 1 string)) | ||
| 1657 | (string-to-number (match-string 2 string)) | ||
| 1658 | (string-to-number (match-string 3 string)) | ||
| 1659 | (string-to-number (match-string 4 string)) | ||
| 1660 | (string-to-number (match-string 5 string)) | ||
| 1661 | (string-to-number (match-string 6 string)) | ||
| 1662 | (string-to-number (match-string 7 string)) | ||
| 1663 | (string-to-number (match-string 8 string)) | ||
| 1664 | (string-to-number (match-string 9 string)) | ||
| 1665 | (string-to-number (match-string 10 string)) | ||
| 1666 | (string-to-number (match-string 11 string)) | ||
| 1667 | (string-to-number (match-string 12 string)) | ||
| 1668 | (string-to-number (match-string 13 string)) | ||
| 1669 | (epg-context-result-for context 'import-status))) | ||
| 1670 | (epg-context-set-result-for context 'import-status nil))) | ||
| 1671 | |||
| 1672 | (defun epg-passphrase-callback-function (context key-id handback) | ||
| 1673 | (if (eq key-id 'SYM) | ||
| 1674 | (read-passwd "Passphrase for symmetric encryption: " | ||
| 1675 | (eq (epg-context-operation context) 'encrypt)) | ||
| 1676 | (read-passwd | ||
| 1677 | (if (eq key-id 'PIN) | ||
| 1678 | "Passphrase for PIN: " | ||
| 1679 | (let ((entry (assoc key-id epg-user-id-alist))) | ||
| 1680 | (if entry | ||
| 1681 | (format "Passphrase for %s %s: " key-id (cdr entry)) | ||
| 1682 | (format "Passphrase for %s: " key-id))))))) | ||
| 1683 | |||
| 1684 | (make-obsolete 'epg-passphrase-callback-function | ||
| 1685 | 'epa-passphrase-callback-function) | ||
| 1686 | |||
| 1687 | (defun epg--list-keys-1 (context name mode) | ||
| 1688 | (let ((args (append (if epg-gpg-home-directory | ||
| 1689 | (list "--homedir" epg-gpg-home-directory)) | ||
| 1690 | '("--with-colons" "--no-greeting" "--batch" | ||
| 1691 | "--with-fingerprint" "--with-fingerprint") | ||
| 1692 | (unless (eq (epg-context-protocol context) 'CMS) | ||
| 1693 | '("--fixed-list-mode")))) | ||
| 1694 | (list-keys-option (if (memq mode '(t secret)) | ||
| 1695 | "--list-secret-keys" | ||
| 1696 | (if (memq mode '(nil public)) | ||
| 1697 | "--list-keys" | ||
| 1698 | "--list-sigs"))) | ||
| 1699 | (coding-system-for-read 'binary) | ||
| 1700 | keys string field index) | ||
| 1701 | (if name | ||
| 1702 | (progn | ||
| 1703 | (unless (listp name) | ||
| 1704 | (setq name (list name))) | ||
| 1705 | (while name | ||
| 1706 | (setq args (append args (list list-keys-option (car name))) | ||
| 1707 | name (cdr name)))) | ||
| 1708 | (setq args (append args (list list-keys-option)))) | ||
| 1709 | (with-temp-buffer | ||
| 1710 | (apply #'call-process | ||
| 1711 | (if (eq (epg-context-protocol context) 'CMS) | ||
| 1712 | epg-gpgsm-program | ||
| 1713 | epg-gpg-program) | ||
| 1714 | nil (list t nil) nil args) | ||
| 1715 | (goto-char (point-min)) | ||
| 1716 | (while (re-search-forward "^[a-z][a-z][a-z]:.*" nil t) | ||
| 1717 | (setq keys (cons (make-vector 15 nil) keys) | ||
| 1718 | string (match-string 0) | ||
| 1719 | index 0 | ||
| 1720 | field 0) | ||
| 1721 | (while (eq index | ||
| 1722 | (string-match "\\([^:]+\\)?:" string index)) | ||
| 1723 | (setq index (match-end 0)) | ||
| 1724 | (aset (car keys) field (match-string 1 string)) | ||
| 1725 | (setq field (1+ field)))) | ||
| 1726 | (nreverse keys)))) | ||
| 1727 | |||
| 1728 | (defun epg--make-sub-key-1 (line) | ||
| 1729 | (epg-make-sub-key | ||
| 1730 | (if (aref line 1) | ||
| 1731 | (cdr (assq (string-to-char (aref line 1)) epg-key-validity-alist))) | ||
| 1732 | (delq nil | ||
| 1733 | (mapcar (lambda (char) (cdr (assq char epg-key-capablity-alist))) | ||
| 1734 | (aref line 11))) | ||
| 1735 | (member (aref line 0) '("sec" "ssb")) | ||
| 1736 | (string-to-number (aref line 3)) | ||
| 1737 | (string-to-number (aref line 2)) | ||
| 1738 | (aref line 4) | ||
| 1739 | (epg--time-from-seconds (aref line 5)) | ||
| 1740 | (if (aref line 6) | ||
| 1741 | (epg--time-from-seconds (aref line 6))))) | ||
| 1742 | |||
| 1743 | ;;;###autoload | ||
| 1744 | (defun epg-list-keys (context &optional name mode) | ||
| 1745 | "Return a list of epg-key objects matched with NAME. | ||
| 1746 | If MODE is nil or 'public, only public keyring should be searched. | ||
| 1747 | If MODE is t or 'secret, only secret keyring should be searched. | ||
| 1748 | Otherwise, only public keyring should be searched and the key | ||
| 1749 | signatures should be included. | ||
| 1750 | NAME is either a string or a list of strings." | ||
| 1751 | (let ((lines (epg--list-keys-1 context name mode)) | ||
| 1752 | keys cert pointer pointer-1 index string) | ||
| 1753 | (while lines | ||
| 1754 | (cond | ||
| 1755 | ((member (aref (car lines) 0) '("pub" "sec" "crt" "crs")) | ||
| 1756 | (setq cert (member (aref (car lines) 0) '("crt" "crs")) | ||
| 1757 | keys (cons (epg-make-key | ||
| 1758 | (if (aref (car lines) 8) | ||
| 1759 | (cdr (assq (string-to-char (aref (car lines) 8)) | ||
| 1760 | epg-key-validity-alist)))) | ||
| 1761 | keys)) | ||
| 1762 | (epg-key-set-sub-key-list | ||
| 1763 | (car keys) | ||
| 1764 | (cons (epg--make-sub-key-1 (car lines)) | ||
| 1765 | (epg-key-sub-key-list (car keys))))) | ||
| 1766 | ((member (aref (car lines) 0) '("sub" "ssb")) | ||
| 1767 | (epg-key-set-sub-key-list | ||
| 1768 | (car keys) | ||
| 1769 | (cons (epg--make-sub-key-1 (car lines)) | ||
| 1770 | (epg-key-sub-key-list (car keys))))) | ||
| 1771 | ((equal (aref (car lines) 0) "uid") | ||
| 1772 | ;; Decode the UID name as a backslash escaped UTF-8 string, | ||
| 1773 | ;; generated by GnuPG/GpgSM. | ||
| 1774 | (setq string (copy-sequence (aref (car lines) 9)) | ||
| 1775 | index 0) | ||
| 1776 | (while (string-match "\"" string index) | ||
| 1777 | (setq string (replace-match "\\\"" t t string) | ||
| 1778 | index (1+ (match-end 0)))) | ||
| 1779 | (condition-case nil | ||
| 1780 | (setq string (epg--decode-coding-string | ||
| 1781 | (car (read-from-string (concat "\"" string "\""))) | ||
| 1782 | 'utf-8)) | ||
| 1783 | (error | ||
| 1784 | (setq string (aref (car lines) 9)))) | ||
| 1785 | (epg-key-set-user-id-list | ||
| 1786 | (car keys) | ||
| 1787 | (cons (epg-make-user-id | ||
| 1788 | (if (aref (car lines) 1) | ||
| 1789 | (cdr (assq (string-to-char (aref (car lines) 1)) | ||
| 1790 | epg-key-validity-alist))) | ||
| 1791 | (if cert | ||
| 1792 | (condition-case nil | ||
| 1793 | (epg-dn-from-string string) | ||
| 1794 | (error string)) | ||
| 1795 | string)) | ||
| 1796 | (epg-key-user-id-list (car keys))))) | ||
| 1797 | ((equal (aref (car lines) 0) "fpr") | ||
| 1798 | (epg-sub-key-set-fingerprint (car (epg-key-sub-key-list (car keys))) | ||
| 1799 | (aref (car lines) 9))) | ||
| 1800 | ((equal (aref (car lines) 0) "sig") | ||
| 1801 | (epg-user-id-set-signature-list | ||
| 1802 | (car (epg-key-user-id-list (car keys))) | ||
| 1803 | (cons | ||
| 1804 | (epg-make-key-signature | ||
| 1805 | (if (aref (car lines) 1) | ||
| 1806 | (cdr (assq (string-to-char (aref (car lines) 1)) | ||
| 1807 | epg-key-validity-alist))) | ||
| 1808 | (string-to-number (aref (car lines) 3)) | ||
| 1809 | (aref (car lines) 4) | ||
| 1810 | (epg--time-from-seconds (aref (car lines) 5)) | ||
| 1811 | (epg--time-from-seconds (aref (car lines) 6)) | ||
| 1812 | (aref (car lines) 9) | ||
| 1813 | (string-to-number (aref (car lines) 10) 16) | ||
| 1814 | (eq (aref (aref (car lines) 10) 2) ?x)) | ||
| 1815 | (epg-user-id-signature-list | ||
| 1816 | (car (epg-key-user-id-list (car keys)))))))) | ||
| 1817 | (setq lines (cdr lines))) | ||
| 1818 | (setq keys (nreverse keys) | ||
| 1819 | pointer keys) | ||
| 1820 | (while pointer | ||
| 1821 | (epg-key-set-sub-key-list | ||
| 1822 | (car pointer) | ||
| 1823 | (nreverse (epg-key-sub-key-list (car pointer)))) | ||
| 1824 | (setq pointer-1 (epg-key-set-user-id-list | ||
| 1825 | (car pointer) | ||
| 1826 | (nreverse (epg-key-user-id-list (car pointer))))) | ||
| 1827 | (while pointer-1 | ||
| 1828 | (epg-user-id-set-signature-list | ||
| 1829 | (car pointer-1) | ||
| 1830 | (nreverse (epg-user-id-signature-list (car pointer-1)))) | ||
| 1831 | (setq pointer-1 (cdr pointer-1))) | ||
| 1832 | (setq pointer (cdr pointer))) | ||
| 1833 | keys)) | ||
| 1834 | |||
| 1835 | (eval-and-compile | ||
| 1836 | (if (fboundp 'make-temp-file) | ||
| 1837 | (defalias 'epg--make-temp-file 'make-temp-file) | ||
| 1838 | (defvar temporary-file-directory) | ||
| 1839 | ;; stolen from poe.el. | ||
| 1840 | (defun epg--make-temp-file (prefix) | ||
| 1841 | "Create a temporary file. | ||
| 1842 | The returned file name (created by appending some random characters at the end | ||
| 1843 | of PREFIX, and expanding against `temporary-file-directory' if necessary), | ||
| 1844 | is guaranteed to point to a newly created empty file. | ||
| 1845 | You can then use `write-region' to write new data into the file." | ||
| 1846 | (let (tempdir tempfile) | ||
| 1847 | (setq prefix (expand-file-name prefix | ||
| 1848 | (if (featurep 'xemacs) | ||
| 1849 | (temp-directory) | ||
| 1850 | temporary-file-directory))) | ||
| 1851 | (unwind-protect | ||
| 1852 | (let (file) | ||
| 1853 | ;; First, create a temporary directory. | ||
| 1854 | (while (condition-case () | ||
| 1855 | (progn | ||
| 1856 | (setq tempdir (make-temp-name | ||
| 1857 | (concat | ||
| 1858 | (file-name-directory prefix) | ||
| 1859 | "DIR"))) | ||
| 1860 | ;; return nil or signal an error. | ||
| 1861 | (make-directory tempdir)) | ||
| 1862 | ;; let's try again. | ||
| 1863 | (file-already-exists t))) | ||
| 1864 | (set-file-modes tempdir 448) | ||
| 1865 | ;; Second, create a temporary file in the tempdir. | ||
| 1866 | ;; There *is* a race condition between `make-temp-name' | ||
| 1867 | ;; and `write-region', but we don't care it since we are | ||
| 1868 | ;; in a private directory now. | ||
| 1869 | (setq tempfile (make-temp-name (concat tempdir "/EMU"))) | ||
| 1870 | (write-region "" nil tempfile nil 'silent) | ||
| 1871 | (set-file-modes tempfile 384) | ||
| 1872 | ;; Finally, make a hard-link from the tempfile. | ||
| 1873 | (while (condition-case () | ||
| 1874 | (progn | ||
| 1875 | (setq file (make-temp-name prefix)) | ||
| 1876 | ;; return nil or signal an error. | ||
| 1877 | (add-name-to-file tempfile file)) | ||
| 1878 | ;; let's try again. | ||
| 1879 | (file-already-exists t))) | ||
| 1880 | file) | ||
| 1881 | ;; Cleanup the tempfile. | ||
| 1882 | (and tempfile | ||
| 1883 | (file-exists-p tempfile) | ||
| 1884 | (delete-file tempfile)) | ||
| 1885 | ;; Cleanup the tempdir. | ||
| 1886 | (and tempdir | ||
| 1887 | (file-directory-p tempdir) | ||
| 1888 | (delete-directory tempdir))))))) | ||
| 1889 | |||
| 1890 | (defun epg--args-from-sig-notations (notations) | ||
| 1891 | (apply #'nconc | ||
| 1892 | (mapcar | ||
| 1893 | (lambda (notation) | ||
| 1894 | (if (and (epg-sig-notation-name notation) | ||
| 1895 | (not (epg-sig-notation-human-readable notation))) | ||
| 1896 | (error "Unreadable")) | ||
| 1897 | (if (epg-sig-notation-name notation) | ||
| 1898 | (list "--sig-notation" | ||
| 1899 | (if (epg-sig-notation-critical notation) | ||
| 1900 | (concat "!" (epg-sig-notation-name notation) | ||
| 1901 | "=" (epg-sig-notation-value notation)) | ||
| 1902 | (concat (epg-sig-notation-name notation) | ||
| 1903 | "=" (epg-sig-notation-value notation)))) | ||
| 1904 | (list "--sig-policy-url" | ||
| 1905 | (if (epg-sig-notation-critical notation) | ||
| 1906 | (concat "!" (epg-sig-notation-value notation)) | ||
| 1907 | (epg-sig-notation-value notation))))) | ||
| 1908 | notations))) | ||
| 1909 | |||
| 1910 | ;;;###autoload | ||
| 1911 | (defun epg-cancel (context) | ||
| 1912 | (if (buffer-live-p (process-buffer (epg-context-process context))) | ||
| 1913 | (save-excursion | ||
| 1914 | (set-buffer (process-buffer (epg-context-process context))) | ||
| 1915 | (epg-context-set-result-for | ||
| 1916 | epg-context 'error | ||
| 1917 | (cons '(quit) | ||
| 1918 | (epg-context-result-for epg-context 'error))))) | ||
| 1919 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 1920 | (delete-process (epg-context-process context)))) | ||
| 1921 | |||
| 1922 | ;;;###autoload | ||
| 1923 | (defun epg-start-decrypt (context cipher) | ||
| 1924 | "Initiate a decrypt operation on CIPHER. | ||
| 1925 | CIPHER must be a file data object. | ||
| 1926 | |||
| 1927 | If you use this function, you will need to wait for the completion of | ||
| 1928 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 1929 | `epg-reset' to clear a temporaly output file. | ||
| 1930 | If you are unsure, use synchronous version of this function | ||
| 1931 | `epg-decrypt-file' or `epg-decrypt-string' instead." | ||
| 1932 | (unless (epg-data-file cipher) | ||
| 1933 | (error "Not a file")) | ||
| 1934 | (epg-context-set-operation context 'decrypt) | ||
| 1935 | (epg-context-set-result context nil) | ||
| 1936 | (epg--start context (list "--decrypt" "--" (epg-data-file cipher))) | ||
| 1937 | ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed. | ||
| 1938 | (unless (eq (epg-context-protocol context) 'CMS) | ||
| 1939 | (epg-wait-for-status context '("BEGIN_DECRYPTION")))) | ||
| 1940 | |||
| 1941 | (defun epg--check-error-for-decrypt (context) | ||
| 1942 | (if (epg-context-result-for context 'decryption-failed) | ||
| 1943 | (signal 'epg-error (list "Decryption failed"))) | ||
| 1944 | (if (epg-context-result-for context 'no-secret-key) | ||
| 1945 | (signal 'epg-error | ||
| 1946 | (list "No secret key" | ||
| 1947 | (epg-context-result-for context 'no-secret-key)))) | ||
| 1948 | (unless (epg-context-result-for context 'decryption-okay) | ||
| 1949 | (let* ((error (epg-context-result-for context 'error))) | ||
| 1950 | (if (assq 'no-data error) | ||
| 1951 | (signal 'epg-error (list "No data"))) | ||
| 1952 | (signal 'epg-error (list "Can't decrypt" error))))) | ||
| 1953 | |||
| 1954 | ;;;###autoload | ||
| 1955 | (defun epg-decrypt-file (context cipher plain) | ||
| 1956 | "Decrypt a file CIPHER and store the result to a file PLAIN. | ||
| 1957 | If PLAIN is nil, it returns the result as a string." | ||
| 1958 | (unwind-protect | ||
| 1959 | (progn | ||
| 1960 | (if plain | ||
| 1961 | (epg-context-set-output-file context plain) | ||
| 1962 | (epg-context-set-output-file context | ||
| 1963 | (epg--make-temp-file "epg-output"))) | ||
| 1964 | (epg-start-decrypt context (epg-make-data-from-file cipher)) | ||
| 1965 | (epg-wait-for-completion context) | ||
| 1966 | (epg--check-error-for-decrypt context) | ||
| 1967 | (unless plain | ||
| 1968 | (epg-read-output context))) | ||
| 1969 | (unless plain | ||
| 1970 | (epg-delete-output-file context)) | ||
| 1971 | (epg-reset context))) | ||
| 1972 | |||
| 1973 | ;;;###autoload | ||
| 1974 | (defun epg-decrypt-string (context cipher) | ||
| 1975 | "Decrypt a string CIPHER and return the plain text." | ||
| 1976 | (let ((input-file (epg--make-temp-file "epg-input")) | ||
| 1977 | (coding-system-for-write 'binary)) | ||
| 1978 | (unwind-protect | ||
| 1979 | (progn | ||
| 1980 | (write-region cipher nil input-file nil 'quiet) | ||
| 1981 | (epg-context-set-output-file context | ||
| 1982 | (epg--make-temp-file "epg-output")) | ||
| 1983 | (epg-start-decrypt context (epg-make-data-from-file input-file)) | ||
| 1984 | (epg-wait-for-completion context) | ||
| 1985 | (epg--check-error-for-decrypt context) | ||
| 1986 | (epg-read-output context)) | ||
| 1987 | (epg-delete-output-file context) | ||
| 1988 | (if (file-exists-p input-file) | ||
| 1989 | (delete-file input-file)) | ||
| 1990 | (epg-reset context)))) | ||
| 1991 | |||
| 1992 | ;;;###autoload | ||
| 1993 | (defun epg-start-verify (context signature &optional signed-text) | ||
| 1994 | "Initiate a verify operation on SIGNATURE. | ||
| 1995 | SIGNATURE and SIGNED-TEXT are a data object if they are specified. | ||
| 1996 | |||
| 1997 | For a detached signature, both SIGNATURE and SIGNED-TEXT should be set. | ||
| 1998 | For a normal or a cleartext signature, SIGNED-TEXT should be nil. | ||
| 1999 | |||
| 2000 | If you use this function, you will need to wait for the completion of | ||
| 2001 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2002 | `epg-reset' to clear a temporaly output file. | ||
| 2003 | If you are unsure, use synchronous version of this function | ||
| 2004 | `epg-verify-file' or `epg-verify-string' instead." | ||
| 2005 | (epg-context-set-operation context 'verify) | ||
| 2006 | (epg-context-set-result context nil) | ||
| 2007 | (if signed-text | ||
| 2008 | ;; Detached signature. | ||
| 2009 | (if (epg-data-file signed-text) | ||
| 2010 | (epg--start context (list "--verify" "--" (epg-data-file signature) | ||
| 2011 | (epg-data-file signed-text))) | ||
| 2012 | (epg--start context (list "--verify" "--" (epg-data-file signature) | ||
| 2013 | "-")) | ||
| 2014 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2015 | (process-send-string (epg-context-process context) | ||
| 2016 | (epg-data-string signed-text))) | ||
| 2017 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2018 | (process-send-eof (epg-context-process context)))) | ||
| 2019 | ;; Normal (or cleartext) signature. | ||
| 2020 | (if (epg-data-file signature) | ||
| 2021 | (epg--start context (list "--" (epg-data-file signature))) | ||
| 2022 | (epg--start context '("-")) | ||
| 2023 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2024 | (process-send-string (epg-context-process context) | ||
| 2025 | (epg-data-string signature))) | ||
| 2026 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2027 | (process-send-eof (epg-context-process context)))))) | ||
| 2028 | |||
| 2029 | ;;;###autoload | ||
| 2030 | (defun epg-verify-file (context signature &optional signed-text plain) | ||
| 2031 | "Verify a file SIGNATURE. | ||
| 2032 | SIGNED-TEXT and PLAIN are also a file if they are specified. | ||
| 2033 | |||
| 2034 | For a detached signature, both SIGNATURE and SIGNED-TEXT should be | ||
| 2035 | string. For a normal or a cleartext signature, SIGNED-TEXT should be | ||
| 2036 | nil. In the latter case, if PLAIN is specified, the plaintext is | ||
| 2037 | stored into the file after successful verification." | ||
| 2038 | (unwind-protect | ||
| 2039 | (progn | ||
| 2040 | (if plain | ||
| 2041 | (epg-context-set-output-file context plain) | ||
| 2042 | (epg-context-set-output-file context | ||
| 2043 | (epg--make-temp-file "epg-output"))) | ||
| 2044 | (if signed-text | ||
| 2045 | (epg-start-verify context | ||
| 2046 | (epg-make-data-from-file signature) | ||
| 2047 | (epg-make-data-from-file signed-text)) | ||
| 2048 | (epg-start-verify context | ||
| 2049 | (epg-make-data-from-file signature))) | ||
| 2050 | (epg-wait-for-completion context) | ||
| 2051 | (unless plain | ||
| 2052 | (epg-read-output context))) | ||
| 2053 | (unless plain | ||
| 2054 | (epg-delete-output-file context)) | ||
| 2055 | (epg-reset context))) | ||
| 2056 | |||
| 2057 | ;;;###autoload | ||
| 2058 | (defun epg-verify-string (context signature &optional signed-text) | ||
| 2059 | "Verify a string SIGNATURE. | ||
| 2060 | SIGNED-TEXT is a string if it is specified. | ||
| 2061 | |||
| 2062 | For a detached signature, both SIGNATURE and SIGNED-TEXT should be | ||
| 2063 | string. For a normal or a cleartext signature, SIGNED-TEXT should be | ||
| 2064 | nil. In the latter case, this function returns the plaintext after | ||
| 2065 | successful verification." | ||
| 2066 | (let ((coding-system-for-write 'binary) | ||
| 2067 | input-file) | ||
| 2068 | (unwind-protect | ||
| 2069 | (progn | ||
| 2070 | (epg-context-set-output-file context | ||
| 2071 | (epg--make-temp-file "epg-output")) | ||
| 2072 | (if signed-text | ||
| 2073 | (progn | ||
| 2074 | (setq input-file (epg--make-temp-file "epg-signature")) | ||
| 2075 | (write-region signature nil input-file nil 'quiet) | ||
| 2076 | (epg-start-verify context | ||
| 2077 | (epg-make-data-from-file input-file) | ||
| 2078 | (epg-make-data-from-string signed-text))) | ||
| 2079 | (epg-start-verify context (epg-make-data-from-string signature))) | ||
| 2080 | (epg-wait-for-completion context) | ||
| 2081 | (epg-read-output context)) | ||
| 2082 | (epg-delete-output-file context) | ||
| 2083 | (if (and input-file | ||
| 2084 | (file-exists-p input-file)) | ||
| 2085 | (delete-file input-file)) | ||
| 2086 | (epg-reset context)))) | ||
| 2087 | |||
| 2088 | ;;;###autoload | ||
| 2089 | (defun epg-start-sign (context plain &optional mode) | ||
| 2090 | "Initiate a sign operation on PLAIN. | ||
| 2091 | PLAIN is a data object. | ||
| 2092 | |||
| 2093 | If optional 3rd argument MODE is t or 'detached, it makes a detached signature. | ||
| 2094 | If it is nil or 'normal, it makes a normal signature. | ||
| 2095 | Otherwise, it makes a cleartext signature. | ||
| 2096 | |||
| 2097 | If you use this function, you will need to wait for the completion of | ||
| 2098 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2099 | `epg-reset' to clear a temporaly output file. | ||
| 2100 | If you are unsure, use synchronous version of this function | ||
| 2101 | `epg-sign-file' or `epg-sign-string' instead." | ||
| 2102 | (epg-context-set-operation context 'sign) | ||
| 2103 | (epg-context-set-result context nil) | ||
| 2104 | (unless (memq mode '(t detached nil normal)) ;i.e. cleartext | ||
| 2105 | (epg-context-set-armor context nil) | ||
| 2106 | (epg-context-set-textmode context nil)) | ||
| 2107 | (epg--start context | ||
| 2108 | (append (list (if (memq mode '(t detached)) | ||
| 2109 | "--detach-sign" | ||
| 2110 | (if (memq mode '(nil normal)) | ||
| 2111 | "--sign" | ||
| 2112 | "--clearsign"))) | ||
| 2113 | (apply #'nconc | ||
| 2114 | (mapcar | ||
| 2115 | (lambda (signer) | ||
| 2116 | (list "-u" | ||
| 2117 | (epg-sub-key-id | ||
| 2118 | (car (epg-key-sub-key-list signer))))) | ||
| 2119 | (epg-context-signers context))) | ||
| 2120 | (epg--args-from-sig-notations | ||
| 2121 | (epg-context-sig-notations context)) | ||
| 2122 | (if (epg-data-file plain) | ||
| 2123 | (list "--" (epg-data-file plain))))) | ||
| 2124 | ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed. | ||
| 2125 | (unless (eq (epg-context-protocol context) 'CMS) | ||
| 2126 | (epg-wait-for-status context '("BEGIN_SIGNING"))) | ||
| 2127 | (when (epg-data-string plain) | ||
| 2128 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2129 | (process-send-string (epg-context-process context) | ||
| 2130 | (epg-data-string plain))) | ||
| 2131 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2132 | (process-send-eof (epg-context-process context))))) | ||
| 2133 | |||
| 2134 | ;;;###autoload | ||
| 2135 | (defun epg-sign-file (context plain signature &optional mode) | ||
| 2136 | "Sign a file PLAIN and store the result to a file SIGNATURE. | ||
| 2137 | If SIGNATURE is nil, it returns the result as a string. | ||
| 2138 | If optional 3rd argument MODE is t or 'detached, it makes a detached signature. | ||
| 2139 | If it is nil or 'normal, it makes a normal signature. | ||
| 2140 | Otherwise, it makes a cleartext signature." | ||
| 2141 | (unwind-protect | ||
| 2142 | (progn | ||
| 2143 | (if signature | ||
| 2144 | (epg-context-set-output-file context signature) | ||
| 2145 | (epg-context-set-output-file context | ||
| 2146 | (epg--make-temp-file "epg-output"))) | ||
| 2147 | (epg-start-sign context (epg-make-data-from-file plain) mode) | ||
| 2148 | (epg-wait-for-completion context) | ||
| 2149 | (unless (epg-context-result-for context 'sign) | ||
| 2150 | (if (epg-context-result-for context 'error) | ||
| 2151 | (error "Sign failed: %S" | ||
| 2152 | (epg-context-result-for context 'error)) | ||
| 2153 | (error "Sign failed"))) | ||
| 2154 | (unless signature | ||
| 2155 | (epg-read-output context))) | ||
| 2156 | (unless signature | ||
| 2157 | (epg-delete-output-file context)) | ||
| 2158 | (epg-reset context))) | ||
| 2159 | |||
| 2160 | ;;;###autoload | ||
| 2161 | (defun epg-sign-string (context plain &optional mode) | ||
| 2162 | "Sign a string PLAIN and return the output as string. | ||
| 2163 | If optional 3rd argument MODE is t or 'detached, it makes a detached signature. | ||
| 2164 | If it is nil or 'normal, it makes a normal signature. | ||
| 2165 | Otherwise, it makes a cleartext signature." | ||
| 2166 | (let ((input-file | ||
| 2167 | (unless (or (eq (epg-context-protocol context) 'CMS) | ||
| 2168 | (condition-case nil | ||
| 2169 | (progn | ||
| 2170 | (epg-check-configuration (epg-configuration)) | ||
| 2171 | t) | ||
| 2172 | (error))) | ||
| 2173 | (epg--make-temp-file "epg-input"))) | ||
| 2174 | (coding-system-for-write 'binary)) | ||
| 2175 | (unwind-protect | ||
| 2176 | (progn | ||
| 2177 | (epg-context-set-output-file context | ||
| 2178 | (epg--make-temp-file "epg-output")) | ||
| 2179 | (if input-file | ||
| 2180 | (write-region plain nil input-file nil 'quiet)) | ||
| 2181 | (epg-start-sign context | ||
| 2182 | (if input-file | ||
| 2183 | (epg-make-data-from-file input-file) | ||
| 2184 | (epg-make-data-from-string plain)) | ||
| 2185 | mode) | ||
| 2186 | (epg-wait-for-completion context) | ||
| 2187 | (unless (epg-context-result-for context 'sign) | ||
| 2188 | (if (epg-context-result-for context 'error) | ||
| 2189 | (error "Sign failed: %S" | ||
| 2190 | (epg-context-result-for context 'error)) | ||
| 2191 | (error "Sign failed"))) | ||
| 2192 | (epg-read-output context)) | ||
| 2193 | (epg-delete-output-file context) | ||
| 2194 | (if input-file | ||
| 2195 | (delete-file input-file)) | ||
| 2196 | (epg-reset context)))) | ||
| 2197 | |||
| 2198 | ;;;###autoload | ||
| 2199 | (defun epg-start-encrypt (context plain recipients | ||
| 2200 | &optional sign always-trust) | ||
| 2201 | "Initiate an encrypt operation on PLAIN. | ||
| 2202 | PLAIN is a data object. | ||
| 2203 | If RECIPIENTS is nil, it performs symmetric encryption. | ||
| 2204 | |||
| 2205 | If you use this function, you will need to wait for the completion of | ||
| 2206 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2207 | `epg-reset' to clear a temporaly output file. | ||
| 2208 | If you are unsure, use synchronous version of this function | ||
| 2209 | `epg-encrypt-file' or `epg-encrypt-string' instead." | ||
| 2210 | (epg-context-set-operation context 'encrypt) | ||
| 2211 | (epg-context-set-result context nil) | ||
| 2212 | (epg--start context | ||
| 2213 | (append (if always-trust '("--always-trust")) | ||
| 2214 | (if recipients '("--encrypt") '("--symmetric")) | ||
| 2215 | (if sign '("--sign")) | ||
| 2216 | (if sign | ||
| 2217 | (apply #'nconc | ||
| 2218 | (mapcar | ||
| 2219 | (lambda (signer) | ||
| 2220 | (list "-u" | ||
| 2221 | (epg-sub-key-id | ||
| 2222 | (car (epg-key-sub-key-list | ||
| 2223 | signer))))) | ||
| 2224 | (epg-context-signers context)))) | ||
| 2225 | (if sign | ||
| 2226 | (epg--args-from-sig-notations | ||
| 2227 | (epg-context-sig-notations context))) | ||
| 2228 | (apply #'nconc | ||
| 2229 | (mapcar | ||
| 2230 | (lambda (recipient) | ||
| 2231 | (list "-r" | ||
| 2232 | (epg-sub-key-id | ||
| 2233 | (car (epg-key-sub-key-list recipient))))) | ||
| 2234 | recipients)) | ||
| 2235 | (if (epg-data-file plain) | ||
| 2236 | (list "--" (epg-data-file plain))))) | ||
| 2237 | ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed. | ||
| 2238 | (unless (eq (epg-context-protocol context) 'CMS) | ||
| 2239 | (if sign | ||
| 2240 | (epg-wait-for-status context '("BEGIN_SIGNING")) | ||
| 2241 | (epg-wait-for-status context '("BEGIN_ENCRYPTION")))) | ||
| 2242 | (when (epg-data-string plain) | ||
| 2243 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2244 | (process-send-string (epg-context-process context) | ||
| 2245 | (epg-data-string plain))) | ||
| 2246 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2247 | (process-send-eof (epg-context-process context))))) | ||
| 2248 | |||
| 2249 | ;;;###autoload | ||
| 2250 | (defun epg-encrypt-file (context plain recipients | ||
| 2251 | cipher &optional sign always-trust) | ||
| 2252 | "Encrypt a file PLAIN and store the result to a file CIPHER. | ||
| 2253 | If CIPHER is nil, it returns the result as a string. | ||
| 2254 | If RECIPIENTS is nil, it performs symmetric encryption." | ||
| 2255 | (unwind-protect | ||
| 2256 | (progn | ||
| 2257 | (if cipher | ||
| 2258 | (epg-context-set-output-file context cipher) | ||
| 2259 | (epg-context-set-output-file context | ||
| 2260 | (epg--make-temp-file "epg-output"))) | ||
| 2261 | (epg-start-encrypt context (epg-make-data-from-file plain) | ||
| 2262 | recipients sign always-trust) | ||
| 2263 | (epg-wait-for-completion context) | ||
| 2264 | (if (and sign | ||
| 2265 | (not (epg-context-result-for context 'sign))) | ||
| 2266 | (if (epg-context-result-for context 'error) | ||
| 2267 | (error "Sign failed: %S" | ||
| 2268 | (epg-context-result-for context 'error)) | ||
| 2269 | (error "Sign failed"))) | ||
| 2270 | (if (epg-context-result-for context 'error) | ||
| 2271 | (error "Encrypt failed: %S" | ||
| 2272 | (epg-context-result-for context 'error))) | ||
| 2273 | (unless cipher | ||
| 2274 | (epg-read-output context))) | ||
| 2275 | (unless cipher | ||
| 2276 | (epg-delete-output-file context)) | ||
| 2277 | (epg-reset context))) | ||
| 2278 | |||
| 2279 | ;;;###autoload | ||
| 2280 | (defun epg-encrypt-string (context plain recipients | ||
| 2281 | &optional sign always-trust) | ||
| 2282 | "Encrypt a string PLAIN. | ||
| 2283 | If RECIPIENTS is nil, it performs symmetric encryption." | ||
| 2284 | (let ((input-file | ||
| 2285 | (unless (or (not sign) | ||
| 2286 | (eq (epg-context-protocol context) 'CMS) | ||
| 2287 | (condition-case nil | ||
| 2288 | (progn | ||
| 2289 | (epg-check-configuration (epg-configuration)) | ||
| 2290 | t) | ||
| 2291 | (error))) | ||
| 2292 | (epg--make-temp-file "epg-input"))) | ||
| 2293 | (coding-system-for-write 'binary)) | ||
| 2294 | (unwind-protect | ||
| 2295 | (progn | ||
| 2296 | (epg-context-set-output-file context | ||
| 2297 | (epg--make-temp-file "epg-output")) | ||
| 2298 | (if input-file | ||
| 2299 | (write-region plain nil input-file nil 'quiet)) | ||
| 2300 | (epg-start-encrypt context | ||
| 2301 | (if input-file | ||
| 2302 | (epg-make-data-from-file input-file) | ||
| 2303 | (epg-make-data-from-string plain)) | ||
| 2304 | recipients sign always-trust) | ||
| 2305 | (epg-wait-for-completion context) | ||
| 2306 | (if (and sign | ||
| 2307 | (not (epg-context-result-for context 'sign))) | ||
| 2308 | (if (epg-context-result-for context 'error) | ||
| 2309 | (error "Sign failed: %S" | ||
| 2310 | (epg-context-result-for context 'error)) | ||
| 2311 | (error "Sign failed"))) | ||
| 2312 | (if (epg-context-result-for context 'error) | ||
| 2313 | (error "Encrypt failed: %S" | ||
| 2314 | (epg-context-result-for context 'error))) | ||
| 2315 | (epg-read-output context)) | ||
| 2316 | (epg-delete-output-file context) | ||
| 2317 | (if input-file | ||
| 2318 | (delete-file input-file)) | ||
| 2319 | (epg-reset context)))) | ||
| 2320 | |||
| 2321 | ;;;###autoload | ||
| 2322 | (defun epg-start-export-keys (context keys) | ||
| 2323 | "Initiate an export keys operation. | ||
| 2324 | |||
| 2325 | If you use this function, you will need to wait for the completion of | ||
| 2326 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2327 | `epg-reset' to clear a temporaly output file. | ||
| 2328 | If you are unsure, use synchronous version of this function | ||
| 2329 | `epg-export-keys-to-file' or `epg-export-keys-to-string' instead." | ||
| 2330 | (epg-context-set-operation context 'export-keys) | ||
| 2331 | (epg-context-set-result context nil) | ||
| 2332 | (epg--start context (cons "--export" | ||
| 2333 | (mapcar | ||
| 2334 | (lambda (key) | ||
| 2335 | (epg-sub-key-id | ||
| 2336 | (car (epg-key-sub-key-list key)))) | ||
| 2337 | keys)))) | ||
| 2338 | |||
| 2339 | ;;;###autoload | ||
| 2340 | (defun epg-export-keys-to-file (context keys file) | ||
| 2341 | "Extract public KEYS." | ||
| 2342 | (unwind-protect | ||
| 2343 | (progn | ||
| 2344 | (if file | ||
| 2345 | (epg-context-set-output-file context file) | ||
| 2346 | (epg-context-set-output-file context | ||
| 2347 | (epg--make-temp-file "epg-output"))) | ||
| 2348 | (epg-start-export-keys context keys) | ||
| 2349 | (epg-wait-for-completion context) | ||
| 2350 | (if (epg-context-result-for context 'error) | ||
| 2351 | (error "Export keys failed: %S" | ||
| 2352 | (epg-context-result-for context 'error))) | ||
| 2353 | (unless file | ||
| 2354 | (epg-read-output context))) | ||
| 2355 | (unless file | ||
| 2356 | (epg-delete-output-file context)) | ||
| 2357 | (epg-reset context))) | ||
| 2358 | |||
| 2359 | ;;;###autoload | ||
| 2360 | (defun epg-export-keys-to-string (context keys) | ||
| 2361 | "Extract public KEYS and return them as a string." | ||
| 2362 | (epg-export-keys-to-file context keys nil)) | ||
| 2363 | |||
| 2364 | ;;;###autoload | ||
| 2365 | (defun epg-start-import-keys (context keys) | ||
| 2366 | "Initiate an import keys operation. | ||
| 2367 | KEYS is a data object. | ||
| 2368 | |||
| 2369 | If you use this function, you will need to wait for the completion of | ||
| 2370 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2371 | `epg-reset' to clear a temporaly output file. | ||
| 2372 | If you are unsure, use synchronous version of this function | ||
| 2373 | `epg-import-keys-from-file' or `epg-import-keys-from-string' instead." | ||
| 2374 | (epg-context-set-operation context 'import-keys) | ||
| 2375 | (epg-context-set-result context nil) | ||
| 2376 | (epg--start context (if (epg-data-file keys) | ||
| 2377 | (list "--import" "--" (epg-data-file keys)) | ||
| 2378 | (list "--import"))) | ||
| 2379 | (when (epg-data-string keys) | ||
| 2380 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2381 | (process-send-string (epg-context-process context) | ||
| 2382 | (epg-data-string keys))) | ||
| 2383 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2384 | (process-send-eof (epg-context-process context))))) | ||
| 2385 | |||
| 2386 | (defun epg--import-keys-1 (context keys) | ||
| 2387 | (unwind-protect | ||
| 2388 | (progn | ||
| 2389 | (epg-start-import-keys context keys) | ||
| 2390 | (epg-wait-for-completion context) | ||
| 2391 | (if (epg-context-result-for context 'error) | ||
| 2392 | (error "Import keys failed: %S" | ||
| 2393 | (epg-context-result-for context 'error)))) | ||
| 2394 | (epg-reset context))) | ||
| 2395 | |||
| 2396 | ;;;###autoload | ||
| 2397 | (defun epg-import-keys-from-file (context keys) | ||
| 2398 | "Add keys from a file KEYS." | ||
| 2399 | (epg--import-keys-1 context (epg-make-data-from-file keys))) | ||
| 2400 | |||
| 2401 | ;;;###autoload | ||
| 2402 | (defun epg-import-keys-from-string (context keys) | ||
| 2403 | "Add keys from a string KEYS." | ||
| 2404 | (epg--import-keys-1 context (epg-make-data-from-string keys))) | ||
| 2405 | |||
| 2406 | ;;;###autoload | ||
| 2407 | (defun epg-start-receive-keys (context key-id-list) | ||
| 2408 | "Initiate a receive key operation. | ||
| 2409 | KEY-ID-LIST is a list of key IDs. | ||
| 2410 | |||
| 2411 | If you use this function, you will need to wait for the completion of | ||
| 2412 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2413 | `epg-reset' to clear a temporaly output file. | ||
| 2414 | If you are unsure, use synchronous version of this function | ||
| 2415 | `epg-generate-key-from-file' or `epg-generate-key-from-string' instead." | ||
| 2416 | (epg-context-set-operation context 'receive-keys) | ||
| 2417 | (epg-context-set-result context nil) | ||
| 2418 | (epg--start context (cons "--recv-keys" key-id-list))) | ||
| 2419 | |||
| 2420 | ;;;###autoload | ||
| 2421 | (defun epg-receive-keys (context keys) | ||
| 2422 | "Add keys from server. | ||
| 2423 | KEYS is a list of key IDs" | ||
| 2424 | (unwind-protect | ||
| 2425 | (progn | ||
| 2426 | (epg-start-receive-keys context keys) | ||
| 2427 | (epg-wait-for-completion context) | ||
| 2428 | (if (epg-context-result-for context 'error) | ||
| 2429 | (error "Receive keys failed: %S" | ||
| 2430 | (epg-context-result-for context 'error)))) | ||
| 2431 | (epg-reset context))) | ||
| 2432 | |||
| 2433 | ;;;###autoload | ||
| 2434 | (defalias 'epg-import-keys-from-server 'epg-receive-keys) | ||
| 2435 | |||
| 2436 | ;;;###autoload | ||
| 2437 | (defun epg-start-delete-keys (context keys &optional allow-secret) | ||
| 2438 | "Initiate an delete keys operation. | ||
| 2439 | |||
| 2440 | If you use this function, you will need to wait for the completion of | ||
| 2441 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2442 | `epg-reset' to clear a temporaly output file. | ||
| 2443 | If you are unsure, use synchronous version of this function | ||
| 2444 | `epg-delete-keys' instead." | ||
| 2445 | (epg-context-set-operation context 'delete-keys) | ||
| 2446 | (epg-context-set-result context nil) | ||
| 2447 | (epg--start context (cons (if allow-secret | ||
| 2448 | "--delete-secret-key" | ||
| 2449 | "--delete-key") | ||
| 2450 | (mapcar | ||
| 2451 | (lambda (key) | ||
| 2452 | (epg-sub-key-id | ||
| 2453 | (car (epg-key-sub-key-list key)))) | ||
| 2454 | keys)))) | ||
| 2455 | |||
| 2456 | ;;;###autoload | ||
| 2457 | (defun epg-delete-keys (context keys &optional allow-secret) | ||
| 2458 | "Delete KEYS from the key ring." | ||
| 2459 | (unwind-protect | ||
| 2460 | (progn | ||
| 2461 | (epg-start-delete-keys context keys allow-secret) | ||
| 2462 | (epg-wait-for-completion context) | ||
| 2463 | (let ((entry (assq 'delete-problem | ||
| 2464 | (epg-context-result-for context 'error)))) | ||
| 2465 | (if entry | ||
| 2466 | (if (setq entry (assq (cdr entry) | ||
| 2467 | epg-delete-problem-reason-alist)) | ||
| 2468 | (error "Delete keys failed: %s" (cdr entry)) | ||
| 2469 | (error "Delete keys failed"))))) | ||
| 2470 | (epg-reset context))) | ||
| 2471 | |||
| 2472 | ;;;###autoload | ||
| 2473 | (defun epg-start-sign-keys (context keys &optional local) | ||
| 2474 | "Initiate a sign keys operation. | ||
| 2475 | |||
| 2476 | If you use this function, you will need to wait for the completion of | ||
| 2477 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2478 | `epg-reset' to clear a temporaly output file. | ||
| 2479 | If you are unsure, use synchronous version of this function | ||
| 2480 | `epg-sign-keys' instead." | ||
| 2481 | (epg-context-set-operation context 'sign-keys) | ||
| 2482 | (epg-context-set-result context nil) | ||
| 2483 | (epg--start context (cons (if local | ||
| 2484 | "--lsign-key" | ||
| 2485 | "--sign-key") | ||
| 2486 | (mapcar | ||
| 2487 | (lambda (key) | ||
| 2488 | (epg-sub-key-id | ||
| 2489 | (car (epg-key-sub-key-list key)))) | ||
| 2490 | keys)))) | ||
| 2491 | (make-obsolete 'epg-start-sign-keys "Do not use.") | ||
| 2492 | |||
| 2493 | ;;;###autoload | ||
| 2494 | (defun epg-sign-keys (context keys &optional local) | ||
| 2495 | "Sign KEYS from the key ring." | ||
| 2496 | (unwind-protect | ||
| 2497 | (progn | ||
| 2498 | (epg-start-sign-keys context keys local) | ||
| 2499 | (epg-wait-for-completion context) | ||
| 2500 | (if (epg-context-result-for context 'error) | ||
| 2501 | (error "Sign keys failed: %S" | ||
| 2502 | (epg-context-result-for context 'error)))) | ||
| 2503 | (epg-reset context))) | ||
| 2504 | (make-obsolete 'epg-sign-keys "Do not use.") | ||
| 2505 | |||
| 2506 | ;;;###autoload | ||
| 2507 | (defun epg-start-generate-key (context parameters) | ||
| 2508 | "Initiate a key generation. | ||
| 2509 | PARAMETERS specifies parameters for the key. | ||
| 2510 | |||
| 2511 | If you use this function, you will need to wait for the completion of | ||
| 2512 | `epg-gpg-program' by using `epg-wait-for-completion' and call | ||
| 2513 | `epg-reset' to clear a temporaly output file. | ||
| 2514 | If you are unsure, use synchronous version of this function | ||
| 2515 | `epg-generate-key-from-file' or `epg-generate-key-from-string' instead." | ||
| 2516 | (epg-context-set-operation context 'generate-key) | ||
| 2517 | (epg-context-set-result context nil) | ||
| 2518 | (if (epg-data-file parameters) | ||
| 2519 | (epg--start context (list "--batch" "--genkey" "--" | ||
| 2520 | (epg-data-file parameters))) | ||
| 2521 | (epg--start context '("--batch" "--genkey")) | ||
| 2522 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2523 | (process-send-string (epg-context-process context) | ||
| 2524 | (epg-data-string parameters))) | ||
| 2525 | (if (eq (process-status (epg-context-process context)) 'run) | ||
| 2526 | (process-send-eof (epg-context-process context))))) | ||
| 2527 | |||
| 2528 | ;;;###autoload | ||
| 2529 | (defun epg-generate-key-from-file (context parameters) | ||
| 2530 | "Generate a new key pair. | ||
| 2531 | PARAMETERS is a file which tells how to create the key." | ||
| 2532 | (unwind-protect | ||
| 2533 | (progn | ||
| 2534 | (epg-start-generate-key context (epg-make-data-from-file parameters)) | ||
| 2535 | (epg-wait-for-completion context) | ||
| 2536 | (if (epg-context-result-for context 'error) | ||
| 2537 | (error "Generate key failed: %S" | ||
| 2538 | (epg-context-result-for context 'error)))) | ||
| 2539 | (epg-reset context))) | ||
| 2540 | |||
| 2541 | ;;;###autoload | ||
| 2542 | (defun epg-generate-key-from-string (context parameters) | ||
| 2543 | "Generate a new key pair. | ||
| 2544 | PARAMETERS is a string which tells how to create the key." | ||
| 2545 | (unwind-protect | ||
| 2546 | (progn | ||
| 2547 | (epg-start-generate-key context (epg-make-data-from-string parameters)) | ||
| 2548 | (epg-wait-for-completion context) | ||
| 2549 | (if (epg-context-result-for context 'error) | ||
| 2550 | (error "Generate key failed: %S" | ||
| 2551 | (epg-context-result-for context 'error)))) | ||
| 2552 | (epg-reset context))) | ||
| 2553 | |||
| 2554 | (defun epg--decode-percent-escape (string) | ||
| 2555 | (let ((index 0)) | ||
| 2556 | (while (string-match "%\\(\\(%\\)\\|\\([0-9A-Fa-f][0-9A-Fa-f]\\)\\)" | ||
| 2557 | string index) | ||
| 2558 | (if (match-beginning 2) | ||
| 2559 | (setq string (replace-match "%" t t string) | ||
| 2560 | index (1- (match-end 0))) | ||
| 2561 | (setq string (replace-match | ||
| 2562 | (string (string-to-number (match-string 3 string) 16)) | ||
| 2563 | t t string) | ||
| 2564 | index (- (match-end 0) 2)))) | ||
| 2565 | string)) | ||
| 2566 | |||
| 2567 | (defun epg--decode-hexstring (string) | ||
| 2568 | (let ((index 0)) | ||
| 2569 | (while (eq index (string-match "[0-9A-Fa-f][0-9A-Fa-f]" string index)) | ||
| 2570 | (setq string (replace-match (string (string-to-number | ||
| 2571 | (match-string 0 string) 16)) | ||
| 2572 | t t string) | ||
| 2573 | index (1- (match-end 0)))) | ||
| 2574 | string)) | ||
| 2575 | |||
| 2576 | (defun epg--decode-quotedstring (string) | ||
| 2577 | (let ((index 0)) | ||
| 2578 | (while (string-match "\\\\\\(\\([,=+<>#;\\\"]\\)\\|\ | ||
| 2579 | \\([0-9A-Fa-f][0-9A-Fa-f]\\)\\)" | ||
| 2580 | string index) | ||
| 2581 | (if (match-beginning 2) | ||
| 2582 | (setq string (replace-match "\\2" t nil string) | ||
| 2583 | index (1- (match-end 0))) | ||
| 2584 | (if (match-beginning 3) | ||
| 2585 | (setq string (replace-match (string (string-to-number | ||
| 2586 | (match-string 0 string) 16)) | ||
| 2587 | t t string) | ||
| 2588 | index (- (match-end 0) 2))))) | ||
| 2589 | string)) | ||
| 2590 | |||
| 2591 | (defun epg-dn-from-string (string) | ||
| 2592 | "Parse STRING as LADPv3 Distinguished Names (RFC2253). | ||
| 2593 | The return value is an alist mapping from types to values." | ||
| 2594 | (let ((index 0) | ||
| 2595 | (length (length string)) | ||
| 2596 | alist type value group) | ||
| 2597 | (while (< index length) | ||
| 2598 | (if (eq index (string-match "[ \t\n\r]*" string index)) | ||
| 2599 | (setq index (match-end 0))) | ||
| 2600 | (if (eq index (string-match | ||
| 2601 | "\\([0-9]+\\(\\.[0-9]+\\)*\\)\[ \t\n\r]*=[ \t\n\r]*" | ||
| 2602 | string index)) | ||
| 2603 | (setq type (match-string 1 string) | ||
| 2604 | index (match-end 0)) | ||
| 2605 | (if (eq index (string-match "\\([0-9A-Za-z]+\\)[ \t\n\r]*=[ \t\n\r]*" | ||
| 2606 | string index)) | ||
| 2607 | (setq type (match-string 1 string) | ||
| 2608 | index (match-end 0)))) | ||
| 2609 | (unless type | ||
| 2610 | (error "Invalid type")) | ||
| 2611 | (if (eq index (string-match | ||
| 2612 | "\\([^,=+<>#;\\\"]\\|\\\\.\\)+" | ||
| 2613 | string index)) | ||
| 2614 | (setq index (match-end 0) | ||
| 2615 | value (epg--decode-quotedstring (match-string 0 string))) | ||
| 2616 | (if (eq index (string-match "#\\([0-9A-Fa-f]+\\)" string index)) | ||
| 2617 | (setq index (match-end 0) | ||
| 2618 | value (epg--decode-hexstring (match-string 1 string))) | ||
| 2619 | (if (eq index (string-match "\"\\([^\\\"]\\|\\\\.\\)*\"" | ||
| 2620 | string index)) | ||
| 2621 | (setq index (match-end 0) | ||
| 2622 | value (epg--decode-quotedstring | ||
| 2623 | (match-string 0 string)))))) | ||
| 2624 | (if group | ||
| 2625 | (if (stringp (car (car alist))) | ||
| 2626 | (setcar alist (list (cons type value) (car alist))) | ||
| 2627 | (setcar alist (cons (cons type value) (car alist)))) | ||
| 2628 | (if (consp (car (car alist))) | ||
| 2629 | (setcar alist (nreverse (car alist)))) | ||
| 2630 | (setq alist (cons (cons type value) alist) | ||
| 2631 | type nil | ||
| 2632 | value nil)) | ||
| 2633 | (if (eq index (string-match "[ \t\n\r]*\\([,;+]\\)" string index)) | ||
| 2634 | (setq index (match-end 0) | ||
| 2635 | group (eq (aref string (match-beginning 1)) ?+)))) | ||
| 2636 | (nreverse alist))) | ||
| 2637 | |||
| 2638 | (defun epg-decode-dn (alist) | ||
| 2639 | "Convert ALIST returned by `epg-dn-from-string' to a human readable form. | ||
| 2640 | Type names are resolved using `epg-dn-type-alist'." | ||
| 2641 | (mapconcat | ||
| 2642 | (lambda (rdn) | ||
| 2643 | (if (stringp (car rdn)) | ||
| 2644 | (let ((entry (assoc (car rdn) epg-dn-type-alist))) | ||
| 2645 | (if entry | ||
| 2646 | (format "%s=%s" (cdr entry) (cdr rdn)) | ||
| 2647 | (format "%s=%s" (car rdn) (cdr rdn)))) | ||
| 2648 | (concat "(" (epg-decode-dn rdn) ")"))) | ||
| 2649 | alist | ||
| 2650 | ", ")) | ||
| 2651 | |||
| 2652 | (provide 'epg) | ||
| 2653 | |||
| 2654 | ;;; epg.el ends here | ||