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