mu4e-draft: fix flycheck warnings + whitespace

This commit is contained in:
djcb
2019-05-19 22:04:53 +03:00
parent 0d33e64dc9
commit 10ddaebf06

View File

@ -1,6 +1,6 @@
;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs ;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs
;; ;;
;; Copyright (C) 2011-2016 Dirk-Jan C. Binnema ;; Copyright (C) 2011-2019 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>
@ -24,7 +24,8 @@
;; In this file, various functions to create draft messages ;; In this file, various functions to create draft messages
;; Code ;;; Code:
(require 'cl-lib) (require 'cl-lib)
(require 'mu4e-vars) (require 'mu4e-vars)
(require 'mu4e-utils) (require 'mu4e-utils)
@ -36,41 +37,39 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defcustom mu4e-compose-dont-reply-to-self nil (defcustom mu4e-compose-dont-reply-to-self nil
"If non-nil, don't include self (that is, any member of "If non-nil, don't include self.
`mu4e-user-mail-address-list') in replies." \(that is, member of `mu4e-user-mail-address-list') in replies."
:type 'boolean :type 'boolean
:group 'mu4e-compose) :group 'mu4e-compose)
(defcustom mu4e-compose-cite-function (defcustom mu4e-compose-cite-function
(or message-cite-function 'message-cite-original-without-signature) (or message-cite-function 'message-cite-original-without-signature)
"The function to use to cite message in replies and forwarded "The function for citing message in replies and forwards.
messages. This is the mu4e-specific version of This is the mu4e-specific version of
`message-cite-function'." `message-cite-function'."
:type 'function :type 'function
:group 'mu4e-compose) :group 'mu4e-compose)
(defcustom mu4e-compose-signature (defcustom mu4e-compose-signature
(or message-signature "Sent with my mu4e") (or message-signature "Sent with my mu4e")
"The message signature (i.e. the blob at the bottom of "The message signature.
messages). This is the mu4e-specific version of \(i.e. the blob at the bottom of messages). This is the
`message-signature'." mu4e-specific version of `message-signature'."
:group 'mu4e-compose) :group 'mu4e-compose)
(defcustom mu4e-compose-signature-auto-include t (defcustom mu4e-compose-signature-auto-include t
"Whether to automatically include a message-signature in new "Whether to automatically include a message-signature."
messages (if it is set)."
:type 'boolean :type 'boolean
:group 'mu4e-compose) :group 'mu4e-compose)
(defcustom mu4e-compose-auto-include-date nil (defcustom mu4e-compose-auto-include-date nil
"Whether to include a date header when starting to draft a "Whether to include a date header.
message; if nil, only do so when sending the message." If nil, only do so when sending the message."
:type 'boolean :type 'boolean
:group 'mu4e-compose) :group 'mu4e-compose)
(defcustom mu4e-compose-in-new-frame nil (defcustom mu4e-compose-in-new-frame nil
"Whether to compose messages in a new frame instead of the "Whether to compose messages in a new frame."
current window."
:type 'boolean :type 'boolean
:group 'mu4e-compose) :group 'mu4e-compose)
@ -85,15 +84,15 @@ its settings apply."
(with-temp-buffer (with-temp-buffer
(when (fboundp 'mu4e-view-message-text) ;; keep bytecompiler happy (when (fboundp 'mu4e-view-message-text) ;; keep bytecompiler happy
(let ((mu4e-view-date-format "%Y-%m-%dT%T%z")) (let ((mu4e-view-date-format "%Y-%m-%dT%T%z"))
(insert (mu4e-view-message-text msg))) (insert (mu4e-view-message-text msg)))
(message-yank-original) (message-yank-original)
(goto-char (point-min)) (goto-char (point-min))
(push-mark (point-max)) (push-mark (point-max))
;; set the the signature separator to 'loose', since in the real world, ;; set the the signature separator to 'loose', since in the real world,
;; many message don't follow the standard... ;; many message don't follow the standard...
(let ((message-signature-separator "^-- *$") (let ((message-signature-separator "^-- *$")
(message-signature-insert-empty-line t)) (message-signature-insert-empty-line t))
(funcall mu4e-compose-cite-function)) (funcall mu4e-compose-cite-function))
(pop-mark) (pop-mark)
(goto-char (point-min)) (goto-char (point-min))
(buffer-string)))) (buffer-string))))
@ -104,40 +103,41 @@ If VAL is nil, return nil."
;; note: the propertize here is currently useless, since gnus sets its own ;; note: the propertize here is currently useless, since gnus sets its own
;; later. ;; later.
(when val (format "%s: %s\n" (when val (format "%s: %s\n"
(propertize hdr 'face 'mu4e-header-key-face) (propertize hdr 'face 'mu4e-header-key-face)
(propertize val 'face 'mu4e-header-value-face)))) (propertize val 'face 'mu4e-header-value-face))))
(defconst mu4e~max-reference-num 21 (defconst mu4e~max-reference-num 21
"Maximum number of References:, as suggested by "Specifies the maximum number of References:.
`message-shorten-references'.") As suggested by `message-shorten-references'.")
(defun mu4e~shorten-1 (list cut surplus) (defun mu4e~shorten-1 (list cut surplus)
"Cut SURPLUS elements out of LIST, beginning with CUTth "Cut SURPLUS elements out of LIST.
Beginning with CUTth
one. Code borrowed from `message-shorten-1'." one. Code borrowed from `message-shorten-1'."
(setcdr (nthcdr (- cut 2) list) (setcdr (nthcdr (- cut 2) list)
(nthcdr (+ (- cut 2) surplus 1) list))) (nthcdr (+ (- cut 2) surplus 1) list)))
(defun mu4e~draft-references-construct (msg) (defun mu4e~draft-references-construct (msg)
"Construct the value of the References: header based on MSG as a "Construct the value of the References: header based on MSG.
comma-separated string. Normally, this the concatenation of the This assumes a comma-separated string. Normally, this the concatenation of the
existing References + In-Reply-To (which may be empty, an note existing References + In-Reply-To (which may be empty, an note
that :references includes the old in-reply-to as well) and the that :references includes the old in-reply-to as well) and the
message-id. If the message-id is empty, returns the old message-id. If the message-id is empty, returns the old
References. If both are empty, return nil." References. If both are empty, return nil."
(let* ( ;; these are the ones from the message being replied to / forwarded (let* ( ;; these are the ones from the message being replied to / forwarded
(refs (mu4e-message-field msg :references)) (refs (mu4e-message-field msg :references))
(msgid (mu4e-message-field msg :message-id)) (msgid (mu4e-message-field msg :message-id))
;; now, append in ;; now, append in
(refs (if (and msgid (not (string= msgid ""))) (refs (if (and msgid (not (string= msgid "")))
(append refs (list msgid)) refs)) (append refs (list msgid)) refs))
;; no doubles ;; no doubles
(refs (cl-delete-duplicates refs :test #'equal)) (refs (cl-delete-duplicates refs :test #'equal))
(refnum (length refs)) (refnum (length refs))
(cut 2)) (cut 2))
;; remove some refs when there are too many ;; remove some refs when there are too many
(when (> refnum mu4e~max-reference-num) (when (> refnum mu4e~max-reference-num)
(let ((surplus (- refnum mu4e~max-reference-num))) (let ((surplus (- refnum mu4e~max-reference-num)))
(mu4e~shorten-1 refs cut surplus))) (mu4e~shorten-1 refs cut surplus)))
(mapconcat (lambda (id) (format "<%s>" id)) refs " "))) (mapconcat (lambda (id) (format "<%s>" id)) refs " ")))
@ -145,16 +145,17 @@ References. If both are empty, return nil."
;; determine the recipient fields for new messages ;; determine the recipient fields for new messages
(defun mu4e~draft-recipients-list-to-string (lst) (defun mu4e~draft-recipients-list-to-string (lst)
"Convert a lst LST of address cells into a string with a list of "Convert a lst LST of address cells into a string.
e-mail addresses. If LST is nil, returns nil." This is specified as a comma-separated list of e-mail addresses.
If LST is nil, returns nil."
(when lst (when lst
(mapconcat (mapconcat
(lambda (addrcell) (lambda (addrcell)
(let ((name (car addrcell)) (let ((name (car addrcell))
(email (cdr addrcell))) (email (cdr addrcell)))
(if name (if name
(format "%s <%s>" (mu4e~rfc822-quoteit name) email) (format "%s <%s>" (mu4e~rfc822-quoteit name) email)
(format "%s" email)))) (format "%s" email))))
lst ", "))) lst ", ")))
(defun mu4e~draft-address-cell-equal (cell1 cell2) (defun mu4e~draft-address-cell-equal (cell1 cell2)
@ -168,99 +169,101 @@ form (NAME . EMAIL)."
(defun mu4e~draft-create-to-lst (origmsg) (defun mu4e~draft-create-to-lst (origmsg)
"Create a list of address for the To: in a new message, based on "Create a list of address for the To: in a new message.
the original message ORIGMSG. If the Reply-To address is set, use This is based on the original message ORIGMSG. If the Reply-To
that, otherwise use the From address. Note, whatever was in the To: address is set, use that, otherwise use the From address. Note,
field before, goes to the Cc:-list (if we're doing a reply-to-all). whatever was in the To: field before, goes to the Cc:-list (if
Special case: if we were the sender of the original, we simple copy we're doing a reply-to-all). Special case: if we were the sender
the list form the original." of the original, we simple copy the list form the original."
(let ((reply-to (let ((reply-to
(or (plist-get origmsg :reply-to) (plist-get origmsg :from)))) (or (plist-get origmsg :reply-to) (plist-get origmsg :from))))
(cl-delete-duplicates reply-to :test #'mu4e~draft-address-cell-equal) (cl-delete-duplicates reply-to :test #'mu4e~draft-address-cell-equal)
(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)
(cl-member-if (cl-member-if
(lambda (addr) (lambda (addr)
(string= (downcase addr) (downcase (cdr to-cell)))) (string= (downcase addr) (downcase (cdr to-cell))))
mu4e-user-mail-address-list)) mu4e-user-mail-address-list))
reply-to) reply-to)
reply-to))) reply-to)))
(defun mu4e~strip-ignored-addresses (addrs) (defun mu4e~strip-ignored-addresses (addrs)
"Return all the addresses in ADDRS not matching "Return all addresses that are not to be ignored.
I.e. return all the addresses in ADDRS not matching
`mu4e-compose-reply-ignore-address'." `mu4e-compose-reply-ignore-address'."
(cond (cond
((null mu4e-compose-reply-ignore-address) ((null mu4e-compose-reply-ignore-address)
addrs) addrs)
((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 (cdr elt)))
addrs)) addrs))
(t (t
;; regexp or list of regexps ;; regexp or list of regexps
(let* ((regexp mu4e-compose-reply-ignore-address) (let* ((regexp mu4e-compose-reply-ignore-address)
(regexp (if (listp regexp) (regexp (if (listp regexp)
(mapconcat (lambda (elt) (concat "\\(" elt "\\)")) (mapconcat (lambda (elt) (concat "\\(" elt "\\)"))
regexp "\\|") regexp "\\|")
regexp))) regexp)))
(cl-remove-if (cl-remove-if
(lambda (elt) (lambda (elt)
(string-match regexp (cdr elt))) (string-match regexp (cdr elt)))
addrs))))) addrs)))))
(defun mu4e~draft-create-cc-lst (origmsg reply-all) (defun mu4e~draft-create-cc-lst (origmsg reply-all)
"Create a list of address for the Cc: in a new message, based on "Create a list of address for the Cc: in a new message.
the original message ORIGMSG, and whether it's a reply-all." This is based on the original message ORIGMSG, and whether it's a
REPLY-ALL."
(when reply-all (when reply-all
(let* ((cc-lst ;; get the cc-field from the original, remove dups (let* ((cc-lst ;; get the cc-field from the original, remove dups
(cl-delete-duplicates (cl-delete-duplicates
(append (append
(plist-get origmsg :to) (plist-get origmsg :to)
(plist-get origmsg :cc)) (plist-get origmsg :cc))
:test #'mu4e~draft-address-cell-equal)) :test #'mu4e~draft-address-cell-equal))
;; now we have the basic list, but we must remove ;; now we have the basic list, but we must remove
;; addresses also in the to list ;; addresses also in the to list
(cc-lst (cc-lst
(cl-delete-if (cl-delete-if
(lambda (cc-cell) (lambda (cc-cell)
(cl-find-if (cl-find-if
(lambda (to-cell) (lambda (to-cell)
(mu4e~draft-address-cell-equal cc-cell to-cell)) (mu4e~draft-address-cell-equal cc-cell to-cell))
(mu4e~draft-create-to-lst origmsg))) (mu4e~draft-create-to-lst origmsg)))
cc-lst)) cc-lst))
;; remove ignored addresses ;; remove ignored addresses
(cc-lst (mu4e~strip-ignored-addresses cc-lst)) (cc-lst (mu4e~strip-ignored-addresses cc-lst))
;; finally, we need to remove ourselves from the cc-list ;; finally, we need to remove ourselves from the cc-list
;; unless mu4e-compose-keep-self-cc is non-nil ;; unless mu4e-compose-keep-self-cc is non-nil
(cc-lst (cc-lst
(if (or mu4e-compose-keep-self-cc (null user-mail-address)) (if (or mu4e-compose-keep-self-cc (null user-mail-address))
cc-lst cc-lst
(cl-delete-if (cl-delete-if
(lambda (cc-cell) (lambda (cc-cell)
(cl-member-if (cl-member-if
(lambda (addr) (lambda (addr)
(string= (downcase addr) (downcase (cdr cc-cell)))) (string= (downcase addr) (downcase (cdr cc-cell))))
mu4e-user-mail-address-list)) mu4e-user-mail-address-list))
cc-lst)))) cc-lst))))
cc-lst))) cc-lst)))
(defun mu4e~draft-recipients-construct (field origmsg &optional reply-all) (defun mu4e~draft-recipients-construct (field origmsg &optional reply-all)
"Create value (a string) for the recipient field FIELD (a "Create value (a string) for the recipient FIELD.
symbol, :to or :cc), based on the original message ORIGMSG, \(which is a symbol, :to or :cc), based on the original message ORIGMSG,
and (optionally) REPLY-ALL which indicates this is a reply-to-all and (optionally) REPLY-ALL which indicates this is a reply-to-all
message. Return nil if there are no recipients for the particular field." message. Return nil if there are no recipients for the particular field."
(mu4e~draft-recipients-list-to-string (mu4e~draft-recipients-list-to-string
(cl-case field (cl-case field
(:to (:to
(mu4e~draft-create-to-lst origmsg)) (mu4e~draft-create-to-lst origmsg))
(:cc (:cc
(mu4e~draft-create-cc-lst origmsg reply-all)) (mu4e~draft-create-cc-lst origmsg reply-all))
(otherwise (otherwise
(mu4e-error "Unsupported field"))))) (mu4e-error "Unsupported field")))))
;;; RFC2822 handling of phrases in mail-addresses ;;; RFC2822 handling of phrases in mail-addresses
;;; The optional display-name contains a phrase, it sits before the angle-addr ;;; The optional display-name contains a phrase, it sits before the angle-addr
@ -268,44 +271,41 @@ message. Return nil if there are no recipients for the particular field."
;;; contributed by jhelberg ;;; contributed by jhelberg
(defun mu4e~rfc822-phrase-type (ph) (defun mu4e~rfc822-phrase-type (ph)
"Return either atom, quoted-string, a corner-case or nil. This "Return an atom or quoted-string for the phrase PH.
checks for empty string first. Then quotes around the phrase This checks for empty string first. Then quotes around the phrase
(returning 'rfc822-quoted-string). Then whether there is a quote \(returning 'rfc822-quoted-string). Then whether there is a quote
inside the phrase (returning 'rfc822-containing-quote). inside the phrase (returning 'rfc822-containing-quote).
The reverse of the RFC atext definition is then tested. The reverse of the RFC atext definition is then tested.
If it matches, nil is returned, if not, it is an 'rfc822-atom, which If it matches, nil is returned, if not, it is an 'rfc822-atom, which
is returned." is returned."
(cond (cond
((= (length ph) 0) 'rfc822-empty) ((= (length ph) 0) 'rfc822-empty)
((= (aref ph 0) ?\") ((= (aref ph 0) ?\")
(if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph)
'rfc822-quoted-string 'rfc822-quoted-string
'rfc822-containing-quote)) ; starts with quote, but doesn't end with one 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one
((string-match-p "[\"]" ph) 'rfc822-containing-quote) ((string-match-p "[\"]" ph) 'rfc822-containing-quote)
((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil)
(t 'rfc822-atom))) (t 'rfc822-atom)))
(defun mu4e~rfc822-quoteit (ph) (defun mu4e~rfc822-quoteit (ph)
"Quote RFC822 phrase only if necessary. "Quote an RFC822 phrase PH only if necessary.
Atoms and quoted strings don't need quotes. The rest do. In Atoms and quoted strings don't need quotes. The rest do. In
case a phrase contains a quote, it will be escaped." case a phrase contains a quote, it will be escaped."
(let ((type (mu4e~rfc822-phrase-type ph))) (let ((type (mu4e~rfc822-phrase-type ph)))
(cond (cond
((eq type 'rfc822-atom) ph) ((eq type 'rfc822-atom) ph)
((eq type 'rfc822-quoted-string) ph) ((eq type 'rfc822-quoted-string) ph)
((eq type 'rfc822-containing-quote) ((eq type 'rfc822-containing-quote)
(format "\"%s\"" (format "\"%s\""
(replace-regexp-in-string "\"" "\\\\\"" ph))) (replace-regexp-in-string "\"" "\\\\\"" ph)))
(t (format "\"%s\"" 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 to MSG, "Construct a value for the From:-field of the reply.
based on `user-full-name' and `user-mail-address'; if the latter is This is based on the variable `user-full-name' and
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 (if user-full-name
(format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address) (format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address)
@ -328,52 +328,54 @@ separator is never written to the message file. Also see
;; make sure there's not one already ;; make sure there's not one already
(mu4e~draft-remove-mail-header-separator) (mu4e~draft-remove-mail-header-separator)
(let ((sepa (propertize mail-header-separator (let ((sepa (propertize mail-header-separator
'intangible t 'intangible t
;; don't make this read-only, message-mode ;; don't make this read-only, message-mode
;; seems to require it being writable in some cases ;; seems to require it being writable in some cases
;;'read-only "Can't touch this" ;;'read-only "Can't touch this"
'rear-nonsticky t 'rear-nonsticky t
'font-lock-face 'mu4e-compose-separator-face))) 'font-lock-face 'mu4e-compose-separator-face)))
(widen) (widen)
;; search for the first empty line ;; search for the first empty line
(goto-char (point-min)) (goto-char (point-min))
(if (search-forward-regexp "^$" nil t) (if (search-forward-regexp "^$" nil t)
(progn (progn
(replace-match sepa) (replace-match sepa)
;; `message-narrow-to-headers` searches for a ;; `message-narrow-to-headers` searches for a
;; `mail-header-separator` followed by a new line. Therefore, we ;; `mail-header-separator` followed by a new line. Therefore, we
;; must insert a newline if on the last line of the buffer. ;; must insert a newline if on the last line of the buffer.
(when (= (point) (point-max)) (when (= (point) (point-max))
(insert "\n"))) (insert "\n")))
(progn ;; no empty line? then prepend one (progn ;; no empty line? then prepend one
(goto-char (point-max)) (goto-char (point-max))
(insert "\n" sepa)))))) (insert "\n" sepa))))))
(defun mu4e~draft-remove-mail-header-separator () (defun mu4e~draft-remove-mail-header-separator ()
"Remove `mail-header-separator; we do this before saving a "Remove `mail-header-separator'.
We do this before saving a
file (and restore it afterwards), to ensure that the separator file (and restore it afterwards), to ensure that the separator
never hits the disk. Also see `mu4e~draft-insert-mail-header-separator." never hits the disk. Also see
`mu4e~draft-insert-mail-header-separator."
(save-excursion (save-excursion
(widen) (widen)
(goto-char (point-min)) (goto-char (point-min))
;; remove the --text follows this line-- separator ;; remove the --text follows this line-- separator
(when (search-forward-regexp (concat "^" mail-header-separator) nil t) (when (search-forward-regexp (concat "^" mail-header-separator) nil t)
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
(replace-match ""))))) (replace-match "")))))
(defun mu4e~draft-reply-all-p (origmsg) (defun mu4e~draft-reply-all-p (origmsg)
"Ask user whether she wants to reply to *all* recipients. "Ask user whether she wants to reply to *all* recipients.
If there is just one recipient of ORIGMSG do nothing." If there is just one recipient of ORIGMSG do nothing."
(let* ((recipnum (let* ((recipnum
(+ (length (mu4e~draft-create-to-lst origmsg)) (+ (length (mu4e~draft-create-to-lst origmsg))
(length (mu4e~draft-create-cc-lst origmsg t)))) (length (mu4e~draft-create-cc-lst origmsg t))))
(response (response
(if (< recipnum 2) (if (< recipnum 2)
'all ;; with less than 2 recipients, we can reply to 'all' 'all ;; with less than 2 recipients, we can reply to 'all'
(mu4e-read-option (mu4e-read-option
"Reply to " "Reply to "
`( (,(format "all %d recipients" recipnum) . all) `( (,(format "all %d recipients" recipnum) . all)
("sender only" . sender-only)))))) ("sender only" . sender-only))))))
(eq response 'all))) (eq response 'all)))
(defun mu4e~draft-message-filename-construct (&optional flagstr) (defun mu4e~draft-message-filename-construct (&optional flagstr)
@ -382,14 +384,14 @@ It looks something like
<time>-<random>.<hostname>:2, <time>-<random>.<hostname>:2,
You can append flags." You can append flags."
(let* ((sysname (if (fboundp 'system-name) (let* ((sysname (if (fboundp 'system-name)
(system-name) (system-name)
(with-no-warnings system-name))) (with-no-warnings system-name)))
(sysname (if (string= sysname "") "localhost" sysname)) (sysname (if (string= sysname "") "localhost" sysname))
(hostname (downcase (hostname (downcase
(save-match-data (save-match-data
(substring sysname (substring sysname
(string-match "^[^.]+" sysname) (string-match "^[^.]+" sysname)
(match-end 0)))))) (match-end 0))))))
(format "%s.%04x%04x%04x%04x.%s:2,%s" (format "%s.%04x%04x%04x%04x.%s:2,%s"
(format-time-string "%s" (current-time)) (format-time-string "%s" (current-time))
(random 65535) (random 65535) (random 65535) (random 65535) (random 65535) (random 65535) (random 65535) (random 65535)
@ -407,46 +409,46 @@ You can append flags."
"String to prefix replies with.") "String to prefix replies with.")
(defun mu4e~draft-reply-construct (origmsg) (defun mu4e~draft-reply-construct (origmsg)
"Create a draft message as a reply to original message "Create a draft message as a reply to ORIGMSG.
ORIGMSG. Replying-to-self is a special; in that case, the To and Cc Replying-to-self is special; in that case, the To and Cc fields
fields will be the same as in the original." will be the same as in the original."
(let* ((reply-to-self (mu4e-message-contact-field-matches-me origmsg :from)) (let* ((reply-to-self (mu4e-message-contact-field-matches-me origmsg :from))
(recipnum (recipnum
(+ (length (mu4e~draft-create-to-lst origmsg)) (+ (length (mu4e~draft-create-to-lst origmsg))
(length (mu4e~draft-create-cc-lst origmsg t)))) (length (mu4e~draft-create-cc-lst origmsg t))))
;; reply-to-self implies reply-all ;; reply-to-self implies reply-all
(reply-all (or reply-to-self (mu4e~draft-reply-all-p origmsg))) (reply-all (or reply-to-self (mu4e~draft-reply-all-p origmsg)))
(old-msgid (plist-get origmsg :message-id)) (old-msgid (plist-get origmsg :message-id))
(subject (subject
(concat mu4e~draft-reply-prefix (concat mu4e~draft-reply-prefix
(message-strip-subject-re (or (plist-get origmsg :subject) ""))))) (message-strip-subject-re (or (plist-get origmsg :subject) "")))))
(concat (concat
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) "")) (mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address) (mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
(if reply-to-self (if reply-to-self
;; When we're replying to ourselves, simply keep the same headers. ;; When we're replying to ourselves, simply keep the same headers.
(concat (concat
(mu4e~draft-header "To" (mu4e~draft-recipients-list-to-string (mu4e~draft-header "To" (mu4e~draft-recipients-list-to-string
(mu4e-message-field origmsg :to))) (mu4e-message-field origmsg :to)))
(mu4e~draft-header "Cc" (mu4e~draft-recipients-list-to-string (mu4e~draft-header "Cc" (mu4e~draft-recipients-list-to-string
(mu4e-message-field origmsg :cc)))) (mu4e-message-field origmsg :cc))))
;; if there's no-one in To, copy the CC-list ;; if there's no-one in To, copy the CC-list
(if (zerop (length (mu4e~draft-create-to-lst origmsg))) (if (zerop (length (mu4e~draft-create-to-lst origmsg)))
(mu4e~draft-header "To" (mu4e~draft-recipients-construct (mu4e~draft-header "To" (mu4e~draft-recipients-construct
:cc origmsg reply-all)) :cc origmsg reply-all))
;; otherwise... ;; otherwise...
(concat (concat
(mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg)) (mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg))
(mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg (mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg
reply-all))))) reply-all)))))
(mu4e~draft-header "Subject" subject) (mu4e~draft-header "Subject" subject)
(mu4e~draft-header "References" (mu4e~draft-header "References"
(mu4e~draft-references-construct origmsg)) (mu4e~draft-references-construct origmsg))
(mu4e~draft-common-construct) (mu4e~draft-common-construct)
(when old-msgid (when old-msgid
(mu4e~draft-header "In-reply-to" (format "<%s>" old-msgid))) (mu4e~draft-header "In-reply-to" (format "<%s>" old-msgid)))
"\n\n" "\n\n"
(mu4e~draft-cite-original origmsg)))) (mu4e~draft-cite-original origmsg))))
@ -456,25 +458,25 @@ fields will be the same as in the original."
(defun mu4e~draft-forward-construct (origmsg) (defun mu4e~draft-forward-construct (origmsg)
"Create a draft forward message for original message ORIGMSG." "Create a draft forward message for original message ORIGMSG."
(let ((subject (let ((subject
(or (plist-get origmsg :subject) ""))) (or (plist-get origmsg :subject) "")))
(concat (concat
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) "")) (mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address) (mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
(mu4e~draft-header "To" "") (mu4e~draft-header "To" "")
(mu4e~draft-common-construct) (mu4e~draft-common-construct)
(mu4e~draft-header "References" (mu4e~draft-header "References"
(mu4e~draft-references-construct origmsg)) (mu4e~draft-references-construct origmsg))
(mu4e~draft-header "Subject" (mu4e~draft-header "Subject"
(concat (concat
;; if there's no Fwd: yet, prepend it ;; if there's no Fwd: yet, prepend it
(if (string-match "^Fwd:" subject) (if (string-match "^Fwd:" subject)
"" ""
mu4e~draft-forward-prefix) mu4e~draft-forward-prefix)
subject)) subject))
(unless mu4e-compose-forward-as-attachment (unless mu4e-compose-forward-as-attachment
(concat (concat
"\n\n" "\n\n"
(mu4e~draft-cite-original origmsg)))))) (mu4e~draft-cite-original origmsg))))))
(defun mu4e~draft-newmsg-construct () (defun mu4e~draft-newmsg-construct ()
"Create a new message." "Create a new message."
@ -486,8 +488,8 @@ fields will be the same as in the original."
(mu4e~draft-common-construct))) (mu4e~draft-common-construct)))
(defvar mu4e~draft-drafts-folder nil (defvar mu4e~draft-drafts-folder nil
"The drafts-folder for this compose buffer, based on "The drafts-folder for this compose buffer.
`mu4e-drafts-folder', which is evaluated once.") This is based on `mu4e-drafts-folder', which is evaluated once.")
(defun mu4e~draft-open-file (path) (defun mu4e~draft-open-file (path)
"Open the the draft file at PATH." "Open the the draft file at PATH."
@ -496,16 +498,16 @@ fields will be the same as in the original."
(find-file path))) (find-file path)))
(defun mu4e~draft-determine-path (draft-dir) (defun mu4e~draft-determine-path (draft-dir)
"Determine the path for a new draft file." "Determines the path for a new draft file in DRAFT-DIR."
(format "%s/%s/cur/%s" (format "%s/%s/cur/%s"
mu4e-maildir draft-dir (mu4e~draft-message-filename-construct "DS"))) mu4e-maildir draft-dir (mu4e~draft-message-filename-construct "DS")))
(defun mu4e-draft-open (compose-type &optional msg) (defun mu4e-draft-open (compose-type &optional msg)
"Open a draft file for a new message (when COMPOSE-TYPE is `reply', "Open a draft file for a message MSG.
`forward' or `new'), open an existing draft (when COMPOSE-TYPE In case of a new message (when COMPOSE-TYPE is `reply', `forward'
is `edit'), or re-send an existing message (when COMPOSE-TYPE is or `new'), open an existing draft (when COMPOSE-TYPE is `edit'),
`resend'). or re-send an existing message (when COMPOSE-TYPE is `resend').
The name of the draft folder is constructed from the The name of the draft folder is constructed from the
concatenation of `mu4e-maildir' and `mu4e-drafts-folder' (the concatenation of `mu4e-maildir' and `mu4e-drafts-folder' (the
@ -513,45 +515,45 @@ latter will be evaluated). The message file name is a unique name
determined by `mu4e-send-draft-file-name'. The initial contents determined by `mu4e-send-draft-file-name'. The initial contents
will be created from either `mu4e~draft-reply-construct', or will be created from either `mu4e~draft-reply-construct', or
`mu4e~draft-forward-construct' or `mu4e~draft-newmsg-construct'." `mu4e~draft-forward-construct' or `mu4e~draft-newmsg-construct'."
(unless mu4e-maildir (mu4e-error "mu4e-maildir not set")) (unless mu4e-maildir (mu4e-error "Variable mu4e-maildir not set"))
(let ((draft-dir nil)) (let ((draft-dir nil))
(cl-case compose-type (cl-case compose-type
(edit (edit
;; case-1: re-editing a draft messages. in this case, we do know the ;; case-1: re-editing a draft messages. in this case, we do know the
;; full path, but we cannot really know 'drafts folder'... we make a ;; full path, but we cannot really know 'drafts folder'... we make a
;; guess ;; guess
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path))) (setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
(mu4e~draft-open-file (mu4e-message-field msg :path))) (mu4e~draft-open-file (mu4e-message-field msg :path)))
(resend (resend
;; case-2: copy some exisisting message to a draft message, then edit ;; case-2: copy some exisisting message to a draft message, then edit
;; that. ;; that.
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path))) (setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
(let ((draft-path (mu4e~draft-determine-path draft-dir))) (let ((draft-path (mu4e~draft-determine-path draft-dir)))
(copy-file (mu4e-message-field msg :path) draft-path) (copy-file (mu4e-message-field msg :path) draft-path)
(mu4e~draft-open-file draft-path))) (mu4e~draft-open-file draft-path)))
((reply forward new) ((reply forward new)
;; case-3: creating a new message; in this case, we can determine ;; case-3: creating a new message; in this case, we can determine
;; mu4e-get-drafts-folder ;; mu4e-get-drafts-folder
(setq draft-dir (mu4e-get-drafts-folder msg)) (setq draft-dir (mu4e-get-drafts-folder msg))
(let ((draft-path (mu4e~draft-determine-path draft-dir)) (let ((draft-path (mu4e~draft-determine-path draft-dir))
(initial-contents (initial-contents
(cl-case compose-type (cl-case compose-type
(reply (mu4e~draft-reply-construct msg)) (reply (mu4e~draft-reply-construct msg))
(forward (mu4e~draft-forward-construct msg)) (forward (mu4e~draft-forward-construct msg))
(new (mu4e~draft-newmsg-construct))))) (new (mu4e~draft-newmsg-construct)))))
(mu4e~draft-open-file draft-path) (mu4e~draft-open-file draft-path)
(insert initial-contents) (insert initial-contents)
(newline) (newline)
;; include the message signature (if it's set) ;; include the message signature (if it's set)
(if (and mu4e-compose-signature-auto-include mu4e-compose-signature) (if (and mu4e-compose-signature-auto-include mu4e-compose-signature)
(let ((message-signature mu4e-compose-signature)) (let ((message-signature mu4e-compose-signature))
(save-excursion (save-excursion
(message-insert-signature) (message-insert-signature)
(mu4e~fontify-signature)))))) (mu4e~fontify-signature))))))
(t (mu4e-error "unsupported compose-type %S" compose-type))) (t (mu4e-error "Unsupported compose-type %S" compose-type)))
;; if we didn't find a draft folder yet, try some default ;; if we didn't find a draft folder yet, try some default
(unless draft-dir (unless draft-dir
(setq draft-dir (mu4e-get-drafts-folder msg))) (setq draft-dir (mu4e-get-drafts-folder msg)))
@ -560,7 +562,8 @@ will be created from either `mu4e~draft-reply-construct', or
(set (make-local-variable 'mu4e~draft-drafts-folder) draft-dir) (set (make-local-variable 'mu4e~draft-drafts-folder) draft-dir)
(put 'mu4e~draft-drafts-folder 'permanent-local t) (put 'mu4e~draft-drafts-folder 'permanent-local t)
(unless mu4e~draft-drafts-folder (unless mu4e~draft-drafts-folder
(mu4e-error "failed to determine drafts folder")))) (mu4e-error "Failed to determine drafts folder"))))
(provide 'mu4e-draft) (provide 'mu4e-draft)
;;; mu4e-draft.el ends here