diff --git a/mu4e/mu4e-compose.el b/mu4e/mu4e-compose.el index 991bdc99..8407d43f 100644 --- a/mu4e/mu4e-compose.el +++ b/mu4e/mu4e-compose.el @@ -859,8 +859,8 @@ buffer buried." (when other-headers (dolist (h other-headers other-headers) (if (symbolp (car h)) (setcar h (symbol-name (car h)))) - (message-add-header (concat (capitalize (car h)) ": " (cdr h) "\n" )) - )) + (message-add-header + (concat (capitalize (car h)) ": " (cdr h) "\n" )))) ;; yank message (if (bufferp yank-action) diff --git a/mu4e/mu4e-contacts.el b/mu4e/mu4e-contacts.el index a1373a8e..beac895b 100644 --- a/mu4e/mu4e-contacts.el +++ b/mu4e/mu4e-contacts.el @@ -1,6 +1,6 @@ ;;; mu4e-contacts.el -- part of mu4e -*- lexical-binding: t -*- -;; Copyright (C) 2021 Dirk-Jan C. Binnema +;; Copyright (C) 2022 Dirk-Jan C. Binnema ;; Author: Dirk-Jan C. Binnema ;; Maintainer: Dirk-Jan C. Binnema @@ -44,14 +44,14 @@ These addresses are the ones specified with `mu init'." :type 'boolean :group 'mu4e-compose) -(defcustom mu4e-compose-complete-only-after "2014-01-01" +(defcustom mu4e-compose-complete-only-after "2018-01-01" "Consider only contacts last seen after this date. -Date must be a string of the form YYY-MM-DD. +Date must be a string of the form YYYY-MM-DD. This is useful for limiting a potentially enormous set of contacts for auto-completion to just those that are present in -the e-mail corpus in recent timses. Set to nil to not have any +the e-mail corpus in recent times. Set to nil to not have any time-based restriction." :type 'string :group 'mu4e-compose) @@ -155,6 +155,73 @@ addresses and /regular expressions/." "determined by server; see `mu4e-personal-addresses'." "1.3.8") + +;; Helpers + + +;;; RFC2822 handling of phrases in mail-addresses +;; +;; The optional display-name contains a phrase, it sits before the +;; angle-addr as specified in RFC2822 for email-addresses in header +;; fields. Contributed by jhelberg. + +(defun mu4e--rfc822-phrase-type (ph) + "Return an atom or quoted-string for the phrase PH. +This checks for empty string first. Then quotes around the phrase +\(returning 'rfc822-quoted-string). Then whether there is a quote +inside the phrase (returning 'rfc822-containing-quote). The +reverse of the RFC atext definition is then tested. If it +matches, nil is returned, if not, it is an 'rfc822-atom, which is +returned." + (cond + ((= (length ph) 0) 'rfc822-empty) + ((= (aref ph 0) ?\") + (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) + 'rfc822-quoted-string + 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one + ((string-match-p "[\"]" ph) 'rfc822-containing-quote) + ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) + (t 'rfc822-atom))) + +(defun mu4e--rfc822-quote-phrase (ph) + "Quote an RFC822 phrase PH only if necessary. +Atoms and quoted strings don't need quotes. The rest do. In +case a phrase contains a quote, it will be escaped." + (let ((type (mu4e--rfc822-phrase-type ph))) + (cond + ((eq type 'rfc822-atom) ph) + ((eq type 'rfc822-quoted-string) ph) + ((eq type 'rfc822-containing-quote) + (format "\"%s\"" + (replace-regexp-in-string "\"" "\\\\\"" ph))) + (t (format "\"%s\"" ph))))) + +(defsubst mu4e-contact-name (contact) + "Get the name of this CONTACT, or nil." + (plist-get contact :name)) + +(defsubst mu4e-contact-email (contact) + "Get the name of this CONTACT, or nil." + (plist-get contact :email)) + +(defsubst mu4e-contact-cons (contact) + "Convert a CONTACT plist into a old-style (name . email)." + (cons + (mu4e-contact-name contact) + (mu4e-contact-email contact))) + +(defsubst mu4e-contact-make (name email) + "Creata contact plist from NAME and EMAIL." + `(:name ,name :email ,email)) + +(defun mu4e-contact-full (contact) + "Get the full combination of name and email address from CONTACT." + (let* ((email (mu4e-contact-email contact)) + (name (mu4e-contact-name contact))) + (if (and name (> (length name) 0)) + (format "%s <%s>" (mu4e--rfc822-quote-phrase name) email) + email))) + (defun mu4e--update-contacts (contacts &optional tstamp) "Receive a sorted list of CONTACTS newer than TSTAMP. @@ -212,7 +279,7 @@ For testing/debugging." (setq contacts (sort contacts (lambda(cell1 cell2) (< (car cell1) (car cell2))))) (dolist (contact contacts) - (insert (format "%s\n" (cdr contact)))))) + (insert (format "%s\n" (mu4e-contact-email contact)))))) (pop-to-buffer "*mu4e-contacts-info*"))) diff --git a/mu4e/mu4e-draft.el b/mu4e/mu4e-draft.el index adc2cd13..305ff444 100644 --- a/mu4e/mu4e-draft.el +++ b/mu4e/mu4e-draft.el @@ -1,6 +1,6 @@ ;;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*- ;; -;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema +;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema ;; Author: Dirk-Jan C. Binnema ;; Maintainer: Dirk-Jan C. Binnema @@ -312,7 +312,6 @@ one. Code borrowed from `message-shorten-1'." (nthcdr (+ (- cut 2) surplus 1) list))) - (defun mu4e~fontify-signature () "Give the message signatures a distinctive color. This is used in the view and compose modes and will color each signature in @@ -360,13 +359,7 @@ This is specified as a comma-separated list of e-mail addresses. If LST is nil, returns nil." (when lst (mapconcat - (lambda (addrcell) - (let ((name (car addrcell)) - (email (cdr addrcell))) - (if name - (format "%s <%s>" (mu4e~rfc822-quoteit name) email) - (format "%s" email)))) - lst ", "))) + (lambda (contact) (mu4e-contact-full contact)) lst ", "))) (defun mu4e~draft-address-cell-equal (cell1 cell2) "Return t if CELL1 and CELL2 have the same e-mail address. @@ -374,8 +367,8 @@ The comparison is done case-insensitively. If the cells done match return nil. CELL1 and CELL2 are cons cells of the form (NAME . EMAIL)." (string= - (downcase (or (cdr cell1) "")) - (downcase (or (cdr cell2) "")))) + (downcase (or (mu4e-contact-email cell1) "")) + (downcase (or (mu4e-contact-email cell2) "")))) (defun mu4e~draft-create-to-lst (origmsg) @@ -391,7 +384,7 @@ of the original, we simple copy the list form the original." (if mu4e-compose-dont-reply-to-self (cl-delete-if (lambda (to-cell) - (mu4e-personal-address-p (cdr to-cell))) + (mu4e-personal-address-p (mu4e-contact-email to-cell))) reply-to) reply-to))) @@ -406,7 +399,7 @@ I.e. return all the addresses in ADDRS not matching ((functionp mu4e-compose-reply-ignore-address) (cl-remove-if (lambda (elt) - (funcall mu4e-compose-reply-ignore-address (cdr elt))) + (funcall mu4e-compose-reply-ignore-address (mu4e-contact-email elt))) addrs)) (t ;; regexp or list of regexps @@ -417,7 +410,7 @@ I.e. return all the addresses in ADDRS not matching regexp))) (cl-remove-if (lambda (elt) - (string-match regexp (cdr elt))) + (string-match regexp (mu4e-contact-email elt))) addrs))))) (defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from) @@ -452,7 +445,7 @@ REPLY-ALL." cc-lst (cl-delete-if (lambda (cc-cell) - (mu4e-personal-address-p (cdr cc-cell))) + (mu4e-personal-address-p (mu4e-contact-email cc-cell))) cc-lst)))) cc-lst))) @@ -470,53 +463,14 @@ message. Return nil if there are no recipients for the particular field." (otherwise (mu4e-error "Unsupported field"))))) -;;; RFC2822 handling of phrases in mail-addresses -;; -;; The optional display-name contains a phrase, it sits before the -;; angle-addr as specified in RFC2822 for email-addresses in header -;; fields. Contributed by jhelberg. - -(defun mu4e~rfc822-phrase-type (ph) - "Return an atom or quoted-string for the phrase PH. -This checks for empty string first. Then quotes around the phrase -\(returning 'rfc822-quoted-string). Then whether there is a quote -inside the phrase (returning 'rfc822-containing-quote). -The reverse of the RFC atext definition is then tested. -If it matches, nil is returned, if not, it is an 'rfc822-atom, which -is returned." - (cond - ((= (length ph) 0) 'rfc822-empty) - ((= (aref ph 0) ?\") - (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) - 'rfc822-quoted-string - 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one - ((string-match-p "[\"]" ph) 'rfc822-containing-quote) - ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) - (t 'rfc822-atom))) - -(defun mu4e~rfc822-quoteit (ph) - "Quote an RFC822 phrase PH only if necessary. -Atoms and quoted strings don't need quotes. The rest do. In -case a phrase contains a quote, it will be escaped." - (let ((type (mu4e~rfc822-phrase-type ph))) - (cond - ((eq type 'rfc822-atom) ph) - ((eq type 'rfc822-quoted-string) ph) - ((eq type 'rfc822-containing-quote) - (format "\"%s\"" - (replace-regexp-in-string "\"" "\\\\\"" ph))) - (t (format "\"%s\"" ph))))) - - (defun mu4e~draft-from-construct () "Construct a value for the From:-field of the reply. This is based on the variable `user-full-name' and `user-mail-address'; if the latter is nil, function returns nil." (when user-mail-address - (if user-full-name - (format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address) - (format "%s" user-mail-address)))) - + (mu4e-contact-full (mu4e-contact-make + user-full-name + user-mail-address)))) ;;; Header separators @@ -527,34 +481,34 @@ the body starts. Note, in `mu4e-compose-mode', we use `before-save-hook' and `after-save-hook' to ensure that this separator is never written to the message file. Also see `mu4e-remove-mail-header-separator'." - ;; we set this here explicitly, since (as it has happened) a wrong - ;; value for this (such as "") breaks address completion and other things - (set (make-local-variable 'mail-header-separator) "--text follows this line--") - (put 'mail-header-separator 'permanent-local t) - (save-excursion - ;; make sure there's not one already - (mu4e~draft-remove-mail-header-separator) - (let ((sepa (propertize mail-header-separator - 'intangible t - ;; don't make this read-only, message-mode - ;; seems to require it being writable in some cases - ;;'read-only "Can't touch this" - 'rear-nonsticky t - 'font-lock-face 'mu4e-compose-separator-face))) - (widen) - ;; search for the first empty line - (goto-char (point-min)) - (if (search-forward-regexp "^$" nil t) - (progn - (replace-match sepa) - ;; `message-narrow-to-headers` searches for a - ;; `mail-header-separator` followed by a new line. Therefore, we - ;; must insert a newline if on the last line of the buffer. - (when (= (point) (point-max)) - (insert "\n"))) - (progn ;; no empty line? then prepend one - (goto-char (point-max)) - (insert "\n" sepa)))))) + ;; we set this here explicitly, since (as it has happened) a wrong + ;; value for this (such as "") breaks address completion and other things + (set (make-local-variable 'mail-header-separator) "--text follows this line--") + (put 'mail-header-separator 'permanent-local t) + (save-excursion + ;; make sure there's not one already + (mu4e~draft-remove-mail-header-separator) + (let ((sepa (propertize mail-header-separator + 'intangible t + ;; don't make this read-only, message-mode + ;; seems to require it being writable in some cases + ;;'read-only "Can't touch this" + 'rear-nonsticky t + 'font-lock-face 'mu4e-compose-separator-face))) + (widen) + ;; search for the first empty line + (goto-char (point-min)) + (if (search-forward-regexp "^$" nil t) + (progn + (replace-match sepa) + ;; `message-narrow-to-headers` searches for a + ;; `mail-header-separator` followed by a new line. Therefore, we + ;; must insert a newline if on the last line of the buffer. + (when (= (point) (point-max)) + (insert "\n"))) + (progn ;; no empty line? then prepend one + (goto-char (point-max)) + (insert "\n" sepa)))))) (defun mu4e~draft-remove-mail-header-separator () "Remove `mail-header-separator'. diff --git a/mu4e/mu4e-headers.el b/mu4e/mu4e-headers.el index 29e8adc6..4bf83958 100644 --- a/mu4e/mu4e-headers.el +++ b/mu4e/mu4e-headers.el @@ -1,4 +1,4 @@ -;;; mu4e-headers.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- +;;; mu4e-headers.el -- part of mu4e -*- lexical-binding: t -*- ;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema @@ -41,6 +41,7 @@ (require 'mu4e-vars) (require 'mu4e-mark) (require 'mu4e-context) +(require 'mu4e-contacts) (require 'mu4e-search) (require 'mu4e-compose) (require 'mu4e-actions) @@ -177,7 +178,7 @@ query have been received and are displayed." ;;; Public variables (defvar mu4e-headers-sort-field :date - "Field to sort the headers by. Must be a symbol, + "Field to sort the headers by. A symbol: one of: `:date', `:subject', `:size', `:prio', `:from', `:to.', `:list'. @@ -305,10 +306,6 @@ In the format needed for `mu4e-read-option'.") "If non-nil, report on the time it took to render the messages. This is mostly useful for profiling.") - - - - ;;; Clear @@ -332,8 +329,9 @@ This is mostly useful for profiling.") "Turn the list of contacts CONTACTS (with elements (NAME . EMAIL) into a string." (mapconcat - (lambda (ct) - (let ((name (car ct)) (email (cdr ct))) + (lambda (contact) + (let ((name (mu4e-contact-name contact)) + (email (mu4e-contact-email contact))) (or name email "?"))) contacts ", ")) (defun mu4e~headers-thread-prefix-map (type) @@ -503,23 +501,20 @@ while our display may be different)." ;;; Special headers -(defconst mu4e-headers-from-or-to-prefix '("" . "To ") - "Prefix for the :from-or-to field. -It's a cons cell with the car element being the From: prefix, the -cdr element the To: prefix.") - (defun mu4e~headers-from-or-to (msg) - "When the from address for message MSG is one of the the user's addresses, + "Get the From: address from MSG if not one of user's; otherwise get To:. +When the from address for message MSG is one of the the user's addresses, \(as per `mu4e-personal-address-p'), show the To address; otherwise ; show the from address; prefixed with the appropriate `mu4e-headers-from-or-to-prefix'." - (let ((addr (cdr-safe (car-safe (mu4e-message-field msg :from))))) - (if (and addr (mu4e-personal-address-p addr)) - (concat (cdr mu4e-headers-from-or-to-prefix) - (mu4e~headers-contact-str (mu4e-message-field msg :to))) - (concat (car mu4e-headers-from-or-to-prefix) - (mu4e~headers-contact-str (mu4e-message-field msg :from)))))) + (let* ((from1 (car-safe (mu4e-message-field msg :from))) + (from1-addr (and from1 (mu4e-contact-email from1))) + (is-user (and from1-addr (mu4e-personal-address-p from1-addr)))) + (if is-user + (concat "To " (mu4e~headers-contact-str (mu4e-message-field msg :to))) + (mu4e~headers-contact-str (mu4e-message-field msg :from))))) + (defun mu4e~headers-human-date (msg) "Show a 'human' date. If the date is today, show the time, otherwise, show the @@ -1406,7 +1401,8 @@ matching messages with that mark." (let* ((value (mu4e-msg-field msg field))) (if (member field '(:to :from :cc :bcc :reply-to)) (cl-find-if (lambda (contact) - (let ((name (car contact)) (email (cdr contact))) + (let ((name (mu4e-contact-name contact)) + (email (mu4e-contact-email contact))) (or (and name (string-match pattern name)) (and email (string-match pattern email))))) value) (string-match pattern (or value "")))))))) diff --git a/mu4e/mu4e-helpers.el b/mu4e/mu4e-helpers.el index d11588b4..e49d12d0 100644 --- a/mu4e/mu4e-helpers.el +++ b/mu4e/mu4e-helpers.el @@ -504,6 +504,10 @@ in an external program." (lambda () (ignore-errors (delete-file tmpfile)))) tmpfile)) +(defsubst mu4e-is-mode-or-derived-p (mode) + "Is the current mode equal to MODE or derived from it?" + (or (eq major-mode 'mode) (derived-mode-p mode))) + (defun mu4e-display-manual () "Display the mu4e manual page for the current mode. Or go to the top level if there is none." diff --git a/mu4e/mu4e-icalendar.el b/mu4e/mu4e-icalendar.el index 3b5bef8f..2bc4ce03 100644 --- a/mu4e/mu4e-icalendar.el +++ b/mu4e/mu4e-icalendar.el @@ -96,7 +96,7 @@ (defun mu4e~icalendar-has-email (email list) "Check that EMAIL is in LIST." (let ((email (downcase email))) - (cl-find-if (lambda (c) (let ((e (cdr c))) + (cl-find-if (lambda (c) (let ((e (mu4e-contact-email c))) (and (stringp e) (string= email (downcase e))))) list))) diff --git a/mu4e/mu4e-message.el b/mu4e/mu4e-message.el index 2613f33b..7298f419 100644 --- a/mu4e/mu4e-message.el +++ b/mu4e/mu4e-message.el @@ -27,6 +27,7 @@ ;;; Code: (require 'mu4e-vars) +(require 'mu4e-contacts) (require 'flow-fill) (require 'shr) @@ -54,9 +55,9 @@ Returns nil if the field does not exist. 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\")) + :from ((:name \"Nikola Tesla\" :email \"niko@example.com\")) + :to ((:name \"Thomas Edison\" :email \"tom@example.com\")) + :cc ((:name \"Rupert The Monkey\" :email \"rupert@example.com\")) :subject \"RE: what about the 50K?\" :date (20369 17624 0) :size 4337 @@ -74,7 +75,9 @@ A message plist looks something like: :body-txt \"Hi Tom, ...\" \)). Some notes on the format: -- The address fields are lists of pairs (NAME . EMAIL), where NAME can be nil. +- The address fields are lists of plist (:name NAME :email EMAIL), + where the :name part can be absent. The `mu4e-contact-name' and + `mu4e-contact-email' accessors can be useful for this. - 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 @@ -134,7 +137,7 @@ This is equivalent to: ) (defun mu4e-message-contact-field-matches (msg cfield rx) - "Does MSG's contact-field CFIELD match rx? + "Does MSG's contact-field CFIELD match regexp RX? Check if any of the of the CFIELD in MSG matches RX. I.e. anything in field CFIELD (either :to, :from, :cc or :bcc, or a list of those) of msg MSG matches (with their name or e-mail @@ -142,8 +145,10 @@ address) regular expressions RX. If there is a match, return non-nil; otherwise return nil. RX can also be a list of regular expressions, in which case any of those are tried for a match." (if (and cfield (listp cfield)) - (or (mu4e-message-contact-field-matches msg (car cfield) rx) - (mu4e-message-contact-field-matches msg (cdr cfield) rx)) + (or (mu4e-message-contact-field-matches + msg (mu4e-contact-name cfield) rx) + (mu4e-message-contact-field-matches + msg (mu4e-contact-email cfield) rx)) (when cfield (if (listp rx) ;; if rx is a list, try each one of them for a match @@ -153,7 +158,8 @@ expressions, in which case any of those are tried for a match." ;; not a list, check the rx (seq-find (lambda (ct) - (let ((name (car ct)) (email (cdr ct)) + (let ((name (mu4e-contact-name ct)) + (email (mu4e-contact-email ct)) ;; the 'rx' may be some `/rx/` from mu4e-personal-addresses; ;; so let's detect and extract in that case. (rx (if (string-match-p "^\\(.*\\)/$" rx) @@ -170,7 +176,8 @@ of the of the contacts in field CFIELD (either :to, :from, :cc or :bcc) of msg MSG matches *me*, that is, any of the addresses for which `mu4e-personal-address-p' return t. Returns the contact cell that matched, or nil." - (seq-find (lambda (cell) (mu4e-personal-address-p (cdr cell))) + (seq-find (lambda (cell) + (mu4e-personal-address-p (mu4e-contact-email cell))) (mu4e-message-field msg cfield))) (defun mu4e-message-sent-by-me (msg) diff --git a/mu4e/mu4e-org.el b/mu4e/mu4e-org.el index 1f113679..3232c3ba 100644 --- a/mu4e/mu4e-org.el +++ b/mu4e/mu4e-org.el @@ -1,6 +1,6 @@ ;;; mu4e-org -- Org-links to mu4e messages/queries -*- lexical-binding: t -*- -;; Copyright (C) 2012-2021 Dirk-Jan C. Binnema +;; Copyright (C) 2012-2022 Dirk-Jan C. Binnema ;; Author: Dirk-Jan C. Binnema ;; Maintainer: Dirk-Jan C. Binnema @@ -29,6 +29,7 @@ (require 'org) (require 'mu4e-view) +(require 'mu4e-contacts) (defgroup mu4e-org nil @@ -79,25 +80,23 @@ the current query; otherwise, it links to the message at point.") (date (format-time-string "%FT%T" (plist-get msg :date))) (msgid (or (plist-get msg :message-id) (mu4e-error "Cannot link message without message-id"))) - (name-or-addr (lambda (addr) (or (car-safe addr) (cdr-safe addr)))) - (full-address (lambda(addr) - (when addr - (if-let ((name (car addr))) - (format "%s <%s>" name (cdr addr)) - (format "%s" (cdr addr))))))) - (org-store-link-props - :type "mu4e" - :date date - :from (funcall full-address from) - :fromnameoraddress (funcall name-or-addr from) ;; mu4e-specific - :maildir (plist-get msg :maildir) - :message-id msgid - :path (plist-get msg :path) - :subject (plist-get msg :subject) - :to (funcall full-address to) - :tonameoraddress (funcall name-or-addr to) ;; mu4e-specific - :link (concat "mu4e:msgid:" msgid) - :description (funcall mu4e-org-link-desc-func msg)))) + (props `(:type "mu4e" + :date ,date + :from ,(mu4e-contact-full from) + :fromname ,(mu4e-contact-name from) + :fromnameoraddress ,(or (mu4e-contact-name from) + (mu4e-contact-email from)) ;; mu4e-specific + :maildir ,(plist-get msg :maildir) + :message-id ,msgid + :path ,(plist-get msg :path) + :subject ,(plist-get msg :subject) + :to ,(mu4e-contact-full to) + :tonameoraddress ,(or (mu4e-contact-name to) + (mu4e-contact-email to)) ;; mu4e-specific + :link ,(concat "mu4e:msgid:" msgid) + :description ,(funcall mu4e-org-link-desc-func msg)))) + (message "PROPS %S" props) + (apply #'org-store-link-props props))) (defun mu4e-org-store-link () "Store a link to a mu4e message or query. @@ -105,13 +104,15 @@ It links to the last known query when in `mu4e-headers-mode' with `mu4e-org-link-query-in-headers-mode' set; otherwise it links to a specific message, based on its message-id, so that links stay valid even after moving the message around." - (when (derived-mode-p 'mu4e-view-mode 'mu4e-headers-mode) - (if (and (derived-mode-p 'mu4e-headers-mode) - mu4e-org-link-query-in-headers-mode) - (mu4e--org-store-link-query) - (when (mu4e-message-at-point) - (message "%S" (mu4e--org-store-link-message)) - (mu4e--org-store-link-message))))) + (let ((view-mode-p (mu4e-is-mode-or-derived-p 'mu4e-view-mode)) + (headers-mode-p (mu4e-is-mode-or-derived-p 'mu4e-headers-mode)) + (message-p (mu4e-message-at-point))) + (if view-mode-p + (mu4e--org-store-link-message) + (if headers-mode-p + (if (or (not message-p) mu4e-org-link-query-in-headers-mode) + (mu4e--org-store-link-query) + (mu4e--org-store-link-message)))))) (defun mu4e-org-open (link) "Open the org LINK. diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index 8a23ee6d..ecade3d4 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -211,15 +211,20 @@ I.e. a message with the draft flag set." :shortname "Cc" :help "Carbon-Copy recipients for the message" :sortable t)) + (:changed + . (:name "Changed" + :shortname "Chg" + :help "Date/time when the message was changed most recently" + :sortable t)) (:date . (:name "Date" :shortname "Date" - :help "Date/time when the message was written" + :help "Date/time when the message was sent" :sortable t)) (:human-date . (:name "Date" :shortname "Date" - :help "Date/time when the message was written." + :help "Date/time when the message was sent" :sortable :date)) (:flags . (:name "Flags" @@ -314,7 +319,7 @@ one of the addresses in `(mu4e-personal-addresses)', in which case it will be equal to `:to'. Furthermore, the property `:sortable' determines whether we can -sort by this field. This can be either a boolean (nil or t), or a +sort by this field. This can be either a boolean (nil or t), or a symbol for /another/ field. For example, the `:human-date' field uses `:date' for that.