Update.
[elisp/epg.git] / epg.el
diff --git a/epg.el b/epg.el
index add41e1..e445aec 100644 (file)
--- a/epg.el
+++ b/epg.el
 
 (defvar epg-prompt-alist nil)
 
+(put 'epg-error 'error-conditions '(epg-error error))
+
 (defun epg-make-data-from-file (file)
   "Make a data object from FILE."
   (cons 'epg-data (vector file nil)))
@@ -250,7 +252,7 @@ message."
     (signal 'wrong-type-argument (list 'epg-context-p context)))
   (aref (cdr context) 9))
 
-(defun epg-context-signature-notations (context)
+(defun epg-context-sig-notations (context)
   "Return the list of notations for singning."
   (unless (eq (car-safe context) 'epg-context)
     (signal 'wrong-type-argument (list 'epg-context-p context)))
@@ -324,18 +326,25 @@ This function is for internal use only."
     (signal 'wrong-type-argument (list 'epg-context-p context)))
   (aset (cdr context) 6 compress-algorithm))
 
-(defun epg-context-set-passphrase-callback (context
-                                                passphrase-callback)
-  "Set the function used to query passphrase."
+(defun epg-context-set-passphrase-callback (context passphrase-callback
+                                                   &optional handback)
+  "Set the function used to query passphrase.
+If optional argument HANDBACK is specified, it is passed to CALLBACK."
   (unless (eq (car-safe context) 'epg-context)
     (signal 'wrong-type-argument (list 'epg-context-p context)))
-  (aset (cdr context) 7 passphrase-callback))
-
-(defun epg-context-set-progress-callback (context progress-callback)
-  "Set the function which handles progress update."
+  (aset (cdr context) 7 (if handback
+                           (cons passphrase-callback handback)
+                         passphrase-callback)))
+
+(defun epg-context-set-progress-callback (context progress-callback
+                                                 &optional handback)
+  "Set the function which handles progress update.
+If optional argument HANDBACK is specified, it is passed to CALLBACK."
   (unless (eq (car-safe context) 'epg-context)
     (signal 'wrong-type-argument (list 'epg-context-p context)))
-  (aset (cdr context) 8 progress-callback))
+  (aset (cdr context) 8 (if handback
+                           (cons progress-callback handback)
+                         progress-callback)))
 
 (defun epg-context-set-signers (context signers)
   "Set the list of key-id for singning."
@@ -343,11 +352,11 @@ This function is for internal use only."
     (signal 'wrong-type-argument (list 'epg-context-p context)))
   (aset (cdr context) 9 signers))
 
-(defun epg-context-set-signature-notations (context notations)
+(defun epg-context-set-sig-notations (context notations)
   "Set the list of notations for singning."
   (unless (eq (car-safe context) 'epg-context)
     (signal 'wrong-type-argument (list 'epg-context-p context)))
-  (aset (cdr context) 10 signers))
+  (aset (cdr context) 10 notations))
 
 (defun epg-context-set-process (context process)
   "Set the process object of `epg-gpg-program'.
@@ -377,7 +386,8 @@ This function is for internal use only."
 
 (defun epg-make-signature (status &optional key-id)
   "Return a signature object."
-  (cons 'epg-signature (vector status key-id nil nil nil nil nil nil nil nil)))
+  (cons 'epg-signature (vector status key-id nil nil nil nil nil nil nil nil
+                              nil)))
 
 (defun epg-signature-status (signature)
   "Return the status code of SIGNATURE."
@@ -439,6 +449,12 @@ This function is for internal use only."
     (signal 'wrong-type-argument (list 'epg-signature-p signature)))
   (aref (cdr signature) 9))
 
+(defun epg-sig-notations (signature)
+  "Return the list of notations of SIGNATURE."
+  (unless (eq (car-safe signature) 'epg-signature)
+    (signal 'wrong-type-argument (list 'epg-signature-p signature)))
+  (aref (cdr signature) 10))
+
 (defun epg-signature-set-status (signature status)
  "Set the status code of SIGNATURE."
   (unless (eq (car-safe signature) 'epg-signature)
@@ -499,6 +515,12 @@ This function is for internal use only."
     (signal 'wrong-type-argument (list 'epg-signature-p signature)))
   (aset (cdr signature) 9 version))
 
