emacs: Improve the acquisition of text parts.

`notmuch-get-bodypart-text' assumed that it is always possible to
acquire text/* parts via the sexp output format. This is not true if the
part in question has a content type of application/octet-stream but is
being interpreted as text/* based on the extension of the part filename.

Rework `notmuch-get-bodypart-text' to use the raw output format to
address this and make the implementation common with that of
`notmuch-get-bodypart-binary'.
This commit is contained in:
David Edmondson 2016-03-08 17:12:59 +00:00 committed by David Bremner
parent 742b566cac
commit c41d0db077

View file

@ -537,22 +537,9 @@ the given type."
(lambda (part) (notmuch-match-content-type (plist-get part :content-type) type)) (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
parts)) parts))
(defun notmuch-get-bodypart-binary (msg part process-crypto &optional cache) (defun notmuch--get-bodypart-raw (msg part process-crypto binaryp cache)
"Return the unprocessed content of PART in MSG as a unibyte string. (let* ((plist-elem (if binaryp :content-binary :content))
(data (or (plist-get part plist-elem)
This returns the \"raw\" content of the given part after content
transfer decoding, but with no further processing (see the
discussion of --format=raw in man notmuch-show). In particular,
this does no charset conversion.
If CACHE is non-nil, the content of this part will be saved in
MSG (if it isn't already)."
(let ((data (plist-get part :binary-content)))
(when (not data)
(let ((args `("show" "--format=raw"
,(format "--part=%d" (plist-get part :id))
,@(when process-crypto '("--decrypt"))
,(notmuch-id-to-query (plist-get msg :id)))))
(with-temp-buffer (with-temp-buffer
;; Emacs internally uses a UTF-8-like multibyte string ;; Emacs internally uses a UTF-8-like multibyte string
;; representation by default (regardless of the coding ;; representation by default (regardless of the coding
@ -564,40 +551,42 @@ MSG (if it isn't already)."
;; corrupts binary image formats. Since the caller is ;; corrupts binary image formats. Since the caller is
;; asking for binary data, a unibyte string is a more ;; asking for binary data, a unibyte string is a more
;; appropriate representation anyway. ;; appropriate representation anyway.
(set-buffer-multibyte nil) (when binaryp
(let ((coding-system-for-read 'no-conversion)) (set-buffer-multibyte nil))
(let ((args `("show" "--format=raw"
,(format "--part=%s" (plist-get part :id))
,@(when process-crypto '("--decrypt"))
,(notmuch-id-to-query (plist-get msg :id))))
(coding-system-for-read
(if binaryp 'no-conversion 'utf-8)))
(apply #'call-process notmuch-command nil '(t nil) nil args) (apply #'call-process notmuch-command nil '(t nil) nil args)
(setq data (buffer-string))))) (buffer-string))))))
(when cache (when (and cache data)
;; Cheat. part is non-nil, and `plist-put' always modifies (plist-put part plist-elem data))
;; the list in place if it's non-nil.
(plist-put part :binary-content data)))
data)) data))
(defun notmuch-get-bodypart-binary (msg part process-crypto &optional cache)
"Return the unprocessed content of PART in MSG as a unibyte string.
This returns the \"raw\" content of the given part after content
transfer decoding, but with no further processing (see the
discussion of --format=raw in man notmuch-show). In particular,
this does no charset conversion.
If CACHE is non-nil, the content of this part will be saved in
MSG (if it isn't already)."
(notmuch--get-bodypart-raw msg part process-crypto t cache))
(defun notmuch-get-bodypart-text (msg part process-crypto &optional cache) (defun notmuch-get-bodypart-text (msg part process-crypto &optional cache)
"Return the text content of PART in MSG. "Return the text content of PART in MSG.
This returns the content of the given part as a multibyte Lisp This returns the content of the given part as a multibyte Lisp
string after performing content transfer decoding and any string after performing content transfer decoding and any
necessary charset decoding. It is an error to use this for necessary charset decoding.
non-text/* parts.
If CACHE is non-nil, the content of this part will be saved in If CACHE is non-nil, the content of this part will be saved in
MSG (if it isn't already)." MSG (if it isn't already)."
(let ((content (plist-get part :content))) (notmuch--get-bodypart-raw msg part process-crypto nil cache))
(when (not content)
;; Use show --format=sexp to fetch decoded content
(let* ((args `("show" "--format=sexp" "--include-html"
,(format "--part=%s" (plist-get part :id))
,@(when process-crypto '("--decrypt"))
,(notmuch-id-to-query (plist-get msg :id))))
(npart (apply #'notmuch-call-notmuch-sexp args)))
(setq content (plist-get npart :content))
(when (not content)
(error "Internal error: No :content from %S" args)))
(when cache
(plist-put part :content content)))
content))
;; Workaround: The call to `mm-display-part' below triggers a bug in ;; Workaround: The call to `mm-display-part' below triggers a bug in
;; Emacs 24 if it attempts to use the shr renderer to display an HTML ;; Emacs 24 if it attempts to use the shr renderer to display an HTML