--- /dev/null
+(require 'epg)
+(require 'font-lock)
+
+(defgroup epa nil
+ "EasyPG Assistant, GUI for EasyPG."
+ :group 'epg)
+
+(defgroup epa-faces nil
+ "Faces for epa-mode."
+ :group 'epa)
+
+(defvar epa-buffer nil)
+
+(defface epa-trust-full-face
+ '((((class color) (background dark))
+ (:foreground "PaleTurquoise" :bold t))
+ (t
+ (:bold t)))
+ "Face used for displaying the trust-full addon."
+ :group 'epa-faces)
+(defvar epa-trust-full-face 'epa-trust-full-face)
+
+(defface epa-trust-disabled-face
+ '((((class color) (background dark))
+ (:foreground "PaleTurquoise" :italic t))
+ (t
+ ()))
+ "Face used for displaying the disabled trust."
+ :group 'epa-faces)
+(defvar epa-trust-disabled-face 'epa-trust-disabled-face)
+
+(defface epa-trust-unknown-face
+ '((t
+ (:italic t)))
+ "Face used for displaying the trust-unknown addon."
+ :group 'epa-faces)
+(defvar epa-trust-unknown-face 'epa-trust-unknown-face)
+
+(defface epa-trust-marginal-face
+ '((t
+ (:italic t :inverse-video t)))
+ "Face used for displaying the trust-marginal addon."
+ :group 'epa-faces)
+(defvar epa-trust-marginal-face 'epa-trust-marginal-face)
+
+(defface epa-user-id-face
+ '((((class color)
+ (background dark))
+ (:foreground "lightyellow"))
+ (((class color)
+ (background light))
+ (:foreground "blue4"))
+ (t
+ ()))
+ "Face used for displaying the user-id addon."
+ :group 'epa-faces)
+(defvar epa-user-id-face 'epa-user-id-face)
+
+(defcustom epa-validity-face-alist
+ '((?o . epa-trust-unknown-face)
+ (?i . epa-trust-disabled-face)
+ (?d . epa-trust-disabled-face)
+ (?r . epa-trust-disabled-face)
+ (?e . epa-trust-disabled-face)
+ (?- . epa-trust-unknown-face)
+ (?q . epa-trust-unknown-face)
+ (?n . epa-trust-disabled-face)
+ (?m . epa-trust-marginal-face)
+ (?f . epa-trust-full-face)
+ (?u . epa-trust-full-face)
+ (? . epa-trust-full-face))
+ "An alist mapping marks on epa-buffer to faces."
+ :type 'list
+ :group 'epa)
+
+(defcustom epa-font-lock-keywords
+ '(("^[* ]\\([-oidreqnmfu ]\\)\\s-+\\(\\S-+\\)\\s-+\\(.*\\)"
+ (2 (cdr (assq (aref (match-string 1) 0)
+ epa-validity-face-alist)))
+ (3 epa-user-id-face)))
+ "Default expressions to addon in epa-mode."
+ :type '(repeat (list string))
+ :group 'epa)
+
+(defvar epa-mode-map
+ (let ((keymap (make-sparse-keymap)))
+ (define-key keymap "m" 'epa-command-mark-key)
+ (define-key keymap "u" 'epa-command-unmark-key)
+ (define-key keymap "n" 'epa-command-next-line)
+ (define-key keymap "p" 'previous-line)
+ (define-key keymap "e" 'epa-command-encrypt-file)
+ (define-key keymap "s" 'epa-command-sign-file)
+ (define-key keymap " " 'scroll-up)
+ (define-key keymap [delete] 'scroll-down)
+ (define-key keymap "q" 'bury-buffer)
+ keymap))
+
+(defun epa-mode ()
+ "Major mode for displaying addon list.
+All normal editing commands are turned off."
+ (kill-all-local-variables)
+ (buffer-disable-undo)
+ (setq major-mode 'epa-mode
+ mode-name "EPA"
+ truncate-lines t
+ buffer-read-only t)
+ (use-local-map epa-mode-map)
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(epa-font-lock-keywords t))
+ ;; In XEmacs, auto-initialization of font-lock is not effective
+ ;; if buffer-file-name is not set.
+ (font-lock-set-defaults)
+ (make-local-variable 'epa-marked-keys)
+ (run-hooks 'epa-mode-hook))
+
+(defun epa ()
+ (interactive)
+ (unless epa-buffer
+ (setq epa-buffer (generate-new-buffer "*EPA*")))
+ (set-buffer epa-buffer)
+ (epa-mode)
+ (let ((inhibit-read-only t)
+ buffer-read-only
+ configuration pointer entry point)
+ (erase-buffer)
+ (insert "EasyPG Assistant\n\n")
+ (setq configuration (epg-configuration))
+ (if (setq entry (assq 'version configuration))
+ (insert (format "GnuPG %s\n" (cdr entry))))
+ (if (setq entry (assq 'pubkey configuration))
+ (insert (format "Pubkey: %s\n"
+ (mapconcat
+ (lambda (algorithm)
+ (if (setq entry
+ (assq algorithm
+ epg-pubkey-algorithm-alist))
+ (cdr entry)
+ (format "(unknown: %d)" algorithm)))
+ (cdr entry) ", "))))
+ (if (setq entry (assq 'cipher configuration))
+ (insert (format "Cipher: %s\n"
+ (mapconcat
+ (lambda (algorithm)
+ (if (setq entry
+ (assq algorithm
+ epg-cipher-algorithm-alist))
+ (cdr entry)
+ (format "(unknown: %d)" algorithm)))
+ (cdr entry) ", "))))
+ (if (setq entry (assq 'digest configuration))
+ (insert (format "Hash: %s\n"
+ (mapconcat
+ (lambda (algorithm)
+ (if (setq entry
+ (assq algorithm
+ epg-digest-algorithm-alist))
+ (cdr entry)
+ (format "(unknown: %d)" algorithm)))
+ (cdr entry) ", "))))
+ (if (setq entry (assq 'compress configuration))
+ (insert (format "Compression: %s\n"
+ (mapconcat
+ (lambda (algorithm)
+ (if (setq entry
+ (assq algorithm
+ epg-compress-algorithm-alist))
+ (cdr entry)
+ (format "(unknown: %d)" algorithm)))
+ (cdr entry) ", "))))
+ (insert "\nSecret keys:\n\n")
+ (setq pointer (epg-list-keys nil t))
+ (while pointer
+ (setq point (point))
+ (setq entry (cdr (assq 'sec (car pointer))))
+ (setq key-id (cdr (assq 'key-id entry)))
+ (insert (format " %s %s\n"
+ key-id
+ (cdr (assq 'user-id (assq 'uid (car pointer))))))
+ (put-text-property point (point) 'epa-key-id key-id)
+ (put-text-property point (point) 'epa-key-secret t)
+ (setq pointer (cdr pointer)))
+ (insert "\nPublic keys:\n\n")
+ (setq pointer (epg-list-keys nil))
+ (while pointer
+ (setq point (point))
+ (setq entry (cdr (assq 'pub (car pointer))))
+ (setq key-id (cdr (assq 'key-id entry)))
+ (insert (format " %s %s %s\n"
+ (or (cdr (assq 'trust entry)) ? )
+ key-id
+ (cdr (assq 'user-id (assq 'uid (car pointer))))))
+ (put-text-property point (point) 'epa-key-id key-id)
+ (setq pointer (cdr pointer)))
+ (goto-char (point-min))
+ (pop-to-buffer (current-buffer))
+ (delete-other-windows)))
+
+(defun epa-key-id ()
+ (let ((key-id (get-text-property (point) 'epa-key-id))
+ point)
+ (unless key-id
+ (setq point (next-single-property-change (point) 'epa-key-id))
+ (when point
+ (goto-char point)
+ (setq key-id (get-text-property (point) 'epa-key-id))))
+ key-id))
+
+(defun epa-command-mark-key (key-id)
+ (interactive
+ (progn
+ (unless (eq major-mode 'epa-mode)
+ (error "Not in `epa-mode'"))
+ (list (epa-key-id))))
+ (let ((point (point))
+ (inhibit-read-only t)
+ buffer-read-only)
+ (while (and point
+ (not (equal (get-text-property point 'epa-key-id) key-id)))
+ (setq point (next-single-property-change point)))
+ (unless point
+ (error "Key %s not found" key-id))
+ (goto-char point)
+ (beginning-of-line)
+ (delete-char)
+ (setq point (point))
+ (insert "*")
+ (put-text-property point (point) 'epa-key-id key-id)
+ (forward-line)))
+
+(defun epa-command-unmark-key (key-id)
+ (interactive
+ (progn
+ (unless (eq major-mode 'epa-mode)
+ (error "Not in `epa-mode'"))
+ (list (epa-key-id))))
+ (let ((point (point))
+ (inhibit-read-only t)
+ buffer-read-only)
+ (while (and point
+ (not (equal (get-text-property point 'epa-key-id) key-id)))
+ (setq point (next-single-property-change point)))
+ (unless point
+ (error "Key %s not found" key-id))
+ (goto-char point)
+ (beginning-of-line)
+ (delete-char)
+ (setq point (point))
+ (insert " ")
+ (put-text-property point (point) 'epa-key-id key-id)
+ (forward-line)))
+
+(defun epa-command-next-line (count)
+ (interactive "p")
+ (if (get-text-property (point) 'epa-key-id)
+ (next-line count)
+ (let ((point (next-single-property-change (point) 'epa-key-id)))
+ (if (and point
+ (get-text-property point 'epa-key-id))
+ (goto-char point)))))
+
+(defun epa-command-encrypt-file (plain cipher recipients sign)
+ (interactive
+ (save-excursion
+ (set-buffer epa-buffer)
+ (goto-char (point-min))
+ (let (plain recipients)
+ (while (re-search-forward "^\\*" nil t)
+ (setq recipients (cons (get-text-property (point) 'epa-key-id)
+ recipients)))
+ (list (setq plain (expand-file-name (read-file-name "Plain file: ")))
+ (expand-file-name
+ (read-file-name (format "Cipher file (default %s.gpg) "
+ (file-name-nondirectory plain))
+ (file-name-directory plain)
+ (concat plain ".gpg")))
+ recipients
+ current-prefix-arg))))
+ (message "Encrypting %s..." (file-name-nondirectory plain))
+ (epg-encrypt-file (epg-make-context)
+ plain
+ recipients
+ (expand-file-name cipher)
+ sign)
+ (message "Encrypting %s...done" (file-name-nondirectory plain)))
+
+(defun epa-command-sign-file (plain signature detached signers)
+ (interactive
+ (save-excursion
+ (set-buffer epa-buffer)
+ (goto-char (point-min))
+ (let ((extension (if current-prefix-arg ".sig" ".gpg"))
+ plain signers)
+ (while (re-search-forward "^\\*" nil t)
+ (if (get-text-property (point) 'epa-key-secret)
+ (setq signers (cons (get-text-property (point) 'epa-key-id)
+ signers))))
+
+ (list (setq plain (expand-file-name (read-file-name "Plain file: ")))
+ (expand-file-name
+ (read-file-name (format "Signature file (default %s%s) "
+ (file-name-nondirectory plain)
+ extension)
+ (file-name-directory plain)
+ (concat plain extension)))
+ current-prefix-arg
+ signers))))
+ (let ((context (epg-make-context)))
+ (epg-context-set-signers context signers)
+ (message "Signing %s..." (file-name-nondirectory plain))
+ (epg-sign-file context
+ plain
+ signature
+ (if detached 'detached))
+ (message "Signing %s...done" (file-name-nondirectory plain))))
+
+(provide 'epa)
+
+;;; epa.el ends here