]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-lib.el
Merge branch 'release'
[notmuch] / emacs / notmuch-lib.el
index a0a95d8f28c27df0ad240b1bde0929bd3ea1729e..5dc6797068c876619bc36f57cd2ffa4c9ae5e9ab 100644 (file)
@@ -1,4 +1,4 @@
-;; notmuch-lib.el --- common variables, functions and function declarations
+;;; notmuch-lib.el --- common variables, functions and function declarations
 ;;
 ;; Copyright © Carl Worth
 ;;
 ;;
 ;; Copyright © Carl Worth
 ;;
 ;; General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
 ;; General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.
+;; along with Notmuch.  If not, see <https://www.gnu.org/licenses/>.
 ;;
 ;; Authors: Carl Worth <cworth@cworth.org>
 
 ;; This is an part of an emacs-based interface to the notmuch mail system.
 
 ;;
 ;; Authors: Carl Worth <cworth@cworth.org>
 
 ;; This is an part of an emacs-based interface to the notmuch mail system.
 
+;;; Code:
+
+(require 'mm-util)
 (require 'mm-view)
 (require 'mm-decode)
 (require 'cl)
 (require 'mm-view)
 (require 'mm-decode)
 (require 'cl)
+(require 'notmuch-compat)
+
+(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)
 
 (custom-add-to-group 'notmuch-send 'message 'custom-group)
 
 
 (custom-add-to-group 'notmuch-send 'message 'custom-group)
 
+(defgroup notmuch-tag nil
+  "Tags and tagging in Notmuch."
+  :group 'notmuch)
+
 (defgroup notmuch-crypto nil
   "Processing and display of cryptographic MIME parts."
   :group 'notmuch)
 (defgroup notmuch-crypto nil
   "Processing and display of cryptographic MIME parts."
   :group 'notmuch)
@@ -140,6 +152,7 @@ For example, if you wanted to remove an \"inbox\" tag and add an
     (define-key map "z" 'notmuch-tree)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "=" 'notmuch-refresh-this-buffer)
     (define-key map "z" 'notmuch-tree)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "=" 'notmuch-refresh-this-buffer)
+    (define-key map (kbd "M-=") 'notmuch-refresh-all-buffers)
     (define-key map "G" 'notmuch-poll-and-refresh-this-buffer)
     (define-key map "j" 'notmuch-jump-search)
     map)
     (define-key map "G" 'notmuch-poll-and-refresh-this-buffer)
     (define-key map "j" 'notmuch-jump-search)
     map)
@@ -192,8 +205,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 +241,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 +252,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.
@@ -402,10 +419,8 @@ of its command symbol."
   "Refresh the current buffer."
   (interactive)
   (when notmuch-buffer-refresh-function
   "Refresh the current buffer."
   (interactive)
   (when notmuch-buffer-refresh-function
-    (if (commandp notmuch-buffer-refresh-function)
-       ;; Pass prefix argument, etc.
-       (call-interactively notmuch-buffer-refresh-function)
-      (funcall notmuch-buffer-refresh-function))))
+    ;; Pass prefix argument, etc.
+    (call-interactively notmuch-buffer-refresh-function)))
 
 (defun notmuch-poll-and-refresh-this-buffer ()
   "Invoke `notmuch-poll' to import mail, then refresh the current buffer."
 
 (defun notmuch-poll-and-refresh-this-buffer ()
   "Invoke `notmuch-poll' to import mail, then refresh the current buffer."
@@ -413,6 +428,21 @@ of its command symbol."
   (notmuch-poll)
   (notmuch-refresh-this-buffer))
 
   (notmuch-poll)
   (notmuch-refresh-this-buffer))
 
+(defun notmuch-refresh-all-buffers ()
+  "Invoke `notmuch-refresh-this-buffer' on all notmuch major-mode buffers.
+
+The buffers are silently refreshed, i.e. they are not forced to
+be displayed."
+  (interactive)
+  (dolist (buffer (buffer-list))
+    (let ((buffer-mode (buffer-local-value 'major-mode buffer)))
+      (when (memq buffer-mode '(notmuch-show-mode
+                               notmuch-tree-mode
+                               notmuch-search-mode
+                               notmuch-hello-mode))
+       (with-current-buffer buffer
+         (notmuch-refresh-this-buffer))))))
+
 (defun notmuch-prettify-subject (subject)
   ;; This function is used by `notmuch-search-process-filter' which
   ;; requires that we not disrupt its' matching state.
 (defun notmuch-prettify-subject (subject)
   ;; This function is used by `notmuch-search-process-filter' which
   ;; requires that we not disrupt its' matching state.
@@ -512,11 +542,23 @@ This replaces spaces, percents, and double quotes in STR with
     "multipart/related"
     ))
 
     "multipart/related"
     ))
 
-(defun notmuch-multipart/alternative-choose (types)
-  "Return a list of preferred types from the given list of types"
+(defun notmuch-multipart/alternative-determine-discouraged (msg)
+  "Return the discouraged alternatives for the specified message."
+  ;; If a function, return the result of calling it.
+  (if (functionp notmuch-multipart/alternative-discouraged)
+      (funcall notmuch-multipart/alternative-discouraged msg)
+    ;; Otherwise simply return the value of the variable, which is
+    ;; assumed to be a list of discouraged alternatives. This is the
+    ;; default behaviour.
+    notmuch-multipart/alternative-discouraged))
+
+(defun notmuch-multipart/alternative-choose (msg types)
+  "Return a list of preferred types from the given list of types
+for this message, if present."
   ;; Based on `mm-preferred-alternative-precedence'.
   ;; Based on `mm-preferred-alternative-precedence'.
-  (let ((seq types))
-    (dolist (pref (reverse notmuch-multipart/alternative-discouraged))
+  (let ((discouraged (notmuch-multipart/alternative-determine-discouraged msg))
+       (seq types))
+    (dolist (pref (reverse discouraged))
       (dolist (elem (copy-sequence seq))
        (when (string-match pref elem)
          (setq seq (nconc (delete elem seq) (list elem))))))
       (dolist (elem (copy-sequence seq))
        (when (string-match pref elem)
          (setq seq (nconc (delete elem seq) (list elem))))))
@@ -529,41 +571,69 @@ 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))
 
-(defun notmuch-get-bodypart-binary (msg part process-crypto)
-  "Return the unprocessed content of PART in MSG.
+(defun notmuch--get-bodypart-raw (msg part process-crypto binaryp cache)
+  (let* ((plist-elem (if binaryp :content-binary :content))
+        (data (or (plist-get part plist-elem)
+                  (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.
+                    (when binaryp
+                      (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
+                             (let ((coding-system (mm-charset-to-coding-system
+                                                   (plist-get part :content-charset))))
+                               ;; Sadly,
+                               ;; `mm-charset-to-coding-system' seems
+                               ;; to return things that are not
+                               ;; considered acceptable values for
+                               ;; `coding-system-for-read'.
+                               (if (coding-system-p coding-system)
+                                   coding-system
+                                 ;; RFC 2047 says that the default
+                                 ;; charset is US-ASCII. RFC6657
+                                 ;; complicates this somewhat.
+                                 'us-ascii)))))
+                      (apply #'call-process notmuch-command nil '(t nil) nil args)
+                      (buffer-string))))))
+    (when (and cache data)
+      (plist-put part plist-elem 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 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."
-  (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
-      (let ((coding-system-for-read 'no-conversion))
-       (apply #'call-process notmuch-command nil '(t nil) nil args)
-       (buffer-string)))))
+this does no charset conversion.
 
 
-(defun notmuch-get-bodypart-text (msg part process-crypto)
+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)
   "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
   "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."
-  (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))))
-    content))
+necessary charset decoding.
+
+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 nil cache))
 
 ;; 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
@@ -739,9 +809,15 @@ You may need to restart Emacs or upgrade your notmuch package."))
                    (insert-file-contents err-file)
                    (unless (eobp)
                      (buffer-string)))))
                    (insert-file-contents err-file)
                    (unless (eobp)
                      (buffer-string)))))
+          (command-string
+           (mapconcat (lambda (arg)
+                        (shell-quote-argument
+                         (cond ((stringp arg) arg)
+                               ((symbolp arg) (symbol-name arg))
+                               (t "*UNKNOWN ARGUMENT*"))))
+                      command " "))
           (extra
           (extra
-           (concat
-            "command: " (mapconcat #'shell-quote-argument command " ") "\n"
+           (concat "command: " command-string "\n"
             (if (integerp exit-status)
                 (format "exit status: %s\n" exit-status)
               (format "exit signal: %s\n" exit-status))
             (if (integerp exit-status)
                 (format "exit status: %s\n" exit-status)
               (format "exit signal: %s\n" exit-status))
@@ -896,3 +972,5 @@ status."
 ;; Local Variables:
 ;; byte-compile-warnings: (not cl-functions)
 ;; End:
 ;; Local Variables:
 ;; byte-compile-warnings: (not cl-functions)
 ;; End:
+
+;;; notmuch-lib.el ends here