* epa-file.el (auto-encryption-mode): Rename from epa-file-mode.
[bpt/emacs.git] / lisp / epa.el
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 :version "23.1"
35 :group 'epg)
36
37 (defcustom epa-popup-info-window t
38 "If non-nil, status information from epa commands is displayed on
39 the separate window."
40 :type 'boolean
41 :group 'epa)
42
43 (defcustom epa-info-window-height 5
44 "Number of lines used to display status information."
45 :type 'integer
46 :group 'epa)
47
48 (defgroup epa-faces nil
49 "Faces for epa-mode."
50 :version "23.1"
51 :group 'epa)
52
53 (defface epa-validity-high
54 `((((class color) (background dark))
55 (:foreground "PaleTurquoise"
56 ,@(if (assq ':weight custom-face-attributes)
57 '(:weight bold)
58 '(:bold t))))
59 (t
60 (,@(if (assq ':weight custom-face-attributes)
61 '(:weight bold)
62 '(:bold t)))))
63 "Face used for displaying the high validity."
64 :group 'epa-faces)
65
66 (defface epa-validity-medium
67 `((((class color) (background dark))
68 (:foreground "PaleTurquoise"
69 ,@(if (assq ':slant custom-face-attributes)
70 '(:slant italic)
71 '(:italic t))))
72 (t
73 (,@(if (assq ':slant custom-face-attributes)
74 '(:slant italic)
75 '(:italic t)))))
76 "Face used for displaying the medium validity."
77 :group 'epa-faces)
78
79 (defface epa-validity-low
80 `((t
81 (,@(if (assq ':slant custom-face-attributes)
82 '(:slant italic)
83 '(:italic t)))))
84 "Face used for displaying the low validity."
85 :group 'epa-faces)
86
87 (defface epa-validity-disabled
88 `((t
89 (,@(if (assq ':slant custom-face-attributes)
90 '(:slant italic)
91 '(:italic t))
92 :inverse-video t)))
93 "Face used for displaying the disabled validity."
94 :group 'epa-faces)
95
96 (defface epa-string
97 '((((class color) (background dark))
98 (:foreground "lightyellow"))
99 (((class color) (background light))
100 (:foreground "blue4")))
101 "Face used for displaying the string."
102 :group 'epa-faces)
103
104 (defface epa-mark
105 `((((class color) (background dark))
106 (:foreground "orange"
107 ,@(if (assq ':weight custom-face-attributes)
108 '(:weight bold)
109 '(:bold t))))
110 (((class color) (background light))
111 (:foreground "red"
112 ,@(if (assq ':weight custom-face-attributes)
113 '(:weight bold)
114 '(:bold t))))
115 (t
116 (,@(if (assq ':weight custom-face-attributes)
117 '(:weight bold)
118 '(:bold t)))))
119 "Face used for displaying the high validity."
120 :group 'epa-faces)
121
122 (defface epa-field-name
123 `((((class color) (background dark))
124 (:foreground "PaleTurquoise"
125 ,@(if (assq ':weight custom-face-attributes)
126 '(:weight bold)
127 '(:bold t))))
128 (t
129 (,@(if (assq ':weight custom-face-attributes)
130 '(:weight bold)
131 '(:bold t)))))
132 "Face for the name of the attribute field."
133 :group 'epa)
134
135 (defface epa-field-body
136 `((((class color) (background dark))
137 (:foreground "turquoise"
138 ,@(if (assq ':slant custom-face-attributes)
139 '(:slant italic)
140 '(:italic t))))
141 (t
142 (,@(if (assq ':slant custom-face-attributes)
143 '(:slant italic)
144 '(:italic t)))))
145 "Face for the body of the attribute field."
146 :group 'epa)
147
148 (defcustom epa-validity-face-alist
149 '((unknown . epa-validity-disabled)
150 (invalid . epa-validity-disabled)
151 (disabled . epa-validity-disabled)
152 (revoked . epa-validity-disabled)
153 (expired . epa-validity-disabled)
154 (none . epa-validity-low)
155 (undefined . epa-validity-low)
156 (never . epa-validity-low)
157 (marginal . epa-validity-medium)
158 (full . epa-validity-high)
159 (ultimate . epa-validity-high))
160 "An alist mapping validity values to faces."
161 :type '(repeat (cons symbol face))
162 :group 'epa)
163
164 (defvar epa-font-lock-keywords
165 '(("^\\*"
166 (0 'epa-mark))
167 ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$"
168 (1 'epa-field-name)
169 (2 'epa-field-body)))
170 "Default expressions to addon in epa-mode.")
171
172 (defconst epa-pubkey-algorithm-letter-alist
173 '((1 . ?R)
174 (2 . ?r)
175 (3 . ?s)
176 (16 . ?g)
177 (17 . ?D)
178 (20 . ?G)))
179
180 (defvar epa-protocol 'OpenPGP
181 "*The default protocol.
182 The value can be either OpenPGP or CMS.
183
184 You should bind this variable with `let', but do not set it globally.")
185
186 (defvar epa-armor nil
187 "*If non-nil, epa commands create ASCII armored output.
188
189 You should bind this variable with `let', but do not set it globally.")
190
191 (defvar epa-textmode nil
192 "*If non-nil, epa commands treat input files as text.
193
194 You should bind this variable with `let', but do not set it globally.")
195
196 (defvar epa-keys-buffer nil)
197 (defvar epa-key-buffer-alist nil)
198 (defvar epa-key nil)
199 (defvar epa-list-keys-arguments nil)
200 (defvar epa-info-buffer nil)
201 (defvar epa-last-coding-system-specified nil)
202
203 (defvar epa-key-list-mode-map
204 (let ((keymap (make-sparse-keymap)))
205 (define-key keymap "m" 'epa-mark-key)
206 (define-key keymap "u" 'epa-unmark-key)
207 (define-key keymap "d" 'epa-decrypt-file)
208 (define-key keymap "v" 'epa-verify-file)
209 (define-key keymap "s" 'epa-sign-file)
210 (define-key keymap "e" 'epa-encrypt-file)
211 (define-key keymap "r" 'epa-delete-keys)
212 (define-key keymap "i" 'epa-import-keys)
213 (define-key keymap "o" 'epa-export-keys)
214 (define-key keymap "g" 'revert-buffer)
215 (define-key keymap "n" 'next-line)
216 (define-key keymap "p" 'previous-line)
217 (define-key keymap " " 'scroll-up)
218 (define-key keymap [delete] 'scroll-down)
219 (define-key keymap "q" 'epa-exit-buffer)
220 keymap))
221
222 (defvar epa-key-mode-map
223 (let ((keymap (make-sparse-keymap)))
224 (define-key keymap "q" 'epa-exit-buffer)
225 keymap))
226
227 (defvar epa-info-mode-map
228 (let ((keymap (make-sparse-keymap)))
229 (define-key keymap "q" 'delete-window)
230 keymap))
231
232 (defvar epa-exit-buffer-function #'bury-buffer)
233
234 (define-widget 'epa-key 'push-button
235 "Button for representing a epg-key object."
236 :format "%[%v%]"
237 :button-face-get 'epa--key-widget-button-face-get
238 :value-create 'epa--key-widget-value-create
239 :action 'epa--key-widget-action
240 :help-echo 'epa--key-widget-help-echo)
241
242 (defun epa--key-widget-action (widget &optional event)
243 (epa--show-key (widget-get widget :value)))
244
245 (defun epa--key-widget-value-create (widget)
246 (let* ((key (widget-get widget :value))
247 (primary-sub-key (car (epg-key-sub-key-list key)))
248 (primary-user-id (car (epg-key-user-id-list key))))
249 (insert (format "%c "
250 (if (epg-sub-key-validity primary-sub-key)
251 (car (rassq (epg-sub-key-validity primary-sub-key)
252 epg-key-validity-alist))
253 ? ))
254 (epg-sub-key-id primary-sub-key)
255 " "
256 (if primary-user-id
257 (if (stringp (epg-user-id-string primary-user-id))
258 (epg-user-id-string primary-user-id)
259 (epg-decode-dn (epg-user-id-string primary-user-id)))
260 ""))))
261
262 (defun epa--key-widget-button-face-get (widget)
263 (let ((validity (epg-sub-key-validity (car (epg-key-sub-key-list
264 (widget-get widget :value))))))
265 (if validity
266 (cdr (assq validity epa-validity-face-alist))
267 'default)))
268
269 (defun epa--key-widget-help-echo (widget)
270 (format "Show %s"
271 (epg-sub-key-id (car (epg-key-sub-key-list
272 (widget-get widget :value))))))
273
274 (eval-and-compile
275 (if (fboundp 'encode-coding-string)
276 (defalias 'epa--encode-coding-string 'encode-coding-string)
277 (defalias 'epa--encode-coding-string 'identity)))
278
279 (eval-and-compile
280 (if (fboundp 'decode-coding-string)
281 (defalias 'epa--decode-coding-string 'decode-coding-string)
282 (defalias 'epa--decode-coding-string 'identity)))
283
284 (defun epa-key-list-mode ()
285 "Major mode for `epa-list-keys'."
286 (kill-all-local-variables)
287 (buffer-disable-undo)
288 (setq major-mode 'epa-key-list-mode
289 mode-name "Keys"
290 truncate-lines t
291 buffer-read-only t)
292 (use-local-map epa-key-list-mode-map)
293 (make-local-variable 'font-lock-defaults)
294 (setq font-lock-defaults '(epa-font-lock-keywords t))
295 ;; In XEmacs, auto-initialization of font-lock is not effective
296 ;; if buffer-file-name is not set.
297 (font-lock-set-defaults)
298 (make-local-variable 'epa-exit-buffer-function)
299 (make-local-variable 'revert-buffer-function)
300 (setq revert-buffer-function 'epa--key-list-revert-buffer)
301 (run-hooks 'epa-key-list-mode-hook))
302
303 (defun epa-key-mode ()
304 "Major mode for a key description."
305 (kill-all-local-variables)
306 (buffer-disable-undo)
307 (setq major-mode 'epa-key-mode
308 mode-name "Key"
309 truncate-lines t
310 buffer-read-only t)
311 (use-local-map epa-key-mode-map)
312 (make-local-variable 'font-lock-defaults)
313 (setq font-lock-defaults '(epa-font-lock-keywords t))
314 ;; In XEmacs, auto-initialization of font-lock is not effective
315 ;; if buffer-file-name is not set.
316 (font-lock-set-defaults)
317 (make-local-variable 'epa-exit-buffer-function)
318 (run-hooks 'epa-key-mode-hook))
319
320 (defun epa-info-mode ()
321 "Major mode for `epa-info-buffer'."
322 (kill-all-local-variables)
323 (buffer-disable-undo)
324 (setq major-mode 'epa-info-mode
325 mode-name "Info"
326 truncate-lines t
327 buffer-read-only t)
328 (use-local-map epa-info-mode-map)
329 (run-hooks 'epa-info-mode-hook))
330
331 (defun epa-mark-key (&optional arg)
332 "Mark a key on the current line.
333 If ARG is non-nil, unmark the key."
334 (interactive "P")
335 (let ((inhibit-read-only t)
336 buffer-read-only
337 properties)
338 (beginning-of-line)
339 (unless (get-text-property (point) 'epa-key)
340 (error "No key on this line"))
341 (setq properties (text-properties-at (point)))
342 (delete-char 1)
343 (insert (if arg " " "*"))
344 (set-text-properties (1- (point)) (point) properties)
345 (forward-line)))
346
347 (defun epa-unmark-key (&optional arg)
348 "Unmark a key on the current line.
349 If ARG is non-nil, mark the key."
350 (interactive "P")
351 (epa-mark-key (not arg)))
352
353 (defun epa-exit-buffer ()
354 "Exit the current buffer.
355 `epa-exit-buffer-function' is called if it is set."
356 (interactive)
357 (funcall epa-exit-buffer-function))
358
359 (defun epa--insert-keys (keys)
360 (save-excursion
361 (save-restriction
362 (narrow-to-region (point) (point))
363 (let (point)
364 (while keys
365 (setq point (point))
366 (insert " ")
367 (add-text-properties point (point)
368 (list 'epa-key (car keys)
369 'front-sticky nil
370 'rear-nonsticky t
371 'start-open t
372 'end-open t))
373 (widget-create 'epa-key :value (car keys))
374 (insert "\n")
375 (setq keys (cdr keys))))
376 (add-text-properties (point-min) (point-max)
377 (list 'epa-list-keys t
378 'front-sticky nil
379 'rear-nonsticky t
380 'start-open t
381 'end-open t)))))
382
383 (defun epa--list-keys (name secret)
384 (unless (and epa-keys-buffer
385 (buffer-live-p epa-keys-buffer))
386 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
387 (set-buffer epa-keys-buffer)
388 (epa-key-list-mode)
389 (let ((inhibit-read-only t)
390 buffer-read-only
391 (point (point-min))
392 (context (epg-make-context epa-protocol)))
393 (unless (get-text-property point 'epa-list-keys)
394 (setq point (next-single-property-change point 'epa-list-keys)))
395 (when point
396 (delete-region point
397 (or (next-single-property-change point 'epa-list-keys)
398 (point-max)))
399 (goto-char point))
400 (epa--insert-keys (epg-list-keys context name secret))
401 (widget-setup)
402 (set-keymap-parent (current-local-map) widget-keymap))
403 (make-local-variable 'epa-list-keys-arguments)
404 (setq epa-list-keys-arguments (list name secret))
405 (goto-char (point-min))
406 (pop-to-buffer (current-buffer)))
407
408 ;;;###autoload
409 (defun epa-list-keys (&optional name)
410 "List all keys matched with NAME from the public keyring."
411 (interactive
412 (if current-prefix-arg
413 (let ((name (read-string "Pattern: "
414 (if epa-list-keys-arguments
415 (car epa-list-keys-arguments)))))
416 (list (if (equal name "") nil name)))
417 (list nil)))
418 (epa--list-keys name nil))
419
420 ;;;###autoload
421 (defun epa-list-secret-keys (&optional name)
422 "List all keys matched with NAME from the private keyring."
423 (interactive
424 (if current-prefix-arg
425 (let ((name (read-string "Pattern: "
426 (if epa-list-keys-arguments
427 (car epa-list-keys-arguments)))))
428 (list (if (equal name "") nil name)))
429 (list nil)))
430 (epa--list-keys name t))
431
432 (defun epa--key-list-revert-buffer (&optional ignore-auto noconfirm)
433 (apply #'epa--list-keys epa-list-keys-arguments))
434
435 (defun epa--marked-keys ()
436 (or (save-excursion
437 (set-buffer epa-keys-buffer)
438 (goto-char (point-min))
439 (let (keys key)
440 (while (re-search-forward "^\\*" nil t)
441 (if (setq key (get-text-property (match-beginning 0)
442 'epa-key))
443 (setq keys (cons key keys))))
444 (nreverse keys)))
445 (save-excursion
446 (beginning-of-line)
447 (let ((key (get-text-property (point) 'epa-key)))
448 (if key
449 (list key))))))
450
451 (defun epa--select-keys (prompt keys)
452 (save-excursion
453 (unless (and epa-keys-buffer
454 (buffer-live-p epa-keys-buffer))
455 (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
456 (set-buffer epa-keys-buffer)
457 (epa-key-list-mode)
458 (let ((inhibit-read-only t)
459 buffer-read-only)
460 (erase-buffer)
461 (insert prompt "\n"
462 (substitute-command-keys "\
463 - `\\[epa-mark-key]' to mark a key on the line
464 - `\\[epa-unmark-key]' to unmark a key on the line\n"))
465 (widget-create 'link
466 :notify (lambda (&rest ignore) (abort-recursive-edit))
467 :help-echo
468 (substitute-command-keys
469 "Click here or \\[abort-recursive-edit] to cancel")
470 "Cancel")
471 (widget-create 'link
472 :notify (lambda (&rest ignore) (exit-recursive-edit))
473 :help-echo
474 (substitute-command-keys
475 "Click here or \\[exit-recursive-edit] to finish")
476 "OK")
477 (insert "\n\n")
478 (epa--insert-keys keys)
479 (widget-setup)
480 (set-keymap-parent (current-local-map) widget-keymap)
481 (setq epa-exit-buffer-function #'abort-recursive-edit)
482 (goto-char (point-min))
483 (pop-to-buffer (current-buffer)))
484 (unwind-protect
485 (progn
486 (recursive-edit)
487 (epa--marked-keys))
488 (if (get-buffer-window epa-keys-buffer)
489 (delete-window (get-buffer-window epa-keys-buffer)))
490 (kill-buffer epa-keys-buffer))))
491
492 ;;;###autoload
493 (defun epa-select-keys (context prompt &optional names secret)
494 "Display a user's keyring and ask him to select keys.
495 CONTEXT is an epg-context.
496 PROMPT is a string to prompt with.
497 NAMES is a list of strings to be matched with keys. If it is nil, all
498 the keys are listed.
499 If SECRET is non-nil, list secret keys instead of public keys."
500 (let ((keys (epg-list-keys context names secret)))
501 (epa--select-keys prompt 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 Since this function operates on regions, it does some tricks such
770 as coding-system detection and unibyte/multibyte conversion. If
771 you are sure how the data in the region should be treated, you
772 should consider using the string based counterpart
773 `epg-decrypt-string', or the file based counterpart
774 `epg-decrypt-file' instead.
775
776 For example:
777
778 \(let ((context (epg-make-context 'OpenPGP)))
779 (decode-coding-string
780 (epg-decrypt-string context (buffer-substring start end))
781 'utf-8))"
782 (interactive "r")
783 (save-excursion
784 (let ((context (epg-make-context epa-protocol))
785 plain)
786 (epg-context-set-passphrase-callback context
787 #'epa-passphrase-callback-function)
788 (epg-context-set-progress-callback context
789 (cons
790 #'epa-progress-callback-function
791 "Decrypting..."))
792 (message "Decrypting...")
793 (setq plain (epg-decrypt-string context (buffer-substring start end)))
794 (message "Decrypting...done")
795 (setq plain (epa--decode-coding-string
796 plain
797 (or coding-system-for-read
798 (get-text-property start 'epa-coding-system-used))))
799 (if (y-or-n-p "Replace the original text? ")
800 (let ((inhibit-read-only t)
801 buffer-read-only)
802 (delete-region start end)
803 (goto-char start)
804 (insert plain))
805 (with-output-to-temp-buffer "*Temp*"
806 (set-buffer standard-output)
807 (insert plain)
808 (epa-info-mode)))
809 (if (epg-context-result-for context 'verify)
810 (epa-display-info (epg-verify-result-to-string
811 (epg-context-result-for context 'verify)))))))
812
813 (defun epa--find-coding-system-for-mime-charset (mime-charset)
814 (if (featurep 'xemacs)
815 (if (fboundp 'find-coding-system)
816 (find-coding-system mime-charset))
817 (let ((pointer (coding-system-list)))
818 (while (and pointer
819 (eq (coding-system-get (car pointer) 'mime-charset)
820 mime-charset))
821 (setq pointer (cdr pointer)))
822 pointer)))
823
824 ;;;###autoload
825 (defun epa-decrypt-armor-in-region (start end)
826 "Decrypt OpenPGP armors in the current region between START and END.
827
828 Don't use this command in Lisp programs!
829 See the reason described in the `epa-decrypt-region' documentation."
830 (interactive "r")
831 (save-excursion
832 (save-restriction
833 (narrow-to-region start end)
834 (goto-char start)
835 (let (armor-start armor-end)
836 (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
837 (setq armor-start (match-beginning 0)
838 armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
839 nil t))
840 (unless armor-end
841 (error "No armor tail"))
842 (goto-char armor-start)
843 (let ((coding-system-for-read
844 (or coding-system-for-read
845 (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
846 (epa--find-coding-system-for-mime-charset
847 (intern (downcase (match-string 1))))))))
848 (goto-char armor-end)
849 (epa-decrypt-region armor-start armor-end)))))))
850
851 ;;;###autoload
852 (defun epa-verify-region (start end)
853 "Verify the current region between START and END.
854
855 Don't use this command in Lisp programs!
856 Since this function operates on regions, it does some tricks such
857 as coding-system detection and unibyte/multibyte conversion. If
858 you are sure how the data in the region should be treated, you
859 should consider using the string based counterpart
860 `epg-verify-string', or the file based counterpart
861 `epg-verify-file' instead.
862
863 For example:
864
865 \(let ((context (epg-make-context 'OpenPGP)))
866 (decode-coding-string
867 (epg-verify-string context (buffer-substring start end))
868 'utf-8))"
869 (interactive "r")
870 (let ((context (epg-make-context epa-protocol))
871 plain)
872 (epg-context-set-progress-callback context
873 (cons
874 #'epa-progress-callback-function
875 "Verifying..."))
876 (message "Verifying...")
877 (setq plain (epg-verify-string
878 context
879 (epa--encode-coding-string
880 (buffer-substring start end)
881 (or coding-system-for-write
882 (get-text-property start 'epa-coding-system-used)))))
883 (message "Verifying...done")
884 (setq plain (epa--decode-coding-string
885 plain
886 (or coding-system-for-read
887 (get-text-property start 'epa-coding-system-used))))
888 (if (y-or-n-p "Replace the original text? ")
889 (let ((inhibit-read-only t)
890 buffer-read-only)
891 (delete-region start end)
892 (goto-char start)
893 (insert plain))
894 (with-output-to-temp-buffer "*Temp*"
895 (set-buffer standard-output)
896 (insert plain)
897 (epa-info-mode)))
898 (if (epg-context-result-for context 'verify)
899 (epa-display-info (epg-verify-result-to-string
900 (epg-context-result-for context 'verify))))))
901
902 ;;;###autoload
903 (defun epa-verify-cleartext-in-region (start end)
904 "Verify OpenPGP cleartext signed messages in the current region
905 between START and END.
906
907 Don't use this command in Lisp programs!
908 See the reason described in the `epa-verify-region' documentation."
909 (interactive "r")
910 (save-excursion
911 (save-restriction
912 (narrow-to-region start end)
913 (goto-char start)
914 (let (cleartext-start cleartext-end)
915 (while (re-search-forward "-----BEGIN PGP SIGNED MESSAGE-----$"
916 nil t)
917 (setq cleartext-start (match-beginning 0))
918 (unless (re-search-forward "^-----BEGIN PGP SIGNATURE-----$"
919 nil t)
920 (error "Invalid cleartext signed message"))
921 (setq cleartext-end (re-search-forward
922 "^-----END PGP SIGNATURE-----$"
923 nil t))
924 (unless cleartext-end
925 (error "No cleartext tail"))
926 (epa-verify-region cleartext-start cleartext-end))))))
927
928 (eval-and-compile
929 (if (fboundp 'select-safe-coding-system)
930 (defalias 'epa--select-safe-coding-system 'select-safe-coding-system)
931 (defun epa--select-safe-coding-system (from to)
932 buffer-file-coding-system)))
933
934 ;;;###autoload
935 (defun epa-sign-region (start end signers mode)
936 "Sign the current region between START and END by SIGNERS keys selected.
937
938 Don't use this command in Lisp programs!
939 Since this function operates on regions, it does some tricks such
940 as coding-system detection and unibyte/multibyte conversion. If
941 you are sure how the data should be treated, you should consider
942 using the string based counterpart `epg-sign-string', or the file
943 based counterpart `epg-sign-file' instead.
944
945 For example:
946
947 \(let ((context (epg-make-context 'OpenPGP)))
948 (epg-sign-string
949 context
950 (encode-coding-string (buffer-substring start end) 'utf-8)))"
951 (interactive
952 (let ((verbose current-prefix-arg))
953 (setq epa-last-coding-system-specified
954 (or coding-system-for-write
955 (epa--select-safe-coding-system
956 (region-beginning) (region-end))))
957 (list (region-beginning) (region-end)
958 (if verbose
959 (epa-select-keys (epg-make-context epa-protocol)
960 "Select keys for signing.
961 If no one is selected, default secret key is used. "
962 nil t))
963 (if verbose
964 (epa--read-signature-type)
965 'clear))))
966 (save-excursion
967 (let ((context (epg-make-context epa-protocol))
968 signature)
969 ;;(epg-context-set-armor context epa-armor)
970 (epg-context-set-armor context t)
971 ;;(epg-context-set-textmode context epa-textmode)
972 (epg-context-set-textmode context t)
973 (epg-context-set-signers context signers)
974 (epg-context-set-passphrase-callback context
975 #'epa-passphrase-callback-function)
976 (epg-context-set-progress-callback context
977 (cons
978 #'epa-progress-callback-function
979 "Signing..."))
980 (message "Signing...")
981 (setq signature (epg-sign-string context
982 (epa--encode-coding-string
983 (buffer-substring start end)
984 epa-last-coding-system-specified)
985 mode))
986 (message "Signing...done")
987 (delete-region start end)
988 (goto-char start)
989 (add-text-properties (point)
990 (progn
991 (insert (epa--decode-coding-string
992 signature
993 (or coding-system-for-read
994 epa-last-coding-system-specified)))
995 (point))
996 (list 'epa-coding-system-used
997 epa-last-coding-system-specified
998 'front-sticky nil
999 'rear-nonsticky t
1000 'start-open t
1001 'end-open t)))))
1002
1003 (eval-and-compile
1004 (if (fboundp 'derived-mode-p)
1005 (defalias 'epa--derived-mode-p 'derived-mode-p)
1006 (defun epa--derived-mode-p (&rest modes)
1007 "Non-nil if the current major mode is derived from one of MODES.
1008 Uses the `derived-mode-parent' property of the symbol to trace backwards."
1009 (let ((parent major-mode))
1010 (while (and (not (memq parent modes))
1011 (setq parent (get parent 'derived-mode-parent))))
1012 parent))))
1013
1014 ;;;###autoload
1015 (defun epa-encrypt-region (start end recipients sign signers)
1016 "Encrypt the current region between START and END for RECIPIENTS.
1017
1018 Don't use this command in Lisp programs!
1019 Since this function operates on regions, it does some tricks such
1020 as coding-system detection and unibyte/multibyte conversion. If
1021 you are sure how the data should be treated, you should consider
1022 using the string based counterpart `epg-encrypt-string', or the
1023 file based counterpart `epg-encrypt-file' instead.
1024
1025 For example:
1026
1027 \(let ((context (epg-make-context 'OpenPGP)))
1028 (epg-encrypt-string
1029 context
1030 (encode-coding-string (buffer-substring start end) 'utf-8)
1031 nil))"
1032 (interactive
1033 (let ((verbose current-prefix-arg)
1034 (context (epg-make-context epa-protocol))
1035 sign)
1036 (setq epa-last-coding-system-specified
1037 (or coding-system-for-write
1038 (epa--select-safe-coding-system
1039 (region-beginning) (region-end))))
1040 (list (region-beginning) (region-end)
1041 (epa-select-keys context
1042 "Select recipients for encryption.
1043 If no one is selected, symmetric encryption will be performed. ")
1044 (setq sign (if verbose (y-or-n-p "Sign? ")))
1045 (if sign
1046 (epa-select-keys context
1047 "Select keys for signing. ")))))
1048 (save-excursion
1049 (let ((context (epg-make-context epa-protocol))
1050 cipher)
1051 ;;(epg-context-set-armor context epa-armor)
1052 (epg-context-set-armor context t)
1053 ;;(epg-context-set-textmode context epa-textmode)
1054 (epg-context-set-textmode context t)
1055 (if sign
1056 (epg-context-set-signers context signers))
1057 (epg-context-set-passphrase-callback context
1058 #'epa-passphrase-callback-function)
1059 (epg-context-set-progress-callback context
1060 (cons
1061 #'epa-progress-callback-function
1062 "Encrypting..."))
1063 (message "Encrypting...")
1064 (setq cipher (epg-encrypt-string context
1065 (epa--encode-coding-string
1066 (buffer-substring start end)
1067 epa-last-coding-system-specified)
1068 recipients
1069 sign))
1070 (message "Encrypting...done")
1071 (delete-region start end)
1072 (goto-char start)
1073 (add-text-properties (point)
1074 (progn
1075 (insert cipher)
1076 (point))
1077 (list 'epa-coding-system-used
1078 epa-last-coding-system-specified
1079 'front-sticky nil
1080 'rear-nonsticky t
1081 'start-open t
1082 'end-open t)))))
1083
1084 ;;;###autoload
1085 (defun epa-delete-keys (keys &optional allow-secret)
1086 "Delete selected KEYS."
1087 (interactive
1088 (let ((keys (epa--marked-keys)))
1089 (unless keys
1090 (error "No keys selected"))
1091 (list keys
1092 (eq (nth 1 epa-list-keys-arguments) t))))
1093 (let ((context (epg-make-context epa-protocol)))
1094 (message "Deleting...")
1095 (epg-delete-keys context keys allow-secret)
1096 (message "Deleting...done")
1097 (apply #'epa-list-keys epa-list-keys-arguments)))
1098
1099 ;;;###autoload
1100 (defun epa-import-keys (file)
1101 "Import keys from FILE."
1102 (interactive "fFile: ")
1103 (setq file (expand-file-name file))
1104 (let ((context (epg-make-context epa-protocol)))
1105 (message "Importing %s..." (file-name-nondirectory file))
1106 (condition-case nil
1107 (progn
1108 (epg-import-keys-from-file context file)
1109 (message "Importing %s...done" (file-name-nondirectory file)))
1110 (error
1111 (message "Importing %s...failed" (file-name-nondirectory file))))
1112 (if (epg-context-result-for context 'import)
1113 (epa-display-info (epg-import-result-to-string
1114 (epg-context-result-for context 'import))))
1115 (if (eq major-mode 'epa-key-list-mode)
1116 (apply #'epa-list-keys epa-list-keys-arguments))))
1117
1118 ;;;###autoload
1119 (defun epa-import-keys-region (start end)
1120 "Import keys from the region."
1121 (interactive "r")
1122 (let ((context (epg-make-context epa-protocol)))
1123 (message "Importing...")
1124 (condition-case nil
1125 (progn
1126 (epg-import-keys-from-string context (buffer-substring start end))
1127 (message "Importing...done"))
1128 (error
1129 (message "Importing...failed")))
1130 (if (epg-context-result-for context 'import)
1131 (epa-display-info (epg-import-result-to-string
1132 (epg-context-result-for context 'import))))))
1133
1134 ;;;###autoload
1135 (defun epa-import-armor-in-region (start end)
1136 "Import keys in the OpenPGP armor format in the current region
1137 between START and END."
1138 (interactive "r")
1139 (save-excursion
1140 (save-restriction
1141 (narrow-to-region start end)
1142 (goto-char start)
1143 (let (armor-start armor-end)
1144 (while (re-search-forward
1145 "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$"
1146 nil t)
1147 (setq armor-start (match-beginning 0)
1148 armor-end (re-search-forward
1149 (concat "^-----END " (match-string 1) "-----$")
1150 nil t))
1151 (unless armor-end
1152 (error "No armor tail"))
1153 (epa-import-keys-region armor-start armor-end))))))
1154
1155 ;;;###autoload
1156 (defun epa-export-keys (keys file)
1157 "Export selected KEYS to FILE."
1158 (interactive
1159 (let ((keys (epa--marked-keys))
1160 default-name)
1161 (unless keys
1162 (error "No keys selected"))
1163 (setq default-name
1164 (expand-file-name
1165 (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys))))
1166 (if epa-armor ".asc" ".gpg"))
1167 default-directory))
1168 (list keys
1169 (expand-file-name
1170 (read-file-name
1171 (concat "To file (default "
1172 (file-name-nondirectory default-name)
1173 ") ")
1174 (file-name-directory default-name)
1175 default-name)))))
1176 (let ((context (epg-make-context epa-protocol)))
1177 (epg-context-set-armor context epa-armor)
1178 (message "Exporting to %s..." (file-name-nondirectory file))
1179 (epg-export-keys-to-file context keys file)
1180 (message "Exporting to %s...done" (file-name-nondirectory file))))
1181
1182 ;;;###autoload
1183 (defun epa-insert-keys (keys)
1184 "Insert selected KEYS after the point."
1185 (interactive
1186 (list (epa-select-keys (epg-make-context epa-protocol)
1187 "Select keys to export. ")))
1188 (let ((context (epg-make-context epa-protocol)))
1189 ;;(epg-context-set-armor context epa-armor)
1190 (epg-context-set-armor context t)
1191 (insert (epg-export-keys-to-string context keys))))
1192
1193 ;; (defun epa-sign-keys (keys &optional local)
1194 ;; "Sign selected KEYS.
1195 ;; If a prefix-arg is specified, the signature is marked as non exportable.
1196
1197 ;; Don't use this command in Lisp programs!"
1198 ;; (interactive
1199 ;; (let ((keys (epa--marked-keys)))
1200 ;; (unless keys
1201 ;; (error "No keys selected"))
1202 ;; (list keys current-prefix-arg)))
1203 ;; (let ((context (epg-make-context epa-protocol)))
1204 ;; (epg-context-set-passphrase-callback context
1205 ;; #'epa-passphrase-callback-function)
1206 ;; (epg-context-set-progress-callback context
1207 ;; (cons
1208 ;; #'epa-progress-callback-function
1209 ;; "Signing keys..."))
1210 ;; (message "Signing keys...")
1211 ;; (epg-sign-keys context keys local)
1212 ;; (message "Signing keys...done")))
1213 ;; (make-obsolete 'epa-sign-keys "Do not use.")
1214
1215 (provide 'epa)
1216
1217 ;; arch-tag: 38d20ced-20d5-4137-b17a-f206335423d7
1218 ;;; epa.el ends here