X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=emacs%2Fnotmuch-show.el;h=ea20ddcef4d8fdb634c59dcaff3ff44a36dc818f;hb=e722b4f4;hp=72e21d94387c698739e7cc435d34d13ce40598d1;hpb=fc4cda07a9afbbb545dcc6cd835ca697f6ef2a1b;p=notmuch diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 72e21d94..ea20ddce 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -23,10 +23,6 @@ ;;; Code: -(eval-when-compile - (require 'cl-lib) - (require 'pcase)) - (require 'mm-view) (require 'message) (require 'mm-decode) @@ -43,25 +39,27 @@ (require 'notmuch-print) (require 'notmuch-draft) -(declare-function notmuch-call-notmuch-process "notmuch" (&rest args)) +(declare-function notmuch-call-notmuch-process "notmuch-lib" (&rest args)) (declare-function notmuch-search-next-thread "notmuch" nil) (declare-function notmuch-search-previous-thread "notmuch" nil) -(declare-function notmuch-search-show-thread "notmuch" nil) +(declare-function notmuch-search-show-thread "notmuch") (declare-function notmuch-foreach-mime-part "notmuch" (function mm-handle)) (declare-function notmuch-count-attachments "notmuch" (mm-handle)) (declare-function notmuch-save-attachments "notmuch" (mm-handle &optional queryp)) (declare-function notmuch-tree "notmuch-tree" (&optional query query-context target buffer-name - open-target unthreaded)) + open-target unthreaded parent-buffer)) (declare-function notmuch-tree-get-message-properties "notmuch-tree" nil) -(declare-function notmuch-unthreaded - (&optional query query-context target buffer-name open-target)) +(declare-function notmuch-unthreaded "notmuch-tree" + (&optional query query-context target buffer-name + open-target)) (declare-function notmuch-read-query "notmuch" (prompt)) (declare-function notmuch-draft-resume "notmuch-draft" (id)) (defvar shr-blocked-images) (defvar gnus-blocked-images) (defvar shr-content-function) +(defvar w3m-ignored-image-url-regexp) ;;; Options @@ -182,6 +180,8 @@ indentation." (defvar-local notmuch-show-indent-content t) +(defvar-local notmuch-show-single-message nil) + (defvar notmuch-show-attachment-debug nil "If t log stdout and stderr from attachment handlers. @@ -193,10 +193,10 @@ each attachment handler is logged in buffers with names beginning ;;; Options (defcustom notmuch-show-stash-mlarchive-link-alist - '(("Gmane" . "https://mid.gmane.org/") - ("MARC" . "https://marc.info/?i=") + '(("MARC" . "https://marc.info/?i=") ("Mail Archive, The" . "https://mid.mail-archive.com/") - ("LKML" . "https://lkml.kernel.org/r/") + ("Lore" . "https://lore.kernel.org/r/") + ("Notmuch" . "https://nmbug.notmuchmail.org/nmweb/show/") ;; FIXME: can these services be searched by `Message-Id' ? ;; ("MarkMail" . "http://markmail.org/") ;; ("Nabble" . "http://nabble.com/") @@ -221,7 +221,7 @@ return the ML archive reference URI." (function :tag "Function returning the URL"))) :group 'notmuch-show) -(defcustom notmuch-show-stash-mlarchive-link-default "Gmane" +(defcustom notmuch-show-stash-mlarchive-link-default "MARC" "Default Mailing List Archive to use when stashing links. This is used when `notmuch-show-stash-mlarchive-link' isn't @@ -279,7 +279,7 @@ position of the message in the thread." (let ((buf (generate-new-buffer (concat "*notmuch-msg-" id "*")))) (with-current-buffer buf (let ((coding-system-for-read 'no-conversion)) - (call-process notmuch-command nil t nil "show" "--format=raw" id)) + (notmuch--call-process notmuch-command nil t nil "show" "--format=raw" id)) ,@body) (kill-buffer buf))))) @@ -337,7 +337,7 @@ operation on the contents of the current buffer." (header (concat "Subject: " subject "\n" "To: " to "\n" - (if (not (string= cc "")) + (if (not (string-empty-p cc)) (concat "Cc: " cc "\n") "") "From: " from "\n" @@ -517,7 +517,7 @@ message at DEPTH in the current thread." 'face 'message-mml :supertype 'notmuch-button-type) -(defun notmuch-show-insert-part-header (nth content-type declared-type +(defun notmuch-show-insert-part-header (_nth content-type declared-type &optional name comment) (let ((base-label (concat (and name (concat name ": ")) declared-type @@ -585,16 +585,17 @@ message at DEPTH in the current thread." ;; alternative (even if we can't render it). (push (list content-id msg part) notmuch-show--cids))) ;; Recurse on sub-parts - (pcase-let ((`(,content ,type) - (split-string (downcase (plist-get part :content-type)) "/"))) - (cond ((equal content "multipart") - (mapc (apply-partially #'notmuch-show--register-cids msg) - (plist-get part :content))) - ((and (equal content "message") - (equal type "rfc822")) - (notmuch-show--register-cids - msg - (car (plist-get (car (plist-get part :content)) :body))))))) + (when-let ((type (plist-get part :content-type))) + (pcase-let ((`(,type ,subtype) + (split-string (downcase type) "/"))) + (cond ((equal type "multipart") + (mapc (apply-partially #'notmuch-show--register-cids msg) + (plist-get part :content))) + ((and (equal type "message") + (equal subtype "rfc822")) + (notmuch-show--register-cids + msg + (car (plist-get (car (plist-get part :content)) :body)))))))) (defun notmuch-show--get-cid-content (cid) "Return a list (CID-content content-type) or nil. @@ -603,16 +604,13 @@ This will only find parts from messages that have been inserted into the current buffer. CID must be a raw content ID, without enclosing angle brackets, a cid: prefix, or URL encoding. This will return nil if the CID is unknown or cannot be retrieved." - (let ((descriptor (cdr (assoc cid notmuch-show--cids)))) - (when descriptor - (let* ((msg (car descriptor)) - (part (cadr descriptor)) - ;; Request caching for this content, as some messages - ;; reference the same cid: part many times (hundreds!). - (content (notmuch-get-bodypart-binary - msg part notmuch-show-process-crypto 'cache)) - (content-type (plist-get part :content-type))) - (list content content-type))))) + (when-let ((descriptor (cdr (assoc cid notmuch-show--cids)))) + (pcase-let ((`(,msg ,part) descriptor)) + ;; Request caching for this content, as some messages + ;; reference the same cid: part many times (hundreds!). + (list (notmuch-get-bodypart-binary + msg part notmuch-show-process-crypto 'cache) + (plist-get part :content-type))))) (defun notmuch-show-setup-w3m () "Instruct w3m how to retrieve content from a \"related\" part of a message." @@ -624,7 +622,7 @@ will return nil if the CID is unknown or cannot be retrieved." (setq mm-html-inhibit-images nil)) (defvar w3m-current-buffer) ;; From `w3m.el'. -(defun notmuch-show--cid-w3m-retrieve (url &rest args) +(defun notmuch-show--cid-w3m-retrieve (url &rest _args) ;; url includes the cid: prefix and is URL encoded (see RFC 2392). (let* ((cid (url-unhex-string (substring url 4))) (content-and-type @@ -640,7 +638,7 @@ will return nil if the CID is unknown or cannot be retrieved." (mapcar (lambda (inner-part) (plist-get inner-part :content-type)) (plist-get part :content))) -(defun notmuch-show-insert-part-multipart/alternative (msg part content-type nth depth button) +(defun notmuch-show-insert-part-multipart/alternative (msg part _content-type _nth depth _button) (let ((chosen-type (car (notmuch-multipart/alternative-choose msg (notmuch-show-multipart/*-to-list part)))) (inner-parts (plist-get part :content)) @@ -659,7 +657,7 @@ will return nil if the CID is unknown or cannot be retrieved." (indent-rigidly start (point) 1))) t) -(defun notmuch-show-insert-part-multipart/related (msg part content-type nth depth button) +(defun notmuch-show-insert-part-multipart/related (msg part _content-type _nth depth _button) (let ((inner-parts (plist-get part :content)) (start (point))) ;; Render the primary part. FIXME: Support RFC 2387 Start header. @@ -672,7 +670,7 @@ will return nil if the CID is unknown or cannot be retrieved." (indent-rigidly start (point) 1))) t) -(defun notmuch-show-insert-part-multipart/signed (msg part content-type nth depth button) +(defun notmuch-show-insert-part-multipart/signed (msg part _content-type _nth depth button) (when button (button-put button 'face 'notmuch-crypto-part-header)) ;; Insert a button detailing the signature status. @@ -688,7 +686,7 @@ will return nil if the CID is unknown or cannot be retrieved." (indent-rigidly start (point) 1))) t) -(defun notmuch-show-insert-part-multipart/encrypted (msg part content-type nth depth button) +(defun notmuch-show-insert-part-multipart/encrypted (msg part _content-type _nth depth button) (when button (button-put button 'face 'notmuch-crypto-part-header)) ;; Insert a button detailing the encryption status. @@ -706,10 +704,10 @@ will return nil if the CID is unknown or cannot be retrieved." (indent-rigidly start (point) 1))) t) -(defun notmuch-show-insert-part-application/pgp-encrypted (msg part content-type nth depth button) +(defun notmuch-show-insert-part-application/pgp-encrypted (_msg _part _content-type _nth _depth _button) t) -(defun notmuch-show-insert-part-multipart/* (msg part content-type nth depth button) +(defun notmuch-show-insert-part-multipart/* (msg part _content-type _nth depth _button) (let ((inner-parts (plist-get part :content)) (start (point))) ;; Show all of the parts. @@ -720,24 +718,26 @@ will return nil if the CID is unknown or cannot be retrieved." (indent-rigidly start (point) 1))) t) -(defun notmuch-show-insert-part-message/rfc822 (msg part content-type nth depth button) - (let* ((message (car (plist-get part :content))) - (body (car (plist-get message :body))) - (start (point))) - ;; Override `notmuch-message-headers' to force `From' to be - ;; displayed. - (let ((notmuch-message-headers '("From" "Subject" "To" "Cc" "Date"))) - (notmuch-show-insert-headers (plist-get message :headers))) - ;; Blank line after headers to be compatible with the normal - ;; message display. - (insert "\n") - ;; Show the body - (notmuch-show-insert-bodypart msg body depth) - (when notmuch-show-indent-multipart - (indent-rigidly start (point) 1))) - t) - -(defun notmuch-show-insert-part-text/plain (msg part content-type nth depth button) +(defun notmuch-show-insert-part-message/rfc822 (msg part _content-type _nth depth _button) + (let ((message (car (plist-get part :content)))) + (and + message + (let ((body (car (plist-get message :body))) + (start (point))) + ;; Override `notmuch-message-headers' to force `From' to be + ;; displayed. + (let ((notmuch-message-headers '("From" "Subject" "To" "Cc" "Date"))) + (notmuch-show-insert-headers (plist-get message :headers))) + ;; Blank line after headers to be compatible with the normal + ;; message display. + (insert "\n") + ;; Show the body + (notmuch-show-insert-bodypart msg body depth) + (when notmuch-show-indent-multipart + (indent-rigidly start (point) 1)) + t)))) + +(defun notmuch-show-insert-part-text/plain (msg part _content-type _nth depth button) ;; For backward compatibility we want to apply the text/plain hook ;; to the whole of the part including the part button if there is ;; one. @@ -751,7 +751,7 @@ will return nil if the CID is unknown or cannot be retrieved." (run-hook-with-args 'notmuch-show-insert-text/plain-hook msg depth)))) t) -(defun notmuch-show-insert-part-text/calendar (msg part content-type nth depth button) +(defun notmuch-show-insert-part-text/calendar (msg part _content-type _nth _depth _button) (insert (with-temp-buffer (insert (notmuch-get-bodypart-text msg part notmuch-show-process-crypto)) ;; notmuch-get-bodypart-text does no newline conversion. @@ -775,8 +775,8 @@ will return nil if the CID is unknown or cannot be retrieved." t) ;; For backwards compatibility. -(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth depth button) - (notmuch-show-insert-part-text/calendar msg part content-type nth depth button)) +(defun notmuch-show-insert-part-text/x-vcalendar (msg part _content-type _nth depth _button) + (notmuch-show-insert-part-text/calendar msg part nil nil depth nil)) (when (version< emacs-version "25.3") ;; https://bugs.gnu.org/28350 @@ -792,7 +792,7 @@ will return nil if the CID is unknown or cannot be retrieved." ;; the first time). (require 'enriched) (cl-letf (((symbol-function 'enriched-decode-display-prop) - (lambda (start end &optional param) (list start end)))) + (lambda (start end &optional _param) (list start end)))) (notmuch-show-insert-part-*/* msg part content-type nth depth button)))) (defun notmuch-show-get-mime-type-of-application/octet-stream (part) @@ -826,7 +826,8 @@ will return nil if the CID is unknown or cannot be retrieved." (let ((mm-inline-text-html-with-w3m-keymap nil) ;; FIXME: If we block an image, offer a button to load external ;; images. - (gnus-blocked-images notmuch-show-text/html-blocked-images)) + (gnus-blocked-images notmuch-show-text/html-blocked-images) + (w3m-ignored-image-url-regexp notmuch-show-text/html-blocked-images)) (notmuch-show-insert-part-*/* msg part content-type nth depth button)))) ;;; Functions used by notmuch-show--insert-part-text/html-shr @@ -850,7 +851,7 @@ will return nil if the CID is unknown or cannot be retrieved." (shr-insert-document dom) t)) -(defun notmuch-show-insert-part-*/* (msg part content-type nth depth button) +(defun notmuch-show-insert-part-*/* (msg part content-type _nth _depth _button) ;; This handler _must_ succeed - it is the handler of last resort. (notmuch-mm-display-part-inline msg part content-type notmuch-show-process-crypto) t) @@ -955,7 +956,8 @@ will return nil if the CID is unknown or cannot be retrieved." (defun notmuch-show-mime-type (part) "Return the correct mime-type to use for PART." - (let ((content-type (downcase (plist-get part :content-type)))) + (when-let ((content-type (plist-get part :content-type))) + (setq content-type (downcase content-type)) (or (and (string= content-type "application/octet-stream") (notmuch-show-get-mime-type-of-application/octet-stream part)) (and (string= content-type "inline patch") @@ -970,13 +972,13 @@ The function should take two parameters, PART and HIDE, and should return non-NIL if a header button should be inserted for this part.") -(defun notmuch-show-insert-header-p (part hide) +(defun notmuch-show-insert-header-p (part _hide) ;; Show all part buttons except for the first part if it is text/plain. (let ((mime-type (notmuch-show-mime-type part))) (not (and (string= mime-type "text/plain") (<= (plist-get part :id) 1))))) -(defun notmuch-show-reply-insert-header-p-never (part hide) +(defun notmuch-show-reply-insert-header-p-never (_part _hide) nil) (defun notmuch-show-reply-insert-header-p-trimmed (part hide) @@ -995,7 +997,7 @@ this part.") HIDE determines whether to show or hide the part and the button as follows: If HIDE is nil, show the part and the button. If HIDE is t, hide the part initially and show the button." - (let* ((content-type (downcase (plist-get part :content-type))) + (let* ((content-type (plist-get part :content-type)) (mime-type (notmuch-show-mime-type part)) (nth (plist-get part :id)) (long (and (notmuch-match-content-type mime-type "text/*") @@ -1007,7 +1009,8 @@ is t, hide the part initially and show the button." ;; the first (or only) part if this is text/plain. (button (and (funcall notmuch-show-insert-header-p-function part hide) (notmuch-show-insert-part-header - nth mime-type content-type + nth mime-type + (and content-type (downcase content-type)) (plist-get part :filename)))) ;; Hide the part initially if HIDE is t, or if it is too long ;; and we have a button to allow toggling. @@ -1318,9 +1321,10 @@ Apply the previously saved STATE if supplied, otherwise show the first relevant message. If no messages match the query return NIL." - (let* ((cli-args (cons "--exclude=false" - (and notmuch-show-elide-non-matching-messages - (list "--entire-thread=false")))) + (let* ((cli-args (list "--exclude=false")) + (cli-args (if notmuch-show-elide-non-matching-messages (cons "--entire-thread=false" cli-args) cli-args)) + ;; "part 0 is the whole message (headers and body)" notmuch-show(1) + (cli-args (if notmuch-show-single-message (cons "--part=0" cli-args) cli-args)) (queries (notmuch-show--build-queries notmuch-show-thread-id notmuch-show-query-context)) (forest nil) @@ -1331,6 +1335,8 @@ If no messages match the query return NIL." (while (and (not forest) queries) (setq forest (notmuch-query-get-threads (append cli-args (list "'") (car queries) (list "'")))) + (when (and forest notmuch-show-single-message) + (setq forest (list (list (list forest))))) (setq queries (cdr queries))) (when forest (notmuch-show-insert-forest forest) @@ -1666,13 +1672,13 @@ It gets property PROP from PROPS or, if PROPS is nil, the current message in either tree or show. This means that several utility functions in notmuch-show can be used directly by notmuch-tree as they just need the correct message properties." - (let ((props (or props - (cond ((eq major-mode 'notmuch-show-mode) - (notmuch-show-get-message-properties)) - ((eq major-mode 'notmuch-tree-mode) - (notmuch-tree-get-message-properties)) - (t nil))))) - (plist-get props prop))) + (plist-get (or props + (cond ((eq major-mode 'notmuch-show-mode) + (notmuch-show-get-message-properties)) + ((eq major-mode 'notmuch-tree-mode) + (notmuch-tree-get-message-properties)) + (t nil))) + prop)) (defun notmuch-show-get-message-id (&optional bare) "Return an id: query for the Message-Id of the current message. @@ -1759,7 +1765,7 @@ marked as unread, i.e. the tag changes in (apply 'notmuch-show-tag-message (notmuch-tag-change-list notmuch-show-mark-read-tags unread)))) -(defun notmuch-show-seen-current-message (start end) +(defun notmuch-show-seen-current-message (_start _end) "Mark the current message read if it is open. We only mark it read once: if it is changed back then that is a @@ -1777,7 +1783,7 @@ user decision and we should not override it." ;; We need to redisplay to get window-start and window-end correct. (redisplay) (save-excursion - (condition-case err + (condition-case nil (funcall notmuch-show-mark-read-function (window-start) (window-end)) ((debug error) (unless notmuch-show--seen-has-errored @@ -1794,7 +1800,7 @@ user decision and we should not override it." Reshows the current thread with matches defined by the new query-string." (interactive (list (notmuch-read-query "Filter thread: "))) (let ((msg-id (notmuch-show-get-message-id))) - (setq notmuch-show-query-context (if (string= query "") nil query)) + (setq notmuch-show-query-context (if (string-empty-p query) nil query)) (notmuch-show-refresh-view t) (notmuch-show-goto-message msg-id))) @@ -2028,7 +2034,7 @@ to show, nil otherwise." (pop-to-buffer-same-window buf) (erase-buffer) (let ((coding-system-for-read 'no-conversion)) - (call-process notmuch-command nil t nil "show" "--format=raw" id)) + (notmuch--call-process notmuch-command nil t nil "show" "--format=raw" id)) (goto-char (point-min)) (set-buffer-modified-p nil) (setq buffer-read-only t) @@ -2074,19 +2080,19 @@ message." (let ((cwd default-directory) (buf (get-buffer-create (concat "*notmuch-pipe*")))) (with-current-buffer buf - (setq buffer-read-only nil) - (erase-buffer) - ;; Use the originating buffer's working directory instead of - ;; that of the pipe buffer. - (cd cwd) - (let ((exit-code (call-process-shell-command shell-command nil buf))) - (goto-char (point-max)) - (set-buffer-modified-p nil) - (setq buffer-read-only t) - (unless (zerop exit-code) - (pop-to-buffer buf) - (message (format "Command '%s' exited abnormally with code %d" - shell-command exit-code)))))))) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (erase-buffer) + ;; Use the originating buffer's working directory instead of + ;; that of the pipe buffer. + (cd cwd) + (let ((exit-code (notmuch--call-process-shell-command shell-command nil buf))) + (goto-char (point-max)) + (set-buffer-modified-p nil) + (unless (zerop exit-code) + (pop-to-buffer buf) + (message (format "Command '%s' exited abnormally with code %d" + shell-command exit-code))))))))) (defun notmuch-show-tag-message (&rest tag-changes) "Change tags for the current message.