Fixed indentation.
[elisp/epg.git] / epa.el
1 ;;; epa.el --- EasyPG Assistant, GUI of EasyPG
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   "EasyPG Assistant, GUI of EasyPG."
33   :group 'epg)
34
35 (defgroup epa-faces nil
36   "Faces for epa-mode."
37   :group 'epa)
38
39 (defvar epa-buffer nil)
40
41 (defface epa-validity-high-face
42   '((((class color) (background dark))
43      (:foreground "PaleTurquoise" :bold t))
44     (t
45      (:bold t)))
46   "Face used for displaying the high validity."
47   :group 'epa-faces)
48 (defvar epa-validity-high-face 'epa-validity-high-face)
49
50 (defface epa-validity-medium-face
51   '((((class color) (background dark))
52      (:foreground "PaleTurquoise" :italic t))
53     (t
54      ()))
55   "Face used for displaying the medium validity."
56   :group 'epa-faces)
57 (defvar epa-validity-medium-face 'epa-validity-medium-face)
58
59 (defface epa-validity-low-face
60   '((t
61      (:italic t)))
62   "Face used for displaying the low validity."
63   :group 'epa-faces)
64 (defvar epa-validity-low-face 'epa-validity-low-face)
65
66 (defface epa-validity-disabled-face
67   '((t
68      (:italic t :inverse-video t)))
69   "Face used for displaying the disabled validity."
70   :group 'epa-faces)
71 (defvar epa-validity-disabled-face 'epa-validity-disabled-face)
72
73 (defface epa-string-face
74   '((((class color)
75       (background dark))
76      (:foreground "lightyellow"))
77     (((class color)
78       (background light))
79      (:foreground "blue4"))
80     (t
81      ()))
82   "Face used for displaying the string."
83   :group 'epa-faces)
84 (defvar epa-string-face 'epa-string-face)
85
86 (defface epa-field-name-face
87   '((((class color) (background dark))
88      (:foreground "PaleTurquoise" :bold t))
89     (t (:bold t)))
90   "Face for the name of the attribute field."
91   :group 'epa)
92 (defvar epa-field-name-face 'epa-field-name-face)
93
94 (defface epa-field-body-face
95   '((((class color) (background dark))
96      (:foreground "turquoise" :italic t))
97     (t (:italic t)))
98   "Face for the body of the attribute field."
99   :group 'epa)
100 (defvar epa-field-body-face 'epa-field-body-face)
101
102 (defcustom epa-validity-face-alist
103   '((?o . epa-validity-disabled-face)
104     (?i . epa-validity-disabled-face)
105     (?d . epa-validity-disabled-face)
106     (?r . epa-validity-disabled-face)
107     (?e . epa-validity-disabled-face)
108     (?- . epa-validity-low-face)
109     (?q . epa-validity-low-face)
110     (?n . epa-validity-low-face)
111     (?m . epa-validity-medium-face)
112     (?f . epa-validity-high-face)
113     (?u . epa-validity-high-face))
114   "An alist mapping marks on epa-keys-buffer to faces."
115   :type 'list
116   :group 'epa)
117
118 (defcustom epa-font-lock-keywords
119   '(("^[* ]\\(\\([oidreqnmfu-]\\) .*\\)"
120      (1 (cdr (assq (aref (match-string 2) 0)
121                    epa-validity-face-alist))))
122     ("^\t\\([^\t:]+:\\)[ \t]*\\(.*\\)$"
123      (1 epa-field-name-face)
124      (2 epa-field-body-face)))
125   "Default expressions to addon in epa-mode."
126   :type '(repeat (list string))
127   :group 'epa)
128
129 (defconst epa-pubkey-algorithm-letter-alist
130   '((1 . ?R)
131     (2 . ?r)
132     (3 . ?s)
133     (16 . ?g)
134     (17 . ?D)
135     (20 . G)))
136
137 (defvar epa-keys-buffer nil)
138 (defvar epa-key-buffer-alist nil)
139 (defvar epa-key nil)
140
141 (defvar epa-keys-mode-map
142   (let ((keymap (make-sparse-keymap)))
143     (define-key keymap "m" 'epa-mark)
144     (define-key keymap "u" 'epa-unmark)
145     (define-key keymap "n" 'next-line)
146     (define-key keymap "p" 'previous-line)
147     (define-key keymap " " 'scroll-up)
148     (define-key keymap [delete] 'scroll-down)
149     (define-key keymap "q" 'bury-buffer)
150     keymap))
151
152 (defun epa-keys-mode ()
153   "Major mode for `epa-list-keys'."
154   (kill-all-local-variables)
155   (buffer-disable-undo)
156   (setq major-mode 'epa-keys-mode
157         mode-name "Keys"
158         truncate-lines t
159         buffer-read-only t)
160   (use-local-map epa-keys-mode-map)
161   (set-keymap-parent (current-local-map) widget-keymap)
162   (make-local-variable 'font-lock-defaults)
163   (setq font-lock-defaults '(epa-font-lock-keywords t))
164   ;; In XEmacs, auto-initialization of font-lock is not effective
165   ;; if buffer-file-name is not set.
166   (font-lock-set-defaults)
167   (widget-setup)
168   (run-hooks 'epa-keys-mode-hook))
169
170 (defvar epa-key-mode-map
171   (let ((keymap (make-sparse-keymap)))
172     (define-key keymap "q" 'bury-buffer)
173     keymap))
174
175 (defun epa-key-mode ()
176   "Major mode for `epa-show-key'."
177   (kill-all-local-variables)
178   (buffer-disable-undo)
179   (setq major-mode 'epa-key-mode
180         mode-name "Key"
181         truncate-lines t
182         buffer-read-only t)
183   (use-local-map epa-key-mode-map)
184   (make-local-variable 'font-lock-defaults)
185   (setq font-lock-defaults '(epa-font-lock-keywords t))
186   ;; In XEmacs, auto-initialization of font-lock is not effective
187   ;; if buffer-file-name is not set.
188   (font-lock-set-defaults)
189   (run-hooks 'epa-key-mode-hook))
190
191 ;;;###autoload
192 (defun epa-list-keys (&optional name)
193   (interactive "sPattern: ")
194   (unless (and epa-keys-buffer
195                (buffer-live-p epa-keys-buffer))
196     (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
197   (set-buffer epa-keys-buffer)
198   (erase-buffer)
199   (epa-list-keys-1 name)
200   (epa-keys-mode)
201   (goto-char (point-min))
202   (pop-to-buffer (current-buffer)))
203
204 (defun epa-list-keys-1 (name)
205   (let ((inhibit-read-only t)
206         buffer-read-only
207         keys point primary-sub-key primary-user-id)
208     (setq keys (epg-list-keys))
209     (while keys
210       (setq point (point)
211             primary-sub-key (car (epg-key-sub-key-list (car keys)))
212             primary-user-id (car (epg-key-user-id-list (car keys))))
213       (insert " " (or (char-to-string
214                        (car (rassq (epg-sub-key-validity primary-sub-key)
215                                    epg-key-validity-alist)))
216                       " ") " ")
217       (widget-create 'link 
218                      :tag (epg-sub-key-id primary-sub-key)
219                      :notify 'epa-show-key-notify
220                      (car keys))
221       (insert " " (epg-user-id-name primary-user-id) "\n")
222       (put-text-property point (point) 'epa-key (car keys))
223       (setq keys (cdr keys)))))
224
225 (defun epa-ask-keys (prompt function &optional names &rest args)
226   (unless (and epa-keys-buffer
227                (buffer-live-p epa-keys-buffer))
228     (setq epa-keys-buffer (generate-new-buffer "*Keys*")))
229   (let ((buffer (current-buffer))
230         (inhibit-read-only t)
231         buffer-read-only)
232     (set-buffer epa-keys-buffer)
233     (erase-buffer)
234     (insert prompt)
235     (widget-create 'push-button
236                    :tag "Done"
237                    :notify (lambda (widget &rest ignore)
238                              (let ((callback (widget-value widget))
239                                    keys key)
240                                (while (re-search-forward "^\\*" nil t)
241                                  (if (setq key (get-text-property (point)
242                                                                   'epa-key))
243                                      (setq keys (cons key keys))))
244                                (set-buffer (car callback))
245                                (apply (car (cdr callback)) keys
246                                       (cdr (cdr callback)))))
247                    (cons buffer (cons function args)))
248     (insert "\n\n")
249     (if names
250         (while names
251           (epa-list-keys-1 (car names))
252           (setq names (cdr names)))
253       (epa-list-keys-1 nil))
254     (epa-keys-mode)
255     (goto-char (point-min))
256     (pop-to-buffer (current-buffer))))
257
258 (defun epa-show-key (key)
259   (let* ((primary-sub-key (car (epg-key-sub-key-list key)))
260          (entry (assoc (epg-sub-key-id primary-sub-key)
261                        epa-key-buffer-alist))
262          (inhibit-read-only t)
263          buffer-read-only
264          pointer)
265     (unless entry
266       (setq entry (cons (epg-sub-key-id primary-sub-key) nil)
267             epa-key-buffer-alist (cons entry epa-key-buffer-alist)))
268     (unless (and (cdr entry)
269                  (buffer-live-p (cdr entry)))
270       (setcdr entry (generate-new-buffer
271                      (format "*Key*%s" (epg-sub-key-id primary-sub-key)))))
272     (set-buffer (cdr entry))
273     (make-local-variable 'epa-key)
274     (setq epa-key key)
275     (erase-buffer)
276     (setq pointer (epg-key-user-id-list key))
277     (while pointer
278       (insert " "
279               (char-to-string
280                (car (rassq (epg-user-id-validity (car pointer))
281                            epg-key-validity-alist)))
282               " "
283               (epg-user-id-name (car pointer))
284               "\n")
285       (setq pointer (cdr pointer)))
286     (setq pointer (epg-key-sub-key-list key))
287     (while pointer
288       (insert " "
289               (char-to-string
290                (car (rassq (epg-sub-key-validity (car pointer))
291                            epg-key-validity-alist)))
292               " "
293               (epg-sub-key-id (car pointer))
294               " "
295               (format "%dbits"
296                       (epg-sub-key-length (car pointer)))
297               " "
298               (cdr (assq (epg-sub-key-algorithm (car pointer))
299                          epg-pubkey-algorithm-alist))
300               "\n\tCreated: "
301               (epg-sub-key-creation-time (car pointer))
302               (if (epg-sub-key-expiration-time (car pointer))
303                   (format "\n\tExpires: %s" (epg-sub-key-expiration-time
304                                                   (car pointer)))
305                 "")
306               "\n\tCapabilities: "
307               (mapconcat #'symbol-name
308                          (epg-sub-key-capability (car pointer))
309                          " ")
310               "\n\tFingerprint: "
311               (epg-sub-key-fingerprint (car pointer))
312               "\n")
313       (setq pointer (cdr pointer)))
314     (goto-char (point-min))
315     (pop-to-buffer (current-buffer))
316     (epa-key-mode)))
317
318 (defun epa-show-key-notify (widget &rest ignore)
319   (epa-show-key (widget-value widget)))
320
321 (defun epa-mark ()
322   "Mark the current line."
323   (interactive)
324   (let ((inhibit-read-only t)
325         buffer-read-only
326         properties)
327     (beginning-of-line)
328     (setq properties (text-properties-at (point)))
329     (delete-char 1)
330     (insert "*")
331     (set-text-properties (1- (point)) (point) properties)
332     (forward-line)))
333
334 (defun epa-unmark ()
335   "Unmark the current line."
336   (interactive)
337   (let ((inhibit-read-only t)
338         buffer-read-only
339         properties)
340     (beginning-of-line)
341     (setq properties (text-properties-at (point)))
342     (delete-char 1)
343     (insert " ")
344     (set-text-properties (1- (point)) (point) properties)
345     (forward-line)))
346
347 (provide 'epa)
348
349 ;;; epa.el ends here