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