* epg-config.el (epg-passphrase-coding-system): Renamed from
[elisp/epg.git] / epg.el
diff --git a/epg.el b/epg.el
index 13156bc..06a10ed 100644 (file)
--- a/epg.el
+++ b/epg.el
 
 ;;; Code:
 
-(defgroup epg ()
-  "The EasyPG Library"
-  :group 'emacs)
-
-(defcustom epg-gpg-program "gpg"
-  "The `gpg' executable."
-  :group 'epg
-  :type 'string)
-
-(defcustom epg-gpgsm-program "gpgsm"
-  "The `gpgsm' executable."
-  :group 'epg
-  :type 'string)
-
-(defconst epg-version-number "0.0.1")
+(require 'epg-config)
 
 (defvar epg-user-id nil
   "GnuPG ID of your default identity.")
   "An alist mapping from key ID to user ID.")
 
 (defvar epg-read-point nil)
+(defvar epg-process-filter-running nil)
 (defvar epg-pending-status-list nil)
 (defvar epg-key-id nil)
 (defvar epg-context nil)
-(defvar epg-debug nil)
 (defvar epg-debug-buffer nil)
 
 ;; from gnupg/include/cipher.h
@@ -759,15 +745,14 @@ This function is for internal use only."
           ((eq (epg-signature-status signature) 'no-pubkey)
            "No public key for "))
      (epg-signature-key-id signature)
-     " "
      (if user-id
-        (concat (if (stringp user-id)
+        (concat " "
+                (if (stringp user-id)
                     user-id
-                  (epg-decode-dn user-id))
-                " ")
+                  (epg-decode-dn user-id)))
        "")
      (if (epg-signature-validity signature)
-        (format "(trust %s)"  (epg-signature-validity signature))
+        (format " (trust %s)"  (epg-signature-validity signature))
        ""))))
 
 (defun epg-verify-result-to-string (verify-result)
@@ -802,7 +787,10 @@ This function is for internal use only."
               epg-gpg-program)))
   (let* ((args (append (list "--no-tty"
                             "--status-fd" "1"
-                            "--yes")
+                            "--yes"
+                            "--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"))
                       (if (epg-context-armor context) '("--armor"))
@@ -829,6 +817,8 @@ This function is for internal use only."
     (with-current-buffer buffer
       (make-local-variable 'epg-read-point)
       (setq epg-read-point (point-min))
+      (make-local-variable 'epg-process-filter-running)
+      (setq epg-process-filter-running nil)
       (make-local-variable 'epg-pending-status-list)
       (setq epg-pending-status-list nil)
       (make-local-variable 'epg-key-id)
@@ -861,21 +851,26 @@ This function is for internal use only."
        (set-buffer (process-buffer process))
        (goto-char (point-max))
        (insert input)
-       (goto-char epg-read-point)
-       (beginning-of-line)
-       (while (looking-at ".*\n")      ;the input line finished
-         (save-excursion
-           (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)")
-               (let* ((status (match-string 1))
-                      (string (match-string 2))
-                      (symbol (intern-soft (concat "epg--status-" status))))
-                 (if (member status epg-pending-status-list)
-                     (setq epg-pending-status-list nil))
-                 (if (and symbol
-                          (fboundp symbol))
-                     (funcall symbol process string)))))
-         (forward-line))
-       (setq epg-read-point (point)))))
+       (unless epg-process-filter-running
+         (unwind-protect
+             (progn
+               (setq epg-process-filter-running t)
+               (goto-char epg-read-point)
+               (beginning-of-line)
+               (while (looking-at ".*\n") ;the input line finished
+                 (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)")
+                     (let* ((status (match-string 1))
+                            (string (match-string 2))
+                            (symbol (intern-soft (concat "epg--status-"
+                                                         status))))
+                       (if (member status epg-pending-status-list)
+                           (setq epg-pending-status-list nil))
+                       (if (and symbol
+                                (fboundp symbol))
+                           (funcall symbol epg-context string))))
+                 (forward-line)
+                 (setq epg-read-point (point))))
+           (setq epg-process-filter-running nil))))))
 
 (defun epg-read-output (context)
   "Read the output file CONTEXT and return the content as a string."
@@ -913,7 +908,7 @@ This function is for internal use only."
           (file-exists-p (epg-context-output-file context)))
       (delete-file (epg-context-output-file context))))
 
