diff --git a/mu/mu-cmd-server.cc b/mu/mu-cmd-server.cc index 23f241fc..df232afa 100644 --- a/mu/mu-cmd-server.cc +++ b/mu/mu-cmd-server.cc @@ -1056,11 +1056,9 @@ sent_handler (Context& context, const Parameters& params) print_expr (std::move(seq)); } -static void -maybe_mark_as_unread (MuMsg *msg, DocId docid) +static bool +maybe_mark_as_read (Mu::Store& store, MuMsg *msg, DocId docid) { - g_debug ("%s", __func__); - if (!msg) throw Error{Error::Code::Store, "missing message"}; if (docid == MU_STORE_INVALID_DOCID) @@ -1247,15 +1245,16 @@ make_command_map (Context& context) cmap.emplace("view", CommandInfo{ - ArgMap{{"docid", ArgInfo{Type::Number, false, "document-id"}}, - {"msgid", ArgInfo{Type::String, false, "message-id"}}, - {"path", ArgInfo{Type::String, false, "message filesystem path"}}, - {"mark-unread", ArgInfo{Type::String, false, "mark message as unread"}}, - {"extract-images", ArgInfo{Type::Symbol, false, + ArgMap{{":docid", ArgInfo{Type::Number, false, "document-id"}}, + {":msgid", ArgInfo{Type::String, false, "message-id"}}, + {":path", ArgInfo{Type::String, false, "message filesystem path"}}, + {":mark-as-read", ArgInfo{Type::Symbol, false, + "mark message as read (if not already)"}}, + {":extract-images", ArgInfo{Type::Symbol, false, "whether to extract images for this messages (if any)"}}, - {"decrypt", ArgInfo{Type::Symbol, false, + {":decrypt", ArgInfo{Type::Symbol, false, "whether to decrypt encrypted parts (if any)" }}, - {"verify", ArgInfo{Type::Symbol, false, + {":verify", ArgInfo{Type::Symbol, false, "whether to verify signatures (if any)" }} }, diff --git a/mu4e/mu4e-headers.el b/mu4e/mu4e-headers.el index bf9e27f8..b73ed188 100644 --- a/mu4e/mu4e-headers.el +++ b/mu4e/mu4e-headers.el @@ -1646,6 +1646,10 @@ window . " (let* ((msg (mu4e-message-at-point)) (docid (or (mu4e-message-field msg :docid) (mu4e-warn "No message at point"))) + (mark-as-read + (if (functionp mu4e-view-auto-mark-as-read) + (funcall mu4e-view-auto-mark-as-read msg) + mu4e-view-auto-mark-as-read)) (decrypt (mu4e~decrypt-p msg)) (verify (not mu4e-view-use-gnus)) (viewwin (mu4e~headers-redraw-get-view-window))) @@ -1668,8 +1672,8 @@ window . " ;; (if mu4e-view-use-gnus ;; (mu4e-view msg) - ;; (mu4e~proc-view docid mu4e-view-show-images decrypt)) - (mu4e~proc-view docid mu4e-view-show-images decrypt verify))) + ;; (mu4e~proc-view dowcid decrypt)) + (mu4e~proc-view docid mark-as-read decrypt verify))) (defun mu4e-headers-rerun-search () "Rerun the search for the last search expression." diff --git a/mu4e/mu4e-proc.el b/mu4e/mu4e-proc.el index e1369887..56a58299 100644 --- a/mu4e/mu4e-proc.el +++ b/mu4e/mu4e-proc.el @@ -468,16 +468,17 @@ respectively." :fcc )." (mu4e~call-mu `(sent :path ,path))) -(defun mu4e~proc-view (docid-or-msgid &optional images decrypt verify) +(defun mu4e~proc-view (docid-or-msgid &optional mark-as-read decrypt verify) "Get a message DOCID-OR-MSGID. -Optionally, if IMAGES is non-nil, backend will any images -attached to the message, and return them as temp files. DECRYPT and VERIFY -if necessary. The result will be delivered to the function -registered as `mu4e-view-func'." +Optionally, if MARK-AS-READ is non-nil, the backend marks the message as +read before returning, if it was not already unread. + DECRYPT and VERIFY if necessary. The result will be delivered to +the function registered as `mu4e-view-func'." (mu4e~call-mu `(view :docid ,(if (stringp docid-or-msgid) nil docid-or-msgid) :msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil) - :extract-images ,(if images t nil) + :mark-as-read ,mark-as-read + :extract-images ,(if mu4e-view-show-images t nil) :decrypt ,(and decrypt t) :verify ,(and verify t)))) @@ -489,7 +490,7 @@ result will be delivered to the function registered as `mu4e-view-func'. Optionally DECRYPT and VERIFY." (mu4e~call-mu `(view :path ,path - :extract-images ,(and images t) + :extract-images ,(if mu4e-view-show-images t nil) :decrypt ,(and decrypt t) :verify ,(and verify t)))) diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index a863d0b9..eb50c034 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -312,6 +312,21 @@ and `mu4e-headers-visible-columns'." (make-obsolete-variable 'mu4e-show-images 'mu4e-view-show-images "0.9.9.x") + +(defcustom mu4e-view-auto-mark-as-read t + "Automatically mark messages are 'read' when you read them. +This is the default behavior, but can be turned off, for example +when using a read-only file-system. + +This can also be set to a function; if so, receives a message +plist which should evaluate to nil if the message should *not* be +marked as read-only, or non-nil otherwise." + :type '(choice + boolean + function) + :group 'mu4e-view) + + (defcustom mu4e-confirm-quit t "Whether to confirm to quit mu4e." :type 'boolean diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index b47b8d92..b124034a 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -106,12 +106,6 @@ the end of a message. Otherwise, don't move to the next message." :type 'boolean :group 'mu4e-view) -(defcustom mu4e-view-auto-mark-as-read t - "Automatically mark messages are 'read' when you read -them. This is typically the expected behavior, but can be turned -off, for example when using a read-only file-system." - :type 'boolean - :group 'mu4e-view) (defcustom mu4e-save-multiple-attachments-without-asking nil "If non-nil, saving multiple attachments asks once for a @@ -337,6 +331,8 @@ marking if it still had that. Depending on the value of `mu4e-view-use-gnus', either use mu4e's internal display mode, or a display mode based on Gnus' article-mode." + (mu4e~headers-update-handler msg nil nil);; update headers, if necessary. + (mu4e~view-define-mode) ;; XXX(djcb): only called for the side-effect of setting up @@ -347,10 +343,9 @@ article-mode." ;; When MSG is unread, mu4e~view-mark-as-read-maybe will trigger ;; another call to mu4e-view (via mu4e~headers-update-handler as ;; the reply handler to mu4e~proc-move) - (unless (mu4e~view-mark-as-read-maybe msg) - (if mu4e-view-use-gnus - (mu4e~view-gnus msg) - (mu4e~view-internal msg)))) + (if mu4e-view-use-gnus + (mu4e~view-gnus msg) + (mu4e~view-internal msg))) (defun mu4e~view-internal (msg) "Display MSG using mu4e's internal view mode." @@ -362,25 +357,23 @@ article-mode." (get-buffer-create mu4e~view-buffer-name)))) (with-current-buffer buf (let ((inhibit-read-only t)) - (when (or embedded (not (mu4e~view-mark-as-read-maybe msg))) - (erase-buffer) - (mu4e~delete-all-overlays) - (insert (mu4e-view-message-text msg)) - (goto-char (point-min)) - (mu4e~fontify-cited) - (mu4e~fontify-signature) - (mu4e~view-make-urls-clickable) - (mu4e~view-show-images-maybe msg) - (when (not embedded) (setq mu4e~view-message msg)) - (mu4e-view-mode) - (when embedded (local-set-key "q" 'kill-buffer-and-window)))) + (erase-buffer) + (mu4e~delete-all-overlays) + (insert (mu4e-view-message-text msg)) + (goto-char (point-min)) + (mu4e~fontify-cited) + (mu4e~fontify-signature) + (mu4e~view-make-urls-clickable) + (mu4e~view-show-images-maybe msg) + (when (not embedded) (setq mu4e~view-message msg)) + (mu4e-view-mode) + (when embedded (local-set-key "q" 'kill-buffer-and-window))) (switch-to-buffer buf)))) (defun mu4e~view-gnus (msg) "View MSG using Gnus' article mode. Experimental." (require 'gnus-art) - (let ((marked-read (mu4e~view-mark-as-read-maybe msg)) - (path (mu4e-message-field msg :path)) + (let ((path (mu4e-message-field msg :path)) (inhibit-read-only t) ;; support signature verification (mm-verify-option 'known) @@ -391,31 +384,28 @@ article-mode." gnus-buttonized-mime-types))) (switch-to-buffer (get-buffer-create mu4e~view-buffer-name)) (erase-buffer) - (unless marked-read - ;; when we're being marked as read, no need to start rendering - ;; the messages; just the minimal so (update... ) can find us. - (insert-file-contents-literally path) - (unless (message-fetch-field "Content-Type" t) - ;; For example, for messages in `mu4e-drafts-folder' - (let ((coding (or (default-value 'buffer-file-coding-system) - 'prefer-utf-8))) - (recode-region (point-min) (point-max) coding 'no-conversion))) - (setq - gnus-summary-buffer (get-buffer-create " *appease-gnus*") - gnus-original-article-buffer (current-buffer)) - (run-hooks 'gnus-article-decode-hook) - (let ((mu4e~view-rendering t) ; customize gnus in mu4e - (max-specpdl-size mu4e-view-max-specpdl-size) - (gnus-blocked-images ".") ;; don't load external images. - ;; Possibly add headers (before "Attachments") - (gnus-display-mime-function (mu4e~view-gnus-display-mime msg)) - (gnus-icalendar-additional-identities (mu4e-personal-addresses))) - (gnus-article-prepare-display)) - (setq mu4e~view-message msg) - (mu4e-view-mode) - (setq gnus-article-decoded-p gnus-article-decode-hook) - (set-buffer-modified-p nil) - (read-only-mode)))) + (insert-file-contents-literally path) + (unless (message-fetch-field "Content-Type" t) + ;; For example, for messages in `mu4e-drafts-folder' + (let ((coding (or (default-value 'buffer-file-coding-system) + 'prefer-utf-8))) + (recode-region (point-min) (point-max) coding 'no-conversion))) + (setq + gnus-summary-buffer (get-buffer-create " *appease-gnus*") + gnus-original-article-buffer (current-buffer)) + (run-hooks 'gnus-article-decode-hook) + (let ((mu4e~view-rendering t) ; customize gnus in mu4e + (max-specpdl-size mu4e-view-max-specpdl-size) + (gnus-blocked-images ".") ;; don't load external images. + ;; Possibly add headers (before "Attachments") + (gnus-display-mime-function (mu4e~view-gnus-display-mime msg)) + (gnus-icalendar-additional-identities (mu4e-personal-addresses))) + (gnus-article-prepare-display)) + (setq mu4e~view-message msg) + (mu4e-view-mode) + (setq gnus-article-decoded-p gnus-article-decode-hook) + (set-buffer-modified-p nil) + (read-only-mode))) (defun mu4e~view-gnus-display-mime (msg) "Same as `gnus-display-mime' but add a mu4e headers to MSG." @@ -1021,26 +1011,6 @@ Gnus' article-mode." "Major mode for viewing an e-mail message in mu4e." (mu4e~view-mode-body)))) -(defun mu4e~view-mark-as-read-maybe (msg) - "Clear the message MSG New/Unread status and set it to Seen. -If the message is not New/Unread, do nothing. Evaluates to t if it -triggers any changes, nil otherwise. If this function does any -changes, it triggers a refresh." - (when (and mu4e-view-auto-mark-as-read msg) - (let ((flags (mu4e-message-field msg :flags)) - (msgid (mu4e-message-field msg :message-id)) - (docid (mu4e-message-field msg :docid))) - ;; attached (embedded) messages don't have docids; leave them alone if it - ;; is a new message - (when (and docid (or (member 'unread flags) (member 'new flags))) - ;; mark /all/ messages with this message-id as read, so all copies of - ;; this message will be marked as read. We don't want an update though, - ;; we want a full message, so images etc. work correctly. - (mu4e~proc-move msgid nil "+S-u-N" 'noview) - (mu4e~proc-view docid mu4e-view-show-images - (mu4e~decrypt-p msg) (not mu4e-view-use-gnus)) - t)))) - (defun mu4e~view-browse-url-func (url) "Return a function that executes `browse-url' with URL. The browser that is called depends on @@ -1538,7 +1508,7 @@ attachments) in response to a (mu4e~proc-extract 'temp ... )." ;; remember the mapping path->docid, which maps the path of the embedded ;; message to the docid of its parent (puthash path docid mu4e~path-parent-docid-map) - (mu4e~proc-view-path path mu4e-view-show-images mu4e-decryption-policy)) + (mu4e~proc-view-path path mu4e-decryption-policy)) ((string= what "emacs") (find-file path) ;; make the buffer read-only since it usually does not make