X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=epg.el;h=3ba189ff49cecead62558434214b246b13868f3c;hb=5944a44f16964313efa58244a1ad0e62f32237fb;hp=3c183a4bbd4b3f7ada1fb84fc087eb209cea7ce9;hpb=aa49ed0dd74477e4f8342d1fe06bf892bebe7a4b;p=elisp%2Fepg.git diff --git a/epg.el b/epg.el index 3c183a4..3ba189f 100644 --- a/epg.el +++ b/epg.el @@ -46,6 +46,7 @@ (defvar epg-key-id nil) (defvar epg-context nil) (defvar epg-debug nil) +(defvar epg-debug-buffer nil) ;; from gnupg/include/cipher.h (defconst epg-cipher-algorithm-alist @@ -405,11 +406,25 @@ This function is for internal use only." (setcdr entry value) (epg-context-set-result context (cons (cons name value) result))))) +(defun epg-signature-to-string (signature) + (format "%s signature from %s %s%s" + (capitalize (symbol-name (epg-signature-status signature))) + (epg-signature-key-id signature) + (epg-signature-user-id signature) + (if (epg-signature-validity signature) + (format " (trust %s)" + (epg-signature-validity signature)) + ""))) + +(defun epg-verify-result-to-string (verify-result) + (mapconcat #'epg-signature-to-string verify-result "\n")) + (defun epg-start (context args) "Start `epg-gpg-program' in a subprocess with given ARGS." (let* ((args (append (list "--no-tty" "--status-fd" "1" - "--command-fd" "0") + "--command-fd" "0" + "--yes") (if (epg-context-armor context) '("--armor")) (if (epg-context-textmode context) '("--textmode")) (if (epg-context-output-file context) @@ -422,7 +437,9 @@ This function is for internal use only." process) (if epg-debug (save-excursion - (set-buffer (get-buffer-create " *epg-debug*")) + (unless epg-debug-buffer + (setq epg-debug-buffer (generate-new-buffer " *epg-debug*"))) + (set-buffer epg-debug-buffer) (goto-char (point-max)) (insert (format "%s %s\n" epg-gpg-program (mapconcat #'identity args " "))))) @@ -447,7 +464,9 @@ This function is for internal use only." (defun epg-process-filter (process input) (if epg-debug (save-excursion - (set-buffer (get-buffer-create " *epg-debug*")) + (unless epg-debug-buffer + (setq epg-debug-buffer (generate-new-buffer " *epg-debug*"))) + (set-buffer epg-debug-buffer) (goto-char (point-max)) (insert input))) (if (buffer-live-p (process-buffer process)) @@ -467,12 +486,7 @@ This function is for internal use only." (setq epg-pending-status-list nil)) (if (and symbol (fboundp symbol)) - (funcall symbol process string)) - (condition-case nil - (run-hook-with-args-until-success - (intern (concat "epg-after-status-" status "-function")) - string) - (error))))) + (funcall symbol process string))))) (forward-line)) (setq epg-read-point (point))))) @@ -494,15 +508,16 @@ This function is for internal use only." epg-pending-status-list) (accept-process-output (epg-context-process context) 1)))) -(defun epg-wait-for-completion (context &optional no-eof) - (if (and (not no-eof) - (eq (process-status (epg-context-process context)) 'run)) - (process-send-eof (epg-context-process context))) +(defun epg-wait-for-completion (context) (while (eq (process-status (epg-context-process context)) 'run) ;; We can't use accept-process-output instead of sit-for here ;; because it may cause an interrupt during the sentinel execution. (sit-for 0.1))) +(defun epg-flush (context) + (if (eq (process-status (epg-context-process context)) 'run) + (process-send-eof (epg-context-process context)))) + (defun epg-reset (context) (if (and (epg-context-process context) (buffer-live-p (process-buffer (epg-context-process context)))) @@ -535,22 +550,26 @@ This function is for internal use only." (setq epg-key-id 'PIN)) (defun epg-status-GET_HIDDEN (process string) - (let ((passphrase - (funcall (if (consp (epg-context-passphrase-callback epg-context)) - (car (epg-context-passphrase-callback epg-context)) - (epg-context-passphrase-callback epg-context)) - (if (consp (epg-context-passphrase-callback epg-context)) - (cdr (epg-context-passphrase-callback epg-context))))) - string) - (if passphrase - (unwind-protect - (progn - (setq string (concat passphrase "\n")) - (fillarray passphrase 0) - (setq passphrase nil) - (process-send-string process string)) - (if string - (fillarray string 0)))))) + (if (and epg-key-id + (string-match "\\`passphrase\\." string)) + (let ((passphrase + (funcall + (if (consp (epg-context-passphrase-callback epg-context)) + (car (epg-context-passphrase-callback epg-context)) + (epg-context-passphrase-callback epg-context)) + epg-key-id + (if (consp (epg-context-passphrase-callback epg-context)) + (cdr (epg-context-passphrase-callback epg-context))))) + string) + (if passphrase + (unwind-protect + (progn + (setq string (concat passphrase "\n")) + (fillarray passphrase 0) + (setq passphrase nil) + (process-send-string process string)) + (if string + (fillarray string 0))))))) (defun epg-status-GET_BOOL (process string) (let ((entry (assoc string epg-prompt-alist))) @@ -721,16 +740,31 @@ This function is for internal use only." (cons (cons 'delete-problem (string-to-number (match-string 1 string))) (epg-context-result-for epg-context 'error))))) -(defun epg-passphrase-callback-function (handback) +(defun epg-status-SIG_CREATED (process 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 + (cons (list (cons 'type (string-to-char (match-string 1 string))) + (cons 'pubkey-algorithm + (string-to-number (match-string 2 string))) + (cons 'digest-algorithm + (string-to-number (match-string 3 string))) + (cons 'class (string-to-number (match-string 4 string) 16)) + (cons 'creation-time (match-string 5 string)) + (cons 'fingerprint (substring string (match-end 0)))) + (epg-context-result-for epg-context 'sign))))) + +(defun epg-passphrase-callback-function (key-id handback) (read-passwd - (if (eq epg-key-id 'SYM) + (if (eq key-id 'SYM) "Passphrase for symmetric encryption: " - (if (eq epg-key-id 'PIN) + (if (eq key-id 'PIN) "Passphrase for PIN: " - (let ((entry (assoc epg-key-id epg-user-id-alist))) + (let ((entry (assoc key-id epg-user-id-alist))) (if entry - (format "Passphrase for %s %s: " epg-key-id (cdr entry)) - (format "Passphrase for %s: " epg-key-id))))))) + (format "Passphrase for %s %s: " key-id (cdr entry)) + (format "Passphrase for %s: " key-id))))))) (defun epg-progress-callback-function (what char current total handback) (message "%s: %d%%/%d%%" what current total)) @@ -909,7 +943,7 @@ If PLAIN is nil, it returns the result as a string." (epg-context-set-output-file context (epg-make-temp-file "epg-output"))) (epg-start-decrypt context (epg-make-data-from-file cipher)) - (epg-wait-for-completion context t) + (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Decrypt failed: %S" (epg-context-result-for context 'error))) @@ -930,6 +964,7 @@ If PLAIN is nil, it returns the result as a string." (epg-context-set-output-file context (epg-make-temp-file "epg-output")) (epg-start-decrypt context (epg-make-data-from-file input-file)) + (epg-flush context) (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Decrypt failed: %S" @@ -990,7 +1025,7 @@ For a normal or a clear text signature, SIGNED-TEXT should be nil." (epg-make-data-from-file signed-text)) (epg-start-verify context (epg-make-data-from-file signature))) - (epg-wait-for-completion context t) + (epg-wait-for-completion context) (unless plain (epg-read-output context))) (unless plain @@ -1018,6 +1053,7 @@ For a normal or a clear text signature, SIGNED-TEXT should be nil." (epg-make-data-from-file input-file) (epg-make-data-from-string signed-text))) (epg-start-verify context (epg-make-data-from-string signature))) + (epg-flush context) (epg-wait-for-completion context) (epg-read-output context)) (epg-delete-output-file context) @@ -1048,9 +1084,12 @@ If you are unsure, use synchronous version of this function "--detach-sign" "--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))) (if (epg-data-file plain) (list (epg-data-file plain))))) (epg-wait-for-status context '("BEGIN_SIGNING")) @@ -1073,7 +1112,7 @@ Otherwise, it makes a normal signature." (epg-context-set-output-file context (epg-make-temp-file "epg-output"))) (epg-start-sign context (epg-make-data-from-file plain) mode) - (epg-wait-for-completion context t) + (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Sign failed: %S" (epg-context-result-for context 'error))) @@ -1094,6 +1133,7 @@ Otherwise, it makes a normal signature." (epg-context-set-output-file context (epg-make-temp-file "epg-output")) (epg-start-sign context (epg-make-data-from-string plain) mode) + (epg-flush context) (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Sign failed: %S" @@ -1125,14 +1165,17 @@ If you are unsure, use synchronous version of this function (list "-u" signer)) (epg-context-signers context))))) (apply #'nconc - (mapcar (lambda (recipient) - (list "-r" recipient)) - recipients)) + (mapcar + (lambda (recipient) + (list "-r" + (epg-sub-key-id + (car (epg-key-sub-key-list recipient))))) + recipients)) (if (epg-data-file plain) (list (epg-data-file plain))))) (if sign - (epg-wait-for-status context '("BEGIN_SIGNING"))) - (epg-wait-for-status context '("BEGIN_ENCRYPTION")) + (epg-wait-for-status context '("BEGIN_SIGNING")) + (epg-wait-for-status context '("BEGIN_ENCRYPTION"))) (if (and (epg-data-string plain) (eq (process-status (epg-context-process context)) 'run)) (process-send-string (epg-context-process context) @@ -1152,7 +1195,7 @@ If RECIPIENTS is nil, it performs symmetric encryption." (epg-make-temp-file "epg-output"))) (epg-start-encrypt context (epg-make-data-from-file plain) recipients sign always-trust) - (epg-wait-for-completion context t) + (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Encrypt failed: %S" (epg-context-result-for context 'error))) @@ -1173,6 +1216,7 @@ If RECIPIENTS is nil, it performs symmetric encryption." (epg-make-temp-file "epg-output")) (epg-start-encrypt context (epg-make-data-from-string plain) recipients sign always-trust) + (epg-flush context) (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Encrypt failed: %S" @@ -1244,7 +1288,9 @@ If you are unsure, use synchronous version of this function (unwind-protect (progn (epg-start-import-keys context keys) - (epg-wait-for-completion context (epg-data-file keys)) + (if (epg-data-file keys) + (epg-flush context)) + (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Import keys failed")) (epg-read-output context)) @@ -1285,7 +1331,7 @@ If you are unsure, use synchronous version of this function (unwind-protect (progn (epg-start-delete-keys context keys) - (epg-wait-for-completion context t) + (epg-wait-for-completion context) (if (epg-context-result-for context 'error) (error "Delete key failed"))) (epg-reset context)))