]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-lib.el
emacs: `notmuch-show-forward-message' can use `notmuch-mua-new-forward-messages'
[notmuch] / emacs / notmuch-lib.el
index fd25f7c9e6279b528c81b1908948ff7554a12015..89c01a578ccdfe331599f21fc3174d1e15807923 100644 (file)
 (require 'mm-decode)
 (require 'cl)
 
 (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)
 
 (autoload 'notmuch-jump-search "notmuch-jump"
   "Jump to a saved search by shortcut key." t)
 
@@ -192,8 +196,8 @@ Otherwise the output will be returned"
 "Perhaps you haven't run \"notmuch setup\" yet? Try running this
 on the command line, and then retry your notmuch command")))
 
 "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)))
   (let ((long-string
         ;; Trim off the trailing newline.
         (substring (notmuch-command-to-string "--version") 0 -1)))
@@ -228,6 +232,9 @@ on the command line, and then retry your notmuch command")))
   "Return the user.other_email value (as a list) from the notmuch configuration."
   (split-string (notmuch-config-get "user.other_email") "\n" t))
 
   "Return the user.other_email value (as a list) from the notmuch configuration."
   (split-string (notmuch-config-get "user.other_email") "\n" t))
 
+(defun notmuch-user-emails ()
+  (cons (notmuch-user-primary-email) (notmuch-user-other-email)))
+
 (defun notmuch-poll ()
   "Run \"notmuch new\" or an external script to import mail.
 
 (defun notmuch-poll ()
   "Run \"notmuch new\" or an external script to import mail.
 
@@ -236,8 +243,9 @@ depending on the value of `notmuch-poll-script'."
   (interactive)
   (if (stringp notmuch-poll-script)
       (unless (string= notmuch-poll-script "")
   (interactive)
   (if (stringp notmuch-poll-script)
       (unless (string= notmuch-poll-script "")
-       (call-process notmuch-poll-script nil nil))
-    (call-process notmuch-command nil nil nil "new")))
+       (unless (equal (call-process notmuch-poll-script nil nil) 0)
+         (error "Notmuch: poll script `%s' failed!" notmuch-poll-script)))
+    (notmuch-call-notmuch-process "new")))
 
 (defun notmuch-bury-or-kill-this-buffer ()
   "Undisplay the current buffer.
 
 (defun notmuch-bury-or-kill-this-buffer ()
   "Undisplay the current buffer.
@@ -529,25 +537,67 @@ the given type."
    (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
    parts))
 
    (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 process-crypto)
-  (or (plist-get part :content)
-      (notmuch-get-bodypart-internal (notmuch-id-to-query (plist-get msg :id))
-                                    (plist-get part :id) 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
 
 ;; 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
@@ -568,18 +618,21 @@ the given type."
 current buffer, if possible."
   (let ((display-buffer (current-buffer)))
     (with-temp-buffer
 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)
                        (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 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)
          (when (mm-inlinable-p handle)
            (set-buffer display-buffer)
            (mm-display-part handle)