* mu4e: mu4e-message part 3

This commit is contained in:
djcb 2012-09-26 17:28:30 +03:00
parent 97c13d0920
commit 5c2025a12c
7 changed files with 80 additions and 92 deletions

View File

@ -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

View File

@ -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."

View File

@ -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)))

View File

@ -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))

View File

@ -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)

View File

@ -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)

View File

@ -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))