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