mirror of https://github.com/djcb/mu.git
* mu4e: abstract access to the mu4e-message plist
This commit is contained in:
parent
3f305f665a
commit
7d831184b7
|
@ -30,6 +30,7 @@ dist_lisp_LISP= \
|
||||||
mu4e-headers.el \
|
mu4e-headers.el \
|
||||||
mu4e-main.el \
|
mu4e-main.el \
|
||||||
mu4e-mark.el \
|
mu4e-mark.el \
|
||||||
|
mu4e-message.el \
|
||||||
mu4e-meta.el \
|
mu4e-meta.el \
|
||||||
mu4e-proc.el \
|
mu4e-proc.el \
|
||||||
mu4e-speedbar.el \
|
mu4e-speedbar.el \
|
||||||
|
|
|
@ -99,7 +99,6 @@ forwarded or edited) in `mu4e-compose-pre-hook.")
|
||||||
"message/rfc822"
|
"message/rfc822"
|
||||||
(or (plist-get mu4e-captured-message :subject) "No subject")
|
(or (plist-get mu4e-captured-message :subject) "No subject")
|
||||||
"attachment")))
|
"attachment")))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defun mu4e~compose-user-agent-construct ()
|
(defun mu4e~compose-user-agent-construct ()
|
||||||
|
@ -137,8 +136,8 @@ comma-separated string. Normally, this the concatenation of the
|
||||||
existing References (which may be empty) and the message-id. If the
|
existing References (which may be empty) and the message-id. If the
|
||||||
message-id is empty, returns the old References. If both are empty,
|
message-id is empty, returns the old References. If both are empty,
|
||||||
return nil."
|
return nil."
|
||||||
(let ((refs (plist-get msg :references))
|
(let ((refs (mu4e-message-field msg :references))
|
||||||
(old-msgid (plist-get msg :message-id)))
|
(old-msgid (mu4e-message-field msg :message-id)))
|
||||||
(when old-msgid
|
(when old-msgid
|
||||||
(setq refs (append refs (list old-msgid)))
|
(setq refs (append refs (list old-msgid)))
|
||||||
(mapconcat
|
(mapconcat
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
(require 'mu4e-mark)
|
(require 'mu4e-mark)
|
||||||
(require 'mu4e-compose)
|
(require 'mu4e-compose)
|
||||||
(require 'mu4e-actions)
|
(require 'mu4e-actions)
|
||||||
|
(require 'mu4e-message)
|
||||||
|
|
||||||
;; the headers view
|
;; the headers view
|
||||||
(defgroup mu4e-headers nil
|
(defgroup mu4e-headers nil
|
||||||
|
@ -197,7 +198,7 @@ in the database. This function will update the current list of
|
||||||
headers."
|
headers."
|
||||||
(when (buffer-live-p mu4e~headers-buffer)
|
(when (buffer-live-p mu4e~headers-buffer)
|
||||||
(with-current-buffer mu4e~headers-buffer
|
(with-current-buffer mu4e~headers-buffer
|
||||||
(let* ((docid (plist-get msg :docid))
|
(let* ((docid (mu4e-message-field msg :docid))
|
||||||
(point (mu4e~headers-docid-pos docid)))
|
(point (mu4e~headers-docid-pos docid)))
|
||||||
(when point ;; is the message present in this list?
|
(when point ;; is the message present in this list?
|
||||||
|
|
||||||
|
@ -316,27 +317,27 @@ display may be different)."
|
||||||
`mu4e-user-mail-address-regexp', show the To address; otherwise
|
`mu4e-user-mail-address-regexp', show the To address; otherwise
|
||||||
show the from address; prefixed with the appropriate
|
show the from address; prefixed with the appropriate
|
||||||
`mu4e-headers-from-or-to-prefix'."
|
`mu4e-headers-from-or-to-prefix'."
|
||||||
(let ((addr (cdr-safe (car-safe (plist-get msg :from)))))
|
(let ((addr (cdr-safe (car-safe (mu4e-message-field msg :from)))))
|
||||||
(if (and addr (string-match mu4e-user-mail-address-regexp addr))
|
(if (and addr (string-match mu4e-user-mail-address-regexp addr))
|
||||||
(concat (cdr mu4e-headers-from-or-to-prefix)
|
(concat (cdr mu4e-headers-from-or-to-prefix)
|
||||||
(mu4e~headers-contact-str (plist-get msg :to)))
|
(mu4e~headers-contact-str (mu4e-message-field msg :to)))
|
||||||
(concat (car mu4e-headers-from-or-to-prefix)
|
(concat (car mu4e-headers-from-or-to-prefix)
|
||||||
(mu4e~headers-contact-str (plist-get msg :from))))))
|
(mu4e~headers-contact-str (mu4e-message-field msg :from))))))
|
||||||
|
|
||||||
;; note: this function is very performance-sensitive
|
;; note: this function is very performance-sensitive
|
||||||
(defun mu4e~headers-header-handler (msg &optional point)
|
(defun mu4e~headers-header-handler (msg &optional point)
|
||||||
"Create a one line description of MSG in this buffer, at POINT,
|
"Create a one line description of MSG in this buffer, at POINT,
|
||||||
if provided, or at the end of the buffer otherwise."
|
if provided, or at the end of the buffer otherwise."
|
||||||
(let ((docid (plist-get msg :docid)) (line ""))
|
(let ((docid (mu4e-message-field msg :docid)) (line ""))
|
||||||
(dolist (f-w mu4e-headers-fields)
|
(dolist (f-w mu4e-headers-fields)
|
||||||
(let ((field (car f-w)) (width (cdr f-w))
|
(let ((field (car f-w)) (width (cdr f-w))
|
||||||
(val (plist-get msg (car f-w))) (str))
|
(val (mu4e-message-field msg (car f-w))) (str))
|
||||||
(setq str
|
(setq str
|
||||||
(case field
|
(case field
|
||||||
(:subject
|
(:subject
|
||||||
(concat ;; prefix subject with a thread indicator
|
(concat ;; prefix subject with a thread indicator
|
||||||
(mu4e~headers-thread-prefix (plist-get msg :thread))
|
(mu4e~headers-thread-prefix (mu4e-message-field msg :thread))
|
||||||
;; "["(plist-get (plist-get msg :thread) :path) "] "
|
;; "["(plist-get (mu4e-message-field msg :thread) :path) "] "
|
||||||
val))
|
val))
|
||||||
((:maildir :path) val)
|
((:maildir :path) val)
|
||||||
((:to :from :cc :bcc) (mu4e~headers-contact-str val))
|
((:to :from :cc :bcc) (mu4e~headers-contact-str val))
|
||||||
|
@ -356,7 +357,7 @@ if provided, or at the end of the buffer otherwise."
|
||||||
(truncate-string-to-width str width 0 ?\s t)) " ")))))
|
(truncate-string-to-width str width 0 ?\s t)) " ")))))
|
||||||
;; now, propertize it.
|
;; now, propertize it.
|
||||||
(setq line (propertize line 'face
|
(setq line (propertize line 'face
|
||||||
(case (car-safe (plist-get msg :flags))
|
(case (car-safe (mu4e-message-field msg :flags))
|
||||||
('draft 'mu4e-draft-face)
|
('draft 'mu4e-draft-face)
|
||||||
('trash 'mu4e-trashed-face)
|
('trash 'mu4e-trashed-face)
|
||||||
((unread new) 'mu4e-unread-face)
|
((unread new) 'mu4e-unread-face)
|
||||||
|
@ -875,7 +876,7 @@ matching messages with that mark."
|
||||||
|
|
||||||
(defun mu4e~headers-get-thread-info (msg what)
|
(defun mu4e~headers-get-thread-info (msg what)
|
||||||
"Get WHAT (a symbol, either path or thread-id) for MSG."
|
"Get WHAT (a symbol, either path or thread-id) for MSG."
|
||||||
(let* ((thread (or (plist-get msg :thread)
|
(let* ((thread (or (mu4e-message-field msg :thread)
|
||||||
(mu4e-error "No thread info found")))
|
(mu4e-error "No thread info found")))
|
||||||
(path (or (plist-get thread :path)
|
(path (or (plist-get thread :path)
|
||||||
(mu4e-error "No threadpath found"))))
|
(mu4e-error "No threadpath found"))))
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
;;; mu4e-message.el -- part of mu4e, the mu mail user agent
|
||||||
|
;;
|
||||||
|
;; Copyright (C) 2012 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
|
||||||
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Functions to get data from mu4e-message plist structure
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
(eval-when-compile (byte-compile-disable-warning 'cl-functions))
|
||||||
|
(require 'cl)
|
||||||
|
(require 'html2text)
|
||||||
|
|
||||||
|
|
||||||
|
(defcustom mu4e-html2text-command nil
|
||||||
|
"Shell command that converts HTML from stdin into plain text on
|
||||||
|
stdout. If this is not defined, the emacs `html2text' tool will be
|
||||||
|
used when faced with html-only message. If you use htmltext, it's
|
||||||
|
recommended you use \"html2text -utf8 -width 72\"."
|
||||||
|
:type 'string
|
||||||
|
:group 'mu4e-view
|
||||||
|
:safe 'stringp)
|
||||||
|
|
||||||
|
(defcustom mu4e-view-prefer-html nil
|
||||||
|
"Whether to base the body display on the HTML-version of the
|
||||||
|
e-mail message (if there is any."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'mu4e-view)
|
||||||
|
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
(defsubst mu4e-message-field (msg field)
|
||||||
|
"Retrieve FIELD from message plist MSG. FIELD is one
|
||||||
|
of :from, :to, :cc, :bcc, :subject, :data, :message-id, :path, :maildir,
|
||||||
|
:priority, :attachments, :references, :in-reply-to, :body-txt, :body-html
|
||||||
|
|
||||||
|
A message plist looks something like:
|
||||||
|
\(:docid 32461
|
||||||
|
:from ((\"Nikola Tesla\" . \"niko@example.com\"))
|
||||||
|
:to ((\"Thomas Edison\" . \"tom@example.com\"))
|
||||||
|
:cc ((\"Rupert The Monkey\" . \"rupert@example.com\"))
|
||||||
|
:subject \"RE: what about the 50K?\"
|
||||||
|
:date (20369 17624 0)
|
||||||
|
:size 4337
|
||||||
|
:message-id \"6BDC23465F79238C8233AB82D81EE81AF0114E4E74@123213.mail.example.com\"
|
||||||
|
:path \"/home/tom/Maildir/INBOX/cur/133443243973_1.10027.atlas:2,S\"
|
||||||
|
:maildir \"/INBOX\"
|
||||||
|
:priority normal
|
||||||
|
:flags (seen)
|
||||||
|
:attachments
|
||||||
|
((:index 2 :name \"photo.jpg\" :mime-type \"image/jpeg\" :size 147331)
|
||||||
|
(:index 3 :name \"book.pdf\" :mime-type \"application/pdf\" :size 192220))
|
||||||
|
:references (\"6BDC23465F79238C8384574032D81EE81AF0114E4E74@123213.mail.example.com\"
|
||||||
|
\"6BDC23465F79238203498230942D81EE81AF0114E4E74@123213.mail.example.com\")
|
||||||
|
:in-reply-to \"6BDC23465F79238203498230942D81EE81AF0114E4E74@123213.mail.example.com\"
|
||||||
|
:body-txt \"Hi Tom, ...\"
|
||||||
|
\)).
|
||||||
|
Some notes on the format:
|
||||||
|
- The address fields are lists of pairs (NAME . EMAIL), where NAME can be nil.
|
||||||
|
- The date is in format emacs uses in `current-time'
|
||||||
|
- Attachments are a list of elements with fields :index (the number of
|
||||||
|
the MIME-part), :name (the file name, if any), :mime-type (the
|
||||||
|
MIME-type, if any) and :size (the size in bytes, if any).
|
||||||
|
- Messages in the Headers view come from the database and do not have
|
||||||
|
:attachments. :body-txt or :body-html fields. Message in the
|
||||||
|
Message view use the actual message file, and do include these fields."
|
||||||
|
;; after all this documentation, the spectacular implementation
|
||||||
|
(plist-get msg field))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-message-for-each (msg field func)
|
||||||
|
"Call FUNC for each element in the field FIELD (which must be a
|
||||||
|
lists-type field). FUNC takes the element as its arg."
|
||||||
|
(let ((lst (mu4e-message-field msg field)))
|
||||||
|
(unless (listp lst)
|
||||||
|
(error "Not a list type"))
|
||||||
|
(dolist (elm (mu4e-message-field msg field))
|
||||||
|
(funcall func elm))))
|
||||||
|
|
||||||
|
(defun mu4e-message-for-each-contact-field (msg field func)
|
||||||
|
"Call FUNC for each element of contact
|
||||||
|
FIELD (:to, :cc, :bcc, :from). FUNC takes two args, strings
|
||||||
|
name (possibly nil) and an email address."
|
||||||
|
(unless (member field '(:to :from :bcc :cc))
|
||||||
|
(error "Not a contacts field"))
|
||||||
|
(mu4e-message-for-each msg field
|
||||||
|
(lambda (contact)
|
||||||
|
(funcall func (car contact) (cdr contact)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-message-body-text (msg)
|
||||||
|
"Get the body in text form for this message, which is either :body-txt,
|
||||||
|
or if not available, :body-html converted to text. By default, it
|
||||||
|
uses the emacs built-in `html2text'. Alternatively, if
|
||||||
|
`mu4e-html2text-command' is non-nil, it will use that. Normally,
|
||||||
|
function prefers the text part, but this can be changed by setting
|
||||||
|
`mu4e-view-prefer-html'."
|
||||||
|
(let* ((txt (mu4e-message-field msg :body-txt))
|
||||||
|
(html (mu4e-message-field msg :body-html))
|
||||||
|
(body
|
||||||
|
(cond
|
||||||
|
;; does it look like some text? ie., 10x the length of the text
|
||||||
|
;; should be longer than the html, an heuristic to guard against
|
||||||
|
;; 'This messages requires html' text bodies.
|
||||||
|
((and (> (* 10 (length txt)) (length html))
|
||||||
|
;; use html if it's prefered, unless there is no html
|
||||||
|
(or (not mu4e-view-prefer-html) (not html)))
|
||||||
|
txt)
|
||||||
|
;; otherwise, it there some html?
|
||||||
|
(html
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert html)
|
||||||
|
;; if defined, use the external tool
|
||||||
|
(if mu4e-html2text-command
|
||||||
|
(shell-command-on-region (point-min) (point-max)
|
||||||
|
mu4e-html2text-command nil t)
|
||||||
|
;; otherwise...
|
||||||
|
(html2text))
|
||||||
|
(buffer-string)))
|
||||||
|
(t ;; otherwise, an empty body
|
||||||
|
""))))
|
||||||
|
;; and finally, remove some crap from the remaining string; it seems
|
||||||
|
;; esp. outlook lies about its encoding (ie., it says 'iso-8859-1' but
|
||||||
|
;; really it's 'windows-1252'), thus giving us these funky chars. here, we
|
||||||
|
;; either remove them, or replace with 'what-was-meant' (heuristically)
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert body)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward "[
]" nil t)
|
||||||
|
(replace-match
|
||||||
|
(cond
|
||||||
|
((string= (match-string 0) "") "'")
|
||||||
|
(t ""))))
|
||||||
|
(buffer-string))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defsubst mu4e-message-part-field (msgpart field)
|
||||||
|
"Get some field in a message part; a part would look something like:
|
||||||
|
(:index 2 :name \"photo.jpg\" :mime-type \"image/jpeg\" :size 147331)."
|
||||||
|
(plist-get msgpart field))
|
||||||
|
|
||||||
|
(provide 'mu4e-message)
|
|
@ -28,25 +28,11 @@
|
||||||
(eval-when-compile (byte-compile-disable-warning 'cl-functions))
|
(eval-when-compile (byte-compile-disable-warning 'cl-functions))
|
||||||
(require 'cl)
|
(require 'cl)
|
||||||
|
|
||||||
(require 'html2text)
|
(require 'mu4e-message)
|
||||||
(require 'mu4e-vars)
|
(require 'mu4e-vars)
|
||||||
(require 'mu4e-about)
|
(require 'mu4e-about)
|
||||||
(require 'doc-view)
|
(require 'doc-view)
|
||||||
|
|
||||||
(defcustom mu4e-html2text-command nil
|
|
||||||
"Shell command that converts HTML from stdin into plain text on
|
|
||||||
stdout. If this is not defined, the emacs `html2text' tool will be
|
|
||||||
used when faced with html-only message. If you use htmltext, it's
|
|
||||||
recommended you use \"html2text -utf8 -width 72\"."
|
|
||||||
:type 'string
|
|
||||||
:group 'mu4e-view
|
|
||||||
:safe 'stringp)
|
|
||||||
|
|
||||||
(defcustom mu4e-view-prefer-html nil
|
|
||||||
"Whether to base the body display on the HTML-version of the
|
|
||||||
e-mail message (if there is any."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'mu4e-view)
|
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -377,52 +363,8 @@ http://cr.yp.to/proto/maildir.html "
|
||||||
(t (propertize "?" 'face 'mu4e-system-face))))
|
(t (propertize "?" 'face 'mu4e-system-face))))
|
||||||
|
|
||||||
|
|
||||||
|
(defalias 'mu4e-body-text 'mu4e-message-body-text) ;; backward compatibility
|
||||||
(defun mu4e-body-text (msg)
|
|
||||||
"Get the body in text form for this message, which is either :body-txt,
|
|
||||||
or if not available, :body-html converted to text. By default, it
|
|
||||||
uses the emacs built-in `html2text'. Alternatively, if
|
|
||||||
`mu4e-html2text-command' is non-nil, it will use that. Normally,
|
|
||||||
function prefers the text part, but this can be changed by setting
|
|
||||||
`mu4e-view-prefer-html'."
|
|
||||||
(let* ((txt (plist-get msg :body-txt))
|
|
||||||
(html (plist-get msg :body-html))
|
|
||||||
(body
|
|
||||||
(cond
|
|
||||||
;; does it look like some text? ie., 10x the length of the text
|
|
||||||
;; should be longer than the html, an heuristic to guard against
|
|
||||||
;; 'This messages requires html' text bodies.
|
|
||||||
((and (> (* 10 (length txt)) (length html))
|
|
||||||
;; use html if it's prefered, unless there is no html
|
|
||||||
(or (not mu4e-view-prefer-html) (not html)))
|
|
||||||
txt)
|
|
||||||
;; otherwise, it there some html?
|
|
||||||
(html
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert html)
|
|
||||||
;; if defined, use the external tool
|
|
||||||
(if mu4e-html2text-command
|
|
||||||
(shell-command-on-region (point-min) (point-max)
|
|
||||||
mu4e-html2text-command nil t)
|
|
||||||
;; otherwise...
|
|
||||||
(html2text))
|
|
||||||
(buffer-string)))
|
|
||||||
(t ;; otherwise, an empty body
|
|
||||||
""))))
|
|
||||||
;; and finally, remove some crap from the remaining string; it seems
|
|
||||||
;; esp. outlook lies about its encoding (ie., it says 'iso-8859-1' but
|
|
||||||
;; really it's 'windows-1252'), thus giving us these funky chars. here, we
|
|
||||||
;; either remove them, or replace with 'what-was-meant' (heuristically)
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert body)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward "[
]" nil t)
|
|
||||||
(replace-match
|
|
||||||
(cond
|
|
||||||
((string= (match-string 0) "") "'")
|
|
||||||
(t ""))))
|
|
||||||
(buffer-string))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-display-manual ()
|
(defun mu4e-display-manual ()
|
||||||
"Display the mu4e manual page for the current mode, or go to the
|
"Display the mu4e manual page for the current mode, or go to the
|
||||||
|
@ -435,44 +377,8 @@ top level if there is none."
|
||||||
(t "mu4e"))))
|
(t "mu4e"))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(defsubst mu4e-msg-field (msg field)
|
(defalias 'mu4e-msg-field 'mu4e-message-field) ;; backward compatibility
|
||||||
"Retrieve FIELD from message plist MSG. FIELD is one
|
|
||||||
of :from, :to, :cc, :bcc, :subject, :data, :message-id, :path, :maildir,
|
|
||||||
:priority, :attachments, :references, :in-reply-to, :body-txt, :body-html
|
|
||||||
|
|
||||||
A message plist looks something like:
|
|
||||||
\(:docid 32461
|
|
||||||
:from ((\"Nikola Tesla\" . \"niko@example.com\"))
|
|
||||||
:to ((\"Thomas Edison\" . \"tom@example.com\"))
|
|
||||||
:cc ((\"Rupert The Monkey\" . \"rupert@example.com\"))
|
|
||||||
:subject \"RE: what about the 50K?\"
|
|
||||||
:date (20369 17624 0)
|
|
||||||
:size 4337
|
|
||||||
:message-id \"6BDC23465F79238C8233AB82D81EE81AF0114E4E74@123213.mail.example.com\"
|
|
||||||
:path \"/home/tom/Maildir/INBOX/cur/133443243973_1.10027.atlas:2,S\"
|
|
||||||
:maildir \"/INBOX\"
|
|
||||||
:priority normal
|
|
||||||
:flags (seen)
|
|
||||||
:attachments
|
|
||||||
((:index 2 :name \"photo.jpg\" :mime-type \"image/jpeg\" :size 147331)
|
|
||||||
(:index 3 :name \"book.pdf\" :mime-type \"application/pdf\" :size 192220))
|
|
||||||
:references (\"6BDC23465F79238C8384574032D81EE81AF0114E4E74@123213.mail.example.com\"
|
|
||||||
\"6BDC23465F79238203498230942D81EE81AF0114E4E74@123213.mail.example.com\")
|
|
||||||
:in-reply-to \"6BDC23465F79238203498230942D81EE81AF0114E4E74@123213.mail.example.com\"
|
|
||||||
:body-txt \"Hi Tom, ...\"
|
|
||||||
\)).
|
|
||||||
Some notes on the format:
|
|
||||||
- The address fields are lists of pairs (NAME . EMAIL), where NAME can be nil.
|
|
||||||
- The date is in format emacs uses in `current-time'
|
|
||||||
- Attachments are a list of elements with fields :index (the number of
|
|
||||||
the MIME-part), :name (the file name, if any), :mime-type (the
|
|
||||||
MIME-type, if any) and :size (the size in bytes, if any).
|
|
||||||
- Messages in the Headers view come from the database and do not have
|
|
||||||
:attachments. :body-txt or :body-html fields. Message in the
|
|
||||||
Message view use the actual message file, and do include these fields."
|
|
||||||
;; after all this documentation, the spectacular implementation
|
|
||||||
(plist-get msg field))
|
|
||||||
|
|
||||||
(defun mu4e-message-at-point (&optional raise-err)
|
(defun mu4e-message-at-point (&optional raise-err)
|
||||||
"Get the message s-expression for the message at point in either
|
"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
|
the headers buffer or the view buffer, or nil if there is no such
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
(require 'mu4e-proc)
|
(require 'mu4e-proc)
|
||||||
(require 'mu4e-compose)
|
(require 'mu4e-compose)
|
||||||
(require 'mu4e-actions)
|
(require 'mu4e-actions)
|
||||||
|
(require 'mu4e-message)
|
||||||
|
|
||||||
(require 'longlines)
|
(require 'longlines)
|
||||||
(require 'comint)
|
(require 'comint)
|
||||||
|
@ -144,7 +145,7 @@ plist."
|
||||||
(concat
|
(concat
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (field)
|
(lambda (field)
|
||||||
(let ((fieldval (plist-get msg field)))
|
(let ((fieldval (mu4e-message-field msg field)))
|
||||||
(case field
|
(case field
|
||||||
(:subject (mu4e~view-construct-header field fieldval))
|
(:subject (mu4e~view-construct-header field fieldval))
|
||||||
(:path (mu4e~view-construct-header field fieldval))
|
(:path (mu4e~view-construct-header field fieldval))
|
||||||
|
@ -159,7 +160,7 @@ plist."
|
||||||
;; if we (`user-mail-address' are the From, show To, otherwise,
|
;; if we (`user-mail-address' are the From, show To, otherwise,
|
||||||
;; show From
|
;; show From
|
||||||
(:from-or-to
|
(:from-or-to
|
||||||
(let* ((from (plist-get msg :from))
|
(let* ((from (mu4e-message-field msg :from))
|
||||||
(from (and from (cdar from))))
|
(from (and from (cdar from))))
|
||||||
(if (and from (string-match mu4e-user-mail-address-regexp from))
|
(if (and from (string-match mu4e-user-mail-address-regexp from))
|
||||||
(mu4e~view-construct-contacts-header msg :to)
|
(mu4e~view-construct-contacts-header msg :to)
|
||||||
|
@ -180,7 +181,7 @@ plist."
|
||||||
(t (mu4e-error "Unsupported field: %S" field)))))
|
(t (mu4e-error "Unsupported field: %S" field)))))
|
||||||
mu4e-view-fields "")
|
mu4e-view-fields "")
|
||||||
"\n"
|
"\n"
|
||||||
(mu4e-body-text msg)
|
(mu4e-message-body-text msg)
|
||||||
;; ;; decrypt maybe; depends on whether there are any such parts
|
;; ;; decrypt maybe; depends on whether there are any such parts
|
||||||
;; ;; and the value of `mu4e-view-decrypt-parts'
|
;; ;; and the value of `mu4e-view-decrypt-parts'
|
||||||
;; (mu4e~decrypt-parts-maybe msg)
|
;; (mu4e~decrypt-parts-maybe msg)
|
||||||
|
@ -204,7 +205,8 @@ REFRESH is for re-showing an already existing message.
|
||||||
As a side-effect, a message that is being viewed loses its 'unread'
|
As a side-effect, a message that is being viewed loses its 'unread'
|
||||||
marking if it still had that."
|
marking if it still had that."
|
||||||
(let* ((embedded ;; is it registered as an embedded msg?
|
(let* ((embedded ;; is it registered as an embedded msg?
|
||||||
(when (gethash (plist-get msg :path) mu4e~path-parent-docid-map) t))
|
(when (gethash (mu4e-message-field msg :path)
|
||||||
|
mu4e~path-parent-docid-map) t))
|
||||||
(buf
|
(buf
|
||||||
(if embedded
|
(if embedded
|
||||||
(mu4e~view-embedded-winbuf)
|
(mu4e~view-embedded-winbuf)
|
||||||
|
@ -315,7 +317,7 @@ at POINT, or if nil, at (point)."
|
||||||
(format "<%s>\n%s\n%s" email
|
(format "<%s>\n%s\n%s" email
|
||||||
"[mouse-1] or [M-RET] to toggle long/short display"
|
"[mouse-1] or [M-RET] to toggle long/short display"
|
||||||
"[mouse-2] or C to compose a mail for this recipient"))))
|
"[mouse-2] or C to compose a mail for this recipient"))))
|
||||||
(plist-get msg field) ", ") t))
|
(mu4e-message-field msg field) ", ") t))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~view-construct-flags-header (flags)
|
(defun mu4e~view-construct-flags-header (flags)
|
||||||
|
@ -331,10 +333,10 @@ at POINT, or if nil, at (point)."
|
||||||
|
|
||||||
(defun mu4e~view-construct-signature-header (msg)
|
(defun mu4e~view-construct-signature-header (msg)
|
||||||
"Construct a Signature: header, if there are any signed parts."
|
"Construct a Signature: header, if there are any signed parts."
|
||||||
(let* ((parts (plist-get msg :parts))
|
(let* ((parts (mu4e-message-field msg :parts))
|
||||||
(verdicts
|
(verdicts
|
||||||
(remove-if 'null
|
(remove-if 'null
|
||||||
(mapcar (lambda (part) (plist-get part :signature)) parts)))
|
(mapcar (lambda (part) (mu4e-message-part-field part :signature)) parts)))
|
||||||
(val (when verdicts
|
(val (when verdicts
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (v)
|
(lambda (v)
|
||||||
|
@ -379,21 +381,21 @@ at POINT, or if nil, at (point)."
|
||||||
;; user-visible numbers and the part indices
|
;; user-visible numbers and the part indices
|
||||||
(remove-if-not
|
(remove-if-not
|
||||||
(lambda (part)
|
(lambda (part)
|
||||||
(let ((mtype (plist-get part :mime-type))
|
(let ((mtype (mu4e-message-part-field part :mime-type))
|
||||||
(isattach (member 'attachment (plist-get part :type))))
|
(isattach (member 'attachment (mu4e-message-part-field part :type))))
|
||||||
(or ;; remove if it's not an attach *or* if it's an
|
(or ;; remove if it's not an attach *or* if it's an
|
||||||
;; image/audio/application type (but not a signature)
|
;; image/audio/application type (but not a signature)
|
||||||
isattach
|
isattach
|
||||||
(string-match "^\\(image\\|audio\\)" mtype)
|
(string-match "^\\(image\\|audio\\)" mtype)
|
||||||
(and (string-match "^application" mtype)
|
(and (string-match "^application" mtype)
|
||||||
(not (string-match "signature" mtype))))))
|
(not (string-match "signature" mtype))))))
|
||||||
(plist-get msg :parts)))
|
(mu4e-message-field msg :parts)))
|
||||||
(attstr
|
(attstr
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (part)
|
(lambda (part)
|
||||||
(let ((index (plist-get part :index))
|
(let ((index (mu4e-message-part-field part :index))
|
||||||
(name (plist-get part :name))
|
(name (mu4e-message-part-field part :name))
|
||||||
(size (plist-get part :size))
|
(size (mu4e-message-part-field part :size))
|
||||||
(map (make-sparse-keymap)))
|
(map (make-sparse-keymap)))
|
||||||
(incf id)
|
(incf id)
|
||||||
(puthash id index mu4e~view-attach-map)
|
(puthash id index mu4e~view-attach-map)
|
||||||
|
@ -431,8 +433,8 @@ at POINT, or if nil, at (point)."
|
||||||
;; (let ((str ""))
|
;; (let ((str ""))
|
||||||
;; (mu4e-view-for-each-part msg
|
;; (mu4e-view-for-each-part msg
|
||||||
;; (lambda (msg part)
|
;; (lambda (msg part)
|
||||||
;; (when (member 'encrypted (plist-get part :type))
|
;; (when (member 'encrypted (mu4e-message-part-field part :type))
|
||||||
;; (let ((file (plist-get part :temp)))
|
;; (let ((file (mu4e-message-part-field part :temp)))
|
||||||
;; (when (and file (file-exists-p file))
|
;; (when (and file (file-exists-p file))
|
||||||
;; ;; if our mu-server was build with crypto support, we only use EPA
|
;; ;; if our mu-server was build with crypto support, we only use EPA
|
||||||
;; ;; to push the password into gpg's memory
|
;; ;; to push the password into gpg's memory
|
||||||
|
@ -730,8 +732,8 @@ browser is called is depending on `browse-url-browser-function' and
|
||||||
(when (and (display-images-p) mu4e-show-images)
|
(when (and (display-images-p) mu4e-show-images)
|
||||||
(mu4e-view-for-each-part msg
|
(mu4e-view-for-each-part msg
|
||||||
(lambda (msg part)
|
(lambda (msg part)
|
||||||
(when (string-match "^image/" (plist-get part :mime-type))
|
(when (string-match "^image/" (mu4e-message-part-field part :mime-type))
|
||||||
(let ((imgfile (plist-get part :temp)))
|
(let ((imgfile (mu4e-message-part-field part :temp)))
|
||||||
(when (and imgfile (file-exists-p imgfile))
|
(when (and imgfile (file-exists-p imgfile))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
|
@ -893,8 +895,8 @@ number ATTNUM."
|
||||||
(attach
|
(attach
|
||||||
(find-if
|
(find-if
|
||||||
(lambda (part)
|
(lambda (part)
|
||||||
(eq (plist-get part :index) partid))
|
(eq (mu4e-message-part-field part :index) partid))
|
||||||
(plist-get msg :parts))))
|
(mu4e-message-field msg :parts))))
|
||||||
(or attach (mu4e-error "Not a valid attachment"))))
|
(or attach (mu4e-error "Not a valid attachment"))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -920,7 +922,7 @@ message-at-point if nil) to disk."
|
||||||
(and (file-exists-p path)
|
(and (file-exists-p path)
|
||||||
(not (y-or-n-p (mu4e-format "Overwrite '%s'?" path))))))
|
(not (y-or-n-p (mu4e-format "Overwrite '%s'?" path))))))
|
||||||
(mu4e~proc-extract
|
(mu4e~proc-extract
|
||||||
'save (plist-get msg :docid) index path)))
|
'save (mu4e-message-field msg :docid) index path)))
|
||||||
|
|
||||||
(defun mu4e-view-save-attachment-multi (&optional msg)
|
(defun mu4e-view-save-attachment-multi (&optional msg)
|
||||||
"Offer to save multiple email attachments from the current message.
|
"Offer to save multiple email attachments from the current message.
|
||||||
|
@ -958,7 +960,7 @@ message-at-point if nil)."
|
||||||
(mu4e~view-get-attach-num "Attachment to open" msg)))
|
(mu4e~view-get-attach-num "Attachment to open" msg)))
|
||||||
(att (or (mu4e~view-get-attach msg attnum)))
|
(att (or (mu4e~view-get-attach msg attnum)))
|
||||||
(index (plist-get att :index))
|
(index (plist-get att :index))
|
||||||
(docid (plist-get msg :docid))
|
(docid (mu4e-message-field msg :docid))
|
||||||
(mimetype (plist-get att :mime-type)))
|
(mimetype (plist-get att :mime-type)))
|
||||||
(if (and mimetype (string= mimetype "message/rfc822"))
|
(if (and mimetype (string= mimetype "message/rfc822"))
|
||||||
;; special handling for message-attachments; we open them in mu4e. we also
|
;; special handling for message-attachments; we open them in mu4e. we also
|
||||||
|
@ -990,7 +992,7 @@ user for it."
|
||||||
(mu4e-format "Shell command to open it with: ")
|
(mu4e-format "Shell command to open it with: ")
|
||||||
nil 'mu4e~view-open-with-hist)))
|
nil 'mu4e~view-open-with-hist)))
|
||||||
(index (plist-get att :index)))
|
(index (plist-get att :index)))
|
||||||
(mu4e~view-temp-action (plist-get msg :docid) index "open-with" cmd)))
|
(mu4e~view-temp-action (mu4e-message-field msg :docid) index "open-with" cmd)))
|
||||||
|
|
||||||
(defvar mu4e~view-pipe-hist nil
|
(defvar mu4e~view-pipe-hist nil
|
||||||
"History list for the pipe argument.")
|
"History list for the pipe argument.")
|
||||||
|
@ -1006,7 +1008,7 @@ PIPECMD is nil, ask user for it."
|
||||||
nil
|
nil
|
||||||
'mu4e~view-pipe-hist)))
|
'mu4e~view-pipe-hist)))
|
||||||
(index (plist-get att :index)))
|
(index (plist-get att :index)))
|
||||||
(mu4e~view-temp-action (plist-get msg :docid) index "pipe" pipecmd)))
|
(mu4e~view-temp-action (mu4e-message-field msg :docid) index "pipe" pipecmd)))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-view-open-attachment-emacs (msg attachnum)
|
(defun mu4e-view-open-attachment-emacs (msg attachnum)
|
||||||
|
@ -1014,7 +1016,7 @@ PIPECMD is nil, ask user for it."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((att (mu4e~view-get-attach msg attachnum))
|
(let* ((att (mu4e~view-get-attach msg attachnum))
|
||||||
(index (plist-get att :index)))
|
(index (plist-get att :index)))
|
||||||
(mu4e~view-temp-action (plist-get msg :docid) index "emacs")))
|
(mu4e~view-temp-action (mu4e-message-field msg :docid) index "emacs")))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-view-attachment-action (&optional msg)
|
(defun mu4e-view-attachment-action (&optional msg)
|
||||||
|
@ -1171,7 +1173,7 @@ the results."
|
||||||
"Pop-up a little signature verification window for (optional) MSG
|
"Pop-up a little signature verification window for (optional) MSG
|
||||||
or message-at-point."
|
or message-at-point."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((path (if msg (plist-get msg :path) (mu4e-field-at-point :path)))
|
(let* ((path (if msg (mu4e-message-field msg :path) (mu4e-field-at-point :path)))
|
||||||
(cmd (format "%s verify --verbose %s"
|
(cmd (format "%s verify --verbose %s"
|
||||||
mu4e-mu-binary
|
mu4e-mu-binary
|
||||||
(shell-quote-argument path)))
|
(shell-quote-argument path)))
|
||||||
|
|
Loading…
Reference in New Issue