From 136d0f28754d1ca71d307cd79104cd2872a6182c Mon Sep 17 00:00:00 2001 From: djcb Date: Wed, 1 Aug 2012 17:07:11 +0300 Subject: [PATCH] * mu4e/crypto: beginnings of crypto (verification, decryption) support. WIP! --- mu4e/mu4e-proc.el | 5 +- mu4e/mu4e-utils.el | 26 ++++++----- mu4e/mu4e-vars.el | 17 +++++-- mu4e/mu4e-view.el | 112 +++++++++++++++++++++++++++------------------ 4 files changed, 97 insertions(+), 63 deletions(-) diff --git a/mu4e/mu4e-proc.el b/mu4e/mu4e-proc.el index 5754daf5..0feb6e92 100644 --- a/mu4e/mu4e-proc.el +++ b/mu4e/mu4e-proc.el @@ -217,7 +217,7 @@ The server output is as follows: ;; received a pong message ((plist-get sexp :pong) (funcall mu4e-pong-func - (plist-get sexp :version) (plist-get sexp :doccount))) + (plist-get sexp :props))) ;; received a contacts message ((plist-get sexp :contacts) @@ -464,7 +464,8 @@ argument). Optionally, if IMAGES is non-nil, backend will any images attached to the message, and return them as temp files. The result will be delivered to the function registered as `mu4e-message-func'." - (mu4e~proc-send-command "view %s extract-images:%s" + (mu4e~proc-send-command + "view %s extract-images:%s extract-encrypted:true" (mu4e--docid-msgid-param docid-or-msgid) (if images "true" "false"))) diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index 067a1287..38f93442 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -629,17 +629,21 @@ FUNC (if non-nil) afterwards." ;; set up the 'pong' handler func (lexical-let ((func func)) (setq mu4e-pong-func - (lambda (version doccount) - (unless (string= version mu4e-mu-version) - (mu4e-error "mu server has version %s, but we need %s" - version mu4e-mu-version)) - (when func (funcall func)) - (when (and mu4e-update-interval (null mu4e~update-timer)) - (setq mu4e~update-timer - (run-at-time - 0 mu4e-update-interval 'mu4e-update-mail))) - (mu4e-message "Started mu4e with %d message%s in store" - doccount (if (= doccount 1) "" "s"))))) + (lambda (props) + (let ((version (plist-get props :version)) + (doccount (plist-get props :doccount))) + (unless (string= version mu4e-mu-version) + (mu4e-error "mu server has version %s, but we need %s" + version mu4e-mu-version)) + (when func (funcall func)) + (when (and mu4e-update-interval (null mu4e~update-timer)) + (setq mu4e~update-timer + (run-at-time + 0 mu4e-update-interval 'mu4e-update-mail))) + (mu4e-message "Started mu4e with %d message%s in store" + doccount (if (= doccount 1) "" "s")) + ;; save the props we got from the server + (setq mu4e~server-props props))))) ;; send the ping (mu4e~proc-ping) ;; get the address list if it's not already set. diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index a545ae09..6e751c8b 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -134,12 +134,15 @@ see `mu4e-headers-visible-lines' and (defcustom mu4e-auto-retrieve-keys nil "Attempt to automatically retrieve public keys when needed." :type 'boolean - :group 'mu4e-compose) + :group 'mu4e-crypto) -(defcustom mu4e-use-agent nil - "Attempt to use GPG-agent when it is available." - :type 'boolean - :group 'mu4e-compose) +(defcustom mu4e-decryption-policy 'auto + "Policy for dealing with encrypted parts. The setting is a symbol: + * `auto': try to decrypt automatically + * `ask': ask before decrypting anything + * `no': don't try to decrypt anything." + :type 'symbol + :group 'mu4e-crypto) ;; completion; we put them here rather than in mu4e-compose, as mu4e-utils needs ;; the variables. @@ -489,6 +492,10 @@ Note, :sortable does not work for custom header fields.") used by the completion functions in mu4e-compose, and filled when mu4e starts.") +(defvar mu4e~server-props nil + "Properties we receive from the mu4e server process (in the + 'pong-handler').") + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; our handlers funcs diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index 0c9bf9bb..07434d42 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -38,6 +38,8 @@ (require 'comint) (require 'browse-url) (require 'button) +(require 'epa) +(require 'epg) (eval-when-compile (byte-compile-disable-warning 'cl-functions)) (require 'cl) @@ -54,12 +56,6 @@ complete list of available headers, see `mu4e-header-info'." :type (list 'symbol) :group 'mu4e-view) -(defcustom mu4e-view-date-format "%c" - "Date format to use in the message view, in the format of - `format-time-string'." - :type 'string - :group 'mu4e-view) - (defcustom mu4e-view-show-addresses nil "Whether to initially show full e-mail addresses for contacts in address fields, rather than only their names. Note that you can @@ -75,15 +71,13 @@ messages, but you can always toggle between wrapped/unwrapped display with `mu4e-view-toggle-wrap-lines (default keybinding: )." :group 'mu4e-view) -(defcustom mu4e-view-wrap-lines nil - "Whether to automatically wrap lines in the body of messages when -viewing them. Note that wrapping does not work well with all -messages, but you can always toggle between wrapped/unwrapped -display with `mu4e-view-toggle-wrap-lines (default keybinding: )." +(defcustom mu4e-view-date-format "%c" + "Date format to use in the message view, in the format of + `format-time-string'." + :type 'string :group 'mu4e-view) - -(defcustom mu4e-view-hide-cited nil + (defcustom mu4e-view-hide-cited nil "Whether to automatically hide cited parts of messages (as determined by the presence of '> ' at the beginning of the line). Note that you can always toggle between hidden/unhidden @@ -198,7 +192,11 @@ plist." (t (mu4e-error "Unsupported field: %S" field))))) mu4e-view-fields "") "\n" - (mu4e-body-text msg))) + (mu4e-body-text msg) + ;; ;; decrypt maybe; depends on whether there are any such parts + ;; ;; and the value of `mu4e-view-decrypt-parts' + ;; (mu4e~decrypt-parts-maybe msg) + )) (defun mu4e-view (msg headersbuf &optional refresh) @@ -383,43 +381,67 @@ is nil, and otherwise open it." (member 'inline (plist-get part :type))) (plist-get msg :parts))) (attstr - (mapconcat - (lambda (part) - (let ((index (plist-get part :index)) - (name (plist-get part :name)) - (size (plist-get part :size)) - (map (make-sparse-keymap))) - (incf id) - (puthash id index mu4e~view-attach-map) - (define-key map [mouse-2] - (mu4e~view-open-save-attach-func msg id nil)) - (define-key map [?\M-\r] - (mu4e~view-open-save-attach-func msg id nil)) - (define-key map [S-mouse-2] - (mu4e~view-open-save-attach-func msg id t)) - (define-key map (kbd "") - (mu4e~view-open-save-attach-func msg id t)) - (concat - (propertize (format "[%d]" id) 'face 'mu4e-view-attach-number-face) - (propertize name 'face 'mu4e-view-link-face - 'keymap map 'mouse-face 'highlight) - (when (and size (> size 0)) - (concat (format "(%s)" - (propertize (mu4e-display-size size) - 'face 'mu4e-view-header-key-face))))))) - attachments ", "))) - (unless (zerop id) - (mu4e~view-construct-header - :attachments (format "%s (%d)" attstr id) t)))) + (mapconcat + (lambda (part) + (let ((index (plist-get part :index)) + (name (plist-get part :name)) + (size (plist-get part :size)) + (map (make-sparse-keymap))) + (incf id) + (puthash id index mu4e~view-attach-map) + (define-key map [mouse-2] + (mu4e~view-open-save-attach-func msg id nil)) + (define-key map [?\M-\r] + (mu4e~view-open-save-attach-func msg id nil)) + (define-key map [S-mouse-2] + (mu4e~view-open-save-attach-func msg id t)) + (define-key map (kbd "") + (mu4e~view-open-save-attach-func msg id t)) + (concat + (propertize (format "[%d]" id) + 'face 'mu4e-view-attach-number-face) + (propertize name 'face 'mu4e-view-link-face + 'keymap map 'mouse-face 'highlight) + (when (and size (> size 0)) + (concat (format "(%s)" + (propertize (mu4e-display-size size) + 'face 'mu4e-view-header-key-face))))))) + attachments ", "))) + (when attachments + (mu4e~view-construct-header :attachments attstr t)))) + +;; (defun mu4e~decrypt-parts-maybe (msg) +;; "Decrypt maybe; depends on whether there are any such parts +;; and the value of `mu4e-view-decrypt-parts'." +;; (let ((str "")) +;; (mu4e-view-for-each-part msg +;; (lambda (msg part) +;; (when (member 'encrypted (plist-get part :type)) +;; (let ((file (plist-get part :temp))) +;; (when (and file (file-exists-p file)) +;; ;; if our mu-server was build with crypto support, we only use EPA +;; ;; to push the password into gpg's memory +;; (let* ((decr +;; (condition-case nil +;; (epg-decrypt-file (epg-make-context epa-protocol) file nil) +;; (err (mu4e-error "Decryption failed: %S" err)))) +;; (decr +;; (if (and decr (plist-get mu4e~server-props :crypto)) + +;; )))) ;; TODO: reload message +;; ;; otherwise, we try to handle it here. +;; ) +;; decr)))))))) (defun mu4e-view-for-each-part (msg func) - "Apply FUNC to each part in MSG. FUNC should be a function taking two arguments; + "Apply FUNC to each part in MSG. FUNC should be a function taking + two arguments: 1. the message MSG, and 2. a plist describing the attachment. The plist looks like: (:index 1 :name \"test123.doc\" :mime-type \"application/msword\" :attachment t :size 1234)." - (dolist (part (mu4e-msg-field msg :parts)) - (funcall func msg part))) + (dolist (part (mu4e-msg-field msg :parts)) + (funcall func msg part))) (defvar mu4e-view-mode-map nil