+(defun epg-signature-set-notations (signature notations)
+  "Set the list of notations of SIGNATURE."
+  (unless (eq (car-safe signature) 'epg-signature)
+    (signal 'wrong-type-argument (list 'epg-signature-p signature)))
+  (aset (cdr signature) 10 notations))
+
 (defun epg-make-new-signature (type pubkey-algorithm digest-algorithm
                                    class creation-time fingerprint)
   "Return a new signature object."
@@ -727,38 +749,190 @@ This function is for internal use only."
     (signal 'wrong-type-argument (list 'epg-key-signature-p key-signature)))
   (aref (cdr key-signature) 7))
 
-(defun epg-make-signature-notation (name value &optional human-readable
+(defun epg-make-sig-notation (name value &optional human-readable
                                         critical)
   "Return a notation object."
-  (cons 'epg-signature-notation (vector name value human-readable critical)))
-
-(defun epg-signature-notation-name (signature-notation)
-  "Return the name of SIGNATURE-NOTATION."
-  (unless (eq (car-safe signature-notation) 'epg-signature-notation)
-    (signal 'wrong-type-argument (list 'epg-signature-notation-p
-                                      signature-notation)))
-  (aref (cdr signature-notation) 0))
-
-(defun epg-signature-notation-value (signature-notation)
-  "Return the value of SIGNATURE-NOTATION."
-  (unless (eq (car-safe signature-notation) 'epg-signature-notation)
-    (signal 'wrong-type-argument (list 'epg-signature-notation-p
-                                      signature-notation)))
-  (aref (cdr signature-notation) 1))
-
-(defun epg-signature-notation-human-readable (signature-notation)
-  "Return the human-readable of SIGNATURE-NOTATION."
-  (unless (eq (car-safe signature-notation) 'epg-signature-notation)
-    (signal 'wrong-type-argument (list 'epg-signature-notation-p
-                                      signature-notation)))
-  (aref (cdr signature-notation) 2))
-
-(defun epg-signature-notation-critical (signature-notation)
-  "Return the critical of SIGNATURE-NOTATION."
-  (unless (eq (car-safe signature-notation) 'epg-signature-notation)
-    (signal 'wrong-type-argument (list 'epg-signature-notation-p
-                                      signature-notation)))
-  (aref (cdr signature-notation) 3))
+  (cons 'epg-sig-notation (vector name value human-readable critical)))
+
+(defun epg-sig-notation-name (sig-notation)
+  "Return the name of SIG-NOTATION."
+  (unless (eq (car-safe sig-notation) 'epg-sig-notation)
+    (signal 'wrong-type-argument (list 'epg-sig-notation-p
+                                      sig-notation)))
+  (aref (cdr sig-notation) 0))
+
+(defun epg-sig-notation-value (sig-notation)
+  "Return the value of SIG-NOTATION."
+  (unless (eq (car-safe sig-notation) 'epg-sig-notation)
+    (signal 'wrong-type-argument (list 'epg-sig-notation-p
+                                      sig-notation)))
+  (aref (cdr sig-notation) 1))
+
+(defun epg-sig-notation-human-readable (sig-notation)
+  "Return the human-readable of SIG-NOTATION."
+  (unless (eq (car-safe sig-notation) 'epg-sig-notation)
+    (signal 'wrong-type-argument (list 'epg-sig-notation-p
+                                      sig-notation)))
+  (aref (cdr sig-notation) 2))
+
+(defun epg-sig-notation-critical (sig-notation)
+  "Return the critical of SIG-NOTATION."
+  (unless (eq (car-safe sig-notation) 'epg-sig-notation)
+    (signal 'wrong-type-argument (list 'epg-sig-notation-p
+                                      sig-notation)))
+  (aref (cdr sig-notation) 3))
+
+(defun epg-sig-notation-set-value (sig-notation value)
+  "Set the value of SIG-NOTATION."
+  (unless (eq (car-safe sig-notation) 'epg-sig-notation)
+    (signal 'wrong-type-argument (list 'epg-sig-notation-p
+                                      sig-notation)))
+  (aset (cdr sig-notation) 1 value))
+
+(defun epg-make-import-status (fingerprint &optional reason new user-id
+                                          signature sub-key secret)
+  "Return a import status object."
+  (cons 'epg-import-status (vector fingerprint reason new user-id signature
+                                  sub-key secret)))
+
+(defun epg-import-status-fingerprint (import-status)
+  "Return the fingerprint of the key that was considered."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 0))
+
+(defun epg-import-status-reason (import-status)
+  "Return the reason code for import failure."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 1))
+
+(defun epg-import-status-new (import-status)
+  "Return t if the imported key was new."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 2))
+
+(defun epg-import-status-user-id (import-status)
+  "Return t if the imported key contained new user IDs."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 3))
+
+(defun epg-import-status-signature (import-status)
+  "Return t if the imported key contained new signatures."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 4))
+
+(defun epg-import-status-sub-key (import-status)
+  "Return t if the imported key contained new sub keys."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 5))
+
+(defun epg-import-status-secret (import-status)
+  "Return t if the imported key contained a secret key."
+  (unless (eq (car-safe import-status) 'epg-import-status)
+    (signal 'wrong-type-argument (list 'epg-import-status-p import-status)))
+  (aref (cdr import-status) 6))
+
+(defun epg-make-import-result (considered no-user-id imported imported-rsa
+                                         unchanged new-user-ids new-sub-keys
+                                         new-signatures new-revocations
+                                         secret-read secret-imported
+                                         secret-unchanged not-imported
+                                         imports)
+  "Return a import result object."
+  (cons 'epg-import-result (vector considered no-user-id imported imported-rsa
+                                  unchanged new-user-ids new-sub-keys
+                                  new-signatures new-revocations secret-read
+                                  secret-imported secret-unchanged
+                                  not-imported imports)))
+
+(defun epg-import-result-considered (import-result)
+  "Return the total number of considered keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 0))
+
+(defun epg-import-result-no-user-id (import-result)
+  "Return the number of keys without user ID."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 1))
+
+(defun epg-import-result-imported (import-result)
+  "Return the number of imported keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 2))
+
+(defun epg-import-result-imported-rsa (import-result)
+  "Return the number of imported RSA keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 3))
+
+(defun epg-import-result-unchanged (import-result)
+  "Return the number of unchanged keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 4))
+
+(defun epg-import-result-new-user-ids (import-result)
+  "Return the number of new user IDs."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 5))
+
+(defun epg-import-result-new-sub-keys (import-result)
+  "Return the number of new sub keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 6))
+
+(defun epg-import-result-new-signatures (import-result)
+  "Return the number of new signatures."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 7))
+
+(defun epg-import-result-new-revocations (import-result)
+  "Return the number of new revocations."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 8))
+
+(defun epg-import-result-secret-read (import-result)
+  "Return the total number of secret keys read."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 9))
+
+(defun epg-import-result-secret-imported (import-result)
+  "Return the number of imported secret keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 10))
+
+(defun epg-import-result-secret-unchanged (import-result)
+  "Return the number of unchanged secret keys."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 11))
+
+(defun epg-import-result-not-imported (import-result)
+  "Return the number of keys not imported."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 12))
+
+(defun epg-import-result-imports (import-result)
+  "Return the list of `epg-import-status' objects."
+  (unless (eq (car-safe import-result) 'epg-import-result)
+    (signal 'wrong-type-argument (list 'epg-import-result-p import-result)))
+  (aref (cdr import-result) 13))
 
 (defun epg-context-result-for (context name)
   "Return the result of CONTEXT associated with NAME."
@@ -822,6 +996,49 @@ This function is for internal use only."
    (format "%02X " (epg-new-signature-class new-signature))
    (epg-new-signature-fingerprint new-signature)))
 
