+(defun epg-find-configuration (protocol &optional no-cache program-alist)
+ "Find or create a usable configuration to handle PROTOCOL.
+This function first looks at the existing configuration found by
+the previous invocation of this function, unless NO-CACHE is non-nil.
+
+Then it walks through PROGRAM-ALIST or
+`epg-config--program-alist'. If `epg-gpg-program' or
+`epg-gpgsm-program' is already set with custom, use it.
+Otherwise, it tries the programs listed in the entry until the
+version requirement is met."
+ (unless program-alist
+ (setq program-alist epg-config--program-alist))
+ (let ((entry (assq protocol program-alist)))
+ (unless entry
+ (error "Unknown protocol %S" protocol))
+ (cl-destructuring-bind (symbol . alist)
+ (cdr entry)
+ (let ((constructor
+ (alist-get protocol epg-config--configuration-constructor-alist)))
+ (or (and (not no-cache) (alist-get protocol epg--configurations))
+ ;; If the executable value is already set with M-x
+ ;; customize, use it without checking.
+ (if (and symbol (get symbol 'saved-value))
+ (let ((configuration
+ (funcall constructor (symbol-value symbol))))
+ (push (cons protocol configuration) epg--configurations)
+ configuration)
+ (catch 'found
+ (dolist (program-version alist)
+ (let ((executable (executable-find (car program-version))))
+ (when executable
+ (let ((configuration
+ (funcall constructor executable)))
+ (when (ignore-errors
+ (epg-check-configuration configuration
+ (cdr program-version))
+ t)
+ (unless no-cache
+ (push (cons protocol configuration)
+ epg--configurations))
+ (throw 'found configuration)))))))))))))
+
+;; Create an `epg-configuration' object for `gpg', using PROGRAM.
+(defun epg-config--make-gpg-configuration (program)