;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP)
-;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+;; 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
;; Keywords: PGP MIME MML
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published
-;; by the Free Software Foundation; either version 2, or (at your
-;; option) any later version.
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
-;; GNU Emacs is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
+;; For Emacs < 22.2.
+(eval-and-compile
+ (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))
+
+ (if (locate-library "password-cache")
+ (require 'password-cache)
+ (require 'password)))
+
(eval-when-compile (require 'cl))
(require 'mm-decode)
(require 'mm-util)
(defvar mc-pgp-always-sign)
+(declare-function epg-check-configuration "ext:epg-config"
+ (config &optional minimum-version))
+(declare-function epg-configuration "ext:epg-config" ())
+
(defvar mml2015-use (or
(condition-case nil
(progn
;; should be done by GnuPG rather than Elisp, but older PGP backends
;; (such as Mailcrypt, PGG, and gpg.el) discard the output from GnuPG.
(defun mml2015-extract-cleartext-signature ()
+ ;; Daiki Ueno in
+ ;; <54a15d860801080142l70b95d7dkac4bf51a86196011@mail.gmail.com>: ``I still
+ ;; believe that the right way is to use the plaintext output from GnuPG as
+ ;; it is, and mml2015-extract-cleartext-signature is just a kludge for
+ ;; misdesigned libraries like PGG, which have no ability to do that. So, I
+ ;; think it should not have descriptive documentation.''
+ ;;
+ ;; This function doesn't handle NotDashEscaped correctly. EasyPG handles it
+ ;; correctly.
+ ;; http://thread.gmane.org/gmane.emacs.gnus.general/66062/focus=66082
+ ;; http://thread.gmane.org/gmane.emacs.gnus.general/65087/focus=65109
(goto-char (point-min))
(forward-line)
;; We need to be careful not to strip beyond the armor headers.
;;; mailcrypt wrapper
-(eval-and-compile
- (autoload 'mailcrypt-decrypt "mailcrypt")
- (autoload 'mailcrypt-verify "mailcrypt")
- (autoload 'mc-pgp-always-sign "mailcrypt")
- (autoload 'mc-encrypt-generic "mc-toplev")
- (autoload 'mc-cleanup-recipient-headers "mc-toplev")
- (autoload 'mc-sign-generic "mc-toplev"))
+(autoload 'mailcrypt-decrypt "mailcrypt")
+(autoload 'mailcrypt-verify "mailcrypt")
+(autoload 'mc-pgp-always-sign "mailcrypt")
+(autoload 'mc-encrypt-generic "mc-toplev")
+(autoload 'mc-cleanup-recipient-headers "mc-toplev")
+(autoload 'mc-sign-generic "mc-toplev")
-(eval-when-compile
- (defvar mc-default-scheme)
- (defvar mc-schemes))
+(defvar mc-default-scheme)
+(defvar mc-schemes)
(defvar mml2015-decrypt-function 'mailcrypt-decrypt)
(defvar mml2015-verify-function 'mailcrypt-verify)
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
+;; We require mm-decode, which requires mm-bodies, which autoloads
+;; message-options-get (!).
+(declare-function message-options-set "message" (symbol value))
+
(defun mml2015-mailcrypt-encrypt (cont &optional sign)
(let ((mc-pgp-always-sign
(or mc-pgp-always-sign
;;; gpg wrapper
-(eval-and-compile
- (autoload 'gpg-decrypt "gpg")
- (autoload 'gpg-verify "gpg")
- (autoload 'gpg-verify-cleartext "gpg")
- (autoload 'gpg-sign-detached "gpg")
- (autoload 'gpg-sign-encrypt "gpg")
- (autoload 'gpg-encrypt "gpg")
- (autoload 'gpg-passphrase-read "gpg"))
+(autoload 'gpg-decrypt "gpg")
+(autoload 'gpg-verify "gpg")
+(autoload 'gpg-verify-cleartext "gpg")
+(autoload 'gpg-sign-detached "gpg")
+(autoload 'gpg-sign-encrypt "gpg")
+(autoload 'gpg-encrypt "gpg")
+(autoload 'gpg-passphrase-read "gpg")
(defun mml2015-gpg-passphrase ()
(or (message-options-get 'gpg-passphrase)
cipher)
(mm-with-unibyte-current-buffer
(with-temp-buffer
+ (mm-disable-multibyte)
;; set up a function to call the correct gpg encrypt routine
;; with the right arguments. (FIXME: this should be done
;; differently.)
;;; pgg wrapper
-(eval-when-compile
- (defvar pgg-default-user-id)
- (defvar pgg-errors-buffer)
- (defvar pgg-output-buffer))
+(defvar pgg-default-user-id)
+(defvar pgg-errors-buffer)
+(defvar pgg-output-buffer)
-(eval-and-compile
- (autoload 'pgg-decrypt-region "pgg")
- (autoload 'pgg-verify-region "pgg")
- (autoload 'pgg-sign-region "pgg")
- (autoload 'pgg-encrypt-region "pgg")
- (autoload 'pgg-parse-armor "pgg-parse"))
+(autoload 'pgg-decrypt-region "pgg")
+(autoload 'pgg-verify-region "pgg")
+(autoload 'pgg-sign-region "pgg")
+(autoload 'pgg-encrypt-region "pgg")
+(autoload 'pgg-parse-armor "pgg-parse")
(defun mml2015-pgg-decrypt (handle ctl)
(catch 'error
;;; epg wrapper
-(eval-and-compile
- (autoload 'epg-make-context "epg"))
-
-(eval-when-compile
- (defvar epg-user-id-alist)
- (defvar epg-digest-algorithm-alist)
- (defvar inhibit-redisplay)
- (autoload 'epg-context-set-armor "epg")
- (autoload 'epg-context-set-textmode "epg")
- (autoload 'epg-context-set-signers "epg")
- (autoload 'epg-context-result-for "epg")
- (autoload 'epg-new-signature-digest-algorithm "epg")
- (autoload 'epg-verify-result-to-string "epg")
- (autoload 'epg-list-keys "epg")
- (autoload 'epg-decrypt-string "epg")
- (autoload 'epg-verify-string "epg")
- (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-key-sub-key-list "epg")
- (autoload 'epg-sub-key-capability "epg")
- (autoload 'epg-sub-key-validity "epg")
- (autoload 'epg-configuration "epg-config")
- (autoload 'epg-expand-group "epg-config")
- (autoload 'epa-select-keys "epa"))
-
-(eval-when-compile
- (defvar password-cache-expiry)
- (autoload 'password-read "password")
- (autoload 'password-cache-add "password")
- (autoload 'password-cache-remove "password"))
+(defvar epg-user-id-alist)
+(defvar epg-digest-algorithm-alist)
+(defvar inhibit-redisplay)
+
+(autoload 'epg-make-context "epg")
+(autoload 'epg-context-set-armor "epg")
+(autoload 'epg-context-set-textmode "epg")
+(autoload 'epg-context-set-signers "epg")
+(autoload 'epg-context-result-for "epg")
+(autoload 'epg-new-signature-digest-algorithm "epg")
+(autoload 'epg-verify-result-to-string "epg")
+(autoload 'epg-list-keys "epg")
+(autoload 'epg-decrypt-string "epg")
+(autoload 'epg-verify-string "epg")
+(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-key-sub-key-list "epg")
+(autoload 'epg-sub-key-capability "epg")
+(autoload 'epg-sub-key-validity "epg")
+(autoload 'epg-configuration "epg-config")
+(autoload 'epg-expand-group "epg-config")
+(autoload 'epa-select-keys "epa")
(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
+ (let* ((password-cache-key-id
+ (if (eq key-id 'PIN)
+ "PIN"
+ key-id))
+ entry
(passphrase
(password-read
(if (eq key-id '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)))
- (if (eq key-id 'PIN)
- "PIN"
- key-id))))
+ password-cache-key-id)))
(when passphrase
(let ((password-cache-expiry mml2015-passphrase-cache-expiry))
- (password-cache-add key-id passphrase))
+ (password-cache-add password-cache-key-id passphrase))
(setq mml2015-epg-secret-key-id-list
- (cons key-id mml2015-epg-secret-key-id-list))
+ (cons password-cache-key-id mml2015-epg-secret-key-id-list))
(copy-sequence passphrase)))))
(defun mml2015-epg-find-usable-key (keys usage)
(let ((pointer (epg-key-sub-key-list (car keys))))
(while pointer
(if (and (memq usage (epg-sub-key-capability (car pointer)))
+ (not (memq 'disabled (epg-sub-key-capability (car pointer))))
(not (memq (epg-sub-key-validity (car pointer))
'(revoked expired))))
(throw 'found (car keys)))
(or (message-options-get 'mml2015-epg-signers)
(message-options-set
'mml2015-epg-signers
- (if mml2015-verbose
+ (if (eq mm-sign-option 'guided)
(epa-select-keys context "\
Select keys for signing.
If no one is selected, default secret key is used. "
mml2015-signers t)
(if mml2015-signers
- (mapcar
- (lambda (signer)
- (setq signer-key (mml2015-epg-find-usable-key
- (epg-list-keys context signer t)
- 'sign))
- (unless (or signer-key
- (y-or-n-p
- (format "No secret key for %s; skip it? "
- signer)))
- (error "No secret key for %s" signer))
- signer-key)
- mml2015-signers))))))
+ (delq nil
+ (mapcar
+ (lambda (signer)
+ (setq signer-key (mml2015-epg-find-usable-key
+ (epg-list-keys context signer t)
+ 'sign))
+ (unless (or signer-key
+ (y-or-n-p
+ (format
+ "No secret key for %s; skip it? "
+ signer)))
+ (error "No secret key for %s" signer))
+ signer-key)
+ mml2015-signers)))))))
signature micalg)
(epg-context-set-armor context t)
(epg-context-set-textmode context t)
(unless mml2015-signers
(error "mml2015-signers not set"))
(setq recipients (nconc recipients mml2015-signers)))
- (if mml2015-verbose
+ (if (eq mm-encrypt-option 'guided)
(setq recipients
(epa-select-keys context "\
Select recipients for encryption.
If no one is selected, symmetric encryption will be performed. "
recipients))
(setq recipients
- (mapcar
- (lambda (recipient)
- (setq recipient-key (mml2015-epg-find-usable-key
- (epg-list-keys context recipient)
- 'encrypt))
- (unless (or recipient-key
- (y-or-n-p
- (format "No public key for %s; skip it? "
- recipient)))
- (error "No public key for %s" recipient))
- recipient-key)
- recipients))
+ (delq nil
+ (mapcar
+ (lambda (recipient)
+ (setq recipient-key (mml2015-epg-find-usable-key
+ (epg-list-keys context recipient)
+ 'encrypt))
+ (unless (or recipient-key
+ (y-or-n-p
+ (format "No public key for %s; skip it? "
+ recipient)))
+ (error "No public key for %s" recipient))
+ recipient-key)
+ recipients)))
(unless recipients
(error "No recipient specified")))
(message-options-set 'mml2015-epg-recipients recipients))
(or (message-options-get 'mml2015-epg-signers)
(message-options-set
'mml2015-epg-signers
- (if mml2015-verbose
+ (if (eq mm-sign-option 'guided)
(epa-select-keys context "\
Select keys for signing.
If no one is selected, default secret key is used. "
mml2015-signers t)
(if mml2015-signers
- (mapcar
- (lambda (signer)
- (setq signer-key (mml2015-epg-find-usable-key
- (epg-list-keys context signer t)
- 'sign))
- (unless (or signer-key
- (y-or-n-p
- (format
- "No secret key for %s; skip it? "
- signer)))
- (error "No secret key for %s" signer))
- signer-key)
- mml2015-signers))))))
+ (delq nil
+ (mapcar
+ (lambda (signer)
+ (setq signer-key (mml2015-epg-find-usable-key
+ (epg-list-keys context signer t)
+ 'sign))
+ (unless (or signer-key
+ (y-or-n-p
+ (format
+ "No secret key for %s; skip it? "
+ signer)))
+ (error "No secret key for %s" signer))
+ signer-key)
+ mml2015-signers)))))))
(epg-context-set-signers context signers))
(epg-context-set-armor context t)
(epg-context-set-textmode context t)
;;; General wrapper
+(autoload 'gnus-buffer-live-p "gnus-util")
+(autoload 'gnus-get-buffer-create "gnus")
+
(defun mml2015-clean-buffer ()
(if (gnus-buffer-live-p mml2015-result-buffer)
(with-current-buffer mml2015-result-buffer
(provide 'mml2015)
-;;; arch-tag: b04701d5-0b09-44d8-bed8-de901bf435f2
;;; mml2015.el ends here