(require 'mm-decode)
(require 'mm-util)
(require 'mml)
-(require 'password)
+(require 'mml-sec)
(defvar mc-pgp-always-sign)
(defvar mml2015-use (or
+ (condition-case nil
+ (progn
+ (require 'epg-config)
+ (epg-check-configuration (epg-configuration))
+ 'epg)
+ (error))
(progn
(ignore-errors
;; Avoid the "Recursive load suspected" error
(fboundp 'mc-cleanup-recipient-headers)
'mailcrypt)))
"The package used for PGP/MIME.
-Valid packages include `pgg', `gpg' and `mailcrypt'.")
+Valid packages include `epg', `pgg', `gpg' and `mailcrypt'.")
;; Something is not RFC2015.
(defvar mml2015-function-alist
:type '(repeat (cons (regexp :tag "GnuPG output regexp")
(boolean :tag "Trust key"))))
-(defcustom mml2015-verbose nil
+(defcustom mml2015-verbose mml-secure-verbose
"If non-nil, ask the user about the current operation more verbosely."
:group 'mime-security
:type 'boolean)
-(defcustom mml2015-cache-passphrase t
+(defcustom mml2015-cache-passphrase mml-secure-cache-passphrase
"If t, cache passphrase."
:group 'mime-security
:type 'boolean)
-(defcustom mml2015-passphrase-cache-expiry 16
+(defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
"How many seconds the passphrase is cached.
Whether the passphrase is cached at all is controlled by
`mml2015-cache-passphrase'."
:group 'mime-security
:type 'integer)
+(defcustom mml2015-signers nil
+ "A list of your own key ID which will be used to sign a message."
+ :group 'mime-security
+ :type '(repeat (string :tag "Key ID")))
+
+(defcustom mml2015-encrypt-to-self t
+ "If t, add your own key ID to recipient list when encryption."
+ :group 'mime-security
+ :type 'boolean)
+
+(defcustom mml2015-always-trust t
+ "If t, GnuPG skip key validation on encryption."
+ :group 'mime-security
+ :type 'boolean)
+
;;; mailcrypt wrapper
(eval-and-compile
;;; epg wrapper
(eval-and-compile
- (autoload 'epg-make-context "epg")
- (autoload 'epa-select-keys "epa"))
+ (autoload 'epg-make-context "epg"))
(eval-when-compile
(defvar epg-user-id-alist)
(autoload 'epg-sign-string "epg")
(autoload 'epg-encrypt-string "epg")
(autoload 'epg-passphrase-callback-function "epg")
- (autoload 'epg-context-set-passphrase-callback "epg"))
+ (autoload 'epg-context-set-passphrase-callback "epg")
+ (autoload 'epg-configuration "epg-config")
+ (autoload 'epg-expand-group "epg-config"))
+
+(eval-when-compile
+ (defvar password-cache-expiry)
+ (autoload 'password-read "password")
+ (autoload 'password-cache-add "password")
+ (autoload 'password-cache-remove "password"))
(defvar mml2015-epg-secret-key-id-list nil)
(defun mml2015-epg-passphrase-callback (context key-id ignore)
(if (eq key-id 'SYM)
(epg-passphrase-callback-function context key-id nil)
- (let* ((entry (assoc key-id epg-user-id-alist))
+ (let* (entry
(passphrase
(password-read
- (format "GnuPG passphrase for %s: "
- (if entry
- (cdr entry)
- key-id))
(if (eq key-id 'PIN)
- "PIN"
- key-id))))
+ "Passphrase for PIN: "
+ (if (setq entry (assoc key-id epg-user-id-alist))
+ (format "Passphrase for %s %s: " key-id (cdr entry))
+ (format "Passphrase for %s: " key-id))))))
(when passphrase
(let ((password-cache-expiry mml2015-passphrase-cache-expiry))
(password-cache-add key-id passphrase))
mm-security-handle 'gnus-info "Corrupted")
(throw 'error handle))
(setq context (epg-make-context))
- (epg-context-set-passphrase-callback
- context
- #'mml2015-epg-passphrase-callback)
+ (if mml2015-cache-passphrase
+ (epg-context-set-passphrase-callback
+ context
+ #'mml2015-epg-passphrase-callback))
(condition-case error
(setq plain (epg-decrypt-string context (mm-get-part child))
mml2015-epg-secret-key-id-list nil)
(let ((inhibit-redisplay t)
(context (epg-make-context))
plain)
- (epg-context-set-passphrase-callback
- context
- #'mml2015-epg-passphrase-callback)
+ (if mml2015-cache-passphrase
+ (epg-context-set-passphrase-callback
+ context
+ #'mml2015-epg-passphrase-callback))
(condition-case error
(setq plain (epg-decrypt-string context (buffer-string))
mml2015-epg-secret-key-id-list nil)
(goto-char (point-min))
(while (search-forward "\r\n" nil t)
(replace-match "\n" t t))
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "OK")
(if (epg-context-result-for context 'verify)
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info
- (concat "OK\n"
- (epg-verify-result-to-string
- (epg-context-result-for context 'verify))))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "OK")))))
+ mm-security-handle 'gnus-details
+ (epg-verify-result-to-string
+ (epg-context-result-for context 'verify)))))))
(defun mml2015-epg-verify (handle ctl)
(catch 'error
(if mml2015-verbose
(setq signers (epa-select-keys context "Select keys for signing.
If no one is selected, default secret key is used. "
- nil t))
- (setq signers (list (car (epg-list-keys
- context
- (message-options-get 'mml-sender) t)))))
+ mml2015-signers t))
+ (if mml2015-signers
+ (setq signers (mapcar (lambda (name)
+ (car (epg-list-keys context name t)))
+ mml2015-signers))))
(epg-context-set-armor context t)
(epg-context-set-textmode context t)
(epg-context-set-signers context signers)
- (epg-context-set-passphrase-callback
- context
- #'mml2015-epg-passphrase-callback)
+ (if mml2015-cache-passphrase
+ (epg-context-set-passphrase-callback
+ context
+ #'mml2015-epg-passphrase-callback))
(condition-case error
(setq signature (epg-sign-string context (buffer-string) t)
mml2015-epg-secret-key-id-list nil)
(defun mml2015-epg-encrypt (cont &optional sign)
(let ((inhibit-redisplay t)
(context (epg-make-context))
- recipients cipher
+ (config (epg-configuration))
+ (recipients (split-string
+ (or (message-options-get 'message-recipients)
+ (message-options-set 'message-recipients
+ (read-string "Recipients: ")))
+ "[ \f\t\n\r\v,]+"))
+ cipher signers
(boundary (mml-compute-boundary cont)))
- (if (or mml2015-verbose
- (null (message-options-get 'message-recipients)))
+ (setq recipients (apply #'nconc
+ (mapcar
+ (lambda (recipient)
+ (or (epg-expand-group config recipient)
+ (list recipient)))
+ recipients)))
+ (if mml2015-verbose
(setq recipients
(epa-select-keys context "Select recipients for encryption.
If no one is selected, symmetric encryption will be performed. "
- (if (message-options-get 'message-recipients)
- (split-string
- (message-options-get 'message-recipients)
- "[ \f\t\n\r\v,]+"))))
+ recipients))
(setq recipients
- (epg-list-keys context
- (split-string
- (message-options-get 'message-recipients)
- "[ \f\t\n\r\v,]+"))))
+ (delq nil (mapcar (lambda (name)
+ (car (epg-list-keys context name)))
+ recipients))))
+ (if mml2015-encrypt-to-self
+ (if mml2015-signers
+ (setq recipients
+ (nconc recipients
+ (mapcar (lambda (name)
+ (car (epg-list-keys context name)))
+ mml2015-signers)))
+ (error "mml2015-signers not set")))
+ (when sign
+ (if mml2015-verbose
+ (setq signers (epa-select-keys context "Select keys for signing.
+If no one is selected, default secret key is used. "
+ mml2015-signers t))
+ (if mml2015-signers
+ (setq signers (mapcar (lambda (name)
+ (car (epg-list-keys context name t)))
+ mml2015-signers))))
+ (epg-context-set-signers context signers))
(epg-context-set-armor context t)
(epg-context-set-textmode context t)
- (epg-context-set-passphrase-callback
- context
- #'mml2015-epg-passphrase-callback)
+ (if mml2015-cache-passphrase
+ (epg-context-set-passphrase-callback
+ context
+ #'mml2015-epg-passphrase-callback))
(condition-case error
(setq cipher
- (epg-encrypt-string context (buffer-string) recipients sign)
+ (epg-encrypt-string context (buffer-string) recipients sign
+ mml2015-always-trust)
mml2015-epg-secret-key-id-list nil)
(error
(while mml2015-epg-secret-key-id-list