* lisp/arc-mode.el: Add support for 7za.
[bpt/emacs.git] / lisp / epa.el
CommitLineData
74f50695 1;;; epa.el --- the EasyPG Assistant -*- lexical-binding: t -*-
e9bffc61 2
ab422c4d 3;; Copyright (C) 2006-2013 Free Software Foundation, Inc.
c154c0be
MO
4
5;; Author: Daiki Ueno <ueno@unixuser.org>
6;; Keywords: PGP, GnuPG
7
8;; This file is part of GNU Emacs.
9
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
c154c0be 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
c154c0be
MO
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
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
c154c0be
MO
22
23;;; Code:
24
25(require 'epg)
26(require 'font-lock)
27(require 'widget)
28(eval-when-compile (require 'wid-edit))
29(require 'derived)
30
31(defgroup epa nil
32 "The EasyPG Assistant"
0bd4f317 33 :version "23.1"
c154c0be
MO
34 :group 'epg)
35
36(defcustom epa-popup-info-window t
aec7da77 37 "If non-nil, display status information from epa commands in another window."
c154c0be
MO
38 :type 'boolean
39 :group 'epa)
40
41(defcustom epa-info-window-height 5
42 "Number of lines used to display status information."
43 :type 'integer
44 :group 'epa)
45
46(defgroup epa-faces nil
47 "Faces for epa-mode."
0bd4f317 48 :version "23.1"
c154c0be
MO
49 :group 'epa)
50
b1fb3596
RS
51(defcustom epa-mail-aliases nil
52 "Alist of aliases of email addresses that stand for encryption keys.
53Each element is (ALIAS EXPANSIONS...).
54It means that when a message is addressed to ALIAS,
55instead of encrypting it for ALIAS, encrypt it for EXPANSIONS...
56If EXPANSIONS is empty, ignore ALIAS as regards encryption.
57That is a handy way to avoid warnings about addresses
58that you don't have any key for."
59 :type '(repeat (cons (string :tag "Alias") (repeat '(string :tag "Expansion"))))
60 :group 'epa
61 :version "24.4")
62
c154c0be 63(defface epa-validity-high
4b56d0fe
CY
64 '((default :weight bold)
65 (((class color) (background dark)) :foreground "PaleTurquoise"))
66 "Face for high validity EPA information."
c154c0be
MO
67 :group 'epa-faces)
68
69(defface epa-validity-medium
4b56d0fe
CY
70 '((default :slant italic)
71 (((class color) (background dark)) :foreground "PaleTurquoise"))
72 "Face for medium validity EPA information."
c154c0be
MO
73 :group 'epa-faces)
74
75(defface epa-validity-low
4b56d0fe 76 '((t :slant italic))
c154c0be
MO
77 "Face used for displaying the low validity."
78 :group 'epa-faces)
79
80(defface epa-validity-disabled
4b56d0fe 81 '((t :slant italic :inverse-video t))
c154c0be
MO
82 "Face used for displaying the disabled validity."
83 :group 'epa-faces)
84
85(defface epa-string
86 '((((class color) (background dark))
4b56d0fe 87 :foreground "lightyellow")
c154c0be 88 (((class color) (background light))
4b56d0fe 89 :foreground "blue4"))
c154c0be
MO
90 "Face used for displaying the string."
91 :group 'epa-faces)
92
93(defface epa-mark
4b56d0fe
CY
94 '((default :weight bold)
95 (((class color) (background dark)) :foreground "orange")
96 (((class color) (background light)) :foreground "red"))
c154c0be
MO
97 "Face used for displaying the high validity."
98 :group 'epa-faces)
99
100(defface epa-field-name
4b56d0fe
CY
101 '((default :weight bold)
102 (((class color) (background dark)) :foreground "PaleTurquoise"))
c154c0be
MO
103 "Face for the name of the attribute field."
104 :group 'epa)
105
106(defface epa-field-body
4b56d0fe
CY
107 '((default :slant italic)
108 (((class color) (background dark)) :foreground "turquoise"))
c154c0be
MO
109 "Face for the body of the attribute field."
110 :group 'epa)
111
112(defcustom epa-validity-face-alist
113 '((unknown . epa-validity-disabled)
114 (invalid . epa-validity-disabled)
115 (disabled . epa-validity-disabled)
116 (revoked . epa-validity-disabled)
117 (expired . epa-validity-disabled)
118 (none . epa-validity-low)
119 (undefined . epa-validity-low)
120 (never . epa-validity-low)
121 (marginal . epa-validity-medium)
122 (full . epa-validity-high)
123 (ultimate . epa-validity-high))
124 "An alist mapping validity values to faces."
125 :type '(repeat (cons symbol face))
126 :group 'epa)
127
128(defvar epa-font-lock-keywords
129 '(("^\\*"
130 (0 'epa-mark))
131 ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$"
132 (1 'epa-field-name)
133 (2 'epa-field-body)))
134 "Default expressions to addon in epa-mode.")
135
136(defconst epa-pubkey-algorithm-letter-alist
137 '((1 . ?R)
138 (2 . ?r)
139 (3 . ?s)
140 (16 . ?g)
141 (17 . ?D)
142 (20 . ?G)))
143
144(defvar epa-protocol 'OpenPGP
fb7ada5f 145 "The default protocol.
c154c0be
MO
146The value can be either OpenPGP or CMS.
147
148You should bind this variable with `let', but do not set it globally.")
149
150(defvar epa-armor nil
fb7ada5f 151 "If non-nil, epa commands create ASCII armored output.
c154c0be
MO
152
153You should bind this variable with `let', but do not set it globally.")
154
155(defvar epa-textmode nil
fb7ada5f 156 "If non-nil, epa commands treat input files as text.
c154c0be
MO
157
158You should bind this variable with `let', but do not set it globally.")
159
160(defvar epa-keys-buffer nil)
161(defvar epa-key-buffer-alist nil)
162(defvar epa-key nil)
163(defvar epa-list-keys-arguments nil)
164(defvar epa-info-buffer nil)
165(defvar epa-last-coding-system-specified nil)
166
167(defvar epa-key-list-mode-map
dc9b613e
GM
168 (let ((keymap (make-sparse-keymap))
169 (menu-map (make-sparse-keymap)))
c154c0be
MO
170 (define-key keymap "m" 'epa-mark-key)
171 (define-key keymap "u" 'epa-unmark-key)
172 (define-key keymap "d" 'epa-decrypt-file)
173 (define-key keymap "v" 'epa-verify-file)
174 (define-key keymap "s" 'epa-sign-file)
175 (define-key keymap "e" 'epa-encrypt-file)
176 (define-key keymap "r" 'epa-delete-keys)
177 (define-key keymap "i" 'epa-import-keys)
178 (define-key keymap "o" 'epa-export-keys)
179 (define-key keymap "g" 'revert-buffer)
180 (define-key keymap "n" 'next-line)
181 (define-key keymap "p" 'previous-line)
ce3cefcc 182 (define-key keymap " " 'scroll-up-command)
958614cf 183 (define-key keymap [?\S-\ ] 'scroll-down-command)
ce3cefcc 184 (define-key keymap [delete] 'scroll-down-command)
c154c0be 185 (define-key keymap "q" 'epa-exit-buffer)
dc9b613e 186 (define-key keymap [menu-bar epa-key-list-mode] (cons "Keys" menu-map))
703b9611
DN
187 (define-key menu-map [epa-key-list-unmark-key]
188 '(menu-item "Unmark Key" epa-unmark-key
189 :help "Unmark a key"))
190 (define-key menu-map [epa-key-list-mark-key]
191 '(menu-item "Mark Key" epa-mark-key
192 :help "Mark a key"))
193 (define-key menu-map [separator-epa-file] '(menu-item "--"))
194 (define-key menu-map [epa-verify-file]
195 '(menu-item "Verify File..." epa-verify-file
196 :help "Verify FILE"))
197 (define-key menu-map [epa-sign-file]
198 '(menu-item "Sign File..." epa-sign-file
199 :help "Sign FILE by SIGNERS keys selected"))
200 (define-key menu-map [epa-decrypt-file]
201 '(menu-item "Decrypt File..." epa-decrypt-file
202 :help "Decrypt FILE"))
203 (define-key menu-map [epa-encrypt-file]
d88444f2 204 '(menu-item "Encrypt File..." epa-encrypt-file
703b9611
DN
205 :help "Encrypt FILE for RECIPIENTS"))
206 (define-key menu-map [separator-epa-key-list] '(menu-item "--"))
dc9b613e 207 (define-key menu-map [epa-key-list-delete-keys]
7cc6e154 208 '(menu-item "Delete Keys" epa-delete-keys
703b9611 209 :help "Delete Marked Keys"))
dc9b613e 210 (define-key menu-map [epa-key-list-import-keys]
703b9611 211 '(menu-item "Import Keys" epa-import-keys
dc9b613e
GM
212 :help "Import keys from a file"))
213 (define-key menu-map [epa-key-list-export-keys]
703b9611 214 '(menu-item "Export Keys" epa-export-keys
dc9b613e 215 :help "Export marked keys to a file"))
c154c0be
MO
216 keymap))
217
218(defvar epa-key-mode-map
219 (let ((keymap (make-sparse-keymap)))
220 (define-key keymap "q" 'epa-exit-buffer)
221 keymap))
222
223(defvar epa-info-mode-map
224 (let ((keymap (make-sparse-keymap)))
225 (define-key keymap "q" 'delete-window)
226 keymap))
227
228(defvar epa-exit-buffer-function #'bury-buffer)
229
230(define-widget 'epa-key 'push-button
231 "Button for representing a epg-key object."
232 :format "%[%v%]"
233 :button-face-get 'epa--key-widget-button-face-get
234 :value-create 'epa--key-widget-value-create
235 :action 'epa--key-widget-action
236 :help-echo 'epa--key-widget-help-echo)
237
74f50695 238(defun epa--key-widget-action (widget &optional _event)
a648af17
DU
239 (save-selected-window
240 (epa--show-key (widget-get widget :value))))
c154c0be
MO
241
242(defun epa--key-widget-value-create (widget)
243 (let* ((key (widget-get widget :value))
244 (primary-sub-key (car (epg-key-sub-key-list key)))
245 (primary-user-id (car (epg-key-user-id-list key))))
246 (insert (format "%c "
247 (if (epg-sub-key-validity primary-sub-key)
248 (car (rassq (epg-sub-key-validity primary-sub-key)
249 epg-key-validity-alist))
250 ? ))
251 (epg-sub-key-id primary-sub-key)
252 " "
253 (if primary-user-id
254 (if (stringp (epg-user-id-string primary-user-id))
255 (epg-user-id-string primary-user-id)
256 (epg-decode-dn (epg-user-id-string primary-user-id)))
257 ""))))
258
259(defun epa--key-widget-button-face-get (widget)
260 (let ((validity (epg-sub-key-validity (car (epg-key-sub-key-list
261 (widget-get widget :value))))))
262 (if validity
263 (cdr (assq validity epa-validity-face-alist))
264 'default)))
265
266(defun epa--key-widget-help-echo (widget)
267 (format "Show %s"
268 (epg-sub-key-id (car (epg-key-sub-key-list
269 (widget-get widget :value))))))
270
271(eval-and-compile
272 (if (fboundp 'encode-coding-string)
273 (defalias 'epa--encode-coding-string 'encode-coding-string)
274 (defalias 'epa--encode-coding-string 'identity)))
275
276(eval-and-compile
277 (if (fboundp 'decode-coding-string)
278 (defalias 'epa--decode-coding-string 'decode-coding-string)
279 (defalias 'epa--decode-coding-string 'identity)))
280
281(defun epa-key-list-mode ()
282 "Major mode for `epa-list-keys'."
283 (kill-all-local-variables)
284 (buffer-disable-undo)
285 (setq major-mode 'epa-key-list-mode
286 mode-name "Keys"
287 truncate-lines t
288 buffer-read-only t)
289 (use-local-map epa-key-list-mode-map)
290 (make-local-variable 'font-lock-defaults)
291 (setq font-lock-defaults '(epa-font-lock-keywords t))
292 ;; In XEmacs, auto-initialization of font-lock is not effective
293 ;; if buffer-file-name is not set.
294 (font-lock-set-defaults)
295 (make-local-variable 'epa-exit-buffer-function)
296 (make-local-variable 'revert-buffer-function)
297 (setq revert-buffer-function 'epa--key-list-revert-buffer)
64cc2f2c 298 (run-mode-hooks 'epa-key-list-mode-hook))
c154c0be
MO
299
300(defun epa-key-mode ()
301 "Major mode for a key description."
302 (kill-all-local-variables)
303 (buffer-disable-undo)
304 (setq major-mode 'epa-key-mode
305 mode-name "Key"
306 truncate-lines t
307 buffer-read-only t)
308 (use-local-map epa-key-mode-map)
309 (make-local-variable 'font-lock-defaults)
310 (setq font-lock-defaults '(epa-font-lock-keywords t))
311 ;; In XEmacs, auto-initialization of font-lock is not effective
312 ;; if buffer-file-name is not set.
313 (font-lock-set-defaults)
314 (make-local-variable 'epa-exit-buffer-function)
64cc2f2c 315 (run-mode-hooks 'epa-key-mode-hook))
c154c0be
MO
316
317(defun epa-info-mode ()
318 "Major mode for `epa-info-buffer'."
319 (kill-all-local-variables)
320 (buffer-disable-undo)
321 (setq major-mode 'epa-info-mode
322 mode-name "Info"
323 truncate-lines t
324 buffer-read-only t)
325 (use-local-map epa-info-mode-map)
64cc2f2c 326 (run-mode-hooks 'epa-info-mode-hook))
c154c0be
MO
327
328(defun epa-mark-key (&optional arg)
329 "Mark a key on the current line.
330If ARG is non-nil, unmark the key."
331 (interactive "P")
332 (let ((inhibit-read-only t)
333 buffer-read-only
334 properties)
335 (beginning-of-line)
336 (unless (get-text-property (point) 'epa-key)
337 (error "No key on this line"))
338 (setq properties (text-properties-at (point)))
339 (delete-char 1)
340 (insert (if arg " " "*"))
341 (set-text-properties (1- (point)) (point) properties)
342 (forward-line)))
343
344(defun epa-unmark-key (&optional arg)
345 "Unmark a key on the current line.
346If ARG is non-nil, mark the key."
347 (interactive "P")
348 (epa-mark-key (not arg)))
349
350(defun epa-exit-buffer ()
351 "Exit the current buffer.
352`epa-exit-buffer-function' is called if it is set."
353 (interactive)
354 (funcall epa-exit-buffer-function))
355
356(defun epa--insert-keys (keys)
357 (save-excursion
358 (save-restriction
359 (narrow-to-region (point) (point))
360 (let (point)
361 (while keys
362 (setq point (point))
363 (insert " ")
364 (add-text-properties point (point)
365 (list 'epa-key (car keys)
366 'front-sticky nil
367 'rear-nonsticky t
368 'start-open t
369 'end-open t))
370 (widget-create 'epa-key :value (car keys))
371 (insert "\n")
f1914c40 372 (setq keys (cdr keys))))
c154c0be
MO
373 (add-text-properties (point-min) (point-max)
374 (list 'epa-list-keys t
375 'front-sticky nil
376 'rear-nonsticky t
377 'start-open t
378 'end-open t)))))
379
380(defun epa--list-keys (name secret)
381 (unless (and epa-keys-buffer
382 (buffer-live-p epa-keys-buffer))
383 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
384 (set-buffer epa-keys-buffer)
385 (epa-key-list-mode)
386 (let ((inhibit-read-only t)
387 buffer-read-only
388 (point (point-min))
389 (context (epg-make-context epa-protocol)))
390 (unless (get-text-property point 'epa-list-keys)
391 (setq point (next-single-property-change point 'epa-list-keys)))
392 (when point
393 (delete-region point
394 (or (next-single-property-change point 'epa-list-keys)
395 (point-max)))
396 (goto-char point))
397 (epa--insert-keys (epg-list-keys context name secret))
398 (widget-setup)
399 (set-keymap-parent (current-local-map) widget-keymap))
400 (make-local-variable 'epa-list-keys-arguments)
401 (setq epa-list-keys-arguments (list name secret))
402 (goto-char (point-min))
403 (pop-to-buffer (current-buffer)))
404
405;;;###autoload
406(defun epa-list-keys (&optional name)
407 "List all keys matched with NAME from the public keyring."
408 (interactive
409 (if current-prefix-arg
410 (let ((name (read-string "Pattern: "
411 (if epa-list-keys-arguments
412 (car epa-list-keys-arguments)))))
413 (list (if (equal name "") nil name)))
414 (list nil)))
415 (epa--list-keys name nil))
416
417;;;###autoload
418(defun epa-list-secret-keys (&optional name)
419 "List all keys matched with NAME from the private keyring."
420 (interactive
421 (if current-prefix-arg
422 (let ((name (read-string "Pattern: "
423 (if epa-list-keys-arguments
424 (car epa-list-keys-arguments)))))
425 (list (if (equal name "") nil name)))
426 (list nil)))
427 (epa--list-keys name t))
428
74f50695 429(defun epa--key-list-revert-buffer (&optional _ignore-auto _noconfirm)
c154c0be
MO
430 (apply #'epa--list-keys epa-list-keys-arguments))
431
432(defun epa--marked-keys ()
7fdbcd83 433 (or (with-current-buffer epa-keys-buffer
c154c0be
MO
434 (goto-char (point-min))
435 (let (keys key)
436 (while (re-search-forward "^\\*" nil t)
437 (if (setq key (get-text-property (match-beginning 0)
438 'epa-key))
439 (setq keys (cons key keys))))
440 (nreverse keys)))
9b026d9f
GM
441 (let ((key (get-text-property (point-at-bol) 'epa-key)))
442 (if key
443 (list key)))))
c154c0be
MO
444
445(defun epa--select-keys (prompt keys)
7fdbcd83
SM
446 (unless (and epa-keys-buffer
447 (buffer-live-p epa-keys-buffer))
448 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
449 (with-current-buffer epa-keys-buffer
c154c0be 450 (epa-key-list-mode)
2d562c0f
DU
451 ;; C-c C-c is the usual way to finish the selection (bug#11159).
452 (define-key (current-local-map) "\C-c\C-c" 'exit-recursive-edit)
c154c0be
MO
453 (let ((inhibit-read-only t)
454 buffer-read-only)
455 (erase-buffer)
456 (insert prompt "\n"
457 (substitute-command-keys "\
458- `\\[epa-mark-key]' to mark a key on the line
459- `\\[epa-unmark-key]' to unmark a key on the line\n"))
460 (widget-create 'link
74f50695 461 :notify (lambda (&rest _ignore) (abort-recursive-edit))
c154c0be
MO
462 :help-echo
463 (substitute-command-keys
464 "Click here or \\[abort-recursive-edit] to cancel")
465 "Cancel")
466 (widget-create 'link
74f50695 467 :notify (lambda (&rest _ignore) (exit-recursive-edit))
c154c0be
MO
468 :help-echo
469 (substitute-command-keys
470 "Click here or \\[exit-recursive-edit] to finish")
471 "OK")
472 (insert "\n\n")
473 (epa--insert-keys keys)
474 (widget-setup)
475 (set-keymap-parent (current-local-map) widget-keymap)
476 (setq epa-exit-buffer-function #'abort-recursive-edit)
477 (goto-char (point-min))
397eb3f3
SM
478 (let ((display-buffer-mark-dedicated 'soft))
479 (pop-to-buffer (current-buffer))))
c154c0be
MO
480 (unwind-protect
481 (progn
482 (recursive-edit)
483 (epa--marked-keys))
c154c0be
MO
484 (kill-buffer epa-keys-buffer))))
485
486;;;###autoload
487(defun epa-select-keys (context prompt &optional names secret)
488 "Display a user's keyring and ask him to select keys.
489CONTEXT is an epg-context.
490PROMPT is a string to prompt with.
491NAMES is a list of strings to be matched with keys. If it is nil, all
492the keys are listed.
493If SECRET is non-nil, list secret keys instead of public keys."
494 (let ((keys (epg-list-keys context names secret)))
2c6c404a 495 (epa--select-keys prompt keys)))
c154c0be
MO
496
497(defun epa--show-key (key)
498 (let* ((primary-sub-key (car (epg-key-sub-key-list key)))
499 (entry (assoc (epg-sub-key-id primary-sub-key)
500 epa-key-buffer-alist))
501 (inhibit-read-only t)
502 buffer-read-only
503 pointer)
504 (unless entry
505 (setq entry (cons (epg-sub-key-id primary-sub-key) nil)
506 epa-key-buffer-alist (cons entry epa-key-buffer-alist)))
507 (unless (and (cdr entry)
508 (buffer-live-p (cdr entry)))
509 (setcdr entry (generate-new-buffer
510 (format "*Key*%s" (epg-sub-key-id primary-sub-key)))))
511 (set-buffer (cdr entry))
512 (epa-key-mode)
513 (make-local-variable 'epa-key)
514 (setq epa-key key)
515 (erase-buffer)
516 (setq pointer (epg-key-user-id-list key))
517 (while pointer
518 (if (car pointer)
519 (insert " "
520 (if (epg-user-id-validity (car pointer))
521 (char-to-string
522 (car (rassq (epg-user-id-validity (car pointer))
523 epg-key-validity-alist)))
524 " ")
525 " "
526 (if (stringp (epg-user-id-string (car pointer)))
527 (epg-user-id-string (car pointer))
528 (epg-decode-dn (epg-user-id-string (car pointer))))
529 "\n"))
530 (setq pointer (cdr pointer)))
531 (setq pointer (epg-key-sub-key-list key))
532 (while pointer
533 (insert " "
534 (if (epg-sub-key-validity (car pointer))
535 (char-to-string
536 (car (rassq (epg-sub-key-validity (car pointer))
537 epg-key-validity-alist)))
538 " ")
539 " "
540 (epg-sub-key-id (car pointer))
541 " "
542 (format "%dbits"
543 (epg-sub-key-length (car pointer)))
544 " "
545 (cdr (assq (epg-sub-key-algorithm (car pointer))
546 epg-pubkey-algorithm-alist))
547 "\n\tCreated: "
548 (condition-case nil
549 (format-time-string "%Y-%m-%d"
550 (epg-sub-key-creation-time (car pointer)))
551 (error "????-??-??"))
552 (if (epg-sub-key-expiration-time (car pointer))
97c07afc
DU
553 (format (if (time-less-p (current-time)
554 (epg-sub-key-expiration-time
555 (car pointer)))
556 "\n\tExpires: %s"
557 "\n\tExpired: %s")
c154c0be
MO
558 (condition-case nil
559 (format-time-string "%Y-%m-%d"
560 (epg-sub-key-expiration-time
561 (car pointer)))
562 (error "????-??-??")))
563 "")
564 "\n\tCapabilities: "
565 (mapconcat #'symbol-name
566 (epg-sub-key-capability (car pointer))
567 " ")
568 "\n\tFingerprint: "
569 (epg-sub-key-fingerprint (car pointer))
570 "\n")
571 (setq pointer (cdr pointer)))
572 (goto-char (point-min))
573 (pop-to-buffer (current-buffer))))
574
575(defun epa-display-info (info)
576 (if epa-popup-info-window
577 (save-selected-window
578 (unless (and epa-info-buffer (buffer-live-p epa-info-buffer))
579 (setq epa-info-buffer (generate-new-buffer "*Info*")))
580 (if (get-buffer-window epa-info-buffer)
581 (delete-window (get-buffer-window epa-info-buffer)))
7fdbcd83 582 (with-current-buffer epa-info-buffer
c154c0be
MO
583 (let ((inhibit-read-only t)
584 buffer-read-only)
585 (erase-buffer)
586 (insert info))
587 (epa-info-mode)
588 (goto-char (point-min)))
589 (if (> (window-height)
590 epa-info-window-height)
591 (set-window-buffer (split-window nil (- (window-height)
592 epa-info-window-height))
593 epa-info-buffer)
594 (pop-to-buffer epa-info-buffer)
595 (if (> (window-height) epa-info-window-height)
596 (shrink-window (- (window-height) epa-info-window-height)))))
597 (message "%s" info)))
598
599(defun epa-display-verify-result (verify-result)
59f7af81 600 (declare (obsolete epa-display-info "23.1"))
c154c0be 601 (epa-display-info (epg-verify-result-to-string verify-result)))
c154c0be
MO
602
603(defun epa-passphrase-callback-function (context key-id handback)
604 (if (eq key-id 'SYM)
7450df5d
LMI
605 (read-passwd
606 (format "Passphrase for symmetric encryption%s: "
446b12da
DU
607 ;; Add the file name to the prompt, if any.
608 (if (stringp handback)
609 (format " for %s" handback)
610 ""))
7450df5d 611 (eq (epg-context-operation context) 'encrypt))
c154c0be
MO
612 (read-passwd
613 (if (eq key-id 'PIN)
614 "Passphrase for PIN: "
615 (let ((entry (assoc key-id epg-user-id-alist)))
616 (if entry
617 (format "Passphrase for %s %s: " key-id (cdr entry))
618 (format "Passphrase for %s: " key-id)))))))
619
74f50695 620(defun epa-progress-callback-function (_context what _char current total
c154c0be 621 handback)
9d5cb631
DU
622 (let ((prompt (or handback
623 (format "Processing %s: " what))))
624 ;; According to gnupg/doc/DETAIL: a "total" of 0 indicates that
625 ;; the total amount is not known. The condition TOTAL && CUR ==
626 ;; TOTAL may be used to detect the end of an operation.
627 (if (> total 0)
628 (if (= current total)
629 (message "%s...done" prompt)
630 (message "%s...%d%%" prompt
631 (floor (* (/ current (float total)) 100))))
632 (message "%s..." prompt))))
c154c0be 633
ff4871b9
GM
634(defun epa-read-file-name (input)
635 "Interactively read an output file name based on INPUT file name."
636 (setq input (file-name-sans-extension (expand-file-name input)))
637 (expand-file-name
638 (read-file-name
639 (concat "To file (default " (file-name-nondirectory input) ") ")
640 (file-name-directory input)
641 input)))
642
c154c0be 643;;;###autoload
ff4871b9
GM
644(defun epa-decrypt-file (decrypt-file &optional plain-file)
645 "Decrypt DECRYPT-FILE into PLAIN-FILE.
646If you do not specify PLAIN-FILE, this functions prompts for the value to use."
212e29f2 647 (interactive
ff4871b9
GM
648 (let* ((file (read-file-name "File to decrypt: "))
649 (plain (epa-read-file-name file)))
212e29f2 650 (list file plain)))
ff4871b9 651 (or plain-file (setq plain-file (epa-read-file-name decrypt-file)))
212e29f2
RS
652 (setq decrypt-file (expand-file-name decrypt-file))
653 (let ((context (epg-make-context epa-protocol)))
c154c0be
MO
654 (epg-context-set-passphrase-callback context
655 #'epa-passphrase-callback-function)
656 (epg-context-set-progress-callback context
657 (cons
658 #'epa-progress-callback-function
659 (format "Decrypting %s..."
212e29f2
RS
660 (file-name-nondirectory decrypt-file))))
661 (message "Decrypting %s..." (file-name-nondirectory decrypt-file))
662 (epg-decrypt-file context decrypt-file plain-file)
663 (message "Decrypting %s...wrote %s" (file-name-nondirectory decrypt-file)
664 (file-name-nondirectory plain-file))
c154c0be
MO
665 (if (epg-context-result-for context 'verify)
666 (epa-display-info (epg-verify-result-to-string
667 (epg-context-result-for context 'verify))))))
668
669;;;###autoload
670(defun epa-verify-file (file)
671 "Verify FILE."
672 (interactive "fFile: ")
673 (setq file (expand-file-name file))
674 (let* ((context (epg-make-context epa-protocol))
675 (plain (if (equal (file-name-extension file) "sig")
676 (file-name-sans-extension file))))
677 (epg-context-set-progress-callback context
678 (cons
679 #'epa-progress-callback-function
680 (format "Verifying %s..."
681 (file-name-nondirectory file))))
682 (message "Verifying %s..." (file-name-nondirectory file))
683 (epg-verify-file context file plain)
684 (message "Verifying %s...done" (file-name-nondirectory file))
685 (if (epg-context-result-for context 'verify)
686 (epa-display-info (epg-verify-result-to-string
687 (epg-context-result-for context 'verify))))))
688
689(defun epa--read-signature-type ()
690 (let (type c)
691 (while (null type)
692 (message "Signature type (n,c,d,?) ")
693 (setq c (read-char))
694 (cond ((eq c ?c)
695 (setq type 'clear))
696 ((eq c ?d)
697 (setq type 'detached))
698 ((eq c ??)
699 (with-output-to-temp-buffer "*Help*"
7fdbcd83 700 (with-current-buffer standard-output
c154c0be
MO
701 (insert "\
702n - Create a normal signature
703c - Create a cleartext signature
704d - Create a detached signature
705? - Show this help
706"))))
707 (t
50f13b3e
DU
708 (setq type 'normal))))
709 type))
c154c0be
MO
710
711;;;###autoload
712(defun epa-sign-file (file signers mode)
713 "Sign FILE by SIGNERS keys selected."
714 (interactive
715 (let ((verbose current-prefix-arg))
716 (list (expand-file-name (read-file-name "File: "))
717 (if verbose
718 (epa-select-keys (epg-make-context epa-protocol)
719 "Select keys for signing.
720If no one is selected, default secret key is used. "
721 nil t))
722 (if verbose
723 (epa--read-signature-type)
724 'clear))))
725 (let ((signature (concat file
726 (if (eq epa-protocol 'OpenPGP)
727 (if (or epa-armor
728 (not (memq mode
729 '(nil t normal detached))))
730 ".asc"
731 (if (memq mode '(t detached))
732 ".sig"
733 ".gpg"))
734 (if (memq mode '(t detached))
735 ".p7s"
736 ".p7m"))))
737 (context (epg-make-context epa-protocol)))
738 (epg-context-set-armor context epa-armor)
739 (epg-context-set-textmode context epa-textmode)
740 (epg-context-set-signers context signers)
741 (epg-context-set-passphrase-callback context
742 #'epa-passphrase-callback-function)
743 (epg-context-set-progress-callback context
744 (cons
745 #'epa-progress-callback-function
746 (format "Signing %s..."
747 (file-name-nondirectory file))))
748 (message "Signing %s..." (file-name-nondirectory file))
749 (epg-sign-file context file signature mode)
750 (message "Signing %s...wrote %s" (file-name-nondirectory file)
751 (file-name-nondirectory signature))))
752
753;;;###autoload
754(defun epa-encrypt-file (file recipients)
755 "Encrypt FILE for RECIPIENTS."
756 (interactive
757 (list (expand-file-name (read-file-name "File: "))
758 (epa-select-keys (epg-make-context epa-protocol)
759 "Select recipients for encryption.
760If no one is selected, symmetric encryption will be performed. ")))
761 (let ((cipher (concat file (if (eq epa-protocol 'OpenPGP)
762 (if epa-armor ".asc" ".gpg")
763 ".p7m")))
764 (context (epg-make-context epa-protocol)))
765 (epg-context-set-armor context epa-armor)
766 (epg-context-set-textmode context epa-textmode)
767 (epg-context-set-passphrase-callback context
768 #'epa-passphrase-callback-function)
769 (epg-context-set-progress-callback context
770 (cons
771 #'epa-progress-callback-function
772 (format "Encrypting %s..."
773 (file-name-nondirectory file))))
774 (message "Encrypting %s..." (file-name-nondirectory file))
775 (epg-encrypt-file context file recipients cipher)
776 (message "Encrypting %s...wrote %s" (file-name-nondirectory file)
777 (file-name-nondirectory cipher))))
778
779;;;###autoload
fe38beef 780(defun epa-decrypt-region (start end &optional make-buffer-function)
c154c0be 781 "Decrypt the current region between START and END.
fe38beef
RS
782
783If MAKE-BUFFER-FUNCTION is non-nil, call it to prepare an output buffer.
784It should return that buffer. If it copies the input, it should
785delete the text now being decrypted. It should leave point at the
786proper place to insert the plaintext.
c154c0be 787
3a99bf64 788Be careful about using this command in Lisp programs!
2c6c404a
MO
789Since this function operates on regions, it does some tricks such
790as coding-system detection and unibyte/multibyte conversion. If
791you are sure how the data in the region should be treated, you
792should consider using the string based counterpart
793`epg-decrypt-string', or the file based counterpart
794`epg-decrypt-file' instead.
795
796For example:
797
798\(let ((context (epg-make-context 'OpenPGP)))
799 (decode-coding-string
800 (epg-decrypt-string context (buffer-substring start end))
801 'utf-8))"
c154c0be
MO
802 (interactive "r")
803 (save-excursion
804 (let ((context (epg-make-context epa-protocol))
805 plain)
806 (epg-context-set-passphrase-callback context
807 #'epa-passphrase-callback-function)
808 (epg-context-set-progress-callback context
809 (cons
810 #'epa-progress-callback-function
811 "Decrypting..."))
812 (message "Decrypting...")
813 (setq plain (epg-decrypt-string context (buffer-substring start end)))
814 (message "Decrypting...done")
815 (setq plain (epa--decode-coding-string
816 plain
817 (or coding-system-for-read
42481bde
DU
818 (get-text-property start 'epa-coding-system-used)
819 'undecided)))
44fede4d
RS
820 (if make-buffer-function
821 (with-current-buffer (funcall make-buffer-function)
822 (let ((inhibit-read-only t))
823 (insert plain)))
824 (if (y-or-n-p "Replace the original text? ")
825 (let ((inhibit-read-only t))
826 (delete-region start end)
827 (goto-char start)
828 (insert plain))
3a99bf64
RS
829 (with-output-to-temp-buffer "*Temp*"
830 (set-buffer standard-output)
831 (insert plain)
832 (epa-info-mode))))
c154c0be
MO
833 (if (epg-context-result-for context 'verify)
834 (epa-display-info (epg-verify-result-to-string
835 (epg-context-result-for context 'verify)))))))
836
837(defun epa--find-coding-system-for-mime-charset (mime-charset)
838 (if (featurep 'xemacs)
839 (if (fboundp 'find-coding-system)
840 (find-coding-system mime-charset))
3a99bf64 841 ;; Find the first coding system which corresponds to MIME-CHARSET.
c154c0be
MO
842 (let ((pointer (coding-system-list)))
843 (while (and pointer
3a99bf64
RS
844 (not (eq (coding-system-get (car pointer) 'mime-charset)
845 mime-charset)))
c154c0be 846 (setq pointer (cdr pointer)))
3a99bf64 847 (car pointer))))
c154c0be
MO
848
849;;;###autoload
850(defun epa-decrypt-armor-in-region (start end)
851 "Decrypt OpenPGP armors in the current region between START and END.
852
2c6c404a
MO
853Don't use this command in Lisp programs!
854See the reason described in the `epa-decrypt-region' documentation."
c154c0be
MO
855 (interactive "r")
856 (save-excursion
857 (save-restriction
858 (narrow-to-region start end)
859 (goto-char start)
860 (let (armor-start armor-end)
861 (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
862 (setq armor-start (match-beginning 0)
863 armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
864 nil t))
865 (unless armor-end
3a99bf64 866 (error "Encryption armor beginning has no matching end"))
c154c0be
MO
867 (goto-char armor-start)
868 (let ((coding-system-for-read
869 (or coding-system-for-read
870 (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
871 (epa--find-coding-system-for-mime-charset
872 (intern (downcase (match-string 1))))))))
873 (goto-char armor-end)
874 (epa-decrypt-region armor-start armor-end)))))))
875
876;;;###autoload
877(defun epa-verify-region (start end)
878 "Verify the current region between START and END.
879
2c6c404a
MO
880Don't use this command in Lisp programs!
881Since this function operates on regions, it does some tricks such
882as coding-system detection and unibyte/multibyte conversion. If
883you are sure how the data in the region should be treated, you
884should consider using the string based counterpart
885`epg-verify-string', or the file based counterpart
886`epg-verify-file' instead.
887
888For example:
889
890\(let ((context (epg-make-context 'OpenPGP)))
891 (decode-coding-string
892 (epg-verify-string context (buffer-substring start end))
893 'utf-8))"
c154c0be
MO
894 (interactive "r")
895 (let ((context (epg-make-context epa-protocol))
896 plain)
897 (epg-context-set-progress-callback context
898 (cons
899 #'epa-progress-callback-function
900 "Verifying..."))
901 (message "Verifying...")
902 (setq plain (epg-verify-string
903 context
904 (epa--encode-coding-string
905 (buffer-substring start end)
906 (or coding-system-for-write
907 (get-text-property start 'epa-coding-system-used)))))
908 (message "Verifying...done")
909 (setq plain (epa--decode-coding-string
910 plain
911 (or coding-system-for-read
42481bde
DU
912 (get-text-property start 'epa-coding-system-used)
913 'undecided)))
c154c0be
MO
914 (if (y-or-n-p "Replace the original text? ")
915 (let ((inhibit-read-only t)
916 buffer-read-only)
917 (delete-region start end)
918 (goto-char start)
919 (insert plain))
920 (with-output-to-temp-buffer "*Temp*"
921 (set-buffer standard-output)
922 (insert plain)
923 (epa-info-mode)))
924 (if (epg-context-result-for context 'verify)
925 (epa-display-info (epg-verify-result-to-string
926 (epg-context-result-for context 'verify))))))
927
928;;;###autoload
929(defun epa-verify-cleartext-in-region (start end)
930 "Verify OpenPGP cleartext signed messages in the current region
931between START and END.
932
2c6c404a
MO
933Don't use this command in Lisp programs!
934See the reason described in the `epa-verify-region' documentation."
c154c0be
MO
935 (interactive "r")
936 (save-excursion
937 (save-restriction
938 (narrow-to-region start end)
939 (goto-char start)
940 (let (cleartext-start cleartext-end)
941 (while (re-search-forward "-----BEGIN PGP SIGNED MESSAGE-----$"
942 nil t)
943 (setq cleartext-start (match-beginning 0))
944 (unless (re-search-forward "^-----BEGIN PGP SIGNATURE-----$"
945 nil t)
946 (error "Invalid cleartext signed message"))
947 (setq cleartext-end (re-search-forward
948 "^-----END PGP SIGNATURE-----$"
949 nil t))
950 (unless cleartext-end
951 (error "No cleartext tail"))
952 (epa-verify-region cleartext-start cleartext-end))))))
953
954(eval-and-compile
955 (if (fboundp 'select-safe-coding-system)
956 (defalias 'epa--select-safe-coding-system 'select-safe-coding-system)
74f50695 957 (defun epa--select-safe-coding-system (_from _to)
c154c0be
MO
958 buffer-file-coding-system)))
959
960;;;###autoload
961(defun epa-sign-region (start end signers mode)
962 "Sign the current region between START and END by SIGNERS keys selected.
963
2c6c404a
MO
964Don't use this command in Lisp programs!
965Since this function operates on regions, it does some tricks such
966as coding-system detection and unibyte/multibyte conversion. If
967you are sure how the data should be treated, you should consider
968using the string based counterpart `epg-sign-string', or the file
969based counterpart `epg-sign-file' instead.
970
971For example:
972
973\(let ((context (epg-make-context 'OpenPGP)))
974 (epg-sign-string
975 context
976 (encode-coding-string (buffer-substring start end) 'utf-8)))"
c154c0be
MO
977 (interactive
978 (let ((verbose current-prefix-arg))
979 (setq epa-last-coding-system-specified
980 (or coding-system-for-write
981 (epa--select-safe-coding-system
982 (region-beginning) (region-end))))
983 (list (region-beginning) (region-end)
984 (if verbose
985 (epa-select-keys (epg-make-context epa-protocol)
986 "Select keys for signing.
987If no one is selected, default secret key is used. "
988 nil t))
989 (if verbose
990 (epa--read-signature-type)
991 'clear))))
992 (save-excursion
993 (let ((context (epg-make-context epa-protocol))
994 signature)
995 ;;(epg-context-set-armor context epa-armor)
996 (epg-context-set-armor context t)
997 ;;(epg-context-set-textmode context epa-textmode)
998 (epg-context-set-textmode context t)
999 (epg-context-set-signers context signers)
1000 (epg-context-set-passphrase-callback context
1001 #'epa-passphrase-callback-function)
1002 (epg-context-set-progress-callback context
1003 (cons
1004 #'epa-progress-callback-function
1005 "Signing..."))
1006 (message "Signing...")
1007 (setq signature (epg-sign-string context
1008 (epa--encode-coding-string
1009 (buffer-substring start end)
1010 epa-last-coding-system-specified)
1011 mode))
1012 (message "Signing...done")
1013 (delete-region start end)
1014 (goto-char start)
1015 (add-text-properties (point)
1016 (progn
1017 (insert (epa--decode-coding-string
1018 signature
1019 (or coding-system-for-read
1020 epa-last-coding-system-specified)))
1021 (point))
1022 (list 'epa-coding-system-used
1023 epa-last-coding-system-specified
1024 'front-sticky nil
1025 'rear-nonsticky t
1026 'start-open t
1027 'end-open t)))))
1028
1029(eval-and-compile
1030 (if (fboundp 'derived-mode-p)
1031 (defalias 'epa--derived-mode-p 'derived-mode-p)
1032 (defun epa--derived-mode-p (&rest modes)
1033 "Non-nil if the current major mode is derived from one of MODES.
1034Uses the `derived-mode-parent' property of the symbol to trace backwards."
1035 (let ((parent major-mode))
1036 (while (and (not (memq parent modes))
1037 (setq parent (get parent 'derived-mode-parent))))
1038 parent))))
1039
1040;;;###autoload
1041(defun epa-encrypt-region (start end recipients sign signers)
1042 "Encrypt the current region between START and END for RECIPIENTS.
1043
2c6c404a
MO
1044Don't use this command in Lisp programs!
1045Since this function operates on regions, it does some tricks such
1046as coding-system detection and unibyte/multibyte conversion. If
1047you are sure how the data should be treated, you should consider
1048using the string based counterpart `epg-encrypt-string', or the
1049file based counterpart `epg-encrypt-file' instead.
1050
1051For example:
1052
1053\(let ((context (epg-make-context 'OpenPGP)))
1054 (epg-encrypt-string
1055 context
1056 (encode-coding-string (buffer-substring start end) 'utf-8)
1057 nil))"
c154c0be
MO
1058 (interactive
1059 (let ((verbose current-prefix-arg)
1060 (context (epg-make-context epa-protocol))
1061 sign)
1062 (setq epa-last-coding-system-specified
1063 (or coding-system-for-write
1064 (epa--select-safe-coding-system
1065 (region-beginning) (region-end))))
1066 (list (region-beginning) (region-end)
1067 (epa-select-keys context
1068 "Select recipients for encryption.
1069If no one is selected, symmetric encryption will be performed. ")
1070 (setq sign (if verbose (y-or-n-p "Sign? ")))
1071 (if sign
1072 (epa-select-keys context
1073 "Select keys for signing. ")))))
1074 (save-excursion
1075 (let ((context (epg-make-context epa-protocol))
1076 cipher)
1077 ;;(epg-context-set-armor context epa-armor)
1078 (epg-context-set-armor context t)
1079 ;;(epg-context-set-textmode context epa-textmode)
1080 (epg-context-set-textmode context t)
1081 (if sign
1082 (epg-context-set-signers context signers))
1083 (epg-context-set-passphrase-callback context
1084 #'epa-passphrase-callback-function)
1085 (epg-context-set-progress-callback context
1086 (cons
1087 #'epa-progress-callback-function
1088 "Encrypting..."))
1089 (message "Encrypting...")
1090 (setq cipher (epg-encrypt-string context
1091 (epa--encode-coding-string
1092 (buffer-substring start end)
1093 epa-last-coding-system-specified)
1094 recipients
1095 sign))
1096 (message "Encrypting...done")
1097 (delete-region start end)
1098 (goto-char start)
1099 (add-text-properties (point)
1100 (progn
1101 (insert cipher)
1102 (point))
1103 (list 'epa-coding-system-used
1104 epa-last-coding-system-specified
1105 'front-sticky nil
1106 'rear-nonsticky t
1107 'start-open t
1108 'end-open t)))))
1109
1110;;;###autoload
1111(defun epa-delete-keys (keys &optional allow-secret)
2c6c404a 1112 "Delete selected KEYS."
c154c0be
MO
1113 (interactive
1114 (let ((keys (epa--marked-keys)))
1115 (unless keys
1116 (error "No keys selected"))
1117 (list keys
1118 (eq (nth 1 epa-list-keys-arguments) t))))
1119 (let ((context (epg-make-context epa-protocol)))
1120 (message "Deleting...")
1121 (epg-delete-keys context keys allow-secret)
1122 (message "Deleting...done")
dc9b613e 1123 (apply #'epa--list-keys epa-list-keys-arguments)))
c154c0be
MO
1124
1125;;;###autoload
1126(defun epa-import-keys (file)
2c6c404a 1127 "Import keys from FILE."
c154c0be
MO
1128 (interactive "fFile: ")
1129 (setq file (expand-file-name file))
1130 (let ((context (epg-make-context epa-protocol)))
1131 (message "Importing %s..." (file-name-nondirectory file))
1132 (condition-case nil
1133 (progn
1134 (epg-import-keys-from-file context file)
1135 (message "Importing %s...done" (file-name-nondirectory file)))
1136 (error
1137 (message "Importing %s...failed" (file-name-nondirectory file))))
1138 (if (epg-context-result-for context 'import)
1139 (epa-display-info (epg-import-result-to-string
1140 (epg-context-result-for context 'import))))
1141 (if (eq major-mode 'epa-key-list-mode)
dc9b613e 1142 (apply #'epa--list-keys epa-list-keys-arguments))))
c154c0be
MO
1143
1144;;;###autoload
1145(defun epa-import-keys-region (start end)
2c6c404a 1146 "Import keys from the region."
c154c0be
MO
1147 (interactive "r")
1148 (let ((context (epg-make-context epa-protocol)))
1149 (message "Importing...")
1150 (condition-case nil
1151 (progn
1152 (epg-import-keys-from-string context (buffer-substring start end))
1153 (message "Importing...done"))
1154 (error
1155 (message "Importing...failed")))
1156 (if (epg-context-result-for context 'import)
1157 (epa-display-info (epg-import-result-to-string
1158 (epg-context-result-for context 'import))))))
1159
1160;;;###autoload
1161(defun epa-import-armor-in-region (start end)
1162 "Import keys in the OpenPGP armor format in the current region
2c6c404a 1163between START and END."
c154c0be
MO
1164 (interactive "r")
1165 (save-excursion
1166 (save-restriction
1167 (narrow-to-region start end)
1168 (goto-char start)
1169 (let (armor-start armor-end)
1170 (while (re-search-forward
1171 "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$"
1172 nil t)
1173 (setq armor-start (match-beginning 0)
1174 armor-end (re-search-forward
1175 (concat "^-----END " (match-string 1) "-----$")
1176 nil t))
1177 (unless armor-end
1178 (error "No armor tail"))
1179 (epa-import-keys-region armor-start armor-end))))))
1180
1181;;;###autoload
1182(defun epa-export-keys (keys file)
2c6c404a 1183 "Export selected KEYS to FILE."
c154c0be
MO
1184 (interactive
1185 (let ((keys (epa--marked-keys))
1186 default-name)
1187 (unless keys
1188 (error "No keys selected"))
1189 (setq default-name
1190 (expand-file-name
1191 (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys))))
1192 (if epa-armor ".asc" ".gpg"))
1193 default-directory))
1194 (list keys
1195 (expand-file-name
1196 (read-file-name
1197 (concat "To file (default "
1198 (file-name-nondirectory default-name)
1199 ") ")
1200 (file-name-directory default-name)
1201 default-name)))))
1202 (let ((context (epg-make-context epa-protocol)))
1203 (epg-context-set-armor context epa-armor)
1204 (message "Exporting to %s..." (file-name-nondirectory file))
1205 (epg-export-keys-to-file context keys file)
1206 (message "Exporting to %s...done" (file-name-nondirectory file))))
1207
1208;;;###autoload
1209(defun epa-insert-keys (keys)
2c6c404a 1210 "Insert selected KEYS after the point."
c154c0be
MO
1211 (interactive
1212 (list (epa-select-keys (epg-make-context epa-protocol)
2d562c0f
DU
1213 "Select keys to export.
1214If no one is selected, default public key is exported. ")))
c154c0be
MO
1215 (let ((context (epg-make-context epa-protocol)))
1216 ;;(epg-context-set-armor context epa-armor)
1217 (epg-context-set-armor context t)
1218 (insert (epg-export-keys-to-string context keys))))
1219
1220;; (defun epa-sign-keys (keys &optional local)
1221;; "Sign selected KEYS.
1222;; If a prefix-arg is specified, the signature is marked as non exportable.
1223
1224;; Don't use this command in Lisp programs!"
1225;; (interactive
1226;; (let ((keys (epa--marked-keys)))
1227;; (unless keys
1228;; (error "No keys selected"))
1229;; (list keys current-prefix-arg)))
1230;; (let ((context (epg-make-context epa-protocol)))
1231;; (epg-context-set-passphrase-callback context
1232;; #'epa-passphrase-callback-function)
1233;; (epg-context-set-progress-callback context
1234;; (cons
1235;; #'epa-progress-callback-function
1236;; "Signing keys..."))
1237;; (message "Signing keys...")
1238;; (epg-sign-keys context keys local)
1239;; (message "Signing keys...done")))
1240;; (make-obsolete 'epa-sign-keys "Do not use.")
1241
1242(provide 'epa)
1243
1244;;; epa.el ends here