(epa-verify-region): Decode the plaintext by
[elisp/epg.git] / epa.el
1 ;;; epa.el --- the EasyPG Assistant
2 ;; Copyright (C) 2006 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Keywords: PGP, GnuPG
6
7 ;; This file is part of EasyPG.
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Code:
25
26 (require 'epg)
27 (require 'font-lock)
28 (require 'widget)
29 (eval-when-compile (require 'wid-edit))
30 (require 'derived)
31
32 (defgroup epa nil
33   "The EasyPG Assistant"
34   :group 'epg)
35
36 (defcustom epa-popup-info-window t
37   "If non-nil, status information from epa commands is displayed on
38 the separate window."
39   :type 'boolean
40   :group 'epa)
41
42 (defcustom epa-info-window-height 5
43   "Number of lines used to display status information."
44   :type 'integer
45   :group 'epa)
46
47 (defgroup epa-faces nil
48   "Faces for epa-mode."
49   :group 'epa)
50
51 (defface epa-validity-high
52   `((((class color) (background dark))
53      (:foreground "PaleTurquoise"
54                   ,@(if (assq ':weight custom-face-attributes)
55                         '(:weight bold)
56                       '(:bold t))))
57     (t
58      (,@(if (assq ':weight custom-face-attributes)
59             '(:weight bold)
60           '(:bold t)))))
61   "Face used for displaying the high validity."
62   :group 'epa-faces)
63
64 (defface epa-validity-medium
65   `((((class color) (background dark))
66      (:foreground "PaleTurquoise"
67                   ,@(if (assq ':slant custom-face-attributes)
68                         '(:slant italic)
69                       '(:italic t))))
70     (t
71      (,@(if (assq ':slant custom-face-attributes)
72             '(:slant italic)
73           '(:italic t)))))
74   "Face used for displaying the medium validity."
75   :group 'epa-faces)
76
77 (defface epa-validity-low
78   `((t
79      (,@(if (assq ':slant custom-face-attributes)
80             '(:slant italic)
81           '(:italic t)))))
82   "Face used for displaying the low validity."
83   :group 'epa-faces)
84
85 (defface epa-validity-disabled
86   `((t
87      (,@(if (assq ':slant custom-face-attributes)
88             '(:slant italic)
89           '(:italic t))
90         :inverse-video t)))
91   "Face used for displaying the disabled validity."
92   :group 'epa-faces)
93
94 (defface epa-string
95   '((((class color) (background dark))
96      (:foreground "lightyellow"))
97     (((class color) (background light))
98      (:foreground "blue4")))
99   "Face used for displaying the string."
100   :group 'epa-faces)
101
102 (defface epa-mark
103   `((((class color) (background dark))
104      (:foreground "orange"
105                   ,@(if (assq ':weight custom-face-attributes)
106                         '(:weight bold)
107                       '(:bold t))))
108     (((class color) (background light))
109      (:foreground "red"
110                   ,@(if (assq ':weight custom-face-attributes)
111                         '(:weight bold)
112                       '(:bold t))))
113     (t
114      (,@(if (assq ':weight custom-face-attributes)
115             '(:weight bold)
116           '(:bold t)))))
117   "Face used for displaying the high validity."
118   :group 'epa-faces)
119
120 (defface epa-field-name
121   `((((class color) (background dark))
122      (:foreground "PaleTurquoise"
123                   ,@(if (assq ':weight custom-face-attributes)
124                         '(:weight bold)
125                       '(:bold t))))
126     (t
127      (,@(if (assq ':weight custom-face-attributes)
128             '(:weight bold)
129           '(:bold t)))))
130   "Face for the name of the attribute field."
131   :group 'epa)
132
133 (defface epa-field-body
134   `((((class color) (background dark))
135      (:foreground "turquoise"
136                   ,@(if (assq ':slant custom-face-attributes)
137                         '(:slant italic)
138                       '(:italic t))))
139     (t
140      (,@(if (assq ':slant custom-face-attributes)
141             '(:slant italic)
142           '(:italic t)))))
143   "Face for the body of the attribute field."
144   :group 'epa)
145
146 (defcustom epa-validity-face-alist
147   '((unknown . epa-validity-disabled)
148     (invalid . epa-validity-disabled)
149     (disabled . epa-validity-disabled)
150     (revoked . epa-validity-disabled)
151     (expired . epa-validity-disabled)
152     (none . epa-validity-low)
153     (undefined . epa-validity-low)
154     (never . epa-validity-low)
155     (marginal . epa-validity-medium)
156     (full . epa-validity-high)
157     (ultimate . epa-validity-high))
158   "An alist mapping validity values to faces."
159   :type 'list
160   :group 'epa)
161
162 (defcustom epa-font-lock-keywords
163   '(("^\\*"
164      (0 'epa-mark))
165     ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$"
166      (1 'epa-field-name)
167      (2 'epa-field-body)))
168   "Default expressions to addon in epa-mode."
169   :type '(repeat (list string))
170   :group 'epa)
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     (if (> (length keys) 1)
502         (epa--select-keys prompt keys)
503       keys)))
504
505 (defun epa--format-fingerprint-1 (fingerprint unit-size block-size)
506   (let ((unit 0))
507     (with-temp-buffer
508       (insert fingerprint)
509       (goto-char (point-min))
510       (while (progn
511                (goto-char (+ (point) unit-size))
512                (not (eobp)))
513         (setq unit (1+ unit))
514         (insert (if (= (% unit block-size) 0) "  " " ")))
515       (buffer-string))))
516
517 (defun epa--format-fingerprint (fingerprint)
518   (if fingerprint
519       (if (= (length fingerprint) 40)
520           ;; 1234 5678 9ABC DEF0 1234  5678 9ABC DEF0 1234 5678
521           (epa--format-fingerprint-1 fingerprint 4 5)
522         ;; 12 34 56 78 9A BC DE F0  12 34 56 78 9A BC DE F0
523         (epa--format-fingerprint-1 fingerprint 2 8))))
524
525 (defun epa--show-key (key)
526   (let* ((primary-sub-key (car (epg-key-sub-key-list key)))
527          (entry (assoc (epg-sub-key-id primary-sub-key)
528                        epa-key-buffer-alist))
529          (inhibit-read-only t)
530          buffer-read-only
531          pointer)
532     (unless entry
533       (setq entry (cons (epg-sub-key-id primary-sub-key) nil)
534             epa-key-buffer-alist (cons entry epa-key-buffer-alist)))
535     (unless (and (cdr entry)
536                  (buffer-live-p (cdr entry)))
537       (setcdr entry (generate-new-buffer
538                      (format "*Key*%s" (epg-sub-key-id primary-sub-key)))))
539     (set-buffer (cdr entry))
540     (epa-key-mode)
541     (make-local-variable 'epa-key)
542     (setq epa-key key)
543     (erase-buffer)
544     (setq pointer (epg-key-user-id-list key))
545     (while pointer
546       (if (car pointer)
547           (insert " "
548                   (if (epg-user-id-validity (car pointer))
549                       (char-to-string
550                        (car (rassq (epg-user-id-validity (car pointer))
551                                    epg-key-validity-alist)))
552                     " ")
553                   " "
554                   (if (stringp (epg-user-id-string (car pointer)))
555                       (epg-user-id-string (car pointer))
556                     (epg-decode-dn (epg-user-id-string (car pointer))))
557                   "\n"))
558       (setq pointer (cdr pointer)))
559     (setq pointer (epg-key-sub-key-list key))
560     (while pointer
561       (insert " "
562               (if (epg-sub-key-validity (car pointer))
563                   (char-to-string
564                    (car (rassq (epg-sub-key-validity (car pointer))
565                                epg-key-validity-alist)))
566                 " ")
567               " "
568               (epg-sub-key-id (car pointer))
569               " "
570               (format "%dbits"
571                       (epg-sub-key-length (car pointer)))
572               " "
573               (cdr (assq (epg-sub-key-algorithm (car pointer))
574                          epg-pubkey-algorithm-alist))
575               "\n\tCreated: "
576               (format-time-string "%Y-%m-%d"
577                                   (epg-sub-key-creation-time (car pointer)))
578               (if (epg-sub-key-expiration-time (car pointer))
579                   (format "\n\tExpires: %s"
580                           (format-time-string "%Y-%m-%d"
581                                               (epg-sub-key-expiration-time
582                                                (car pointer))))
583                 "")
584               "\n\tCapabilities: "
585               (mapconcat #'symbol-name
586                          (epg-sub-key-capability (car pointer))
587                          " ")
588               "\n\tFingerprint: "
589               (epa--format-fingerprint (epg-sub-key-fingerprint (car pointer)))
590               "\n")
591       (setq pointer (cdr pointer)))
592     (goto-char (point-min))
593     (pop-to-buffer (current-buffer))))
594
595 (defun epa-display-info (info)
596   (if epa-popup-info-window
597       (save-selected-window
598         (unless (and epa-info-buffer (buffer-live-p epa-info-buffer))
599           (setq epa-info-buffer (generate-new-buffer "*Info*")))
600         (if (get-buffer-window epa-info-buffer)
601             (delete-window (get-buffer-window epa-info-buffer)))
602         (save-excursion
603           (set-buffer epa-info-buffer)
604           (let ((inhibit-read-only t)
605                 buffer-read-only)
606             (erase-buffer)
607             (insert info))
608           (epa-info-mode)
609           (goto-char (point-min)))
610         (if (> (window-height)
611                epa-info-window-height)
612             (set-window-buffer (split-window nil (- (window-height)
613                                                     epa-info-window-height))
614                                epa-info-buffer)
615           (pop-to-buffer epa-info-buffer)
616           (if (> (window-height) epa-info-window-height)
617               (shrink-window (- (window-height) epa-info-window-height)))))
618     (message "%s" info)))
619
620 (defun epa-display-verify-result (verify-result)
621   (epa-display-info (epg-verify-result-to-string verify-result)))
622 (make-obsolete 'epa-display-verify-result 'epa-display-info)
623
624 (defun epa-passphrase-callback-function (context key-id handback)
625   (if (eq key-id 'SYM)
626       (read-passwd "Passphrase for symmetric encryption: "
627                    (eq (epg-context-operation context) 'encrypt))
628     (read-passwd
629      (if (eq key-id 'PIN)
630         "Passphrase for PIN: "
631        (let ((entry (assoc key-id epg-user-id-alist)))
632          (if entry
633              (format "Passphrase for %s %s: " key-id (cdr entry))
634            (format "Passphrase for %s: " key-id)))))))
635
636 (defun epa-progress-callback-function (context what char current total
637                                                handback)
638   (message "%s%d%% (%d/%d)" (or handback
639                                 (concat what ": "))
640            (if (> total 0) (floor (* (/ current (float total)) 100)) 0)
641            current total))
642
643 ;;;###autoload
644 (defun epa-decrypt-file (file)
645   "Decrypt FILE."
646   (interactive "fFile: ")
647   (setq file (expand-file-name file))
648   (let* ((default-name (file-name-sans-extension file))
649          (plain (expand-file-name
650                  (read-file-name
651                   (concat "To file (default "
652                           (file-name-nondirectory default-name)
653                           ") ")
654                   (file-name-directory default-name)
655                   default-name)))
656          (context (epg-make-context epa-protocol)))
657     (epg-context-set-passphrase-callback context
658                                          #'epa-passphrase-callback-function)
659     (epg-context-set-progress-callback context
660                                        #'epa-progress-callback-function
661                                        (format "Decrypting %s..."
662                                                (file-name-nondirectory file)))
663     (message "Decrypting %s..." (file-name-nondirectory file))
664     (epg-decrypt-file context file plain)
665     (message "Decrypting %s...wrote %s" (file-name-nondirectory file)
666              (file-name-nondirectory plain))
667     (if (epg-context-result-for context 'verify)
668         (epa-display-info (epg-verify-result-to-string
669                            (epg-context-result-for context 'verify))))))
670
671 ;;;###autoload
672 (defun epa-verify-file (file)
673   "Verify FILE."
674   (interactive "fFile: ")
675   (setq file (expand-file-name file))
676   (let* ((context (epg-make-context epa-protocol))
677          (plain (if (equal (file-name-extension file) "sig")
678                     (file-name-sans-extension file))))
679     (epg-context-set-progress-callback context
680                                        #'epa-progress-callback-function
681                                        (format "Verifying %s..."
682                                                (file-name-nondirectory file)))
683     (message "Verifying %s..." (file-name-nondirectory file))
684     (epg-verify-file context file plain)
685     (message "Verifying %s...done" (file-name-nondirectory file))
686     (if (epg-context-result-for context 'verify)
687         (epa-display-info (epg-verify-result-to-string
688                            (epg-context-result-for context 'verify))))))
689
690 (defun epa--read-signature-type ()
691   (let (type c)
692     (while (null type)
693       (message "Signature type (n,c,d,?) ")
694       (setq c (read-char))
695       (cond ((eq c ?c)
696              (setq type 'clear))
697             ((eq c ?d)
698              (setq type 'detached))
699             ((eq c ??)
700              (with-output-to-temp-buffer "*Help*"
701                (save-excursion
702                  (set-buffer standard-output)
703                  (insert "\
704 n - Create a normal signature
705 c - Create a cleartext signature
706 d - Create a detached signature
707 ? - Show this help
708 "))))
709             (t
710              (setq type 'normal))))))
711
712 ;;;###autoload
713 (defun epa-sign-file (file signers mode)
714   "Sign FILE by SIGNERS keys selected."
715   (interactive
716    (let ((verbose current-prefix-arg))
717      (list (expand-file-name (read-file-name "File: "))
718            (if verbose
719                (epa-select-keys (epg-make-context epa-protocol)
720                                 "Select keys for signing.
721 If no one is selected, default secret key is used.  "
722                                 nil t))
723            (if verbose
724                (epa--read-signature-type)
725              'clear))))
726   (let ((signature (concat file
727                            (if (eq epa-protocol 'OpenPGP)
728                                (if (or epa-armor
729                                        (not (memq mode
730                                                   '(nil t normal detached))))
731                                    ".asc"
732                                  (if (memq mode '(t detached))
733                                      ".sig"
734                                    ".gpg"))
735                              (if (memq mode '(t detached))
736                                  ".p7s"
737                                ".p7m"))))
738         (context (epg-make-context epa-protocol)))
739     (epg-context-set-armor context epa-armor)
740     (epg-context-set-textmode context epa-textmode)
741     (epg-context-set-signers context signers)
742     (epg-context-set-passphrase-callback context
743                                          #'epa-passphrase-callback-function)
744     (epg-context-set-progress-callback context
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.
760 If 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                                        #'epa-progress-callback-function
771                                        (format "Encrypting %s..."
772                                                (file-name-nondirectory file)))
773     (message "Encrypting %s..." (file-name-nondirectory file))
774     (epg-encrypt-file context file recipients cipher)
775     (message "Encrypting %s...wrote %s" (file-name-nondirectory file)
776              (file-name-nondirectory cipher))))
777
778 ;;;###autoload
779 (defun epa-decrypt-region (start end)
780   "Decrypt the current region between START and END.
781
782 Don't use this command in Lisp programs!"
783   (interactive "r")
784   (save-excursion
785     (let ((context (epg-make-context epa-protocol))
786           plain)
787       (epg-context-set-passphrase-callback context
788                                            #'epa-passphrase-callback-function)
789       (epg-context-set-progress-callback context
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   (interactive "r")
830   (save-excursion
831     (save-restriction
832       (narrow-to-region start end)
833       (goto-char start)
834       (let (armor-start armor-end)
835         (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
836           (setq armor-start (match-beginning 0)
837                 armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
838                                              nil t))
839           (unless armor-end
840             (error "No armor tail"))
841           (goto-char armor-start)
842           (let ((coding-system-for-read
843                  (or coding-system-for-read
844                      (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
845                          (epa--find-coding-system-for-mime-charset
846                           (intern (downcase (match-string 1))))))))
847             (goto-char armor-end)
848             (epa-decrypt-region armor-start armor-end)))))))
849
850 ;;;###autoload
851 (defun epa-verify-region (start end)
852   "Verify the current region between START and END.
853
854 Don't use this command in Lisp programs!"
855   (interactive "r")
856   (let ((context (epg-make-context epa-protocol))
857         plain)
858     (epg-context-set-progress-callback context
859                                        #'epa-progress-callback-function
860                                        "Verifying...")
861     (message "Verifying...")
862     (setq plain (epg-verify-string
863                  context
864                  (epa--encode-coding-string
865                   (buffer-substring start end)
866                   (or coding-system-for-write
867                       (get-text-property start 'epa-coding-system-used)))))
868     (message "Verifying...done")
869     (setq plain (epa--decode-coding-string
870                  plain
871                  (or coding-system-for-read
872                      (get-text-property start 'epa-coding-system-used))))
873     (if (y-or-n-p "Replace the original text? ")
874         (let ((inhibit-read-only t)
875               buffer-read-only)
876           (delete-region start end)
877           (goto-char start)
878           (insert plain))
879       (with-output-to-temp-buffer "*Temp*"
880         (set-buffer standard-output)
881         (insert plain)
882         (epa-info-mode)))
883     (if (epg-context-result-for context 'verify)
884         (epa-display-info (epg-verify-result-to-string
885                            (epg-context-result-for context 'verify))))))
886
887 ;;;###autoload
888 (defun epa-verify-cleartext-in-region (start end)
889   "Verify OpenPGP cleartext signed messages in the current region
890 between START and END.
891
892 Don't use this command in Lisp programs!"
893   (interactive "r")
894   (save-excursion
895     (save-restriction
896       (narrow-to-region start end)
897       (goto-char start)
898       (let (cleartext-start cleartext-end)
899         (while (re-search-forward "-----BEGIN PGP SIGNED MESSAGE-----$"
900                                   nil t)
901           (setq cleartext-start (match-beginning 0))
902           (unless (re-search-forward "^-----BEGIN PGP SIGNATURE-----$"
903                                            nil t)
904             (error "Invalid cleartext signed message"))
905           (setq cleartext-end (re-search-forward
906                            "^-----END PGP SIGNATURE-----$"
907                            nil t))
908           (unless cleartext-end
909             (error "No cleartext tail"))
910           (epa-verify-region cleartext-start cleartext-end))))))
911
912 (eval-and-compile
913   (if (fboundp 'select-safe-coding-system)
914       (defalias 'epa--select-safe-coding-system 'select-safe-coding-system)
915     (defun epa--select-safe-coding-system (from to)
916       buffer-file-coding-system)))
917
918 ;;;###autoload
919 (defun epa-sign-region (start end signers mode)
920   "Sign the current region between START and END by SIGNERS keys selected.
921
922 Don't use this command in Lisp programs!"
923   (interactive
924    (let ((verbose current-prefix-arg))
925      (setq epa-last-coding-system-specified
926            (or coding-system-for-write
927                (epa--select-safe-coding-system
928                 (region-beginning) (region-end))))
929      (list (region-beginning) (region-end)
930            (if verbose
931                (epa-select-keys (epg-make-context epa-protocol)
932                                 "Select keys for signing.
933 If no one is selected, default secret key is used.  "
934                                 nil t))
935            (if verbose
936                (epa--read-signature-type)
937              'clear))))
938   (save-excursion
939     (let ((context (epg-make-context epa-protocol))
940           signature)
941       ;;(epg-context-set-armor context epa-armor)
942       (epg-context-set-armor context t)
943       ;;(epg-context-set-textmode context epa-textmode)
944       (epg-context-set-textmode context t)
945       (epg-context-set-signers context signers)
946       (epg-context-set-passphrase-callback context
947                                            #'epa-passphrase-callback-function)
948       (epg-context-set-progress-callback context
949                                          #'epa-progress-callback-function
950                                          "Signing...")
951       (message "Signing...")
952       (setq signature (epg-sign-string context
953                                        (epa--encode-coding-string
954                                         (buffer-substring start end)
955                                         epa-last-coding-system-specified)
956                                        mode))
957       (message "Signing...done")
958       (delete-region start end)
959       (goto-char start)
960       (add-text-properties (point)
961                            (progn
962                              (insert (epa--decode-coding-string
963                                       signature
964                                       (or coding-system-for-read
965                                           epa-last-coding-system-specified)))
966                              (point))
967                            (list 'epa-coding-system-used
968                                  epa-last-coding-system-specified
969                                  'front-sticky nil
970                                  'rear-nonsticky t
971                                  'start-open t
972                                  'end-open t)))))
973
974 (eval-and-compile
975   (if (fboundp 'derived-mode-p)
976       (defalias 'epa--derived-mode-p 'derived-mode-p)
977     (defun epa--derived-mode-p (&rest modes)
978       "Non-nil if the current major mode is derived from one of MODES.
979 Uses the `derived-mode-parent' property of the symbol to trace backwards."
980       (let ((parent major-mode))
981         (while (and (not (memq parent modes))
982                     (setq parent (get parent 'derived-mode-parent))))
983         parent))))
984
985 ;;;###autoload
986 (defun epa-encrypt-region (start end recipients sign signers)
987   "Encrypt the current region between START and END for RECIPIENTS.
988
989 Don't use this command in Lisp programs!"
990   (interactive
991    (let ((verbose current-prefix-arg)
992          (context (epg-make-context epa-protocol))
993          sign)
994      (setq epa-last-coding-system-specified
995            (or coding-system-for-write
996                (epa--select-safe-coding-system
997                 (region-beginning) (region-end))))
998      (list (region-beginning) (region-end)
999            (epa-select-keys context
1000                             "Select recipients for encryption.
1001 If no one is selected, symmetric encryption will be performed.  ")
1002            (setq sign (if verbose (y-or-n-p "Sign? ")))
1003            (if sign
1004                (epa-select-keys context
1005                                 "Select keys for signing.  ")))))
1006   (save-excursion
1007     (let ((context (epg-make-context epa-protocol))
1008           cipher)
1009       ;;(epg-context-set-armor context epa-armor)
1010       (epg-context-set-armor context t)
1011       ;;(epg-context-set-textmode context epa-textmode)
1012       (epg-context-set-textmode context t)
1013       (if sign
1014           (epg-context-set-signers context signers))
1015       (epg-context-set-passphrase-callback context
1016                                            #'epa-passphrase-callback-function)
1017       (epg-context-set-progress-callback context
1018                                          #'epa-progress-callback-function
1019                                          "Encrypting...")
1020       (message "Encrypting...")
1021       (setq cipher (epg-encrypt-string context
1022                                        (epa--encode-coding-string
1023                                         (buffer-substring start end)
1024                                         epa-last-coding-system-specified)
1025                                        recipients
1026                                        sign))
1027       (message "Encrypting...done")
1028       (delete-region start end)
1029       (goto-char start)
1030       (add-text-properties (point)
1031                            (progn
1032                              (insert cipher)
1033                              (point))
1034                            (list 'epa-coding-system-used
1035                                  epa-last-coding-system-specified
1036                                  'front-sticky nil
1037                                  'rear-nonsticky t
1038                                  'start-open t
1039                                  'end-open t)))))
1040
1041 ;;;###autoload
1042 (defun epa-delete-keys (keys &optional allow-secret)
1043   "Delete selected KEYS.
1044
1045 Don't use this command in Lisp programs!"
1046   (interactive
1047    (let ((keys (epa--marked-keys)))
1048      (unless keys
1049        (error "No keys selected"))
1050      (list keys
1051            (eq (nth 1 epa-list-keys-arguments) t))))
1052   (let ((context (epg-make-context epa-protocol)))
1053     (message "Deleting...")
1054     (epg-delete-keys context keys allow-secret)
1055     (message "Deleting...done")
1056     (apply #'epa-list-keys epa-list-keys-arguments)))
1057
1058 ;;;###autoload
1059 (defun epa-import-keys (file)
1060   "Import keys from FILE.
1061
1062 Don't use this command in Lisp programs!"
1063   (interactive "fFile: ")
1064   (setq file (expand-file-name file))
1065   (let ((context (epg-make-context epa-protocol)))
1066     (message "Importing %s..." (file-name-nondirectory file))
1067     (condition-case nil
1068         (progn
1069           (epg-import-keys-from-file context file)
1070           (message "Importing %s...done" (file-name-nondirectory file)))
1071       (error
1072        (message "Importing %s...failed" (file-name-nondirectory file))))
1073     (if (epg-context-result-for context 'import)
1074         (epa-display-info (epg-import-result-to-string
1075                            (epg-context-result-for context 'import))))
1076     (if (eq major-mode 'epa-key-list-mode)
1077         (apply #'epa-list-keys epa-list-keys-arguments))))
1078
1079 ;;;###autoload
1080 (defun epa-import-keys-region (start end)
1081   "Import keys from the region.
1082
1083 Don't use this command in Lisp programs!"
1084   (interactive "r")
1085   (let ((context (epg-make-context epa-protocol)))
1086     (message "Importing...")
1087     (condition-case nil
1088         (progn
1089           (epg-import-keys-from-string context (buffer-substring start end))
1090           (message "Importing...done"))
1091       (error
1092        (message "Importing...failed")))
1093     (if (epg-context-result-for context 'import)
1094         (epa-display-info (epg-import-result-to-string
1095                            (epg-context-result-for context 'import))))))
1096
1097 ;;;###autoload
1098 (defun epa-import-armor-in-region (start end)
1099   "Import keys in the OpenPGP armor format in the current region
1100 between START and END.
1101
1102 Don't use this command in Lisp programs!"
1103   (interactive "r")
1104   (save-excursion
1105     (save-restriction
1106       (narrow-to-region start end)
1107       (goto-char start)
1108       (let (armor-start armor-end)
1109         (while (re-search-forward
1110                 "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$"
1111                 nil t)
1112           (setq armor-start (match-beginning 0)
1113                 armor-end (re-search-forward
1114                            (concat "^-----END " (match-string 1) "-----$")
1115                            nil t))
1116           (unless armor-end
1117             (error "No armor tail"))
1118           (epa-import-keys-region armor-start armor-end))))))
1119
1120 ;;;###autoload
1121 (defun epa-export-keys (keys file)
1122   "Export selected KEYS to FILE.
1123
1124 Don't use this command in Lisp programs!"
1125   (interactive
1126    (let ((keys (epa--marked-keys))
1127          default-name)
1128      (unless keys
1129        (error "No keys selected"))
1130      (setq default-name
1131            (expand-file-name
1132             (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys))))
1133                     (if epa-armor ".asc" ".gpg"))
1134             default-directory))
1135      (list keys
1136            (expand-file-name
1137             (read-file-name
1138              (concat "To file (default "
1139                      (file-name-nondirectory default-name)
1140                      ") ")
1141              (file-name-directory default-name)
1142              default-name)))))
1143   (let ((context (epg-make-context epa-protocol)))
1144     (epg-context-set-armor context epa-armor)
1145     (message "Exporting to %s..." (file-name-nondirectory file))
1146     (epg-export-keys-to-file context keys file)
1147     (message "Exporting to %s...done" (file-name-nondirectory file))))
1148
1149 ;;;###autoload
1150 (defun epa-insert-keys (keys)
1151   "Insert selected KEYS after the point.
1152
1153 Don't use this command in Lisp programs!"
1154   (interactive
1155    (list (epa-select-keys (epg-make-context epa-protocol)
1156                           "Select keys to export.  ")))
1157   (let ((context (epg-make-context epa-protocol)))
1158     ;;(epg-context-set-armor context epa-armor)
1159     (epg-context-set-armor context t)
1160     (insert (epg-export-keys-to-string context keys))))
1161
1162 ;;;###autoload
1163 (defun epa-sign-keys (keys &optional local)
1164   "Sign selected KEYS.
1165 If a prefix-arg is specified, the signature is marked as non exportable.
1166
1167 Don't use this command in Lisp programs!"
1168   (interactive
1169    (let ((keys (epa--marked-keys)))
1170      (unless keys
1171        (error "No keys selected"))
1172      (list keys current-prefix-arg)))
1173   (let ((context (epg-make-context epa-protocol)))
1174     (epg-context-set-passphrase-callback context
1175                                          #'epa-passphrase-callback-function)
1176     (epg-context-set-progress-callback context
1177                                        #'epa-progress-callback-function
1178                                        "Signing keys...")
1179     (message "Signing keys...")
1180     (epg-sign-keys context keys local)
1181     (message "Signing keys...done")))
1182 (make-obsolete 'epa-sign-keys "Do not use.")
1183
1184 (provide 'epa)
1185
1186 ;;; epa.el ends here