-(defun epg--status-USERID_HINT (process string)
+(defun epg--status-USERID_HINT (context string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
       (let* ((key-id (match-string 1 string))
             (user-id (match-string 2 string))
@@ -923,94 +918,107 @@ This function is for internal use only."
          (setq epg-user-id-alist (cons (cons key-id user-id)
                                        epg-user-id-alist))))))
 
-(defun epg--status-NEED_PASSPHRASE (process string)
+(defun epg--status-NEED_PASSPHRASE (context string)
   (if (string-match "\\`\\([^ ]+\\)" string)
       (setq epg-key-id (match-string 1 string))))
 
-(defun epg--status-NEED_PASSPHRASE_SYM (process string)
+(defun epg--status-NEED_PASSPHRASE_SYM (context string)
   (setq epg-key-id 'SYM))
 
-(defun epg--status-NEED_PASSPHRASE_PIN (process string)
+(defun epg--status-NEED_PASSPHRASE_PIN (context string)
   (setq epg-key-id 'PIN))
 
-(defun epg--status-GET_HIDDEN (process string)
+(defun epg--status-GET_HIDDEN (context string)
   (if (and epg-key-id
           (string-match "\\`passphrase\\." string))
       (let (inhibit-quit
            passphrase
-           passphrase-with-new-line)
+           passphrase-with-new-line
+           encoded-passphrase-with-new-line)
        (unwind-protect
            (condition-case nil
                (progn
                  (setq passphrase
                        (funcall
-                        (if (consp (epg-context-passphrase-callback
-                                    epg-context))
-                            (car (epg-context-passphrase-callback
-                                  epg-context))
-                          (epg-context-passphrase-callback epg-context))
-                        epg-context
+                        (if (consp (epg-context-passphrase-callback context))
+                            (car (epg-context-passphrase-callback context))
+                          (epg-context-passphrase-callback context))
+                        context
                         epg-key-id
-                        (if (consp (epg-context-passphrase-callback
-                                    epg-context))
-                            (cdr (epg-context-passphrase-callback
-                                  epg-context)))))
+                        (if (consp (epg-context-passphrase-callback context))
+                            (cdr (epg-context-passphrase-callback context)))))
                  (when passphrase
                    (setq passphrase-with-new-line (concat passphrase "\n"))
-                   (fillarray passphrase 0)
+                   (epg--clear-string passphrase)
                    (setq passphrase nil)
-                   (process-send-string process passphrase-with-new-line)))
+                   (if epg-passphrase-coding-system
+                       (progn
+                         (setq encoded-passphrase-with-new-line
+                               (encode-coding-string
+                                passphrase-with-new-line
+                                epg-passphrase-coding-system))
+                         (epg--clear-string passphrase-with-new-line)
+                         (setq passphrase-with-new-line nil))
+                     (setq encoded-passphrase-with-new-line
+                           passphrase-with-new-line
+                           passphrase-with-new-line nil))
+                   (process-send-string (epg-context-process context)
+                                        encoded-passphrase-with-new-line)))
              (quit
               (epg-context-set-result-for
-               epg-context 'error
+               context 'error
                (cons '(quit)
-                     (epg-context-result-for epg-context 'error)))
-              (delete-process process)))
+                     (epg-context-result-for context 'error)))
+              (delete-process (epg-context-process context))))
          (if passphrase
-             (fillarray passphrase 0))
+             (epg--clear-string passphrase))
          (if passphrase-with-new-line
-             (fillarray passphrase-with-new-line 0))))))
+             (epg--clear-string passphrase-with-new-line))
+         (if encoded-passphrase-with-new-line
+             (epg--clear-string encoded-passphrase-with-new-line))))))
 
-(defun epg--status-GET_BOOL (process string)
+(defun epg--status-GET_BOOL (context string)
   (let ((entry (assoc string epg-prompt-alist))
        inhibit-quit)
     (condition-case nil
       (if (y-or-n-p (if entry (cdr entry) (concat string "? ")))
-         (process-send-string process "y\n")
-       (process-send-string process "n\n"))
+         (process-send-string (epg-context-process context) "y\n")
+       (process-send-string (epg-context-process context) "n\n"))
       (quit
        (epg-context-set-result-for
-       epg-context 'error
+       context 'error
        (cons '(quit)
-             (epg-context-result-for epg-context 'error)))
-       (delete-process process)))))
+             (epg-context-result-for context 'error)))
+       (delete-process (epg-context-process context))))))
 
