Added missing (interactive).
[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   (interactive)
853   (epa-verify-cleartext-in-region (point-min) (point-max)))
854
855 ;;;###autoload
856 (defun epa-sign-region (start end signers mode)
857   "Sign the current region between START and END by SIGNERS keys selected.
858
859 Don't use this command in Lisp programs!"
860   (interactive
861    (progn
862      (setq epa-last-coding-system-specified
863            (or coding-system-for-write
864                (epa--select-safe-coding-system
865                 (region-beginning) (region-end))))
866      (list (region-beginning) (region-end)
867            (if current-prefix-arg
868                (epa-select-keys (epg-make-context epa-protocol)
869                                 "Select keys for signing.
870 If no one is selected, default secret key is used.  "
871                                 nil t))
872            (if current-prefix-arg
873                (epa--read-signature-type)
874              'clear))))
875   (save-excursion
876     (let ((context (epg-make-context epa-protocol))
877           signature)
878       ;;(epg-context-set-armor context epa-armor)
879       (epg-context-set-armor context t)
880       ;;(epg-context-set-textmode context epa-textmode)
881       (epg-context-set-textmode context t)
882       (epg-context-set-signers context signers)
883       (epg-context-set-passphrase-callback context
884                                            #'epa-passphrase-callback-function)
885       (epg-context-set-progress-callback context
886                                          #'epa-progress-callback-function)
887       (message "Signing...")
888       (setq signature (epg-sign-string context
889                                        (epa--encode-coding-string
890                                         (buffer-substring start end)
891                                         epa-last-coding-system-specified)
892                                        mode))
893       (message "Signing...done")
894       (delete-region start end)
895       (add-text-properties (point)
896                            (progn
897                              (insert (epa--decode-coding-string
898                                       signature
899                                       (or coding-system-for-read
900                                           epa-last-coding-system-specified)))
901                              (point))
902                            (list 'epa-coding-system-used
903                                  epa-last-coding-system-specified
904                                  'front-sticky nil
905                                  'rear-nonsticky t
906                                  'start-open t
907                                  'end-open t)))))
908
909 ;;;###autoload
910 (defun epa-sign (start end signers mode)
911   "Sign the current buffer.
912
913 Don't use this command in Lisp programs!"
914   (interactive
915    (save-excursion
916      (goto-char (point-min))
917      (if (and (or (eq major-mode 'mail-mode)
918                   (eq (derived-mode-class major-mode) 'mail-mode))
919               (search-forward mail-header-separator nil t))
920          (forward-line))
921      (setq epa-last-coding-system-specified
922            (or coding-system-for-write
923                (epa--select-safe-coding-system (point) (point-max))))
924      (list (point) (point-max)
925            (if current-prefix-arg
926                (epa-select-keys (epg-make-context epa-protocol)
927                                 "Select keys for signing.
928 If no one is selected, default secret key is used.  "
929                                 nil t))
930            (if current-prefix-arg
931                (epa--read-signature-type)
932              'clear))))
933   (epa-sign-region start end signers mode))
934
935 ;;;###autoload
936 (defun epa-encrypt-region (start end recipients)
937   "Encrypt the current region between START and END for RECIPIENTS.
938
939 Don't use this command in Lisp programs!"
940   (interactive
941    (progn
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 (epg-make-context epa-protocol)
948                             "Select recipients for encryption.
949 If no one is selected, symmetric encryption will be performed.  "))))
950   (save-excursion
951     (let ((context (epg-make-context epa-protocol))
952           cipher)
953       ;;(epg-context-set-armor context epa-armor)
954       (epg-context-set-armor context t)
955       ;;(epg-context-set-textmode context epa-textmode)
956       (epg-context-set-textmode context t)
957       (epg-context-set-passphrase-callback context
958                                            #'epa-passphrase-callback-function)
959       (epg-context-set-progress-callback context
960                                          #'epa-progress-callback-function)
961       (message "Encrypting...")
962       (setq cipher (epg-encrypt-string context
963                                        (epa--encode-coding-string
964                                         (buffer-substring start end)
965                                         epa-last-coding-system-specified)
966                                        recipients))
967       (message "Encrypting...done")
968       (delete-region start end)
969       (add-text-properties (point)
970                            (progn
971                              (insert cipher)
972                              (point))
973                            (list 'epa-coding-system-used
974                                  epa-last-coding-system-specified
975                                  'front-sticky nil
976                                  'rear-nonsticky t
977                                  'start-open t
978                                  'end-open t)))))
979
980 ;;;###autoload
981 (defun epa-encrypt (start end recipients)
982   "Encrypt the current buffer.
983
984 Don't use this command in Lisp programs!"
985   (interactive
986    (save-excursion
987      (let (recipients)
988        (goto-char (point-min))
989        (when (or (eq major-mode 'mail-mode)
990                  (eq (derived-mode-class major-mode) 'mail-mode))
991          (save-restriction
992            (narrow-to-region (point)
993                              (progn
994                                (search-forward mail-header-separator nil 0)
995                                (match-beginning 0)))
996            (setq recipients
997                  (mail-strip-quoted-names
998                   (mapconcat #'identity
999                              (nconc (mail-fetch-field "to" nil nil t)
1000                                     (mail-fetch-field "cc" nil nil t)
1001                                     (mail-fetch-field "bcc" nil nil t))
1002                              ","))))
1003          (if recipients
1004              (setq recipients (delete "" (split-string recipients "[ \t\n]+"))))
1005          (goto-char (point-min))
1006          (if (search-forward mail-header-separator nil t)
1007              (forward-line)))
1008        (setq epa-last-coding-system-specified
1009              (or coding-system-for-write
1010                  (epa--select-safe-coding-system (point) (point-max))))
1011        (list (point) (point-max)
1012              (if current-prefix-arg
1013                  (epa-select-keys
1014                   (epg-make-context epa-protocol)
1015                   "Select recipients for encryption.
1016 If no one is selected, symmetric encryption will be performed.  "
1017                   recipients)
1018                (if recipients
1019                    (delq nil
1020                          (apply #'nconc
1021                                 (mapcar
1022                                  (lambda (recipient)
1023                                    (epg-list-keys
1024                                     (epg-make-context epa-protocol)
1025                                     (concat "<" recipient ">")))
1026                                  recipients)))))))))
1027   (epa-encrypt-region start end recipients))
1028
1029 ;;;###autoload
1030 (defun epa-delete-keys (keys &optional allow-secret)
1031   "Delete selected KEYS.
1032
1033 Don't use this command in Lisp programs!"
1034   (interactive
1035    (let ((keys (epa--marked-keys)))
1036      (unless keys
1037        (error "No keys selected"))
1038      (list keys
1039            (eq (nth 1 epa-list-keys-arguments) t))))
1040   (let ((context (epg-make-context epa-protocol)))
1041     (message "Deleting...")
1042     (epg-delete-keys context keys allow-secret)
1043     (message "Deleting...done")
1044     (apply #'epa-list-keys epa-list-keys-arguments)))
1045
1046 ;;;###autoload
1047 (defun epa-import-keys (file)
1048   "Import keys from FILE.
1049
1050 Don't use this command in Lisp programs!"
1051   (interactive "fFile: ")
1052   (setq file (expand-file-name file))
1053   (let ((context (epg-make-context epa-protocol)))
1054     (message "Importing %s..." (file-name-nondirectory file))
1055     (condition-case nil
1056         (progn
1057           (epg-import-keys-from-file context file)
1058           (message "Importing %s...done" (file-name-nondirectory file)))
1059       (error
1060        (message "Importing %s...failed" (file-name-nondirectory file))))
1061     (if (epg-context-result-for context 'import)
1062         (epa-display-info (epg-import-result-to-string
1063                            (epg-context-result-for context 'import))))
1064     (if (eq major-mode 'epa-keys-mode)
1065         (apply #'epa-list-keys epa-list-keys-arguments))))
1066
1067 ;;;###autoload
1068 (defun epa-import-keys-region (start end)
1069   "Import keys from the region.
1070
1071 Don't use this command in Lisp programs!"
1072   (interactive "r")
1073   (let ((context (epg-make-context epa-protocol)))
1074     (message "Importing...")
1075     (condition-case nil
1076         (progn
1077           (epg-import-keys-from-string context (buffer-substring start end))
1078           (message "Importing...done"))
1079       (error
1080        (message "Importing...failed")))
1081     (if (epg-context-result-for context 'import)
1082         (epa-display-info (epg-import-result-to-string
1083                            (epg-context-result-for context 'import))))))
1084
1085 ;;;###autoload
1086 (defun epa-import-armor-in-region (start end)
1087   "Import keys in the OpenPGP armor format in the current region
1088 between START and END.
1089
1090 Don't use this command in Lisp programs!"
1091   (interactive "r")
1092   (save-excursion
1093     (save-restriction
1094       (narrow-to-region start end)
1095       (goto-char start)
1096       (let (armor-start armor-end)
1097         (while (re-search-forward
1098                 "-----BEGIN \\(PGP \\(PUBLIC\\|PRIVATE\\) KEY BLOCK\\)-----$"
1099                 nil t)
1100           (setq armor-start (match-beginning 0)
1101                 armor-end (re-search-forward
1102                            (concat "^-----END " (match-string 1) "-----$")
1103                            nil t))
1104           (unless armor-end
1105             (error "No armor tail"))
1106           (epa-import-keys-region armor-start armor-end))))))
1107
1108 ;;;###autoload
1109 (defun epa-import ()
1110   "Import keys in the OpenPGP armor format in the current buffer.
1111
1112 Don't use this command in Lisp programs!"
1113   (interactive)
1114   (epa-import-armor-in-region (point-min) (point-max)))
1115
1116 ;;;###autoload
1117 (defun epa-export-keys (keys file)
1118   "Export selected KEYS to FILE.
1119
1120 Don't use this command in Lisp programs!"
1121   (interactive
1122    (let ((keys (epa--marked-keys))
1123          default-name)
1124      (unless keys
1125        (error "No keys selected"))
1126      (setq default-name
1127            (expand-file-name
1128             (concat (epg-sub-key-id (car (epg-key-sub-key-list (car keys))))
1129                     (if epa-armor ".asc" ".gpg"))
1130             default-directory))
1131      (list keys
1132            (expand-file-name
1133             (read-file-name
1134              (concat "To file (default "
1135                      (file-name-nondirectory default-name)
1136                      ") ")
1137              (file-name-directory default-name)
1138              default-name)))))
1139   (let ((context (epg-make-context epa-protocol)))
1140     (epg-context-set-armor context epa-armor)
1141     (message "Exporting to %s..." (file-name-nondirectory file))
1142     (epg-export-keys-to-file context keys file)
1143     (message "Exporting to %s...done" (file-name-nondirectory file))))
1144
1145 ;;;###autoload
1146 (defun epa-insert-keys (keys)
1147   "Insert selected KEYS after the point.
1148
1149 Don't use this command in Lisp programs!"
1150   (interactive
1151    (list (epa-select-keys (epg-make-context epa-protocol)
1152                           "Select keys to export.  ")))
1153   (let ((context (epg-make-context epa-protocol)))
1154     ;;(epg-context-set-armor context epa-armor)
1155     (epg-context-set-armor context t)
1156     (insert (epg-export-keys-to-string context keys))))
1157
1158 ;;;###autoload
1159 (defun epa-sign-keys (keys &optional local)
1160   "Sign selected KEYS.
1161 If a prefix-arg is specified, the signature is marked as non exportable.
1162
1163 Don't use this command in Lisp programs!"
1164   (interactive
1165    (let ((keys (epa--marked-keys)))
1166      (unless keys
1167        (error "No keys selected"))
1168      (list keys current-prefix-arg)))
1169   (let ((context (epg-make-context epa-protocol)))
1170     (epg-context-set-passphrase-callback context
1171                                          #'epa-passphrase-callback-function)
1172     (epg-context-set-progress-callback context
1173                                        #'epa-progress-callback-function)
1174     (message "Signing keys...")
1175     (epg-sign-keys context keys local)
1176     (message "Signing keys...done")))
1177 (make-obsolete 'epa-sign-keys "Do not use.")
1178
1179 (provide 'epa)
1180
1181 ;;; epa.el ends here