(require 'mm-decode)
(require 'cl)
+(unless (require 'notmuch-version nil t)
+ (defconst notmuch-emacs-version "unknown"
+ "Placeholder variable when notmuch-version.el[c] is not available."))
+
(autoload 'notmuch-jump-search "notmuch-jump"
"Jump to a saved search by shortcut key." t)
(defvar notmuch-common-keymap
(let ((map (make-sparse-keymap)))
(define-key map "?" 'notmuch-help)
- (define-key map "q" 'notmuch-kill-this-buffer)
+ (define-key map "q" 'notmuch-bury-or-kill-this-buffer)
(define-key map "s" 'notmuch-search)
(define-key map "z" 'notmuch-tree)
(define-key map "m" 'notmuch-mua-new-mail)
"Perhaps you haven't run \"notmuch setup\" yet? Try running this
on the command line, and then retry your notmuch command")))
-(defun notmuch-version ()
- "Return a string with the notmuch version number."
+(defun notmuch-cli-version ()
+ "Return a string with the notmuch cli command version number."
(let ((long-string
;; Trim off the trailing newline.
(substring (notmuch-command-to-string "--version") 0 -1)))
(call-process notmuch-poll-script nil nil))
(call-process notmuch-command nil nil nil "new")))
-(defun notmuch-kill-this-buffer ()
- "Kill the current buffer."
+(defun notmuch-bury-or-kill-this-buffer ()
+ "Undisplay the current buffer.
+
+Bury the current buffer, unless there is only one window showing
+it, in which case it is killed."
(interactive)
- (kill-buffer (current-buffer)))
+ (if (> (length (get-buffer-window-list nil nil t)) 1)
+ (bury-buffer)
+ (kill-buffer)))
(defun notmuch-documentation-first-line (symbol)
"Return the first line of the documentation string for SYMBOL."
(lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
parts))
-;; Helper for parts which are generally not included in the default
-;; SEXP output.
-(defun notmuch-get-bodypart-internal (query part-number process-crypto)
- (let ((args '("show" "--format=raw"))
- (part-arg (format "--part=%s" part-number)))
- (setq args (append args (list part-arg)))
- (if process-crypto
- (setq args (append args '("--decrypt"))))
- (setq args (append args (list query)))
- (with-temp-buffer
- (let ((coding-system-for-read 'no-conversion))
- (progn
- (apply 'call-process (append (list notmuch-command nil (list t nil) nil) args))
- (buffer-string))))))
-
-(defun notmuch-get-bodypart-content (msg part nth process-crypto)
- (or (plist-get part :content)
- (notmuch-get-bodypart-internal (notmuch-id-to-query (plist-get msg :id)) nth process-crypto)))
+(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)."
+ (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
+ ;; Emacs internally uses a UTF-8-like multibyte string
+ ;; representation by default (regardless of the coding
+ ;; system, which only affects how it goes from outside data
+ ;; to this internal representation). This *almost* never
+ ;; matters. Annoyingly, it does matter if we use this data
+ ;; in an image descriptor, since Emacs will use its internal
+ ;; data buffer directly and this multibyte representation
+ ;; corrupts binary image formats. Since the caller is
+ ;; asking for binary data, a unibyte string is a more
+ ;; appropriate representation anyway.
+ (set-buffer-multibyte nil)
+ (let ((coding-system-for-read 'no-conversion))
+ (apply #'call-process notmuch-command nil '(t nil) nil args)
+ (setq data (buffer-string)))))
+ (when cache
+ ;; Cheat. part is non-nil, and `plist-put' always modifies
+ ;; the list in place if it's non-nil.
+ (plist-put part :binary-content data)))
+ data))
+
+(defun notmuch-get-bodypart-text (msg part process-crypto &optional cache)
+ "Return the text content of PART in MSG.
+
+This returns the content of the given part as a multibyte Lisp
+string after performing content transfer decoding and any
+necessary charset decoding. It is an error to use this for
+non-text/* parts.
+
+If CACHE is non-nil, the content of this part will be saved in
+MSG (if it isn't already)."
+ (let ((content (plist-get part :content)))
+ (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
;; Emacs 24 if it attempts to use the shr renderer to display an HTML
(ad-disable-advice 'mm-shr 'before 'load-gnus-arts)
(ad-activate 'mm-shr)))
-(defun notmuch-mm-display-part-inline (msg part nth content-type process-crypto)
+(defun notmuch-mm-display-part-inline (msg part content-type process-crypto)
"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
- ;; In case there is :content, the content string is already converted
- ;; into emacs internal format. `gnus-decoded' is a fake charset,
- ;; which means no further decoding (to be done by mm- functions).
- (let* ((charset (if (plist-member part :content)
- 'gnus-decoded
+ ;; In case we already have :content, use it and tell mm-* that
+ ;; it's already been charset-decoded by using the fake
+ ;; `gnus-decoded' charset. Otherwise, we'll fetch the binary
+ ;; part content and let mm-* decode it.
+ (let* ((have-content (plist-member part :content))
+ (charset (if have-content 'gnus-decoded
(plist-get part :content-charset)))
(handle (mm-make-handle (current-buffer) `(,content-type (charset . ,charset)))))
;; If the user wants the part inlined, insert the content and
;; test whether we are able to inline it (which includes both
;; capability and suitability tests).
(when (mm-inlined-p handle)
- (insert (notmuch-get-bodypart-content msg part nth process-crypto))
+ (if have-content
+ (insert (notmuch-get-bodypart-text msg part process-crypto))
+ (insert (notmuch-get-bodypart-binary msg part process-crypto)))
(when (mm-inlinable-p handle)
(set-buffer display-buffer)
(mm-display-part handle)