-(defun epg--status-GET_LINE (process string)
+(defun epg--status-GET_LINE (context string)
   (let ((entry (assoc string epg-prompt-alist))
        inhibit-quit)
     (condition-case nil
-       (process-send-string
-        process
-        (concat (read-string (if entry (cdr entry) (concat string ": ")))
-                "\n"))
+       (process-send-string (epg-context-process context)
+                            (concat (read-string
+                                     (if entry
+                                         (cdr entry)
+                                       (concat string ": ")))
+                                    "\n"))
       (quit
        (epg-context-set-result-for
-       epg-context 'error
+       context 'error
        (cons '(quit)
-             (epg-context-result-for epg-context 'error)))
-       (delete-process process)))))
+             (epg-context-result-for context 'error)))
+       (delete-process (epg-context-process context))))))
 
-(defun epg--status-*SIG (status string)
+(defun epg--status-*SIG (context status string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
       (let* ((key-id (match-string 1 string))
             (user-id (match-string 2 string))
             (entry (assoc key-id epg-user-id-alist)))
        (epg-context-set-result-for
-        epg-context
+        context
         'verify
         (cons (epg-make-signature status key-id)
-              (epg-context-result-for epg-context 'verify)))
-       (if (eq (epg-context-protocol epg-context) 'CMS)
+              (epg-context-result-for context 'verify)))
+       (if (eq (epg-context-protocol context) 'CMS)
            (condition-case nil
                (setq user-id (epg-dn-from-string user-id))
              (error)))
@@ -1019,38 +1027,48 @@ This function is for internal use only."
          (setq epg-user-id-alist
                (cons (cons key-id user-id) epg-user-id-alist))))
     (epg-context-set-result-for
-     epg-context
+     context
      'verify
      (cons (epg-make-signature status)
-          (epg-context-result-for epg-context 'verify)))))
+          (epg-context-result-for context 'verify)))))
 
-(defun epg--status-GOODSIG (process string)
-  (epg--status-*SIG 'good string))
+(defun epg--status-GOODSIG (context string)
+  (epg--status-*SIG context 'good string))
 
-(defun epg--status-EXPSIG (process string)
-  (epg--status-*SIG 'expired string))
+(defun epg--status-EXPSIG (context string)
+  (epg--status-*SIG context 'expired string))
 
-(defun epg--status-EXPKEYSIG (process string)
-  (epg--status-*SIG 'expired-key string))
+(defun epg--status-EXPKEYSIG (context string)
+  (epg--status-*SIG context 'expired-key string))
 
-(defun epg--status-REVKEYSIG (process string)
-  (epg--status-*SIG 'revoked-key string))
+(defun epg--status-REVKEYSIG (context string)
+  (epg--status-*SIG context 'revoked-key string))
 
-(defun epg--status-BADSIG (process string)
-  (epg--status-*SIG 'bad string))
+(defun epg--status-BADSIG (context string)
+  (epg--status-*SIG context 'bad string))
 
-(defun epg--status-NO_PUBKEY (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-NO_PUBKEY (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
-            (eq (epg-signature-status signature) 'error))
+            (eq (epg-signature-status signature) 'error)
+            (equal (epg-signature-key-id signature) string))
        (epg-signature-set-status signature 'no-pubkey))))
 
-(defun epg--status-ERRSIG (process string)
+(defun epg--time-from-seconds (seconds)
+  (let ((number-seconds (string-to-number (concat seconds ".0"))))
+    (cons (floor (/ number-seconds 65536))
+         (floor (mod number-seconds 65536)))))
+
+(defun epg--status-ERRSIG (context string)
   (if (string-match "\\`\\([^ ]+\\) \\([0-9]+\\) \\([0-9]+\\) \
 \\([0-9A-Fa-f][0-9A-Fa-f]\\) \\([^ ]+\\) \\([0-9]+\\)"
                    string)
       (let ((signature (epg-make-signature 'error)))
-       (epg-context-set-result-for epg-context 'verify (list signature))
+       (epg-context-set-result-for
+        context
+        'verify
+        (cons signature
+              (epg-context-result-for context 'verify)))
        (epg-signature-set-key-id
         signature
         (match-string 1 string))
@@ -1065,10 +1083,10 @@ This function is for internal use only."
         (string-to-number (match-string 4 string) 16))
        (epg-signature-set-creation-time
         signature
-        (match-string 5 string)))))
+        (epg--time-from-seconds (match-string 5 string))))))
 
-(defun epg--status-VALIDSIG (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-VALIDSIG (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (when (and signature
               (eq (epg-signature-status signature) 'good)
               (string-match "\\`\\([^ ]+\\) [^ ]+ \\([^ ]+\\) \\([^ ]+\\) \
@@ -1080,10 +1098,10 @@ This function is for internal use only."
        (match-string 1 string))
       (epg-signature-set-creation-time
        signature
-       (match-string 2 string))
+       (epg--time-from-seconds (match-string 2 string)))
       (epg-signature-set-expiration-time
        signature
-       (match-string 3 string))
+       (epg--time-from-seconds (match-string 3 string)))
       (epg-signature-set-version
        signature
        (string-to-number (match-string 4 string)))
@@ -1097,141 +1115,142 @@ This function is for internal use only."
        signature
        (string-to-number (match-string 7 string) 16)))))
 
-(defun epg--status-TRUST_UNDEFINED (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-TRUST_UNDEFINED (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
        (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 (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
        (epg-signature-set-validity signature 'never))))
 
-(defun epg--status-TRUST_MARGINAL (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-TRUST_MARGINAL (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'marginal))
        (epg-signature-set-validity signature 'marginal))))
 
-(defun epg--status-TRUST_FULLY (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-TRUST_FULLY (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
        (epg-signature-set-validity signature 'full))))
 
-(defun epg--status-TRUST_ULTIMATE (process string)
-  (let ((signature (car (epg-context-result-for epg-context 'verify))))
+(defun epg--status-TRUST_ULTIMATE (context string)
+  (let ((signature (car (epg-context-result-for context 'verify))))
     (if (and signature
             (eq (epg-signature-status signature) 'good))
        (epg-signature-set-validity signature 'ultimate))))
 
-(defun epg--status-PROGRESS (process string)
+(defun epg--status-PROGRESS (context string)
   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
                    string)
-      (funcall (if (consp (epg-context-progress-callback epg-context))
-                  (car (epg-context-progress-callback epg-context))
-                (epg-context-progress-callback epg-context))
-              epg-context
+      (funcall (if (consp (epg-context-progress-callback context))
+                  (car (epg-context-progress-callback context))
+                (epg-context-progress-callback context))
+              context
               (match-string 1 string)
               (match-string 2 string)
               (string-to-number (match-string 3 string))
               (string-to-number (match-string 4 string))
-              (if (consp (epg-context-progress-callback epg-context))
-                  (cdr (epg-context-progress-callback epg-context))))))
+              (if (consp (epg-context-progress-callback context))
+                  (cdr (epg-context-progress-callback context))))))
 
-(defun epg--status-DECRYPTION_FAILED (process string)
+(defun epg--status-DECRYPTION_FAILED (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons '(decryption-failed)
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-NODATA (process string)
+(defun epg--status-NODATA (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons (list 'no-data (cons 'reason (string-to-number string)))
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-UNEXPECTED (process string)
+(defun epg--status-UNEXPECTED (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons (list 'unexpected (cons 'reason (string-to-number string)))
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-KEYEXPIRED (process string)
+(defun epg--status-KEYEXPIRED (context string)
   (epg-context-set-result-for
-   epg-context 'error
-   (cons (list 'key-expired (cons 'expiration-time string))
-        (epg-context-result-for epg-context 'error))))
+   context 'error
+   (cons (list 'key-expired (cons 'expiration-time
+                                 (epg--time-from-seconds string)))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-KEYREVOKED (process string)
+(defun epg--status-KEYREVOKED (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons '(key-revoked)
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-BADARMOR (process string)
+(defun epg--status-BADARMOR (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons '(bad-armor)
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-INV_RECP (process string)
+(defun epg--status-INV_RECP (context string)
   (if (string-match "\\`\\([0-9]+\\) \\(.*\\)" string)
       (epg-context-set-result-for
-       epg-context 'error
+       context 'error
        (cons (list 'invalid-recipient
                   (cons 'reason
                         (string-to-number (match-string 1 string)))
                   (cons 'requested-recipient
                         (match-string 2 string)))
-            (epg-context-result-for epg-context 'error)))))
+            (epg-context-result-for context 'error)))))
 
-(defun epg--status-NO_RECP (process string)
+(defun epg--status-NO_RECP (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons '(no-recipients)
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-DELETE_PROBLEM (process string)
+(defun epg--status-DELETE_PROBLEM (context string)
   (if (string-match "\\`\\([0-9]+\\)" string)
       (epg-context-set-result-for
-       epg-context 'error
+       context 'error
        (cons (list 'delete-problem
                   (cons 'reason (string-to-number (match-string 1 string))))
-            (epg-context-result-for epg-context 'error)))))
+            (epg-context-result-for context 'error)))))
 
-(defun epg--status-SIG_CREATED (process string)
+(defun epg--status-SIG_CREATED (context string)
   (if (string-match "\\`\\([DCS]\\) \\([0-9]+\\) \\([0-9]+\\) \
 \\([0-9A-Fa-F][0-9A-Fa-F]\\) \\(.*\\) " string)
       (epg-context-set-result-for
-       epg-context 'sign
+       context 'sign
        (cons (epg-make-new-signature
              (cdr (assq (aref (match-string 1 string) 0)
                         epg-new-signature-type-alist))
              (string-to-number (match-string 2 string))
              (string-to-number (match-string 3 string))
              (string-to-number (match-string 4 string) 16)
-             (match-string 5 string)
+             (epg--time-from-seconds (match-string 5 string))
              (substring string (match-end 0)))
-            (epg-context-result-for epg-context 'sign)))))
+            (epg-context-result-for context 'sign)))))
 
-(defun epg--status-KEY_CREATED (process string)
+(defun epg--status-KEY_CREATED (context string)
   (if (string-match "\\`\\([BPS]\\) \\([^ ]+\\)" string)
       (epg-context-set-result-for
-       epg-context 'generate-key
+       context 'generate-key
        (cons (list (cons 'type (string-to-char (match-string 1 string)))
                   (cons 'fingerprint (match-string 2 string)))
-            (epg-context-result-for epg-context 'generate-key)))))
+            (epg-context-result-for context 'generate-key)))))
 
-(defun epg--status-KEY_NOT_CREATED (process string)
+(defun epg--status-KEY_NOT_CREATED (context string)
   (epg-context-set-result-for
-   epg-context 'error
+   context 'error
    (cons '(key-not-created)
-        (epg-context-result-for epg-context 'error))))
+        (epg-context-result-for context 'error))))
 
-(defun epg--status-IMPORTED (process string)
+(defun epg--status-IMPORTED (context string)
   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
       (let* ((key-id (match-string 1 string))
             (user-id (match-string 2 string))
@@ -1241,13 +1260,13 @@ This function is for internal use only."
          (setq epg-user-id-alist (cons (cons key-id user-id)
                                        epg-user-id-alist)))
        (epg-context-set-result-for
-        epg-context 'import
+        context 'import
         (cons (list (cons 'key-id key-id)
                     (cons 'user-id user-id))
-              (epg-context-result-for epg-context 'import))))))
+              (epg-context-result-for context 'import))))))
 
-(defun epg--status-IMPORT_OK (process string)
-  (let ((result (epg-context-result-for epg-context 'import)))
+(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
@@ -1259,10 +1278,10 @@ This function is for internal use only."
                                        (match-string 3 string))))
                        (car result))))))
 
-(defun epg--status-IMPORT_PROBLEM (process string)
+(defun epg--status-IMPORT_PROBLEM (context string)
   (if (string-match "\\`\\([0-9]+\\)\\( \\(.+\\)\\)?" string)
       (epg-context-set-result-for
-       epg-context 'error
+       context 'error
        (cons (cons 'import-problem
                   (append (list (cons 'reason
                                       (string-to-number
@@ -1270,7 +1289,7 @@ This function is for internal use only."
                           (if (match-beginning 2)
                               (list (cons 'fingerprint
                                           (match-string 3 string))))))
-            (epg-context-result-for epg-context 'error)))))
+            (epg-context-result-for context 'error)))))
 
 (defun epg-passphrase-callback-function (context key-id handback)
   (if (eq key-id 'SYM)
@@ -1286,30 +1305,12 @@ This function is for internal use only."
 
 (defun epg-progress-callback-function (context what char current total
                                               handback)
-  (message "%s: %d%%/%d%%" what current total))
-
-(defun epg-configuration ()
-  "Return a list of internal configuration parameters of `epg-gpg-program'."
-  (let (config type)
-    (with-temp-buffer
-      (apply #'call-process epg-gpg-program nil (list t nil) nil
-            '("--with-colons" "--list-config"))
-      (goto-char (point-min))
-      (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t)
-       (setq type (intern (match-string 1))
-             config (cons (cons type
-                                (if (memq type
-                                          '(pubkey cipher digest compress))
-                                    (mapcar #'string-to-number
-                                            (delete "" (split-string
-                                                        (match-string 2)
-                                                        ";")))
-                                  (match-string 2)))
-                          config))))
-    config))
+  (message "%s: %d/%d" what current total))
 
 (defun epg--list-keys-1 (context name mode)
-  (let ((args (append (list "--with-colons" "--no-greeting" "--batch"
+  (let ((args (append (if epg-gpg-home-directory
+                         (list "--homedir" epg-gpg-home-directory))
+                     (list "--with-colons" "--no-greeting" "--batch"
                            "--with-fingerprint"
                            "--with-fingerprint"
                            (if (memq mode '(t secret))
@@ -1351,8 +1352,8 @@ This function is for internal use only."
    (string-to-number (aref line 3))
    (string-to-number (aref line 2))
    (aref line 4)
-   (aref line 5)
-   (aref line 6)))
+   (epg--time-from-seconds (aref line 5))
+   (epg--time-from-seconds (aref line 6))))
 
 ;;;###autoload
 (defun epg-list-keys (context &optional name mode)
@@ -1407,8 +1408,8 @@ signatures should be included."
                          epg-key-validity-alist)))
           (string-to-number (aref (car lines) 3))
           (aref (car lines) 4)
-          (aref (car lines) 5)
-          (aref (car lines) 6)
+          (epg--time-from-seconds (aref (car lines) 5))
+          (epg--time-from-seconds (aref (car lines) 6))
           (aref (car lines) 9)
           (string-to-number (aref (car lines) 10) 16)
           (eq (aref (aref (car lines) 10) 2) ?x))
@@ -1486,6 +1487,11 @@ You can then use `write-region' to write new data into the file."
             (file-directory-p tempdir)
             (delete-directory tempdir))))))
 
+(if (fboundp 'clear-string)
+    (defalias 'epg--clear-string 'clear-string)
+  (defun epg--clear-string (string)
+    (fillarray string 0)))
+
 ;;;###autoload
 (defun epg-cancel (context)
   (if (buffer-live-p (process-buffer (epg-context-process context)))
@@ -1764,9 +1770,13 @@ If you are unsure, use synchronous version of this function
                     (if sign
                         (cons "--sign"
                               (apply #'nconc
-                                     (mapcar (lambda (signer)
-                                               (list "-u" signer))
-                                             (epg-context-signers context)))))
+                                     (mapcar
+                                      (lambda (signer)
+                                        (list "-u"
+                                              (epg-sub-key-id
+                                               (car (epg-key-sub-key-list
+                                                     signer)))))
+                                      (epg-context-signers context)))))
                     (apply #'nconc
                            (mapcar
                             (lambda (recipient)
@@ -1898,7 +1908,9 @@ If you are unsure, use synchronous version of this function
 `epg-import-keys-from-file' or `epg-import-keys-from-string' instead."
   (epg-context-set-operation context 'import-keys)
   (epg-context-set-result context nil)
-  (epg--start context (list "--import" (epg-data-file keys)))
+  (epg--start context (if (epg-data-file keys)
+                         (list "--import" (epg-data-file keys))
+                       (list "--import")))
   (when (epg-data-string keys)
     (if (eq (process-status (epg-context-process context)) 'run)
        (process-send-string (epg-context-process context)