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