From dde3f09c761a6cedafed24b186eb8f798958876b Mon Sep 17 00:00:00 2001 From: djcb Date: Thu, 19 Jul 2012 11:42:38 +0300 Subject: [PATCH] * crypto/mu4e: support signature verification in mu4e (WIP) --- mu4e/mu4e-utils.el | 8 ++++---- mu4e/mu4e-vars.el | 32 +++++++++++++++++++++++++++++- mu4e/mu4e-view.el | 49 +++++++++++++++++++++++++++++++++++++++------- mu4e/mu4e.texi | 28 ++++++++++++++++++++++++-- 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index c59a4ebf..98e12c2d 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -60,7 +60,7 @@ dir already existed, or has been created, nil otherwise." ((yes-or-no-p (mu4e-format "%s does not exist yes. Create now?" dir)) (mu4e~proc-mkdir dir)) (t nil))) - + (defun mu4e-format (frm &rest args) "Create [mu4e]-prefixed string based on format FRM and ARGS." (concat @@ -77,7 +77,7 @@ user-input, don't show anyhting." "Create [mu4e]-prefixed error based on format FRM and ARGS." (mu4e-log 'error (apply 'mu4e-format frm args)) (message "%s" (apply 'mu4e-format frm args))) - + (defun mu4e~read-char-choice (prompt choices) "Compatiblity wrapper for `read-char-choice', which is emacs-24 only." @@ -526,8 +526,8 @@ process." (defun mu4e-error-handler (errcode errmsg) "Handler function for showing an error." (case errcode - (4 (mu4e-message "No matches for this search query.")) - (t (mu4e-message "Error %d: %s" errcode errmsg)))) + (4 (mu4e-error "No matches for this search query.")) + (t (mu4e-error "Error %d: %s" errcode errmsg)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index a520e6cb..3449e329 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -122,6 +122,24 @@ else: don't split (show either headers or messages, not both) Also see `mu4e-headers-visible-lines' and `mu4e-headers-visible-columns'.") + + + +;; crypto +(defgroup mu4e-crypto nil + "Crypto-related settings." + :group 'mu4e) + +(defcustom mu4e-auto-retrieve-keys nil + "Attempt to automatically retrieve public keys when needed." + :type 'boolean + :group 'mu4e-compose) + +(defcustom mu4e-use-agent nil + "Attempt to use GPG-agent when it is available." + :type 'boolean + :group 'mu4e-compose) + ;; completion; we put them here rather than in mu4e-compose, as mu4e-utils needs ;; the variables. @@ -273,6 +291,7 @@ flag set)." "Face for special header values in the message view." :group 'mu4e-faces) + (defface mu4e-view-link-face '((t :inherit font-lock-type-face :underline t)) "Face for showing URLs and attachments in the message view." @@ -350,6 +369,17 @@ flag set)." headers)." :group 'mu4e-faces) +(defface mu4e-ok-face + '((t :inherit font-lock-comment-face :bold t :slant normal)) + "Face for things that are okay." + :group 'mu4e-faces) + +(defface mu4e-warning-face + '((t :inherit font-lock-warning-face :bold t :slant normal)) + "Face for warnings / error." + :group 'mu4e-faces) + + ;; headers info (defconst mu4e-header-info @@ -403,7 +433,7 @@ headers)." ( :name "Signature" :shortname "Sgn" :help "Check for the cryptographic signature" - :sortable nil)) + :sortable nil)) (:subject . ( :name "Subject" :shortname "Subject" diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index 75bb5378..b2cc4711 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -37,6 +37,7 @@ (require 'filladapt nil 'noerror) (require 'comint) (require 'browse-url) +(require 'button) (eval-when-compile (byte-compile-disable-warning 'cl-functions)) (require 'cl) @@ -331,7 +332,7 @@ at POINT, or if nil, at (point)." (propertize (symbol-name flag) 'face 'mu4e-view-special-header-value-face)) flags (propertize ", " 'face 'mu4e-view-header-value-face)) t)) - + (defun mu4e~view-construct-signature-header (msg) "Construct a Signature: header, if there are any signed parts." (let* ((parts (plist-get msg :parts)) @@ -339,14 +340,20 @@ at POINT, or if nil, at (point)." (remove-if 'null (mapcar (lambda (part) (plist-get part :signature)) parts))) (val (when verdicts - (mapconcat (lambda (v) (symbol-name v)) verdicts ", "))) + (mapconcat + (lambda (v) + (propertize (symbol-name v) + 'face (if (eq v 'good) 'mu4e-ok-face 'mu4e-warning-face))) + verdicts ", "))) (btn (when val (with-temp-buffer - (insert-text-button "Details") (buffer-string)))) - (val (when val - (concat (propertize val 'face 'mu4e-view-special-header-value-face) - " (" btn ")")))) - (mu4e~view-construct-header :signature val t))) + (insert-text-button "Details" + 'msg msg + 'action (lambda (b) + (mu4e-view-verify-msg-popup (button-get b 'msg)))) + (buffer-string)))) + (val (when val (concat val " (" btn ")")))) + (mu4e~view-construct-header :signature val t))) (defun mu4e~view-open-save-attach-func (msg attachnum is-open) "Return a function that offers to save attachment NUM. If IS-OPEN @@ -441,6 +448,8 @@ is nil, and otherwise open it." (define-key map "t" 'mu4e-view-mark-subthread) (define-key map "T" 'mu4e-view-mark-thread) + (define-key map "v" 'mu4e-view-verify-msg-popup) + (define-key map "j" 'mu4e~headers-jump-to-maildir) (define-key map "g" 'mu4e-view-go-to-url) @@ -1113,6 +1122,32 @@ the results." (let ((path (mu4e-field-at-point :path))) (mu4e-process-file-through-pipe path cmd))) +(defconst mu4e~verify-buffer-name " *mu4e-verify*") + +(defun mu4e-view-verify-msg-popup (&optional msg) + "Pop-up a little signature verification window for (optional) MSG +or message-at-point." + (interactive) + (let* ((path (if msg (plist-get msg :path) (mu4e-field-at-point :path))) + (cmd (format "%s verify --verbose %s" + mu4e-mu-binary + (shell-quote-argument path))) + (output (shell-command-to-string cmd)) + ;; create a new one + (buf (get-buffer-create mu4e~verify-buffer-name)) + (win (or (get-buffer-window buf) + (split-window-vertically (- (window-height) 6))))) + (with-selected-window win + (let ((inhibit-read-only t)) + ;; (set-window-dedicated-p win t) + (switch-to-buffer buf) + (erase-buffer) + (insert output) + (goto-char (point-min)) + (local-set-key "q" 'kill-buffer-and-window))) + (select-window win))) + + (defun mu4e~view-quit-buffer () "Quit the mu4e-view buffer. This is a rather complex function, to ensure we don't disturb other windows." diff --git a/mu4e/mu4e.texi b/mu4e/mu4e.texi index df4b5b97..c273b78a 100644 --- a/mu4e/mu4e.texi +++ b/mu4e/mu4e.texi @@ -828,6 +828,8 @@ misc w toggle line wrapping h toggle showing cited parts +v show details about the cryptographic signature + . show the raw message view. 'q' takes you back. C-+,C-- increase / decrease the number of headers shown H get help @@ -941,6 +943,28 @@ As mentioned, by default @t{mu4e} prefers the text-version of an e-mail message over the html version. You can change this by setting @code{mu4e-view-prefer-html} to @t{t}. +@subsection Verifying signatures + +Some e-mail messages are cryptographically signed, and @t{mu4e} can check the +validity of the signatures@footnote{Signature-verification is only available +if @t{mu} was built with crypto-support; this requires at least @t{mu} version 0.9.9 +and @t{GMime 2.6}, and the @t{gpg} program}. + +If a message has a signature, the message view shows an extra header +@t{Signature:} (assuming it is part of your @code{mu4e-view-fields}), and one +or more 'verdicts' of the signatures found; either @t{good}, @t{bad} or +@t{error}. For instance: + +@verbatim +Signature: good, error (Details) +@end verbatim + +You can see the details of the signature verification by activating the +@t{Details} or pressing @key{v}. This will pop-up a little window with the +details of the signatures found and whether they could be verified or not. + +For more information, see the @t{mu-verify} manual page. + @node Editor view @section Editor view @@ -2041,7 +2065,7 @@ Now, let's make a @t{mu4e} configuration for this: (require 'smtpmail) (setq message-send-mail-function 'smtpmail-send-it - starttls-use-gnutls t + starttls-use-gnutls t smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil)) smtpmail-auth-credentials '(("smtp.gmail.com" 587 "USERNAME@@gmail.com" nil)) smtpmail-default-smtp-server "smtp.gmail.com" @@ -2051,7 +2075,7 @@ Now, let's make a @t{mu4e} configuration for this: ;; alternatively, for emacs-24 you can use: ;;(setq message-send-mail-function 'smtpmail-send-it ;; smtpmail-stream-type 'starttls -;; smtpmail-default-smtp-server "smtp.gmail.com" +;; smtpmail-default-smtp-server "smtp.gmail.com" ;; smtpmail-smtp-server "smtp.gmail.com" ;; smtpmail-smtp-service 587)