+(defun epg-import-result-to-string (import-result)
+  "Convert IMPORT-RESULT to a human readable string."
+  (concat (format "Total number processed: %d\n"
+                 (epg-import-result-considered import-result))
+         (if (> (epg-import-result-not-imported import-result) 0)
+             (format "      skipped new keys: %d\n"
+                     (epg-import-result-not-imported import-result)))
+         (if (> (epg-import-result-no-user-id import-result) 0)
+             (format "          w/o user IDs: %d\n"
+                     (epg-import-result-no-user-id import-result)))
+         (if (> (epg-import-result-imported import-result) 0)
+             (concat (format "              imported: %d"
+                             (epg-import-result-imported import-result))
+                     (if (> (epg-import-result-imported-rsa import-result) 0)
+                         (format "  (RSA: %d)"
+                                 (epg-import-result-imported-rsa
+                                  import-result)))
+                     "\n"))
+         (if (> (epg-import-result-unchanged import-result) 0)
+             (format "             unchanged: %d\n"
+                     (epg-import-result-unchanged import-result)))
+         (if (> (epg-import-result-new-user-ids import-result) 0)
+             (format "          new user IDs: %d\n"
+                     (epg-import-result-new-user-ids import-result)))
+         (if (> (epg-import-result-new-sub-keys import-result) 0)
+             (format "           new subkeys: %d\n"
+                     (epg-import-result-new-sub-keys import-result)))
+         (if (> (epg-import-result-new-signatures import-result) 0)
+             (format "        new signatures: %d\n"
+                     (epg-import-result-new-signatures import-result)))
+         (if (> (epg-import-result-new-revocations import-result) 0)
+             (format "   new key revocations: %d\n"
+                     (epg-import-result-new-revocations import-result)))
+         (if (> (epg-import-result-secret-read import-result) 0)
+             (format "      secret keys read: %d\n"
+                     (epg-import-result-secret-read import-result)))
+         (if (> (epg-import-result-secret-imported import-result) 0)
+             (format "  secret keys imported: %d\n"
+                     (epg-import-result-secret-imported import-result)))
+         (if (> (epg-import-result-secret-unchanged import-result) 0)
+             (format " secret keys unchanged: %d\n"
+                     (epg-import-result-secret-unchanged import-result)))))
+
 (defun epg--start (context args)
   "Start `epg-gpg-program' in a subprocess with given ARGS."
   (if (and (epg-context-process context)
@@ -833,12 +1050,15 @@ This function is for internal use only."
   (let* ((args (append (list "--no-tty"
                             "--status-fd" "1"
                             "--yes")
-                      (if (epg-context-progress-callback context)
-                          (list "--enable-progress-filter"))
+                      (if (string-match ":" (or (getenv "GPG_AGENT_INFO") ""))
+                          '("--use-agent"))
+                      (if (and (not (eq (epg-context-protocol context) 'CMS))
+                               (epg-context-progress-callback context))
+                          '("--enable-progress-filter"))
                       (if epg-gpg-home-directory
                           (list "--homedir" epg-gpg-home-directory))
                       (unless (eq (epg-context-protocol context) 'CMS)
-                        (list "--command-fd" "0"))
+                        '("--command-fd" "0"))
                       (if (epg-context-armor context) '("--armor"))
                       (if (epg-context-textmode context) '("--textmode"))
                       (if (epg-context-output-file context)
@@ -1002,9 +1222,10 @@ This function is for internal use only."
                  (if epg-passphrase-coding-system
                      (progn
                        (setq encoded-passphrase-with-new-line
-                             (encode-coding-string
+                             (epg--encode-coding-string
                               passphrase-with-new-line
-                              epg-passphrase-coding-system))
+                              (coding-system-change-eol-conversion
+                               epg-passphrase-coding-system 'unix)))
                        (epg--clear-string passphrase-with-new-line)
                        (setq passphrase-with-new-line nil))
                    (setq encoded-passphrase-with-new-line
@@ -1193,9 +1414,33 @@ This function is for internal use only."
             (eq (epg-signature-status signature) 'good))
        (epg-signature-set-validity signature 'ultimate))))
 
+(defun epg--status-NOTATION_NAME (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
+    (if signature
+       (epg-signature-set-notations
+        signature
+        (cons (epg-make-sig-notation string nil t nil)
+              (epg-sig-notations signature))))))
+
+(defun epg--status-NOTATION_DATA (context string)
+  (let ((signature (car (epg-context-result-for context 'verify)))
+       notation)
+    (if (and signature
+            (setq notation (car (epg-sig-notations signature))))
+       (epg-sig-notation-set-value notation string))))
+
+(defun epg--status-POLICY_URL (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
+    (if signature
+       (epg-signature-set-notations
+        signature
+        (cons (epg-make-sig-notation nil string t nil)
+              (epg-sig-notations signature))))))
+
 (defun epg--status-PROGRESS (context string)
-  (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
-                   string)
+  (if (and (epg-context-progress-callback context)
+          (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
+                        string))
       (funcall (if (consp (epg-context-progress-callback context))
                   (car (epg-context-progress-callback context))
                 (epg-context-progress-callback context))
@@ -1208,21 +1453,21 @@ This function is for internal use only."
                   (cdr (epg-context-progress-callback context))))))
 
 (defun epg--status-DECRYPTION_FAILED (context string)
-  (epg-context-set-result-for
-   context 'error
-   (cons '(decryption-failed)
-        (epg-context-result-for context 'error))))
+  (epg-context-set-result-for context 'decryption-failed t))
+
+(defun epg--status-DECRYPTION_OKAY (context string)
+  (epg-context-set-result-for context 'decryption-okay t))
 
 (defun epg--status-NODATA (context string)
   (epg-context-set-result-for
    context 'error
-   (cons (list 'no-data (cons 'reason (string-to-number string)))
+   (cons (cons 'no-data (string-to-number string))
         (epg-context-result-for context 'error))))
 
 (defun epg--status-UNEXPECTED (context string)
   (epg-context-set-result-for
    context 'error
-   (cons (list 'unexpected (cons 'reason (string-to-number string)))
+   (cons (cons 'unexpected (string-to-number string))
         (epg-context-result-for context 'error))))
 
 (defun epg--status-KEYEXPIRED (context string)
@@ -1265,8 +1510,8 @@ This function is for internal use only."
   (if (string-match "\\`\\([0-9]+\\)" string)
       (epg-context-set-result-for
        context 'error
-       (cons (list 'delete-problem
-                  (cons 'reason (string-to-number (match-string 1 string))))
+       (cons (cons 'delete-problem
+                  (string-to-number (match-string 1 string)))
             (epg-context-result-for context 'error)))))
 
 (defun epg--status-SIG_CREATED (context string)
@@ -1306,38 +1551,54 @@ This function is for internal use only."
        (if entry
            (setcdr entry user-id)
          (setq epg-user-id-alist (cons (cons key-id user-id)
-                                       epg-user-id-alist)))
-       (epg-context-set-result-for
-        context 'import
-        (cons (list (cons 'key-id key-id)
-                    (cons 'user-id user-id))
-              (epg-context-result-for context 'import))))))
+                                       epg-user-id-alist))))))
 
 (defun epg--status-IMPORT_OK (context string)
-  (let ((result (epg-context-result-for context 'import)))
-    (if (and result
-            (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string))
-       (setcar result
-               (append (list (cons 'reason
-                                   (string-to-number
-                                    (match-string 1 string))))
-                       (if (match-beginning 2)
-                           (list (cons 'fingerprint
-                                       (match-string 3 string))))
-                       (car result))))))
+  (if (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string)
+      (let ((reason (string-to-number (match-string 1 string))))
+       (epg-context-set-result-for
+        context 'import-status
+        (cons (epg-make-import-status (if (match-beginning 2)
+                                          (match-string 3 string))
+                                      nil
+                                      (/= (logand reason 1) 0)
+                                      (/= (logand reason 2) 0)
+                                      (/= (logand reason 4) 0)
+                                      (/= (logand reason 8) 0)
+                                      (/= (logand reason 16) 0))
+              (epg-context-result-for context 'import-status))))))
 
 (defun epg--status-IMPORT_PROBLEM (context string)
   (if (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string)
       (epg-context-set-result-for
-       context 'error
-       (cons (cons 'import-problem
-                  (append (list (cons 'reason
-                                      (string-to-number
-                                       (match-string 1 string))))
-                          (if (match-beginning 2)
-                              (list (cons 'fingerprint
-                                          (match-string 3 string))))))
-            (epg-context-result-for context 'error)))))
+       context 'import-status
+       (cons (epg-make-import-status
+             (if (match-beginning 2)
+                 (match-string 3 string))
+             (string-to-number (match-string 1 string)))
+            (epg-context-result-for context 'import-status)))))
+
+(defun epg--status-IMPORT_RES (context string)
+  (when (string-match "\\`\\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \
+\\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\) \
+\\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" string)
+    (epg-context-set-result-for
+     context 'import
+     (epg-make-import-result (string-to-number (match-string 1 string))
+                            (string-to-number (match-string 2 string))
+                            (string-to-number (match-string 3 string))
+                            (string-to-number (match-string 4 string))
+                            (string-to-number (match-string 5 string))
+                            (string-to-number (match-string 6 string))
+                            (string-to-number (match-string 7 string))
+                            (string-to-number (match-string 8 string))
+                            (string-to-number (match-string 9 string))
+                            (string-to-number (match-string 10 string))
+                            (string-to-number (match-string 11 string))
+                            (string-to-number (match-string 12 string))
+                            (string-to-number (match-string 13 string))
+                            (epg-context-result-for context 'import-status)))
+    (epg-context-set-result-for context 'import-status nil)))
 
 (defun epg-passphrase-callback-function (context key-id handback)
   (if (eq key-id 'SYM)
@@ -1539,23 +1800,29 @@ You can then use `write-region' to write new data into the file."
   (defun epg--clear-string (string)
     (fillarray string 0)))
 
-(defun epg--args-from-signature-notations (notations)
+(if (fboundp 'encode-coding-string)
+    (defalias 'epg--encode-coding-string 'encode-coding-string)
+  (defalias 'epg--encode-coding-string 'identity))
+
+(defun epg--args-from-sig-notations (notations)
   (apply #'nconc
         (mapcar
          (lambda (notation)
-           (if (and (epg-signature-notation-name notation)
-                    (not (epg-signature-notation-human-readable notation)))
+           (if (and (epg-sig-notation-name notation)
+                    (not (epg-sig-notation-human-readable notation)))
                (error "Unreadable"))
-           (if (epg-signature-notation-name notation)
+           (if (epg-sig-notation-name notation)
                (list "--sig-notation"
-                     (if (epg-signature-notation-critical notation)
-                         (concat "!" (epg-signature-notation-name notation)
-                                 "=" (epg-signature-notation-value notation))
-                       (concat (epg-signature-notation-name notation)
-                               "=" (epg-signature-notation-value notation))))
+                     (if (epg-sig-notation-critical notation)
+                         (concat "!" (epg-sig-notation-name notation)
+                                 "=" (epg-sig-notation-value notation))
+                       (concat (epg-sig-notation-name notation)
+                               "=" (epg-sig-notation-value notation))))
              (list "--sig-policy-url"
-                   (epg-signature-notation-value notation))))
-         notations))
+                   (if (epg-sig-notation-critical notation)
+                       (concat "!" (epg-sig-notation-value notation))
+                     (epg-sig-notation-value notation)))))
+         notations)))
 
 ;;;###autoload
 (defun epg-cancel (context)
@@ -1568,7 +1835,7 @@ You can then use `write-region' to write new data into the file."
               (epg-context-result-for epg-context 'error)))))
   (if (eq (process-status (epg-context-process context)) 'run)
       (delete-process (epg-context-process context))))
-  
+
 ;;;###autoload
 (defun epg-start-decrypt (context cipher)
   "Initiate a decrypt operation on CIPHER.
@@ -1588,6 +1855,19 @@ If you are unsure, use synchronous version of this function
   (unless (eq (epg-context-protocol context) 'CMS)
     (epg-wait-for-status context '("BEGIN_DECRYPTION"))))
 
+(defun epg--check-error-for-decrypt (context)
+  (if (epg-context-result-for context 'decryption-failed)
+      (signal 'epg-error (list "Decryption failed")))
+  (if (epg-context-result-for context 'no-secret-key)
+      (signal 'epg-error
+             (list "No secret key"
+                   (epg-context-result-for context 'no-secret-key))))
+    (unless (epg-context-result-for context 'decryption-okay)
+      (let* ((error (epg-context-result-for context 'error)))
+       (if (assq 'no-data error)
+           (signal 'epg-error (list "No data")))
+       (signal 'epg-error (list "Can't decrypt" error)))))
+
 ;;;###autoload
 (defun epg-decrypt-file (context cipher plain)
   "Decrypt a file CIPHER and store the result to a file PLAIN.
@@ -1600,9 +1880,7 @@ If PLAIN is nil, it returns the result as a string."
                                       (epg--make-temp-file "epg-output")))
        (epg-start-decrypt context (epg-make-data-from-file cipher))
        (epg-wait-for-completion context)
-       (if (epg-context-result-for context 'error)
-           (error "Decrypt failed: %S"
-                  (epg-context-result-for context 'error)))
+       (epg--check-error-for-decrypt context)
        (unless plain
          (epg-read-output context)))
     (unless plain
@@ -1621,9 +1899,7 @@ If PLAIN is nil, it returns the result as a string."
                                       (epg--make-temp-file "epg-output"))
          (epg-start-decrypt context (epg-make-data-from-file input-file))
          (epg-wait-for-completion context)
-         (if (epg-context-result-for context 'error)
-             (error "Decrypt failed: %S"
-                    (epg-context-result-for context 'error)))
+         (epg--check-error-for-decrypt context)
          (epg-read-output context))
       (epg-delete-output-file context)
       (if (file-exists-p input-file)
@@ -1758,8 +2034,8 @@ If you are unsure, use synchronous version of this function
                                     (epg-sub-key-id
                                      (car (epg-key-sub-key-list signer)))))
                             (epg-context-signers context)))
-                    (epg--args-from-signature-notations
-                     (epg-context-signature-notations context))
+                    (epg--args-from-sig-notations
+                     (epg-context-sig-notations context))
                     (if (epg-data-file plain)
                         (list "--" (epg-data-file plain)))))
   ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed.
@@ -1847,8 +2123,8 @@ If you are unsure, use synchronous version of this function
                                                signer)))))
                                 (epg-context-signers context))))
                     (if sign
-                        (epg--args-from-signature-notations
-                         (epg-context-signature-notations context)))
+                        (epg--args-from-sig-notations
+                         (epg-context-sig-notations context)))
                     (apply #'nconc
                            (mapcar
                             (lambda (recipient)
@@ -1948,7 +2224,7 @@ If you are unsure, use synchronous version of this function
   "Extract public KEYS."
   (unwind-protect
       (progn
-       (if keys
+       (if file
            (epg-context-set-output-file context file)
          (epg-context-set-output-file context
                                       (epg--make-temp-file "epg-output")))
@@ -2054,11 +2330,11 @@ If you are unsure, use synchronous version of this function
   (epg--start context (cons (if allow-secret
                               "--delete-secret-key"
                             "--delete-key")
-                          (mapcar
-                           (lambda (key)
-                             (epg-sub-key-id
-                              (car (epg-key-sub-key-list key))))
-                           keys))))
+                           (mapcar
+                            (lambda (key)
+                              (epg-sub-key-id
+                               (car (epg-key-sub-key-list key))))
+                            keys))))
 
 ;;;###autoload
 (defun epg-delete-keys (context keys &optional allow-secret)
@@ -2067,9 +2343,13 @@ If you are unsure, use synchronous version of this function
       (progn
        (epg-start-delete-keys context keys allow-secret)
        (epg-wait-for-completion context)
-       (if (epg-context-result-for context 'error)
-           (error "Delete keys failed: %S"
-                  (epg-context-result-for context 'error))))
+       (let ((entry (assq 'delete-problem
+                          (epg-context-result-for context 'error))))
+         (if entry
+             (if (setq entry (assq (cdr entry)
+                                   epg-delete-problem-reason-alist))
+                 (error "Delete keys failed: %s" (cdr entry))
+               (error "Delete keys failed")))))
     (epg-reset context)))
 
 ;;;###autoload
@@ -2091,6 +2371,7 @@ If you are unsure, use synchronous version of this function
                              (epg-sub-key-id
                               (car (epg-key-sub-key-list key))))
                            keys))))
+(make-obsolete 'epg-start-sign-keys "Do not use.")
 
 ;;;###autoload
 (defun epg-sign-keys (context keys &optional local)
@@ -2103,6 +2384,7 @@ If you are unsure, use synchronous version of this function
            (error "Sign keys failed: %S"
                   (epg-context-result-for context 'error))))
     (epg-reset context)))
+(make-obsolete 'epg-sign-keys "Do not use.")
 
 ;;;###autoload
 (defun epg-start-generate-key (context parameters)