diff options
Diffstat (limited to 'lisp/epg-config.el')
-rw-r--r-- | lisp/epg-config.el | 133 |
1 files changed, 100 insertions, 33 deletions
diff --git a/lisp/epg-config.el b/lisp/epg-config.el index dff5e99a8de..6501434e030 100644 --- a/lisp/epg-config.el +++ b/lisp/epg-config.el @@ -1,6 +1,6 @@ -;;; epg-config.el --- configuration of the EasyPG Library +;;; epg-config.el --- configuration of the EasyPG Library -*- lexical-binding: t -*- -;; Copyright (C) 2006-2017 Free Software Foundation, Inc. +;; Copyright (C) 2006-2022 Free Software Foundation, Inc. ;; Author: Daiki Ueno <ueno@unixuser.org> ;; Keywords: PGP, GnuPG @@ -21,7 +21,10 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. +;;; Commentary: + ;;; Code: +;;; Prelude (eval-when-compile (require 'cl-lib)) @@ -31,8 +34,10 @@ (defconst epg-version-number "1.0.0" "Version number of this package.") -(defconst epg-bug-report-address "ueno@unixuser.org" - "Report bugs to this address.") +(define-obsolete-variable-alias 'epg-bug-report-address + 'report-emacs-bug-address "27.1") + +;;; Options (defgroup epg () "Interface to the GNU Privacy Guard (GnuPG)." @@ -44,48 +49,79 @@ (defcustom epg-gpg-program (if (executable-find "gpg2") "gpg2" "gpg") - "The `gpg' executable. -Setting this variable directly does not take effect; -instead use \\[customize] (see the info node `Easy Customization')." + "Say what gpg program to prefer (if it satisfies minimum requirements). + +If this variable is \"gpg2\", but the version of gpg2 installed +is less than `epg-gpg2-minimum-version', then version 1 of +GnuPG (i.e., \"gpg\") will be used instead. If the version of +version 1 is less than `epg-gpg-minimum-version', then that won't +be used either. + +If you want to explicitly specify what gpg program to use, you +have to use \\[customize] instead (see the info node `Easy +Customization'). Setting this variable without \\[customize] has +no effect." :version "25.1" - :group 'epg :type 'string) (defcustom epg-gpgsm-program "gpgsm" "The `gpgsm' executable. Setting this variable directly does not take effect; instead use \\[customize] (see the info node `Easy Customization')." - :group 'epg :type 'string) (defcustom epg-gpgconf-program "gpgconf" "The `gpgconf' executable." :version "25.1" - :group 'epg :type 'string) (defcustom epg-gpg-home-directory nil "The directory which contains the configuration files of `epg-gpg-program'." - :group 'epg :type '(choice (const :tag "Default" nil) directory)) (defcustom epg-passphrase-coding-system nil "Coding system to use with messages from `epg-gpg-program'." - :group 'epg :type 'symbol) +(define-obsolete-variable-alias + 'epa-pinentry-mode 'epg-pinentry-mode "27.1") + +;; In the doc string below, we say "symbol `error'" to avoid producing +;; a hyperlink for `error' the function. +(defcustom epg-pinentry-mode nil + "The pinentry mode. + +GnuPG 2.1 or later has an option to control the behavior of +Pinentry invocation. The value should be the symbol `error', +`ask', `cancel', or `loopback'. See the GnuPG manual for the +meanings. + +A particularly useful mode is `loopback', which redirects all +Pinentry queries to the caller, so Emacs can query passphrase +through the minibuffer, instead of external Pinentry program." + :type '(choice (const nil) + (const ask) + (const cancel) + (const error) + (const loopback)) + :version "27.1") + (defcustom epg-debug nil "If non-nil, debug output goes to the \" *epg-debug*\" buffer. Note that the buffer name starts with a space." - :group 'epg :type 'boolean) +;;; Constants + (defconst epg-gpg-minimum-version "1.4.3") +(defconst epg-gpg2-minimum-version "2.1.6") (defconst epg-config--program-alist `((OpenPGP epg-gpg-program - ("gpg2" . "2.1.6") ("gpg" . ,epg-gpg-minimum-version)) + ("gpg2" . ,epg-gpg2-minimum-version) + ("gpg" . ((,epg-gpg-minimum-version . "2.0") + ,epg-gpg2-minimum-version))) (CMS epg-gpgsm-program ("gpgsm" . "2.0.4"))) @@ -104,6 +140,8 @@ The first element of each entry is protocol symbol, which is either `OpenPGP' or `CMS'. The second element is a function which constructs a configuration object (actually a plist).") +;;; "Configuration" + (defvar epg--configurations nil) ;;;###autoload @@ -121,7 +159,7 @@ version requirement is met." (setq program-alist epg-config--program-alist)) (let ((entry (assq protocol program-alist))) (unless entry - (error "Unknown protocol %S" protocol)) + (error "Unknown protocol `%S'" protocol)) (cl-destructuring-bind (symbol . alist) (cdr entry) (let ((constructor @@ -154,10 +192,18 @@ version requirement is met." (defun epg-config--make-gpg-configuration (program) (let (config groups type args) (with-temp-buffer - (apply #'call-process program nil (list t nil) nil - (append (if epg-gpg-home-directory - (list "--homedir" epg-gpg-home-directory)) - '("--with-colons" "--list-config"))) + ;; The caller might have bound coding-system-for-* to something + ;; like 'no-conversion, but the below needs to call PROGRAM + ;; expecting human-readable text in both directions (since we + ;; are going to parse the output as text), so let Emacs guess + ;; the encoding of that text by its usual encoding-detection + ;; machinery. + (let ((coding-system-for-read 'undecided) + (coding-system-for-write 'undecided)) + (apply #'call-process program nil (list t nil) nil + (append (if epg-gpg-home-directory + (list "--homedir" epg-gpg-home-directory)) + '("--with-colons" "--list-config")))) (goto-char (point-min)) (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t) (setq type (intern (match-string 1)) @@ -165,13 +211,13 @@ version requirement is met." (cond ((eq type 'group) (if (string-match "\\`\\([^:]+\\):" args) - (setq groups - (cons (cons (downcase (match-string 1 args)) - (delete "" (split-string - (substring args - (match-end 0)) - ";"))) - groups)) + (setq groups + (cons (cons (downcase (match-string 1 args)) + (delete "" (split-string + (substring args + (match-end 0)) + ";"))) + groups)) (if epg-debug (message "Invalid group configuration: %S" args)))) ((memq type '(pubkey cipher digest compress)) @@ -200,9 +246,9 @@ version requirement is met." (goto-char (match-end 0)) (backward-char) (forward-sexp) - (skip-syntax-forward "-" (point-at-eol)) + (skip-syntax-forward "-" (line-end-position)) (list (cons 'program program) - (cons 'version (buffer-substring (point) (point-at-eol))))))) + (cons 'version (buffer-substring (point) (line-end-position))))))) ;;;###autoload (defun epg-configuration () @@ -211,16 +257,37 @@ version requirement is met." (epg-config--make-gpg-configuration epg-gpg-program)) ;;;###autoload -(defun epg-check-configuration (config &optional minimum-version) - "Verify that a sufficient version of GnuPG is installed." +(defun epg-check-configuration (config &optional req-versions) + "Verify that a sufficient version of GnuPG is installed. +CONFIG should be a `epg-configuration' object (a plist). +REQ-VERSIONS should be a list with elements of the form (MIN +. MAX) where MIN and MAX are version strings indicating a +semi-open range of acceptable versions. REQ-VERSIONS may also be +a single minimum version string." (let ((version (alist-get 'version config))) (unless (stringp version) (error "Undetermined version: %S" version)) - (unless (version<= (or minimum-version - epg-gpg-minimum-version) - version) + (catch 'version-ok + (pcase-dolist ((or `(,min . ,max) + (and min (let max nil))) + (if (listp req-versions) req-versions + (list req-versions))) + (when (and (version<= (or min epg-gpg-minimum-version) + version) + (or (null max) + (version< version max))) + (throw 'version-ok t))) (error "Unsupported version: %s" version)))) +(defun epg-required-version-p (protocol required-version) + "Verify a sufficient version of GnuPG for specific protocol. +PROTOCOL is symbol, either `OpenPGP' or `CMS'. REQUIRED-VERSION +is a string containing the required version number. Return +non-nil if that version or higher is installed." + (let ((version (cdr (assq 'version (epg-find-configuration protocol))))) + (and (stringp version) + (version<= required-version version)))) + ;;;###autoload (defun epg-expand-group (config group) "Look at CONFIG and try to expand GROUP." |