* epg.el (epg-status-GET_BOOL): New function.
[elisp/epg.git] / epg.el
diff --git a/epg.el b/epg.el
index 6a3401d..de72571 100644 (file)
--- a/epg.el
+++ b/epg.el
@@ -1,3 +1,30 @@
+;;; epg.el --- EasyPG, yet another GnuPG interface.
+;; Copyright (C) 1999, 2000, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
+;; Copyright (C) 2006 Daiki Ueno
+
+;; Author: Daiki Ueno <ueno@unixuser.org>
+;; Keywords: PGP, GnuPG
+
+;; This file is part of EasyPG.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Code:
+
 (defgroup epg ()
   "EasyPG, yet another GnuPG interface.")
 
 (defgroup epg ()
   "EasyPG, yet another GnuPG interface.")
 
@@ -57,6 +84,8 @@ This is used by `epg-list-keys'.")
     (user-id "[^:]+"))
   "The schema of keylisting output whose type is \"uid\".
 This is used by `epg-list-keys'.")
     (user-id "[^:]+"))
   "The schema of keylisting output whose type is \"uid\".
 This is used by `epg-list-keys'.")
+
+(defvar epg-prompt-alist nil)
     
 (defun epg-make-context (&optional protocol armor textmode include-certs)
   "Return a context object."
     
 (defun epg-make-context (&optional protocol armor textmode include-certs)
   "Return a context object."
@@ -153,7 +182,7 @@ This function is for internal use only."
 
 (defun epg-make-signature (status key-id user-id)
   "Return a signature object."
 
 (defun epg-make-signature (status key-id user-id)
   "Return a signature object."
-  (vector status key-id user-id nil))
+  (vector status key-id user-id nil nil))
 
 (defun epg-signature-status (signature)
   "Return the status code of SIGNATURE."
 
 (defun epg-signature-status (signature)
   "Return the status code of SIGNATURE."
@@ -171,6 +200,10 @@ This function is for internal use only."
   "Return the validity of SIGNATURE."
   (aref signature 3))
 
   "Return the validity of SIGNATURE."
   (aref signature 3))
 
+(defun epg-signature-fingerprint (signature)
+  "Return the fingerprint of SIGNATURE."
+  (aref signature 4))
+
 (defun epg-signature-set-status (signature status)
  "Set the status code of SIGNATURE."
   (aset signature 0 status))
 (defun epg-signature-set-status (signature status)
  "Set the status code of SIGNATURE."
   (aset signature 0 status))
@@ -187,6 +220,10 @@ This function is for internal use only."
  "Set the validity of SIGNATURE."
   (aset signature 3 validity))
 
  "Set the validity of SIGNATURE."
   (aset signature 3 validity))
 
+(defun epg-signature-set-fingerprint (signature fingerprint)
+ "Set the fingerprint of SIGNATURE."
+  (aset signature 4 fingerprint))
+
 (defun epg-context-result-for (context name)
   (cdr (assq name (epg-context-result context))))
 
 (defun epg-context-result-for (context name)
   (cdr (assq name (epg-context-result context))))
 
@@ -290,8 +327,7 @@ This function is for internal use only."
       (kill-buffer (process-buffer (epg-context-process context))))
   (epg-context-set-process context nil)
   (if (file-exists-p (epg-context-output-file context))
       (kill-buffer (process-buffer (epg-context-process context))))
   (epg-context-set-process context nil)
   (if (file-exists-p (epg-context-output-file context))
-      (delete-file (epg-context-output-file context)))
-  (aset context 9 nil))
+      (delete-file (epg-context-output-file context))))
 
 (defun epg-status-USERID_HINT (process string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
 
 (defun epg-status-USERID_HINT (process string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
@@ -329,6 +365,17 @@ This function is for internal use only."
          (if string
              (fillarray string 0))))))
 
          (if string
              (fillarray string 0))))))
 
+(defun epg-status-GET_BOOL (process string)
+  (let ((entry (assoc string epg-prompt-alist)))
+    (if (y-or-n-p (if entry (cdr entry) (concat string "? ")))
+       (process-send-string process "y\n")
+      (process-send-string process "n\n"))))
+
+(defun epg-status-GET_LINE (process string)
+  (let* ((entry (assoc string epg-prompt-alist))
+        (string (read-string (if entry (cdr entry) (concat string ": ")))))
+    (process-send-string process (concat string "\n")))))
+
 (defun epg-status-GOODSIG (process string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
       (epg-context-set-result-for
 (defun epg-status-GOODSIG (process string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
       (epg-context-set-result-for
@@ -379,11 +426,18 @@ This function is for internal use only."
                                 (match-string 2 string))
             (epg-context-result-for epg-context 'verify)))))
 
                                 (match-string 2 string))
             (epg-context-result-for epg-context 'verify)))))
 
+(defun epg-status-VALIDSIG (process string)
+  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+    (if (and signature
+            (eq (epg-signature-status signature) 'good)
+            (string-match "\\`\\([^ ]+\\) " string))
+       (epg-signature-set-fingerprint signature (match-string 1 string)))))
+
 (defun epg-status-TRUST_UNDEFINED (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
 (defun epg-status-TRUST_UNDEFINED (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
-       (epg-signature-set-validity signature 'unknown))))
+       (epg-signature-set-validity signature 'undefined))))
 
 (defun epg-status-TRUST_NEVER (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
 
 (defun epg-status-TRUST_NEVER (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
@@ -401,13 +455,13 @@ This function is for internal use only."
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
-       (epg-signature-set-validity signature 'full))))
+       (epg-signature-set-validity signature 'fully))))
 
 (defun epg-status-TRUST_ULTIMATE (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
 
 (defun epg-status-TRUST_ULTIMATE (process string)
   (let ((signature (car (epg-context-result-for epg-context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
-       (epg-signature-set-validity signature 'full))))
+       (epg-signature-set-validity signature 'ultimate))))
 
 (defun epg-status-PROGRESS (process string)
   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
 
 (defun epg-status-PROGRESS (process string)
   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
@@ -572,7 +626,7 @@ You can then use `write-region' to write new data into the file."
             (delete-directory tempdir))))))
 
 ;;;###autoload
             (delete-directory tempdir))))))
 
 ;;;###autoload
-(defun epg-decrypt-start (context input-file)
+(defun epg-start-decrypt (context input-file)
   "Initiate a decrypt operation on INPUT-FILE.
 
 If you use this function, you will need to wait for the completion of
   "Initiate a decrypt operation on INPUT-FILE.
 
 If you use this function, you will need to wait for the completion of
@@ -580,6 +634,7 @@ If you use this function, you will need to wait for the completion of
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-decrypt-string' instead."
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-decrypt-string' instead."
+  (epg-context-set-result context nil)
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (list "--decrypt" input-file))
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (list "--decrypt" input-file))
@@ -590,7 +645,7 @@ If you are unsure, use synchronous version of this function
   "Decrypt INPUT-FILE and return the plain text."
   (unwind-protect
       (progn
   "Decrypt INPUT-FILE and return the plain text."
   (unwind-protect
       (progn
-       (epg-decrypt-start context input-file)
+       (epg-start-decrypt context input-file)
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Decryption failed"))
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Decryption failed"))
@@ -610,7 +665,7 @@ If you are unsure, use synchronous version of this function
          (delete-file input-file)))))
 
 ;;;###autoload
          (delete-file input-file)))))
 
 ;;;###autoload
-(defun epg-verify-start (context signature &optional string)
+(defun epg-start-verify (context signature &optional string)
   "Initiate a verify operation on SIGNATURE.
 
 For a detached signature, both SIGNATURE and STRING should be string.
   "Initiate a verify operation on SIGNATURE.
 
 For a detached signature, both SIGNATURE and STRING should be string.
@@ -621,6 +676,7 @@ If you use this function, you will need to wait for the completion of
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-verify-string' instead."
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-verify-string' instead."
+  (epg-context-set-result context nil)
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (if string
       ;; Detached signature.
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (if string
       ;; Detached signature.
@@ -636,6 +692,19 @@ If you are unsure, use synchronous version of this function
        (process-send-string (epg-context-process context) signature))))
 
 ;;;###autoload
        (process-send-string (epg-context-process context) signature))))
 
 ;;;###autoload
+(defun epg-verify-file (context input-file &optional string)
+  "Verify INPUT-FILE.
+
+For a detached signature, both INPUT-FILE and STRING should be string.
+For a normal or a clear text signature, STRING should be nil."
+  (unwind-protect
+      (progn
+       (epg-start-verify context input-file string)
+       (epg-wait-for-completion context)
+       (epg-context-result-for context 'verify))
+    (epg-reset context)))
+
+;;;###autoload
 (defun epg-verify-string (context signature &optional string)
   "Verify SIGNATURE.
 
 (defun epg-verify-string (context signature &optional string)
   "Verify SIGNATURE.
 
@@ -647,15 +716,12 @@ For a normal or a clear text signature, STRING should be nil."
        (progn
          (if string
              (write-region signature nil input-file))
        (progn
          (if string
              (write-region signature nil input-file))
-         (epg-verify-start context input-file string)
-         (epg-wait-for-completion context)
-         (epg-context-result-for context 'verify))
-      (epg-reset context)
+         (epg-verify-file context input-file string))
       (if (file-exists-p input-file)
          (delete-file input-file)))))
 
 ;;;###autoload
       (if (file-exists-p input-file)
          (delete-file input-file)))))
 
 ;;;###autoload
-(defun epg-sign-start (context string &optional mode)
+(defun epg-start-sign (context string &optional mode)
   "Initiate a sign operation on STRING.
 
 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
   "Initiate a sign operation on STRING.
 
 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
@@ -667,6 +733,7 @@ If you use this function, you will need to wait for the completion of
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-sign-string' instead."
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-sign-string' instead."
+  (epg-context-set-result context nil)
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (append (list (if (eq mode 'clearsign)
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (append (list (if (eq mode 'clearsign)
@@ -690,7 +757,7 @@ If MODE is t or 'detached, it makes a detached signature.
 Otherwise, it makes a normal signature."
   (unwind-protect
       (progn
 Otherwise, it makes a normal signature."
   (unwind-protect
       (progn
-       (epg-sign-start context string mode)
+       (epg-start-sign context string mode)
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Sign failed"))
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Sign failed"))
@@ -698,9 +765,9 @@ Otherwise, it makes a normal signature."
     (epg-reset context)))
 
 ;;;###autoload
     (epg-reset context)))
 
 ;;;###autoload
-(defun epg-encrypt-start (context string recipients
+(defun epg-start-encrypt (context string recipients
                                  &optional sign always-trust)
                                  &optional sign always-trust)
-  "Initiate a encrypt operation on STRING.
+  "Initiate an encrypt operation on STRING.
 If RECIPIENTS is nil, it performs symmetric encryption.
 
 If you use this function, you will need to wait for the completion of
 If RECIPIENTS is nil, it performs symmetric encryption.
 
 If you use this function, you will need to wait for the completion of
@@ -708,6 +775,7 @@ If you use this function, you will need to wait for the completion of
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-encrypt-string' instead."
 `epg-reset' to clear a temporaly output file.
 If you are unsure, use synchronous version of this function
 `epg-encrypt-string' instead."
+  (epg-context-set-result context nil)
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (append (if always-trust '("--always-trust"))
   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
   (epg-start context
             (append (if always-trust '("--always-trust"))
@@ -736,13 +804,65 @@ If you are unsure, use synchronous version of this function
 If RECIPIENTS is nil, it performs symmetric encryption."
   (unwind-protect
       (progn
 If RECIPIENTS is nil, it performs symmetric encryption."
   (unwind-protect
       (progn
-       (epg-encrypt-start context string recipients sign always-trust)
+       (epg-start-encrypt context string recipients sign always-trust)
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Encrypt failed"))
        (epg-read-output context))
     (epg-reset context)))
 
        (epg-wait-for-completion context)
        (if (epg-context-result-for context 'error)
            (error "Encrypt failed"))
        (epg-read-output context))
     (epg-reset context)))
 
+;;;###autoload
+(defun epg-start-export-keys (context pattern)
+  "Initiate an export keys operation.
+
+If you use this function, you will need to wait for the completion of
+`epg-gpg-program' by using `epg-wait-for-completion' and call
+`epg-reset' to clear a temporaly output file.
+If you are unsure, use synchronous version of this function
+`epg-export-keys' instead."
+  (epg-context-set-result context nil)
+  (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
+  (epg-start context (list "--export" pattern)))
+
+;;;###autoload
+(defun epg-export-keys (context pattern)
+  "Extract public keys matched with PATTERN and return them."
+  (unwind-protect
+      (progn
+       (epg-start-export-keys context pattern)
+       (epg-wait-for-completion context)
+       (if (epg-context-result-for context 'error)
+           (error "Export keys failed"))
+       (epg-read-output context))
+    (epg-reset context)))
+
+;;;###autoload
+(defun epg-start-import-keys (context keys)
+  "Initiate an import key operation.
+
+If you use this function, you will need to wait for the completion of
+`epg-gpg-program' by using `epg-wait-for-completion' and call
+`epg-reset' to clear a temporaly output file.
+If you are unsure, use synchronous version of this function
+`epg-import-keys' instead."
+  (epg-context-set-result context nil)
+  (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
+  (epg-start context (list "--import"))
+  (if (eq (process-status (epg-context-process context)) 'run)
+      (process-send-string (epg-context-process context) keys)))
+
+;;;###autoload
+(defun epg-import-keys (context keys)
+  "Add KEYS."
+  (unwind-protect
+      (progn
+       (epg-start-import-keys context keys)
+       (epg-wait-for-completion context)
+       (if (epg-context-result-for context 'error)
+           (error "Import keys failed"))
+       (epg-read-output context))
+    (epg-reset context)))
+
 (provide 'epg)
 
 ;;; epg.el ends here
 (provide 'epg)
 
 ;;; epg.el ends here