-(defun notmuch-show-markup-citations ()
- "Markup citations, and up to one signature in the buffer."
- (let ((depth 0)
- (indent "\n"))
- (goto-char (point-min))
- (beginning-of-line)
- (while (and (< (point) (point-max))
- (re-search-forward notmuch-show-citation-regexp nil t))
- (let* ((cite-start (match-beginning 0))
- (cite-end (match-end 0))
- (cite-lines (count-lines cite-start cite-end)))
- (when (> cite-lines (1+ notmuch-show-citation-lines-prefix))
- (goto-char cite-start)
- (forward-line notmuch-show-citation-lines-prefix)
- (let ((hidden-start (point-marker)))
- (goto-char cite-end)
- (notmuch-show-region-to-button
- hidden-start (point-marker)
- "citation" indent
- (format notmuch-show-citation-button-format
- (- cite-lines notmuch-show-citation-lines-prefix)))))))
- (if (and (not (eobp))
- (re-search-forward notmuch-show-signature-regexp nil t))
- (let* ((sig-start (match-beginning 0))
- (sig-end (match-end 0))
- (sig-lines (1- (count-lines sig-start (point-max)))))
- (if (<= sig-lines notmuch-show-signature-lines-max)
- (let ((sig-start-marker (make-marker))
- (sig-end-marker (make-marker)))
- (set-marker sig-start-marker sig-start)
- (set-marker sig-end-marker (point-max))
- (notmuch-show-region-to-button
- sig-start-marker sig-end-marker
- "signature" indent
- (format notmuch-show-signature-button-format sig-lines))))))))
-
-(defun notmuch-show-insert-part-text/plain (part content-type depth)
+(defun notmuch-show-save-part (message-id nth &optional filename)
+ (with-temp-buffer
+ ;; Always acquires the part via `notmuch part', even if it is
+ ;; available in the JSON output.
+ (insert (notmuch-show-get-bodypart-internal message-id nth))
+ (let ((file (read-file-name
+ "Filename to save as: "
+ (or mailcap-download-directory "~/")
+ nil nil
+ filename))
+ (require-final-newline nil)
+ (coding-system-for-write 'no-conversion))
+ (write-region (point-min) (point-max) file))))
+
+(defun notmuch-show-mm-display-part-inline (msg part content-type content)
+ "Use the mm-decode/mm-view functions to display a part in the
+current buffer, if possible."
+ (let ((display-buffer (current-buffer)))
+ (with-temp-buffer
+ (insert content)
+ (let ((handle (mm-make-handle (current-buffer) (list content-type))))
+ (set-buffer display-buffer)
+ (if (and (mm-inlinable-p handle)
+ (mm-inlined-p handle))
+ (progn
+ (mm-display-part handle)
+ t)
+ nil)))))
+
+(defvar notmuch-show-multipart/alternative-discouraged
+ '(
+ ;; Avoid HTML parts.
+ "text/html"
+ ;; multipart/related usually contain a text/html part and some associated graphics.
+ "multipart/related"
+ ))
+
+(defun notmuch-show-multipart/*-to-list (part)
+ (mapcar '(lambda (inner-part) (plist-get inner-part :content-type))
+ (plist-get part :content)))
+
+(defun notmuch-show-multipart/alternative-choose (types)
+ ;; Based on `mm-preferred-alternative-precedence'.
+ (let ((seq types))
+ (dolist (pref (reverse notmuch-show-multipart/alternative-discouraged))
+ (dolist (elem (copy-sequence seq))
+ (when (string-match pref elem)
+ (setq seq (nconc (delete elem seq) (list elem))))))
+ seq))
+
+(defun notmuch-show-insert-part-multipart/alternative (msg part content-type nth depth declared-type)
+ (notmuch-show-insert-part-header nth declared-type content-type nil)
+ (let ((chosen-type (car (notmuch-show-multipart/alternative-choose (notmuch-show-multipart/*-to-list part))))
+ (inner-parts (plist-get part :content))
+ (start (point)))
+ ;; This inserts all parts of the chosen type rather than just one,
+ ;; but it's not clear that this is the wrong thing to do - which
+ ;; should be chosen if there are more than one that match?
+ (mapc (lambda (inner-part)
+ (let ((inner-type (plist-get inner-part :content-type)))
+ (if (or notmuch-show-all-multipart/alternative-parts
+ (string= chosen-type inner-type))
+ (notmuch-show-insert-bodypart msg inner-part depth)
+ (notmuch-show-insert-part-header (plist-get inner-part :id) inner-type inner-type nil " (not shown)"))))
+ inner-parts)
+
+ (when notmuch-show-indent-multipart
+ (indent-rigidly start (point) 1)))
+ t)
+
+(defun notmuch-show-insert-part-multipart/* (msg part content-type nth depth declared-type)
+ (notmuch-show-insert-part-header nth declared-type content-type nil)
+ (let ((inner-parts (plist-get part :content))
+ (start (point)))
+ ;; Show all of the parts.
+ (mapc (lambda (inner-part)
+ (notmuch-show-insert-bodypart msg inner-part depth))
+ inner-parts)
+
+ (when notmuch-show-indent-multipart
+ (indent-rigidly start (point) 1)))
+ t)
+
+(defun notmuch-show-insert-part-message/rfc822 (msg part content-type nth depth declared-type)
+ (let* ((message-part (plist-get part :content))
+ (inner-parts (plist-get message-part :content)))
+ (notmuch-show-insert-part-header nth declared-type content-type nil)
+ ;; 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 part :headers)))
+ ;; Blank line after headers to be compatible with the normal
+ ;; message display.
+ (insert "\n")
+
+ ;; Show all of the parts.
+ (mapc (lambda (inner-part)
+ (notmuch-show-insert-bodypart msg inner-part depth))
+ inner-parts))
+ t)
+
+(defun notmuch-show-insert-part-text/plain (msg part content-type nth depth declared-type)