mirror of https://github.com/djcb/mu.git
mu4e: updates for core changes
Deal with (name . email) --> (:name "boo" :email "boo@example.com") Add support for the new "changed" field.
This commit is contained in:
parent
4b56b8779d
commit
45aec819f6
|
@ -859,8 +859,8 @@ buffer buried."
|
||||||
(when other-headers
|
(when other-headers
|
||||||
(dolist (h other-headers other-headers)
|
(dolist (h other-headers other-headers)
|
||||||
(if (symbolp (car h)) (setcar h (symbol-name (car h))))
|
(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
|
;; yank message
|
||||||
(if (bufferp yank-action)
|
(if (bufferp yank-action)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-contacts.el -- part of mu4e -*- lexical-binding: t -*-
|
;;; 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 <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -44,14 +44,14 @@ These addresses are the ones specified with `mu init'."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'mu4e-compose)
|
: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.
|
"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
|
This is useful for limiting a potentially enormous set of
|
||||||
contacts for auto-completion to just those that are present in
|
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."
|
time-based restriction."
|
||||||
:type 'string
|
:type 'string
|
||||||
:group 'mu4e-compose)
|
:group 'mu4e-compose)
|
||||||
|
@ -155,6 +155,73 @@ addresses and /regular expressions/."
|
||||||
"determined by server; see `mu4e-personal-addresses'."
|
"determined by server; see `mu4e-personal-addresses'."
|
||||||
"1.3.8")
|
"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)
|
(defun mu4e--update-contacts (contacts &optional tstamp)
|
||||||
"Receive a sorted list of CONTACTS newer than TSTAMP.
|
"Receive a sorted list of CONTACTS newer than TSTAMP.
|
||||||
|
@ -212,7 +279,7 @@ For testing/debugging."
|
||||||
(setq contacts (sort contacts
|
(setq contacts (sort contacts
|
||||||
(lambda(cell1 cell2) (< (car cell1) (car cell2)))))
|
(lambda(cell1 cell2) (< (car cell1) (car cell2)))))
|
||||||
(dolist (contact contacts)
|
(dolist (contact contacts)
|
||||||
(insert (format "%s\n" (cdr contact))))))
|
(insert (format "%s\n" (mu4e-contact-email contact))))))
|
||||||
|
|
||||||
(pop-to-buffer "*mu4e-contacts-info*")))
|
(pop-to-buffer "*mu4e-contacts-info*")))
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*-
|
;;; 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 <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -312,7 +312,6 @@ one. Code borrowed from `message-shorten-1'."
|
||||||
(nthcdr (+ (- cut 2) surplus 1) list)))
|
(nthcdr (+ (- cut 2) surplus 1) list)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~fontify-signature ()
|
(defun mu4e~fontify-signature ()
|
||||||
"Give the message signatures a distinctive color. This is used
|
"Give the message signatures a distinctive color. This is used
|
||||||
in the view and compose modes and will color each signature in
|
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."
|
If LST is nil, returns nil."
|
||||||
(when lst
|
(when lst
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (addrcell)
|
(lambda (contact) (mu4e-contact-full contact)) lst ", ")))
|
||||||
(let ((name (car addrcell))
|
|
||||||
(email (cdr addrcell)))
|
|
||||||
(if name
|
|
||||||
(format "%s <%s>" (mu4e~rfc822-quoteit name) email)
|
|
||||||
(format "%s" email))))
|
|
||||||
lst ", ")))
|
|
||||||
|
|
||||||
(defun mu4e~draft-address-cell-equal (cell1 cell2)
|
(defun mu4e~draft-address-cell-equal (cell1 cell2)
|
||||||
"Return t if CELL1 and CELL2 have the same e-mail address.
|
"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
|
match return nil. CELL1 and CELL2 are cons cells of the
|
||||||
form (NAME . EMAIL)."
|
form (NAME . EMAIL)."
|
||||||
(string=
|
(string=
|
||||||
(downcase (or (cdr cell1) ""))
|
(downcase (or (mu4e-contact-email cell1) ""))
|
||||||
(downcase (or (cdr cell2) ""))))
|
(downcase (or (mu4e-contact-email cell2) ""))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~draft-create-to-lst (origmsg)
|
(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
|
(if mu4e-compose-dont-reply-to-self
|
||||||
(cl-delete-if
|
(cl-delete-if
|
||||||
(lambda (to-cell)
|
(lambda (to-cell)
|
||||||
(mu4e-personal-address-p (cdr to-cell)))
|
(mu4e-personal-address-p (mu4e-contact-email to-cell)))
|
||||||
reply-to)
|
reply-to)
|
||||||
reply-to)))
|
reply-to)))
|
||||||
|
|
||||||
|
@ -406,7 +399,7 @@ I.e. return all the addresses in ADDRS not matching
|
||||||
((functionp mu4e-compose-reply-ignore-address)
|
((functionp mu4e-compose-reply-ignore-address)
|
||||||
(cl-remove-if
|
(cl-remove-if
|
||||||
(lambda (elt)
|
(lambda (elt)
|
||||||
(funcall mu4e-compose-reply-ignore-address (cdr elt)))
|
(funcall mu4e-compose-reply-ignore-address (mu4e-contact-email elt)))
|
||||||
addrs))
|
addrs))
|
||||||
(t
|
(t
|
||||||
;; regexp or list of regexps
|
;; regexp or list of regexps
|
||||||
|
@ -417,7 +410,7 @@ I.e. return all the addresses in ADDRS not matching
|
||||||
regexp)))
|
regexp)))
|
||||||
(cl-remove-if
|
(cl-remove-if
|
||||||
(lambda (elt)
|
(lambda (elt)
|
||||||
(string-match regexp (cdr elt)))
|
(string-match regexp (mu4e-contact-email elt)))
|
||||||
addrs)))))
|
addrs)))))
|
||||||
|
|
||||||
(defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from)
|
(defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from)
|
||||||
|
@ -452,7 +445,7 @@ REPLY-ALL."
|
||||||
cc-lst
|
cc-lst
|
||||||
(cl-delete-if
|
(cl-delete-if
|
||||||
(lambda (cc-cell)
|
(lambda (cc-cell)
|
||||||
(mu4e-personal-address-p (cdr cc-cell)))
|
(mu4e-personal-address-p (mu4e-contact-email cc-cell)))
|
||||||
cc-lst))))
|
cc-lst))))
|
||||||
cc-lst)))
|
cc-lst)))
|
||||||
|
|
||||||
|
@ -470,53 +463,14 @@ message. Return nil if there are no recipients for the particular field."
|
||||||
(otherwise
|
(otherwise
|
||||||
(mu4e-error "Unsupported field")))))
|
(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 ()
|
(defun mu4e~draft-from-construct ()
|
||||||
"Construct a value for the From:-field of the reply.
|
"Construct a value for the From:-field of the reply.
|
||||||
This is based on the variable `user-full-name' and
|
This is based on the variable `user-full-name' and
|
||||||
`user-mail-address'; if the latter is nil, function returns nil."
|
`user-mail-address'; if the latter is nil, function returns nil."
|
||||||
(when user-mail-address
|
(when user-mail-address
|
||||||
(if user-full-name
|
(mu4e-contact-full (mu4e-contact-make
|
||||||
(format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address)
|
user-full-name
|
||||||
(format "%s" user-mail-address))))
|
user-mail-address))))
|
||||||
|
|
||||||
|
|
||||||
;;; Header separators
|
;;; Header separators
|
||||||
|
|
||||||
|
|
|
@ -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
|
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@
|
||||||
(require 'mu4e-vars)
|
(require 'mu4e-vars)
|
||||||
(require 'mu4e-mark)
|
(require 'mu4e-mark)
|
||||||
(require 'mu4e-context)
|
(require 'mu4e-context)
|
||||||
|
(require 'mu4e-contacts)
|
||||||
(require 'mu4e-search)
|
(require 'mu4e-search)
|
||||||
(require 'mu4e-compose)
|
(require 'mu4e-compose)
|
||||||
(require 'mu4e-actions)
|
(require 'mu4e-actions)
|
||||||
|
@ -177,7 +178,7 @@ query have been received and are displayed."
|
||||||
;;; Public variables
|
;;; Public variables
|
||||||
|
|
||||||
(defvar mu4e-headers-sort-field :date
|
(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.',
|
one of: `:date', `:subject', `:size', `:prio', `:from', `:to.',
|
||||||
`:list'.
|
`: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.
|
"If non-nil, report on the time it took to render the messages.
|
||||||
This is mostly useful for profiling.")
|
This is mostly useful for profiling.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Clear
|
;;; Clear
|
||||||
|
@ -332,8 +329,9 @@ This is mostly useful for profiling.")
|
||||||
"Turn the list of contacts CONTACTS (with elements (NAME . EMAIL)
|
"Turn the list of contacts CONTACTS (with elements (NAME . EMAIL)
|
||||||
into a string."
|
into a string."
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (ct)
|
(lambda (contact)
|
||||||
(let ((name (car ct)) (email (cdr ct)))
|
(let ((name (mu4e-contact-name contact))
|
||||||
|
(email (mu4e-contact-email contact)))
|
||||||
(or name email "?"))) contacts ", "))
|
(or name email "?"))) contacts ", "))
|
||||||
|
|
||||||
(defun mu4e~headers-thread-prefix-map (type)
|
(defun mu4e~headers-thread-prefix-map (type)
|
||||||
|
@ -503,23 +501,20 @@ while our display may be different)."
|
||||||
|
|
||||||
;;; Special headers
|
;;; 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)
|
(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;
|
\(as per `mu4e-personal-address-p'), show the To address;
|
||||||
otherwise ; show the from address; prefixed with the appropriate
|
otherwise ; 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 (mu4e-message-field msg :from)))))
|
(let* ((from1 (car-safe (mu4e-message-field msg :from)))
|
||||||
(if (and addr (mu4e-personal-address-p addr))
|
(from1-addr (and from1 (mu4e-contact-email from1)))
|
||||||
(concat (cdr mu4e-headers-from-or-to-prefix)
|
(is-user (and from1-addr (mu4e-personal-address-p from1-addr))))
|
||||||
(mu4e~headers-contact-str (mu4e-message-field msg :to)))
|
(if is-user
|
||||||
(concat (car mu4e-headers-from-or-to-prefix)
|
(concat "To " (mu4e~headers-contact-str (mu4e-message-field msg :to)))
|
||||||
(mu4e~headers-contact-str (mu4e-message-field msg :from))))))
|
(mu4e~headers-contact-str (mu4e-message-field msg :from)))))
|
||||||
|
|
||||||
|
|