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