diff --git a/mu4e/mu4e-actions.el b/mu4e/mu4e-actions.el index 41a3f43c..a1557a21 100644 --- a/mu4e/mu4e-actions.el +++ b/mu4e/mu4e-actions.el @@ -30,8 +30,10 @@ (require 'cl) (require 'mu4e-utils) +(require 'mu4e-message) (require 'mu4e-meta) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun mu4e-action-count-lines (msg) @@ -39,7 +41,7 @@ headers view and message-view." (message "Number of lines: %s" (shell-command-to-string - (concat "wc -l < " (shell-quote-argument (plist-get msg :path)))))) + (concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -58,13 +60,12 @@ view." (let* ((pdf (shell-command-to-string (concat mu4e-msg2pdf " " - (shell-quote-argument (mu4e-msg-field msg :path)) + (shell-quote-argument (mu4e-message-field msg :path)) " 2> /dev/null"))) (pdf (and pdf (> (length pdf) 5) (substring pdf 0 -1)))) ;; chop \n (unless (and pdf (file-exists-p pdf)) - (message "==> %S %S" pdf (mu4e-msg-field msg :path)) - (mu4e-error "Failed to create PDF file")) + (mu4e-warn "Failed to create PDF file")) (find-file pdf))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -75,8 +76,8 @@ view." (defun mu4e-action-view-in-browser (msg) "View the body of the message in a web browser. You can influence the browser to use with the variable `browse-url-generic-program'." - (let* ((html (mu4e-msg-field msg :body-html)) - (txt (mu4e-msg-field msg :body-txt)) + (let* ((html (mu4e-message-field msg :body-html)) + (txt (mu4e-message-field msg :body-txt)) (tmpfile (format "%s%x.html" temporary-file-directory (random t)))) (unless (or html txt) (mu4e-error "No body part for this message")) @@ -96,10 +97,10 @@ the browser to use with the variable `browse-url-generic-program'." (defun mu4e-action-message-to-speech (msg) "Pronounce the message text using `mu4e-text2speech-command'." - (unless (mu4e-msg-field msg :body-txt) - (mu4e-error "No text body for this message")) + (unless (mu4e-message-field msg :body-txt) + (mu4e-warn "No text body for this message")) (with-temp-buffer - (insert (mu4e-msg-field msg :body-txt)) + (insert (mu4e-message-field msg :body-txt)) (shell-command-on-region (point-min) (point-max) mu4e-text2speech-command))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -142,7 +143,7 @@ store your org-contacts." (mu4e-error "org-capture is not available.")) (unless mu4e-org-contacts-file (mu4e-error "`mu4e-org-contacts-file' is not defined.")) - (let* ((sender (car-safe (mu4e-msg-field msg :from))) + (let* ((sender (car-safe (mu4e-message-field msg :from))) (name (car-safe sender)) (email (cdr-safe sender)) (blurb (format diff --git a/mu4e/mu4e-compose.el b/mu4e/mu4e-compose.el index 4fa3c989..7c0e4f18 100644 --- a/mu4e/mu4e-compose.el +++ b/mu4e/mu4e-compose.el @@ -40,6 +40,7 @@ (require 'mu4e-vars) (require 'mu4e-proc) (require 'mu4e-actions) +(require 'mu4e-message) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Composing / Sending messages @@ -688,32 +689,33 @@ or replied to, otherwise it is nil." a symbol, one of `reply', `forward', `edit', `new'. All but `new' take the message at point as input. Symbol `edit' is only allowed for draft messages." + (let ((msg (mu4e-message-at-point 'noerror))) + ;; some sanity checks + (unless (or msg (eq compose-type 'new)) + (mu4e-warn "No message at point")) + (unless (member compose-type '(reply forward edit new)) + (mu4e-error "Invalid compose type '%S'" compose-type)) + (when (and (eq compose-type 'edit) + (not (member 'draft (mu4e-message-field msg :flags)))) + (mu4e-warn "Editing is only allowed for draft messages")) + ;; run the hooks + (mu4e~compose-run-hooks compose-type) - (unless (member compose-type '(reply forward edit new)) - (mu4e-error "Invalid compose type '%S'" compose-type)) - (when (and (eq compose-type 'edit) - (not (member 'draft (mu4e-field-at-point :flags)))) - (mu4e-warn "Editing is only allowed for draft messages")) - - ;; run the hooks - (mu4e~compose-run-hooks compose-type) - - ;; 'new is special, since it takes no existing message as arg therefore, - ;; we don't need to call thec backend, and call the handler *directly* - (if (eq compose-type 'new) - (mu4e~compose-handler 'new) - - ;; otherwise, we need the doc-id - (let ((docid (mu4e-field-at-point :docid))) - ;; if there's a visible view window, select that before starting composing - ;; a new message, so that one will be replaced by the compose window. The - ;; 10-or-so line headers buffer is not a good place to write it... + ;; 'new is special, since it takes no existing message as arg therefore, + ;; we don't need to call thec backend, and call the handler *directly* + (if (eq compose-type 'new) + (mu4e~compose-handler 'new) + ;; otherwise, we need the doc-id + (let ((docid (mu4e-message-field msg :docid))) + ;; if there's a visible view window, select that before starting composing + ;; a new message, so that one will be replaced by the compose window. The + ;; 10-or-so line headers buffer is not a good place to write it... (let ((viewwin (get-buffer-window mu4e~view-buffer))) (when (window-live-p viewwin) (select-window viewwin))) - ;; talk to the backend - (mu4e~proc-compose compose-type docid)))) + ;; talk to the backend + (mu4e~proc-compose compose-type docid))))) (defun mu4e-compose-reply () "Compose a reply for the message at point in the headers buffer." diff --git a/mu4e/mu4e-headers.el b/mu4e/mu4e-headers.el index fd3bb812..b987ed3b 100644 --- a/mu4e/mu4e-headers.el +++ b/mu4e/mu4e-headers.el @@ -706,7 +706,7 @@ docid DOCID, or nil if it cannot be found." with DOCID which must be present in the headers buffer." (save-excursion (when (mu4e~headers-goto-docid docid) - (mu4e-message-field (mu4e-message-at-point t) field)))) + (mu4e-message-field (mu4e-message-at-point) field)))) ;;;; markers mark headers for (defun mu4e~headers-mark (docid mark) @@ -895,28 +895,27 @@ matching messages with that mark." limited to the message at point and its descendants." ;; the tread id is shared by all messages in a thread (interactive "P") - (let* ((thread-id (mu4e~headers-get-thread-info - (mu4e-message-at-point t) 'thread-id)) - (path (mu4e~headers-get-thread-info - (mu4e-message-at-point t) 'path)) + (let* ((msg (mu4e-message-at-point)) + (thread-id (mu4e~headers-get-thread-info msg 'thread-id)) + (path (mu4e~headers-get-thread-info msg 'path)) (markpair (mu4e~mark-get-markpair (if subthread "Mark subthread with: " "Mark whole thread with: ") t)) (last-marked-point)) (mu4e-headers-for-each - (lambda (msg) - (let ((my-thread-id (mu4e~headers-get-thread-info msg 'thread-id))) + (lambda (mymsg) + (let ((my-thread-id (mu4e~headers-get-thread-info mymsg 'thread-id))) (if subthread - ;; subthread matching; msg's thread path should have path as its + ;; subthread matching; mymsg's thread path should have path as its ;; prefix (when (string-match (concat "^" path) - (mu4e~headers-get-thread-info msg 'path)) + (mu4e~headers-get-thread-info mymsg 'path)) (mu4e-mark-at-point (car markpair) (cdr markpair)) (setq last-marked-point (point))) ;; nope; not looking for the subthread; looking for the whole thread (when (string= thread-id - (mu4e~headers-get-thread-info msg 'thread-id)) + (mu4e~headers-get-thread-info mymsg 'thread-id)) (mu4e-mark-at-point (car markpair) (cdr markpair)) (setq last-marked-point (point))))))) (when last-marked-point @@ -1106,7 +1105,7 @@ current window. " (interactive) (unless (eq major-mode 'mu4e-headers-mode) (mu4e-error "Must be in mu4e-headers-mode (%S)" major-mode)) - (let* ((msg (mu4e-message-at-point t)) + (let* ((msg (mu4e-message-at-point)) (docid (or (mu4e-message-field msg :docid) (mu4e-warn "No message at point"))) ;; decrypt (or not), based on `mu4e-decryption-policy'. @@ -1234,7 +1233,7 @@ N. Otherwise, don't do anything." "Ask user what to do with message-at-point, then do it. The actions are specified in `mu4e-headers-actions'." (interactive) - (let ((msg (mu4e-message-at-point t)) + (let ((msg (mu4e-message-at-point)) (actionfunc (mu4e-read-option "Action: " mu4e-headers-actions))) (funcall actionfunc msg))) diff --git a/mu4e/mu4e-mark.el b/mu4e/mu4e-mark.el index 6e257445..ce0bf758 100644 --- a/mu4e/mu4e-mark.el +++ b/mu4e/mu4e-mark.el @@ -28,6 +28,7 @@ ;; Code: (require 'mu4e-proc) (require 'mu4e-utils) +(require 'mu4e-message) (defcustom mu4e-headers-leave-behavior 'ask "What to do when user leaves the headers view (e.g. quits, @@ -101,7 +102,8 @@ The following marks are available, and the corresponding props: `deferred' n mark this message for *something* (decided later) `unmark' n unmark this message" (interactive) - (let* ((docid (mu4e-field-at-point :docid)) + (let* ((msg (mu4e-message-at-point)) + (docid (mu4e-message-field msg :docid)) ;; get a cell with the mark char and the 'target' 'move' already has a ;; target (the target folder) the other ones get a pseudo "target", as ;; info for the user. @@ -174,7 +176,7 @@ headers in the region." the region, for moving to maildir TARGET. If target is not provided, function asks for it." (interactive) - (mu4e-field-at-point :docid) ;; will raise an error if there is none + (mu4e-message-at-point) ;; raises error if there is none (let* ((target (or target (mu4e-ask-maildir "Move message to: "))) (target (if (string= (substring target 0 1) "/") target @@ -281,8 +283,7 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation." mu4e~mark-map) ;; in any case, clear the marks map (mu4e~mark-clear)) - - + (defun mu4e-mark-docid-marked-p (docid) "Is the given docid marked?" (when (gethash docid mu4e~mark-map) t)) diff --git a/mu4e/mu4e-message.el b/mu4e/mu4e-message.el index e912c4de..0b97311b 100644 --- a/mu4e/mu4e-message.el +++ b/mu4e/mu4e-message.el @@ -28,10 +28,11 @@ (eval-when-compile (byte-compile-disable-warning 'cl-functions)) (require 'mu4e-vars) +(require 'mu4e-utils) (require 'cl) (require 'html2text) - + (defcustom mu4e-html2text-command nil "Shell command that converts HTML from stdin into plain text on @@ -88,16 +89,15 @@ Some notes on the format: ;; after all this documentation, the spectacular implementation (plist-get msg field)) -(defsubst mu4e-message-at-point (&optional raise-err) +(defsubst mu4e-message-at-point (&optional noerror) "Get the message s-expression for the message at point in either the headers buffer or the view buffer, or nil if there is no such -message. If optional RAISE-ERR is non-nil, raise an error when +message. If optional NOERROR is non-nil, do not raise an error when there is no message at point." (let ((msg (or (get-text-property (point) 'msg) mu4e~view-msg))) (if msg msg - (when raise-err - (mu4e-warn "No message at point"))))) + (unless noerror (mu4e-warn "No message at point"))))) (defun mu4e-message-for-each (msg field func) @@ -171,4 +171,17 @@ function prefers the text part, but this can be changed by setting (:index 2 :name \"photo.jpg\" :mime-type \"image/jpeg\" :size 147331)." (plist-get msgpart field)) + + +;; backward compatibility ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defalias 'mu4e-msg-field 'mu4e-message-field) +(defalias 'mu4e-body-text 'mu4e-message-body-text) ;; backward compatibility + +(defun mu4e-field-at-point (field) + "Get FIELD (a symbol, see `mu4e-header-info') for the message at +point in eiter the headers buffer or the view buffer." + (plist-get (mu4e-message-at-point) field)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + (provide 'mu4e-message) diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index 33a89322..084c20fc 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -28,19 +28,18 @@ (eval-when-compile (byte-compile-disable-warning 'cl-functions)) (require 'cl) -(require 'mu4e-message) (require 'mu4e-vars) (require 'mu4e-about) (require 'doc-view) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; the following is taken from org.el; we copy it here since we don't want to ;; depend on org-mode directly (it causes byte-compilation errors) TODO: a ;; cleaner solution.... (defconst mu4e~ts-regexp0 - "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)\\( +[^]+0-9>\r\n -]+\\)?\\( +\\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)" + (concat + "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)" + "\\( +[^]+0-9>\r\n -]+\\)?\\( +\\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)") "Regular expression matching time strings for analysis. This one does not require the space after the date, so it can be used on a string that terminates immediately after the date.") @@ -90,13 +89,15 @@ user-input, don't show anyhting." (defun mu4e-error (frm &rest args) "Create [mu4e]-prefixed error based on format FRM and ARGS. Does -a local-exit and does not return." +a local-exit and does not return, and raises a +debuggable (backtrace) error." (mu4e-log 'error (apply 'mu4e-format frm args)) (error "%s" (apply 'mu4e-format frm args))) (defun mu4e-warn (frm &rest args) "Create [mu4e]-prefixed warning based on format FRM and -ARGS. Does a local-exit and does not return." +ARGS. Does a local-exit and does not return. In emacs versions +below 24.2, the functions is the same as `mu4e-error'." (mu4e-log 'error (apply 'mu4e-format frm args)) (if (fboundp 'user-error) (user-error "%s" (apply 'mu4e-format frm args)) ;; only in emacs-trunk @@ -239,25 +240,6 @@ and offer to create it if it does not exist yet." mdir)) -(defun mu4e-mark-for-move-set (&optional target) - "Mark message at point or, if region is active, all messages in -the region, for moving to maildir TARGET. If target is not -provided, function asks for it." - (interactive) - (unless (mu4e~headers-docid-at-point) - (mu4e-warn "No message at point.")) - (let* ((target (or target (mu4e-ask-maildir "Move message to: "))) - (target (if (string= (substring target 0 1) "/") - target - (concat "/" target))) - (fulltarget (concat mu4e-maildir target))) - (when (or (file-directory-p fulltarget) - (and (yes-or-no-p - (mu4e-format "%s does not exist. Create now?" fulltarget)) - (mu4e~proc-mkdir fulltarget))) - (mu4e-mark-set 'move target)))) - - (defun mu4e-ask-bookmark (prompt &optional kar) "Ask the user for a bookmark (using PROMPT) as defined in `mu4e-bookmarks', then return the corresponding query." @@ -361,9 +343,6 @@ http://cr.yp.to/proto/maildir.html " (format "%2.1fK" (/ size 1000.0))) ((< size 1000) (format "%d" size)) (t (propertize "?" 'face 'mu4e-system-face)))) - - -(defalias 'mu4e-body-text 'mu4e-message-body-text) ;; backward compatibility (defun mu4e-display-manual () @@ -377,13 +356,6 @@ top level if there is none." (t "mu4e")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defalias 'mu4e-msg-field 'mu4e-message-field) ;; backward compatibility - -(defun mu4e-field-at-point (field) - "Get FIELD (a symbol, see `mu4e-header-info') for the message at -point in eiter the headers buffer or the view buffer." - (plist-get (mu4e-message-at-point t) field)) - (defun mu4e-last-query () "Get the most recent query or nil if there is none." (when (buffer-live-p mu4e~headers-buffer) diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index 102713ed..8a8db949 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -782,7 +782,7 @@ current message." `(progn (unless '(buffer-live-p mu4e~view-headers-buffer) (mu4e-error "no headers-buffer connected")) - (let* ((msg (mu4e-message-at-point t)) + (let* ((msg (mu4e-message-at-point)) (docid (mu4e-message-field msg :docid))) (unless docid (mu4e-error "message without docid: action is not possible.")) @@ -831,7 +831,7 @@ N (prefix argument), to the Nth previous header." if nil), then do it. The actions are specified in `mu4e-view-actions'." (interactive) - (let* ((msg (or msg (mu4e-message-at-point t))) + (let* ((msg (or msg (mu4e-message-at-point))) (actionfunc (mu4e-read-option "Action: " mu4e-view-actions))) (funcall actionfunc msg))) @@ -935,7 +935,7 @@ will save attachments 1,3,4,5,6 and 8. Furthermore, there is a shortcut \"a\" which so means all attachments, but as this is the default, you may not need it." (interactive) - (let* ((msg (or msg (mu4e-message-at-point t))) + (let* ((msg (or msg (mu4e-message-at-point))) (attachstr (mu4e~view-get-attach-num "Attachment number range (or 'a' for 'all')" msg t)) (count (hash-table-count mu4e~view-attach-map)) @@ -956,7 +956,7 @@ attachments." "Open attachment number ATTNUM (or ask if nil) from MSG (or message-at-point if nil)." (interactive) - (let* ((msg (or msg (mu4e-message-at-point t))) + (let* ((msg (or msg (mu4e-message-at-point))) (attnum (or attnum (mu4e~view-get-attach-num "Attachment to open" msg))) (att (or (mu4e~view-get-attach msg attnum))) @@ -1025,7 +1025,7 @@ PIPECMD is nil, ask user for it." message-at-point, then do it. The actions are specified in `mu4e-view-attachment-actions'." (interactive) - (let* ((msg (or msg (mu4e-message-at-point t))) + (let* ((msg (or msg (mu4e-message-at-point))) (actionfunc (mu4e-read-option "Action on attachment: " mu4e-view-attachment-actions))