mirror of https://github.com/djcb/mu.git
mu4e: Fix indentation
This commit is contained in:
parent
be1ba1ce68
commit
6790c0d015
|
@ -47,8 +47,8 @@
|
|||
"Count the number of lines in the e-mail MSG.
|
||||
Works for headers view and message-view."
|
||||
(message "Number of lines: %s"
|
||||
(shell-command-to-string
|
||||
(concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path))))))
|
||||
(shell-command-to-string
|
||||
(concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path))))))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
@ -66,12 +66,12 @@ Works for the message view."
|
|||
(unless (file-executable-p mu4e-msg2pdf)
|
||||
(mu4e-error "Program msg2pdf not found; please set `mu4e-msg2pdf'"))
|
||||
(let* ((pdf
|
||||
(shell-command-to-string
|
||||
(concat mu4e-msg2pdf " "
|
||||
(shell-quote-argument (mu4e-message-field msg :path))
|
||||
" 2> /dev/null")))
|
||||
(pdf (and pdf (> (length pdf) 5)
|
||||
(substring pdf 0 -1)))) ;; chop \n
|
||||
(shell-command-to-string
|
||||
(concat mu4e-msg2pdf " "
|
||||
(shell-quote-argument (mu4e-message-field msg :path))
|
||||
" 2> /dev/null")))
|
||||
(pdf (and pdf (> (length pdf) 5)
|
||||
(substring pdf 0 -1)))) ;; chop \n
|
||||
(unless (and pdf (file-exists-p pdf))
|
||||
(mu4e-warn "Failed to create PDF file"))
|
||||
(find-file pdf)))
|
||||
|
@ -100,22 +100,22 @@ Works for the message view."
|
|||
"Write MSG's body (either html or text) to a temporary file;
|
||||
return the filename."
|
||||
(let* ((html (mu4e-message-field msg :body-html))
|
||||
(txt (mu4e-message-field msg :body-txt))
|
||||
(tmpfile (mu4e-make-temp-file "html"))
|
||||
(attachments (cl-remove-if (lambda (part)
|
||||
(or (null (plist-get part :attachment))
|
||||
(null (plist-get part :cid))))
|
||||
(mu4e-message-field msg :parts))))
|
||||
(txt (mu4e-message-field msg :body-txt))
|
||||
(tmpfile (mu4e-make-temp-file "html"))
|
||||
(attachments (cl-remove-if (lambda (part)
|
||||
(or (null (plist-get part :attachment))
|
||||
(null (plist-get part :cid))))
|
||||
(mu4e-message-field msg :parts))))
|
||||
(unless (or html txt)
|
||||
(mu4e-error "No body part for this message"))
|
||||
(with-temp-buffer
|
||||
(insert "<head><meta charset=\"UTF-8\"></head>\n")
|
||||
(insert (concat "<p><strong>From</strong>: "
|
||||
(mu4e~action-header-to-html msg :from) "</br>"))
|
||||
(mu4e~action-header-to-html msg :from) "</br>"))
|
||||
(insert (concat "<strong>To</strong>: "
|
||||
(mu4e~action-header-to-html msg :to) "</br>"))
|
||||
(mu4e~action-header-to-html msg :to) "</br>"))
|
||||
(insert (concat "<strong>Date</strong>: "
|
||||
(format-time-string mu4e-view-date-format (mu4e-message-field msg :date)) "</br>"))
|
||||
(format-time-string mu4e-view-date-format (mu4e-message-field msg :date)) "</br>"))
|
||||
(insert (concat "<strong>Subject</strong>: " (mu4e-message-field msg :subject) "</p>"))
|
||||
(insert (or html (concat "<pre>" txt "</pre>")))
|
||||
(write-file tmpfile)
|
||||
|
@ -123,20 +123,20 @@ return the filename."
|
|||
(mapc (lambda (attachment)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward (format "src=\"cid:%s\""
|
||||
(plist-get attachment :cid)) nil t)
|
||||
(plist-get attachment :cid)) nil t)
|
||||
(if (plist-get attachment :temp)
|
||||
(replace-match (format "src=\"%s\""
|
||||
(plist-get attachment :temp)))
|
||||
(replace-match (format "src=\"%s\""
|
||||
(plist-get attachment :temp)))
|
||||
(replace-match (format "src=\"%s%s\"" temporary-file-directory
|
||||
(plist-get attachment :name)))
|
||||
(plist-get attachment :name)))
|
||||
(let ((tmp-attachment-name
|
||||
(format "%s%s" temporary-file-directory
|
||||
(plist-get attachment :name))))
|
||||
(format "%s%s" temporary-file-directory
|
||||
(plist-get attachment :name))))
|
||||
(mu4e~proc-extract 'save (mu4e-message-field msg :docid)
|
||||
(plist-get attachment :index)
|
||||
mu4e-decryption-policy tmp-attachment-name)
|
||||
(plist-get attachment :index)
|
||||
mu4e-decryption-policy tmp-attachment-name)
|
||||
(mu4e-remove-file-later tmp-attachment-name)))))
|
||||
attachments)
|
||||
attachments)
|
||||
(save-buffer)
|
||||
tmpfile)))
|
||||
|
||||
|
@ -146,7 +146,7 @@ You can influence the browser to use with the variable
|
|||
`browse-url-generic-program', and see the discussion of privacy
|
||||
aspects in `(mu4e) Displaying rich-text messages'."
|
||||
(browse-url (concat "file://"
|
||||
(mu4e~write-body-to-html msg))))
|
||||
(mu4e~write-body-to-html msg))))
|
||||
|
||||
(defun mu4e-action-view-with-xwidget (msg)
|
||||
"View the body of MSG inside xwidget-webkit.
|
||||
|
@ -155,7 +155,7 @@ privacy aspects in `(mu4e) Displaying rich-text messages'."
|
|||
(unless (fboundp 'xwidget-webkit-browse-url)
|
||||
(mu4e-error "No xwidget support available"))
|
||||
(xwidget-webkit-browse-url
|
||||
(concat "file://" (mu4e~write-body-to-html msg)) t))
|
||||
(concat "file://" (mu4e~write-body-to-html msg)) t))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
@ -172,7 +172,7 @@ privacy aspects in `(mu4e) Displaying rich-text messages'."
|
|||
(with-temp-buffer
|
||||
(insert (mu4e-message-field msg :body-txt))
|
||||
(shell-command-on-region (point-min) (point-max)
|
||||
mu4e-text2speech-command)))
|
||||
mu4e-text2speech-command)))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
@ -216,23 +216,23 @@ file where you store your org-contacts."
|
|||
(unless mu4e-org-contacts-file
|
||||
(mu4e-error "Variable `mu4e-org-contacts-file' is nil"))
|
||||
(let* ((sender (car-safe (mu4e-message-field msg :from)))
|
||||
(name (car-safe sender)) (email (cdr-safe sender))
|
||||
(blurb
|
||||
(format
|
||||
(concat
|
||||
"* %%?%s\n"
|
||||
":PROPERTIES:\n"
|
||||
":EMAIL: %s\n"
|
||||
":NICK:\n"
|
||||
":BIRTHDAY:\n"
|
||||
":END:\n\n")
|
||||
(or name email "")
|
||||
(or email "")))
|
||||
(key "mu4e-add-org-contact-key")
|
||||
(org-capture-templates
|
||||
(append org-capture-templates
|
||||
(list (list key "contacts" 'entry
|
||||
(list 'file mu4e-org-contacts-file) blurb)))))
|
||||
(name (car-safe sender)) (email (cdr-safe sender))
|
||||
(blurb
|
||||
(format
|
||||
(concat
|
||||
"* %%?%s\n"
|
||||
":PROPERTIES:\n"
|
||||
":EMAIL: %s\n"
|
||||
":NICK:\n"
|
||||
":BIRTHDAY:\n"
|
||||
":END:\n\n")
|
||||
(or name email "")
|
||||
(or email "")))
|
||||
(key "mu4e-add-org-contact-key")
|
||||
(org-capture-templates
|
||||
(append org-capture-templates
|
||||
(list (list key "contacts" 'entry
|
||||
(list 'file mu4e-org-contacts-file) blurb)))))
|
||||
(message "%S" org-capture-templates)
|
||||
(when (fboundp 'org-capture)
|
||||
(org-capture nil key))))
|
||||
|
@ -252,16 +252,16 @@ file where you store your org-contacts."
|
|||
(unless prompt
|
||||
(setq prompt "Target directory:"))
|
||||
(file-truename
|
||||
(completing-read prompt 'read-file-name-internal #'file-directory-p
|
||||
nil nil 'mu4e~patch-directory-history)))
|
||||
(completing-read prompt 'read-file-name-internal #'file-directory-p
|
||||
nil nil 'mu4e~patch-directory-history)))
|
||||
|
||||
(defun mu4e-action-git-apply-patch (msg)
|
||||
"Apply `MSG' as a git patch."
|
||||
(let ((path (mu4e~read-patch-directory "Target directory: ")))
|
||||
(let ((default-directory path))
|
||||
(shell-command
|
||||
(format "git apply %s"
|
||||
(shell-quote-argument (mu4e-message-field msg :path)))))))
|
||||
(format "git apply %s"
|
||||
(shell-quote-argument (mu4e-message-field msg :path)))))))
|
||||
|
||||
(defun mu4e-action-git-apply-mbox (msg &optional signoff)
|
||||
"Apply `MSG' a git patch with optional `SIGNOFF'.
|
||||
|
@ -270,15 +270,15 @@ If the `default-directory' matches the most recent history entry don't
|
|||
bother asking for the git tree again (useful for bulk actions)."
|
||||
|
||||
(let ((cwd (substring-no-properties
|
||||
(or (car mu4e~patch-directory-history)
|
||||
"not-a-dir"))))
|
||||
(or (car mu4e~patch-directory-history)
|
||||
"not-a-dir"))))
|
||||
(unless (and (stringp cwd) (string= default-directory cwd))
|
||||
(setq cwd (mu4e~read-patch-directory "Target directory: ")))
|
||||
(let ((default-directory cwd))
|
||||
(shell-command
|
||||
(format "git am %s %s"
|
||||
(if signoff "--signoff" "")
|
||||
(shell-quote-argument (mu4e-message-field msg :path)))))))
|
||||
(format "git am %s %s"
|
||||
(if signoff "--signoff" "")
|
||||
(shell-quote-argument (mu4e-message-field msg :path)))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -302,7 +302,7 @@ messages can lead to messages with multiple tags headers.")
|
|||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward regexp nil t)
|
||||
t
|
||||
t
|
||||
nil))))
|
||||
|
||||
(defun mu4e~replace-first-line-matching (regexp to-string path)
|
||||
|
@ -312,7 +312,7 @@ messages can lead to messages with multiple tags headers.")
|
|||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward regexp nil t)
|
||||
(replace-match to-string nil nil)))))
|
||||
(replace-match to-string nil nil)))))
|
||||
|
||||
(defun mu4e-action-retag-message (msg &optional retag-arg)
|
||||
"Change tags of MSG with RETAG-ARG.
|
||||
|
@ -322,33 +322,33 @@ RETAG-ARG is a comma-separated list of additions and removals.
|
|||
Example: +tag,+long tag,-oldtag
|
||||
would add 'tag' and 'long tag', and remove 'oldtag'."
|
||||
(let* (
|
||||
(path (mu4e-message-field msg :path))
|
||||
(oldtags (mu4e-message-field msg :tags))
|
||||
(tags-completion
|
||||
(append
|
||||
mu4e-action-tags-completion-list
|
||||
(mapcar (lambda (tag) (format "+%s" tag))
|
||||
mu4e-action-tags-completion-list)
|
||||
(mapcar (lambda (tag) (format "-%s" tag))
|
||||
oldtags)))
|
||||
(retag (if retag-arg
|
||||
(split-string retag-arg ",")
|
||||
(completing-read-multiple "Tags: " tags-completion)))
|
||||
(header mu4e-action-tags-header)
|
||||
(sep (cond ((string= header "Keywords") ", ")
|
||||
((string= header "X-Label") " ")
|
||||
((string= header "X-Keywords") ", ")
|
||||
(t ", ")))
|
||||
(taglist (if oldtags (copy-sequence oldtags) '()))
|
||||
tagstr)
|
||||
(path (mu4e-message-field msg :path))
|
||||
(oldtags (mu4e-message-field msg :tags))
|
||||
(tags-completion
|
||||
(append
|
||||
mu4e-action-tags-completion-list
|
||||
(mapcar (lambda (tag) (format "+%s" tag))
|
||||
mu4e-action-tags-completion-list)
|
||||
(mapcar (lambda (tag) (format "-%s" tag))
|
||||
oldtags)))
|
||||
(retag (if retag-arg
|
||||
(split-string retag-arg ",")
|
||||
(completing-read-multiple "Tags: " tags-completion)))
|
||||
(header mu4e-action-tags-header)
|
||||
(sep (cond ((string= header "Keywords") ", ")
|
||||
((string= header "X-Label") " ")
|
||||
((string= header "X-Keywords") ", ")
|
||||
(t ", ")))
|
||||
(taglist (if oldtags (copy-sequence oldtags) '()))
|
||||
tagstr)
|
||||
(dolist (tag retag taglist)
|
||||
(cond
|
||||
((string-match "^\\+\\(.+\\)" tag)
|
||||
(setq taglist (push (match-string 1 tag) taglist)))
|
||||
((string-match "^\\-\\(.+\\)" tag)
|
||||
(setq taglist (delete (match-string 1 tag) taglist)))
|
||||
(t
|
||||
(setq taglist (push tag taglist)))))
|
||||
((string-match "^\\+\\(.+\\)" tag)
|
||||
(setq taglist (push (match-string 1 tag) taglist)))
|
||||
((string-match "^\\-\\(.+\\)" tag)
|
||||
(setq taglist (delete (match-string 1 tag) taglist)))
|
||||
(t
|
||||
(setq taglist (push tag taglist)))))
|
||||
|
||||
(setq taglist (sort (delete-dups taglist) 'string<))
|
||||
(setq tagstr (mapconcat 'identity taglist sep))
|
||||
|
@ -357,15 +357,15 @@ would add 'tag' and 'long tag', and remove 'oldtag'."
|
|||
(setq tagstr (replace-regexp-in-string "[/]" "\\&" tagstr))
|
||||
|
||||
(if (not (mu4e~contains-line-matching (concat header ":.*") path))
|
||||
;; Add tags header just before the content
|
||||
(mu4e~replace-first-line-matching
|
||||
"^$" (concat header ": " tagstr "\n") path)
|
||||
;; Add tags header just before the content
|
||||
(mu4e~replace-first-line-matching
|
||||
"^$" (concat header ": " tagstr "\n") path)
|
||||
|
||||
;; replaces keywords, restricted to the header
|
||||
(mu4e~replace-first-line-matching
|
||||
(concat header ":.*")
|
||||
(concat header ": " tagstr)
|
||||
path))
|
||||
(concat header ":.*")
|
||||
(concat header ": " tagstr)
|
||||
path))
|
||||
|
||||
(mu4e-message (concat "tagging: " (mapconcat 'identity taglist ", ")))
|
||||
(mu4e-refresh-message path)))
|
||||
|
@ -378,12 +378,12 @@ the message."
|
|||
(let ((msgid (mu4e-message-field msg :message-id)))
|
||||
(when msgid
|
||||
(let ((mu4e-headers-show-threads t)
|
||||
(mu4e-headers-include-related t))
|
||||
(mu4e-headers-include-related t))
|
||||
(mu4e-headers-search
|
||||
(format "msgid:%s" msgid)
|
||||
nil nil nil
|
||||
msgid (and (eq major-mode 'mu4e-view-mode)
|
||||
(not (eq mu4e-split-view 'single-window))))))))
|
||||
(format "msgid:%s" msgid)
|
||||
nil nil nil
|
||||
msgid (and (eq major-mode 'mu4e-view-mode)
|
||||
(not (eq mu4e-split-view 'single-window))))))))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(provide 'mu4e-actions)
|
||||
|
|
|
@ -109,8 +109,8 @@ symbols, for example:
|
|||
The various `message-' functions from `message-mode' are available
|
||||
for querying the message information."
|
||||
:type '(choice (const :tag "move message to mu4e-sent-folder" sent)
|
||||
(const :tag "move message to mu4e-trash-folder" trash)
|
||||
(const :tag "delete message" delete))
|
||||
(const :tag "move message to mu4e-trash-folder" trash)
|
||||
(const :tag "delete message" delete))
|
||||
:group 'mu4e-compose)
|
||||
|
||||
(defcustom mu4e-compose-context-policy 'ask
|
||||
|
@ -129,11 +129,11 @@ contexts match, we have the following choices:
|
|||
|
||||
Also see `mu4e-context-policy'."
|
||||
:type '(choice
|
||||
(const :tag "Always ask what context to use" always-ask)
|
||||
(const :tag "Ask if none of the contexts match" ask)
|
||||
(const :tag "Ask when there's no context yet" ask-if-none)
|
||||
(const :tag "Pick the first context if none match" pick-first)
|
||||
(const :tag "Don't change the context when none match" nil))
|
||||
(const :tag "Always ask what context to use" always-ask)
|
||||
(const :tag "Ask if none of the contexts match" ask)
|
||||
(const :tag "Ask when there's no context yet" ask-if-none)
|
||||
(const :tag "Pick the first context if none match" pick-first)
|
||||
(const :tag "Don't change the context when none match" nil))
|
||||
:safe 'symbolp
|
||||
:group 'mu4e-compose)
|
||||
|
||||
|
@ -146,10 +146,10 @@ We have the following choices:
|
|||
- `encrypt': encrypt the reply, but don't sign it.
|
||||
- anything else: do nothing."
|
||||
:type '(choice
|
||||
(const :tag "Sign the reply" sign)
|
||||
(const :tag "Sign and encrypt the reply" sign-and-encrypt)
|
||||
(const :tag "Encrypt the reply" encrypt)
|
||||
(const :tag "Don't do anything" nil))
|
||||
(const :tag "Sign the reply" sign)
|
||||
(const :tag "Sign and encrypt the reply" sign-and-encrypt)
|
||||
(const :tag "Encrypt the reply" encrypt)
|
||||
(const :tag "Don't do anything" nil))
|
||||
:safe 'symbolp
|
||||
:group 'mu4e-compose)
|
||||
|
||||
|
@ -162,10 +162,10 @@ We have the following choices:
|
|||
- `encrypt': encrypt the reply, but don't sign it.
|
||||
- anything else: do nothing."
|
||||
:type '(choice
|
||||
(const :tag "Sign the reply" sign)
|
||||
(const :tag "Sign and encrypt the reply" sign-and-encrypt)
|
||||
(const :tag "Encrypt the reply" encrypt)
|
||||
(const :tag "Don't do anything" nil))
|
||||
(const :tag "Sign the reply" sign)
|
||||
(const :tag "Sign and encrypt the reply" sign-and-encrypt)
|
||||
(const :tag "Encrypt the reply" encrypt)
|
||||
(const :tag "Don't do anything" nil))
|
||||
:safe 'symbolp
|
||||
:group 'mu4e-compose)
|
||||
|
||||
|
@ -173,7 +173,7 @@ We have the following choices:
|
|||
'mu4e-compose-crypto-reply-policy' variable is deprecated.
|
||||
'mu4e-compose-crypto-reply-plain-policy' and
|
||||
'mu4e-compose-crypto-reply-encrypted-policy' should be used instead"
|
||||
"2017-09-02")
|
||||
"2017-09-02")
|
||||
|
||||
(defcustom mu4e-compose-format-flowed nil
|
||||
"Whether to compose messages to be sent as format=flowed.
|
||||
|
@ -211,10 +211,10 @@ This is a symbol, `new', `forward', `reply' or `edit'.")
|
|||
(unless (file-exists-p path)
|
||||
(mu4e-warn "Message file not found"))
|
||||
(mml-attach-file
|
||||
path
|
||||
"message/rfc822"
|
||||
(or (plist-get msg :subject) "No subject")
|
||||
"attachment")))
|
||||
path
|
||||
"message/rfc822"
|
||||
(or (plist-get msg :subject) "No subject")
|
||||
"attachment")))
|
||||
|
||||
(defun mu4e-compose-attach-captured-message ()
|
||||
"Insert the last captured message file as an attachment.
|
||||
|
@ -243,25 +243,25 @@ Messages are captured with `mu4e-action-capture-message'."
|
|||
"Maybe setup Fcc, based on `mu4e-sent-messages-behavior'.
|
||||
If needed, set the Fcc header, and register the handler function."
|
||||
(let* ((sent-behavior
|
||||
;; Note; we cannot simply use functionp here, since at least
|
||||
;; delete is a function, too...
|
||||
(if (member mu4e-sent-messages-behavior '(delete trash sent))
|
||||
mu4e-sent-messages-behavior
|
||||
(if (functionp mu4e-sent-messages-behavior)
|
||||
(funcall mu4e-sent-messages-behavior)
|
||||
mu4e-sent-messages-behavior)))
|
||||
(mdir
|
||||
(cl-case sent-behavior
|
||||
(delete nil)
|
||||
(trash (mu4e-get-trash-folder mu4e-compose-parent-message))
|
||||
(sent (mu4e-get-sent-folder mu4e-compose-parent-message))
|
||||
(otherwise
|
||||
(mu4e-error "Unsupported value '%S'
|
||||
;; Note; we cannot simply use functionp here, since at least
|
||||
;; delete is a function, too...
|
||||
(if (member mu4e-sent-messages-behavior '(delete trash sent))
|
||||
mu4e-sent-messages-behavior
|
||||
(if (functionp mu4e-sent-messages-behavior)
|
||||
(funcall mu4e-sent-messages-behavior)
|
||||
mu4e-sent-messages-behavior)))
|
||||
(mdir
|
||||
(cl-case sent-behavior
|
||||
(delete nil)
|
||||
(trash (mu4e-get-trash-folder mu4e-compose-parent-message))
|
||||
(sent (mu4e-get-sent-folder mu4e-compose-parent-message))
|
||||
(otherwise
|
||||
(mu4e-error "Unsupported value '%S'
|
||||
`mu4e-sent-messages-behavior'"
|
||||
mu4e-sent-messages-behavior))))
|
||||
(fccfile (and mdir
|
||||
(concat (mu4e-root-maildir) mdir "/cur/"
|
||||
(mu4e~draft-message-filename-construct "S")))))
|
||||
mu4e-sent-messages-behavior))))
|
||||
(fccfile (and mdir
|
||||
(concat (mu4e-root-maildir) mdir "/cur/"
|
||||
(mu4e~draft-message-filename-construct "S")))))
|
||||
;; if there's an fcc header, add it to the file
|
||||
(when fccfile
|
||||
(message-add-header (concat "Fcc: " fccfile "\n"))
|
||||
|
@ -269,22 +269,22 @@ If needed, set the Fcc header, and register the handler function."
|
|||
;; etc. if you run it after mu4e so, (hack hack) we reset it to the old
|
||||
;; handler after we've done our thing.
|
||||
(setq message-fcc-handler-function
|
||||
(let ((maildir mdir)
|
||||
(old-handler message-fcc-handler-function))
|
||||
(lambda (file)
|
||||
(setq message-fcc-handler-function old-handler) ;; reset the fcc handler
|
||||
(let ((mdir-path (concat (mu4e-root-maildir) maildir)))
|
||||
;; Create the full maildir structure for the sent folder if it doesn't exist.
|
||||
;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after
|
||||
;; `write-file`, the sent maildir ends up in the correct state.
|
||||
(unless (file-exists-p mdir-path)
|
||||
(mu4e~proc-mkdir mdir-path)))
|
||||
(write-file file) ;; writing maildirs files is easy
|
||||
(mu4e~proc-add file))))))) ;; update the database
|
||||
(let ((maildir mdir)
|
||||
(old-handler message-fcc-handler-function))
|
||||
(lambda (file)
|
||||
(setq message-fcc-handler-function old-handler) ;; reset the fcc handler
|
||||
(let ((mdir-path (concat (mu4e-root-maildir) maildir)))
|
||||
;; Create the full maildir structure for the sent folder if it doesn't exist.
|
||||
;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after
|
||||
;; `write-file`, the sent maildir ends up in the correct state.
|
||||
(unless (file-exists-p mdir-path)
|
||||
(mu4e~proc-mkdir mdir-path)))
|
||||
(write-file file) ;; writing maildirs files is easy
|
||||
(mu4e~proc-add file))))))) ;; update the database
|
||||
|
||||
(defvar mu4e-compose-hidden-headers
|
||||
`("^References:" "^Face:" "^X-Face:"
|
||||
"^X-Draft-From:" "^User-agent:")
|
||||
"^X-Draft-From:" "^User-agent:")
|
||||
"Hidden headers when composing.")
|
||||
|
||||
(defun mu4e~compose-hide-headers ()
|
||||
|
@ -301,25 +301,25 @@ Just after saving we restore it; thus, the separator should never
|
|||
appear on disk. Also update the Date and ensure we have a
|
||||
Message-ID."
|
||||
(add-hook 'before-save-hook
|
||||
(lambda()
|
||||
;; replace the date
|
||||
(save-excursion
|
||||
(message-remove-header "Date")
|
||||
(message-generate-headers '(Date Message-ID))
|
||||
(save-match-data
|
||||
(mu4e~draft-remove-mail-header-separator)))) nil t)
|
||||
(lambda()
|
||||
;; replace the date
|
||||
(save-excursion
|
||||
(message-remove-header "Date")
|
||||
(message-generate-headers '(Date Message-ID))
|
||||
(save-match-data
|
||||
(mu4e~draft-remove-mail-header-separator)))) nil t)
|
||||
(add-hook 'after-save-hook
|
||||
(lambda ()
|
||||
(save-match-data
|
||||
(mu4e~compose-set-friendly-buffer-name)
|
||||
(mu4e~draft-insert-mail-header-separator)
|
||||
;; hide some headers again
|
||||
(mu4e~compose-hide-headers)
|
||||
(widen)
|
||||
(set-buffer-modified-p nil)
|
||||
(mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max)))
|
||||
;; update the file on disk -- ie., without the separator
|
||||
(mu4e~proc-add (buffer-file-name)))) nil t))
|
||||
(lambda ()
|
||||
(save-match-data
|
||||
(mu4e~compose-set-friendly-buffer-name)
|
||||
(mu4e~draft-insert-mail-header-separator)
|
||||
;; hide some headers again
|
||||
(mu4e~compose-hide-headers)
|
||||
(widen)
|
||||
(set-buffer-modified-p nil)
|
||||
(mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max)))
|
||||
;; update the file on disk -- ie., without the separator
|
||||
(mu4e~proc-add (buffer-file-name)))) nil t))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; address completion; inspired by org-contacts.el and
|
||||
|
@ -327,37 +327,37 @@ Message-ID."
|
|||
(defun mu4e~compose-complete-handler (str pred action)
|
||||
"Complete address STR with predication PRED for ACTION."
|
||||
(cond
|
||||
((eq action nil)
|
||||
(try-completion str mu4e~contacts pred))
|
||||
((eq action t)
|
||||
(all-completions str mu4e~contacts pred))
|
||||
((eq action 'metadata)
|
||||
;; our contacts are already sorted - just need to tell the
|
||||
;; completion machinery not to try to undo that...
|
||||
'(metadata
|
||||
(display-sort-function . identity)
|
||||
(cycle-sort-function . identity)))))
|
||||
((eq action nil)
|
||||
(try-completion str mu4e~contacts pred))
|
||||
((eq action t)
|
||||
(all-completions str mu4e~contacts pred))
|
||||
((eq action 'metadata)
|
||||
;; our contacts are already sorted - just need to tell the
|
||||
;; completion machinery not to try to undo that...
|
||||
'(metadata
|
||||
(display-sort-function . identity)
|
||||
(cycle-sort-function . identity)))))
|
||||
|
||||
(defun mu4e~compose-complete-contact (&optional start)
|
||||
"Complete the text at START with a contact.
|
||||
Ie. either 'name <email>' or 'email')."
|
||||
(interactive)
|
||||
(let ((mail-abbrev-mode-regexp mu4e~compose-address-fields-regexp)
|
||||
(eoh ;; end-of-headers
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp mail-header-separator nil t))))
|
||||
(eoh ;; end-of-headers
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp mail-header-separator nil t))))
|
||||
;; try to complete only when we're in the headers area,
|
||||
;; looking at an address field.
|
||||
(when (and eoh (> eoh (point)) (mail-abbrev-in-expansion-header-p))
|
||||
(let* ((end (point))
|
||||
(start
|
||||
(or start
|
||||
(save-excursion
|
||||
(re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
|
||||
(goto-char (match-end 0))
|
||||
(point)))))
|
||||
(list start end 'mu4e~compose-complete-handler)))))
|
||||
(start
|
||||
(or start
|
||||
(save-excursion
|
||||
(re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
|
||||
(goto-char (match-end 0))
|
||||
(point)))))
|
||||
(list start end 'mu4e~compose-complete-handler)))))
|
||||
|
||||
(defun mu4e~compose-setup-completion ()
|
||||
"Set up auto-completion of addresses."
|
||||
|
@ -365,7 +365,7 @@ Ie. either 'name <email>' or 'email')."
|
|||
(set (make-local-variable 'completion-cycle-threshold) 7)
|
||||
(add-to-list (make-local-variable 'completion-styles) 'substring)
|
||||
(add-hook 'completion-at-point-functions
|
||||
'mu4e~compose-complete-contact nil t))
|
||||
'mu4e~compose-complete-contact nil t))
|
||||
|
||||
(defun mu4e~remove-refs-maybe ()
|
||||
"Remove References: if In-Reply-To: is missing.
|
||||
|
@ -379,12 +379,12 @@ removing the In-Reply-To header."
|
|||
"Keymap for \"*mu4e-compose*\" buffers.")
|
||||
(unless mu4e-compose-mode-map
|
||||
(setq mu4e-compose-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index)
|
||||
(define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index)
|
||||
(define-key map (kbd "C-c C-k") 'mu4e-message-kill-buffer)
|
||||
(define-key map (kbd "M-q") 'mu4e-fill-paragraph)
|
||||
map)))
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index)
|
||||
(define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index)
|
||||
(define-key map (kbd "C-c C-k") 'mu4e-message-kill-buffer)
|
||||
(define-key map (kbd "M-q") 'mu4e-fill-paragraph)
|
||||
map)))
|
||||
|
||||
(defun mu4e-fill-paragraph (&optional region)
|
||||
"Re-layout either the whole message or REGION.
|
||||
|
@ -395,11 +395,11 @@ set, this simply executes `fill-paragraph'."
|
|||
;; Inspired by https://www.emacswiki.org/emacs/UnfillParagraph
|
||||
(interactive (progn (barf-if-buffer-read-only) '(t)))
|
||||
(if mu4e-compose-format-flowed
|
||||
(let ((fill-column (point-max))
|
||||
(use-hard-newlines nil)); rfill "across" hard newlines
|
||||
(when (use-region-p)
|
||||
(delete-trailing-whitespace (region-beginning) (region-end)))
|
||||
(fill-paragraph nil region))
|
||||
(let ((fill-column (point-max))
|
||||
(use-hard-newlines nil)); rfill "across" hard newlines
|
||||
(when (use-region-p)
|
||||
(delete-trailing-whitespace (region-beginning) (region-end)))
|
||||
(fill-paragraph nil region))
|
||||
(when (use-region-p)
|
||||
(delete-trailing-whitespace (region-beginning) (region-end)))
|
||||
(fill-paragraph nil region)))
|
||||
|
@ -408,7 +408,7 @@ set, this simply executes `fill-paragraph'."
|
|||
(interactive)
|
||||
(setq use-hard-newlines (not use-hard-newlines))
|
||||
(if use-hard-newlines
|
||||
(turn-off-auto-fill)
|
||||
(turn-off-auto-fill)
|
||||
(turn-on-auto-fill)))
|
||||
|
||||
(defun mu4e~compose-remap-faces ()
|
||||
|
@ -417,23 +417,23 @@ Our parent `message-mode' uses font-locking for the compose
|
|||
buffers; lets remap its faces so it uses the ones for mu4e."
|
||||
;; normal headers
|
||||
(face-remap-add-relative 'message-header-name
|
||||
'((:inherit mu4e-header-key-face)))
|
||||
'((:inherit mu4e-header-key-face)))
|
||||
(face-remap-add-relative 'message-header-other
|
||||
'((:inherit mu4e-header-value-face)))
|
||||
'((:inherit mu4e-header-value-face)))
|
||||
;; special headers
|
||||
(face-remap-add-relative 'message-header-from
|
||||
'((:inherit mu4e-contact-face)))
|
||||
'((:inherit mu4e-contact-face)))
|
||||
(face-remap-add-relative 'message-header-to
|
||||
'((:inherit mu4e-contact-face)))
|
||||
'((:inherit mu4e-contact-face)))
|
||||
(face-remap-add-relative 'message-header-cc
|
||||
'((:inherit mu4e-contact-face)))
|
||||
'((:inherit mu4e-contact-face)))
|
||||
(face-remap-add-relative 'message-header-bcc
|
||||
'((:inherit mu4e-contact-face)))
|
||||
'((:inherit mu4e-contact-face)))
|
||||
(face-remap-add-relative 'message-header-subject
|
||||
'((:inherit mu4e-special-header-value-face)))
|
||||
'((:inherit mu4e-special-header-value-face)))
|
||||
;; citation
|
||||
(face-remap-add-relative 'message-cited-text
|
||||
'((:inherit mu4e-cited-1-face))))
|
||||
'((:inherit mu4e-cited-1-face))))
|
||||
|
||||
(define-derived-mode mu4e-compose-mode message-mode "mu4e:compose"
|
||||
"Major mode for the mu4e message composition, derived from `message-mode'.
|
||||
|
@ -465,68 +465,68 @@ buffers; lets remap its faces so it uses the ones for mu4e."
|
|||
;; offer completion for e-mail addresses
|
||||
(when mu4e-compose-complete-addresses
|
||||
(unless mu4e~contacts ;; work-around for https://github.com/djcb/mu/issues/1016
|
||||
(mu4e~request-contacts-maybe))
|
||||
(mu4e~request-contacts-maybe))
|
||||
(mu4e~compose-setup-completion))
|
||||
(if mu4e-compose-format-flowed
|
||||
(progn
|
||||
(turn-off-auto-fill)
|
||||
(setq truncate-lines nil
|
||||
word-wrap t
|
||||
mml-enable-flowed t
|
||||
use-hard-newlines t)
|
||||
(visual-line-mode t))
|
||||
(progn
|
||||
(turn-off-auto-fill)
|
||||
(setq truncate-lines nil
|
||||
word-wrap t
|
||||
mml-enable-flowed t
|
||||
use-hard-newlines t)
|
||||
(visual-line-mode t))
|
||||
(setq mml-enable-flowed nil))
|
||||
|
||||
(let ((keymap (lookup-key message-mode-map [menu-bar text])))
|
||||
(when keymap
|
||||
(define-key-after
|
||||
keymap
|
||||
[mu4e-hard-newlines]
|
||||
'(menu-item "Format=flowed" mu4e-toggle-use-hard-newlines
|
||||
:button (:toggle . use-hard-newlines)
|
||||
:help "Toggle format=flowed"
|
||||
:visible (eq major-mode 'mu4e-compose-mode)
|
||||
:enable mu4e-compose-format-flowed)
|
||||
'sep)
|
||||
(define-key-after
|
||||
keymap
|
||||
[mu4e-hard-newlines]
|
||||
'(menu-item "Format=flowed" mu4e-toggle-use-hard-newlines
|
||||
:button (:toggle . use-hard-newlines)
|
||||
:help "Toggle format=flowed"
|
||||
:visible (eq major-mode 'mu4e-compose-mode)
|
||||
:enable mu4e-compose-format-flowed)
|
||||
'sep)
|
||||
|
||||
(define-key-after
|
||||
keymap
|
||||
[mu4e-electric-quote-mode]
|
||||
'(menu-item "Electric quote" electric-quote-local-mode
|
||||
:button (:toggle . electric-quote-mode)
|
||||
:help "Toggle Electric quote mode"
|
||||
:visible (and (eq major-mode 'mu4e-compose-mode)
|
||||
(functionp 'electric-quote-local-mode)))
|
||||
'mu4e-hard-newlines)))
|
||||
(define-key-after
|
||||
keymap
|
||||
[mu4e-electric-quote-mode]
|
||||
'(menu-item "Electric quote" electric-quote-local-mode
|
||||
:button (:toggle . electric-quote-mode)
|
||||
:help "Toggle Electric quote mode"
|
||||
:visible (and (eq major-mode 'mu4e-compose-mode)
|
||||
(functionp 'electric-quote-local-mode)))
|
||||
'mu4e-hard-newlines)))
|
||||
|
||||
(when (lookup-key mml-mode-map [menu-bar Attachments])
|
||||
(define-key-after
|
||||
(lookup-key mml-mode-map [menu-bar Attachments])
|
||||
[mu4e-compose-attach-captured-message]
|
||||
'(menu-item "Attach captured message"
|
||||
mu4e-compose-attach-captured-message
|
||||
:help "Attach message captured in Headers View (with 'a c')"
|
||||
:visible (eq major-mode 'mu4e-compose-mode))
|
||||
(quote Attach\ External...)))
|
||||
(lookup-key mml-mode-map [menu-bar Attachments])
|
||||
[mu4e-compose-attach-captured-message]
|
||||
'(menu-item "Attach captured message"
|
||||
mu4e-compose-attach-captured-message
|
||||
:help "Attach message captured in Headers View (with 'a c')"
|
||||
:visible (eq major-mode 'mu4e-compose-mode))
|
||||
(quote Attach\ External...)))
|
||||
|
||||
;; setup the fcc-stuff, if needed
|
||||
(add-hook 'message-send-hook
|
||||
(lambda () ;; mu4e~compose-save-before-sending
|
||||
;; when in-reply-to was removed, remove references as well.
|
||||
(when (eq mu4e-compose-type 'reply)
|
||||
(mu4e~remove-refs-maybe))
|
||||
(when use-hard-newlines
|
||||
(mu4e-send-harden-newlines))
|
||||
;; for safety, always save the draft before sending
|
||||
(set-buffer-modified-p t)
|
||||
(save-buffer)
|
||||
(mu4e~compose-setup-fcc-maybe)
|
||||
(widen)) nil t)
|
||||
(lambda () ;; mu4e~compose-save-before-sending
|
||||
;; when in-reply-to was removed, remove references as well.
|
||||
(when (eq mu4e-compose-type 'reply)
|
||||
(mu4e~remove-refs-maybe))
|
||||
(when use-hard-newlines
|
||||
(mu4e-send-harden-newlines))
|
||||
;; for safety, always save the draft before sending
|
||||
(set-buffer-modified-p t)
|
||||
(save-buffer)
|
||||
(mu4e~compose-setup-fcc-maybe)
|
||||
(widen)) nil t)
|
||||
;; when the message has been sent.
|
||||
(add-hook 'message-sent-hook
|
||||
(lambda () ;; mu4e~compose-mark-after-sending
|
||||
(setq mu4e-sent-func 'mu4e-sent-handler)
|
||||
(mu4e~proc-sent (buffer-file-name))) nil t))
|
||||
(lambda () ;; mu4e~compose-mark-after-sending
|
||||
(setq mu4e-sent-func 'mu4e-sent-handler)
|
||||
(mu4e~proc-sent (buffer-file-name))) nil t))
|
||||
;; mark these two hooks as permanent-local, so they'll survive mode-changes
|
||||
;; (put 'mu4e~compose-save-before-sending 'permanent-local-hook t)
|
||||
(put 'mu4e~compose-mark-after-sending 'permanent-local-hook t))
|
||||
|
@ -544,17 +544,17 @@ buffers; lets remap its faces so it uses the ones for mu4e."
|
|||
(defun mu4e~compose-set-friendly-buffer-name (&optional compose-type)
|
||||
"Set some user-friendly buffer name based on the COMPOSE-TYPE."
|
||||
(let* ((subj (message-field-value "subject"))
|
||||
(subj (unless (and subj (string-match "^[:blank:]*$" subj)) subj))
|
||||
(str (or subj
|
||||
(cl-case compose-type
|
||||
(reply "*reply*")
|
||||
(forward "*forward*")
|
||||
(otherwise "*draft*")))))
|
||||
(subj (unless (and subj (string-match "^[:blank:]*$" subj)) subj))
|
||||
(str (or subj
|
||||
(cl-case compose-type
|
||||
(reply "*reply*")
|
||||
(forward "*forward*")
|
||||
(otherwise "*draft*")))))
|
||||
(rename-buffer (generate-new-buffer-name
|
||||
(truncate-string-to-width str
|
||||
mu4e~compose-buffer-max-name-length
|
||||
nil nil t)
|
||||
(buffer-name)))))
|
||||
(truncate-string-to-width str
|
||||
mu4e~compose-buffer-max-name-length
|
||||
nil nil t)
|
||||
(buffer-name)))))
|
||||
|
||||
(defun mu4e~compose-crypto-reply (parent compose-type)
|
||||
"Possibly encrypt or sign a message based on PARENT and COMPOSE-TYPE.
|
||||
|
@ -562,17 +562,17 @@ When composing a reply to an encrypted message, we can
|
|||
automatically encrypt that reply. When the message is unencrypted,
|
||||
we can decide what we want to do."
|
||||
(if (and (eq compose-type 'reply)
|
||||
(and parent (member 'encrypted (mu4e-message-field parent :flags))))
|
||||
(cl-case mu4e-compose-crypto-reply-encrypted-policy
|
||||
(sign (mml-secure-message-sign))
|
||||
(encrypt (mml-secure-message-encrypt))
|
||||
(sign-and-encrypt (mml-secure-message-sign-encrypt))
|
||||
(message "Do nothing"))
|
||||
(cl-case mu4e-compose-crypto-reply-plain-policy
|
||||
(sign (mml-secure-message-sign))
|
||||
(encrypt (mml-secure-message-encrypt))
|
||||
(sign-and-encrypt (mml-secure-message-sign-encrypt))
|
||||
(message "Do nothing")))
|
||||
(and parent (member 'encrypted (mu4e-message-field parent :flags))))
|
||||
(cl-case mu4e-compose-crypto-reply-encrypted-policy
|
||||
(sign (mml-secure-message-sign))
|
||||
(encrypt (mml-secure-message-encrypt))
|
||||
(sign-and-encrypt (mml-secure-message-sign-encrypt))
|
||||
(message "Do nothing"))
|
||||
(cl-case mu4e-compose-crypto-reply-plain-policy
|
||||
(sign (mml-secure-message-sign))
|
||||
(encrypt (mml-secure-message-encrypt))
|
||||
(sign-and-encrypt (mml-secure-message-sign-encrypt))
|
||||
(message "Do nothing")))
|
||||
)
|
||||
|
||||
|
||||
|
@ -599,21 +599,21 @@ tempfile)."
|
|||
;; message being forwarded or replied to, otherwise it is nil.
|
||||
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
|
||||
(put 'mu4e-compose-parent-message 'permanent-local t)
|
||||
;; remember the compose-type
|
||||
;; remember the compose-type
|
||||
(set (make-local-variable 'mu4e-compose-type) compose-type)
|
||||
(put 'mu4e-compose-type 'permanent-local t)
|
||||
;; maybe switch the context
|
||||
(mu4e~context-autoswitch mu4e-compose-parent-message
|
||||
mu4e-compose-context-policy)
|
||||
mu4e-compose-context-policy)
|
||||
(run-hooks 'mu4e-compose-pre-hook)
|
||||
|
||||
;; this opens (or re-opens) a messages with all the basic headers set.
|
||||
(let ((winconf (current-window-configuration)))
|
||||
(condition-case nil
|
||||
(mu4e-draft-open compose-type original-msg)
|
||||
(mu4e-draft-open compose-type original-msg)
|
||||
(quit (set-window-configuration winconf)
|
||||
(mu4e-message "Operation aborted")
|
||||
(cl-return-from mu4e~compose-handler))))
|
||||
(mu4e-message "Operation aborted")
|
||||
(cl-return-from mu4e~compose-handler))))
|
||||
;; insert mail-header-separator, which is needed by message mode to separate
|
||||
;; headers and body. will be removed before saving to disk
|
||||
(mu4e~draft-insert-mail-header-separator)
|
||||
|
@ -625,23 +625,23 @@ tempfile)."
|
|||
(goto-char (point-max)) ;; put attachments at the end
|
||||
|
||||
(if (and (eq compose-type 'forward) mu4e-compose-forward-as-attachment)
|
||||
(mu4e-compose-attach-message original-msg)
|
||||
(mu4e-compose-attach-message original-msg)
|
||||
(dolist (att includes)
|
||||
(mml-attach-file
|
||||
(plist-get att :file-name) (plist-get att :mime-type)))))
|
||||
(mml-attach-file
|
||||
(plist-get att :file-name) (plist-get att :mime-type)))))
|
||||
|
||||
(mu4e~compose-set-friendly-buffer-name compose-type)
|
||||
|
||||
;; now jump to some useful positions, and start writing that mail!
|
||||
(if (member compose-type '(new forward))
|
||||
(message-goto-to)
|
||||
(message-goto-to)
|
||||
;; otherwise, it depends...
|
||||
(cl-case message-cite-reply-position
|
||||
((above traditional)
|
||||
(message-goto-body))
|
||||
(message-goto-body))
|
||||
(t
|
||||
(when (message-goto-signature)
|
||||
(forward-line -2)))))
|
||||
(when (message-goto-signature)
|
||||
(forward-line -2)))))
|
||||
|
||||
;; bind to `mu4e-compose-parent-message' of compose buffer
|
||||
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
|
||||
|
@ -670,11 +670,11 @@ tempfile)."
|
|||
"Try to go back to some previous buffer, in the order view->headers->main."
|
||||
(unless (eq mu4e-split-view 'single-window)
|
||||
(if (buffer-live-p (mu4e-get-view-buffer))
|
||||
(switch-to-buffer (mu4e-get-view-buffer))
|
||||
(switch-to-buffer (mu4e-get-view-buffer))
|
||||
(if (buffer-live-p (mu4e-get-headers-buffer))
|
||||
(switch-to-buffer (mu4e-get-headers-buffer))
|
||||
;; if all else fails, back to the main view
|
||||
(when (fboundp 'mu4e) (mu4e))))))
|
||||
(switch-to-buffer (mu4e-get-headers-buffer))
|
||||
;; if all else fails, back to the main view
|
||||
(when (fboundp 'mu4e) (mu4e))))))
|
||||
|
||||
(defun mu4e-sent-handler (docid path)
|
||||
"Handler called with DOCID and PATH for the just-sent message.
|
||||
|
@ -687,9 +687,9 @@ appropriate flag at the message forwarded or replied-to."
|
|||
;; this seems a bit hamfisted...
|
||||
(dolist (buf (buffer-list))
|
||||
(when (and (buffer-file-name buf)
|
||||
(string= (buffer-file-name buf) path))
|
||||
(string= (buffer-file-name buf) path))
|
||||
(if message-kill-buffer-on-exit
|
||||
(kill-buffer buf))))
|
||||
(kill-buffer buf))))
|
||||
(mu4e~switch-back-to-mu4e-buffer)
|
||||
(mu4e-message "Message sent"))
|
||||
|
||||
|
@ -703,8 +703,8 @@ It restores mu4e window layout after killing the compose-buffer."
|
|||
(when (not (equal current-buffer (current-buffer)))
|
||||
;; Restore mu4e
|
||||
(if mu4e-compose-in-new-frame
|
||||
(delete-frame)
|
||||
(mu4e~switch-back-to-mu4e-buffer)))))
|
||||
(delete-frame)
|
||||
(mu4e~switch-back-to-mu4e-buffer)))))
|
||||
|
||||
(defun mu4e~compose-set-parent-flag (path)
|
||||
"Set flags for replied-t and forwarded for the message at PATH.
|
||||
|
@ -728,25 +728,25 @@ buffer."
|
|||
(let ((buf (find-file-noselect path)))
|
||||
(when buf
|
||||
(with-current-buffer buf
|
||||
(message-narrow-to-headers-or-head)
|
||||
(let ((in-reply-to (message-fetch-field "in-reply-to"))
|
||||
(forwarded-from)
|
||||
(references (message-fetch-field "references")))
|
||||
(unless in-reply-to
|
||||
(when references
|
||||
(with-temp-buffer ;; inspired by `message-shorten-references'.
|
||||
(insert references)
|
||||
(goto-char (point-min))
|
||||
(let ((refs))
|
||||
(while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
|
||||
(push (match-string 0) refs))
|
||||
;; the last will be the first
|
||||
(setq forwarded-from (cl-first refs))))))
|
||||
;; remove the <>
|
||||
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
|
||||
(mu4e~proc-move (match-string 1 in-reply-to) nil "+R-N"))
|
||||
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
|
||||
(mu4e~proc-move (match-string 1 forwarded-from) nil "+P-N")))))))
|
||||
(message-narrow-to-headers-or-head)
|
||||
(let ((in-reply-to (message-fetch-field "in-reply-to"))
|
||||
(forwarded-from)
|
||||
(references (message-fetch-field "references")))
|
||||
(unless in-reply-to
|
||||
(when references
|
||||
(with-temp-buffer ;; inspired by `message-shorten-references'.
|
||||
(insert references)
|
||||
(goto-char (point-min))
|
||||
(let ((refs))
|
||||
(while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
|
||||
(push (match-string 0) refs))
|
||||
;; the last will be the first
|
||||
(setq forwarded-from (cl-first refs))))))
|
||||
;; remove the <>
|
||||
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
|
||||
(mu4e~proc-move (match-string 1 in-reply-to) nil "+R-N"))
|
||||
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
|
||||
(mu4e~proc-move (match-string 1 forwarded-from) nil "+P-N")))))))
|
||||
|
||||
(defun mu4e-compose (compose-type)
|
||||
"Start composing a message of COMPOSE-TYPE.
|
||||
|
@ -760,31 +760,31 @@ Symbol `edit' is only allowed for draft messages."
|
|||
(unless (member compose-type '(reply forward edit resend new))
|
||||
(mu4e-error "Invalid compose type '%S'" compose-type))
|
||||
(when (and (eq compose-type 'edit)
|
||||
(not (member 'draft (mu4e-message-field msg :flags))))
|
||||
(not (member 'draft (mu4e-message-field msg :flags))))
|
||||
(mu4e-warn "Editing is only allowed for draft messages"))
|
||||
|
||||
;; 'new is special, since it takes no existing message as arg; therefore, we
|
||||
;; don't need to involve the backend, and call the handler *directly*
|
||||
(if (eq compose-type 'new)
|
||||
(mu4e~compose-handler 'new)
|
||||
(mu4e~compose-handler 'new)
|
||||
;; otherwise, we need the doc-id
|
||||
(let* ((docid (mu4e-message-field msg :docid))
|
||||
;; decrypt (or not), based on `mu4e-decryption-policy'.
|
||||
(decrypt
|
||||
(and (member 'encrypted (mu4e-message-field msg :flags))
|
||||
(if (eq mu4e-decryption-policy 'ask)
|
||||
(yes-or-no-p (mu4e-format "Decrypt message?"))
|
||||
mu4e-decryption-policy))))
|
||||
;; if there's a visible view window, select that before starting
|
||||
;; composing a new message, so that one will be replaced by the compose
|
||||
;; window. The 10-or-so line headers buffer is not a good place to write
|
||||
;; it...
|
||||
(unless (eq mu4e-split-view 'single-window)
|
||||
(let ((viewwin (get-buffer-window (mu4e-get-view-buffer))))
|
||||
(when (window-live-p viewwin)
|
||||
(select-window viewwin))))
|
||||
;; talk to the backend
|
||||
(mu4e~proc-compose compose-type decrypt docid)))))
|
||||
;; decrypt (or not), based on `mu4e-decryption-policy'.
|
||||
(decrypt
|
||||
(and (member 'encrypted (mu4e-message-field msg :flags))
|
||||
(if (eq mu4e-decryption-policy 'ask)
|
||||
(yes-or-no-p (mu4e-format "Decrypt message?"))
|
||||
mu4e-decryption-policy))))
|
||||
;; if there's a visible view window, select that before starting
|
||||
;; composing a new message, so that one will be replaced by the compose
|
||||
;; window. The 10-or-so line headers buffer is not a good place to write
|
||||
;; it...
|
||||
(unless (eq mu4e-split-view 'single-window)
|
||||
(let ((viewwin (get-buffer-window (mu4e-get-view-buffer))))
|
||||
(when (window-live-p viewwin)
|
||||
(select-window viewwin))))
|
||||
;; talk to the backend
|
||||
(mu4e~proc-compose compose-type decrypt docid)))))
|
||||
|
||||
(defun mu4e-compose-reply ()
|
||||
"Compose a reply for the message at point in the headers buffer."
|
||||
|
@ -820,7 +820,7 @@ draft message."
|
|||
|
||||
;;;###autoload
|
||||
(defun mu4e~compose-mail (&optional to subject other-headers _continue
|
||||
_switch-function yank-action _send-actions _return-action)
|
||||
_switch-function yank-action _send-actions _return-action)
|
||||
"This is mu4e's implementation of `compose-mail'.
|
||||
Quoting its docstring:
|
||||
Start composing a mail message to send.
|
||||
|
@ -874,14 +874,14 @@ buffer buried."
|
|||
|
||||
;; yank message
|
||||
(if (bufferp yank-action)
|
||||
(list 'insert-buffer yank-action)
|
||||
(list 'insert-buffer yank-action)
|
||||
yank-action)
|
||||
|
||||
;; try to put the user at some reasonable spot...
|
||||
(if (not to)
|
||||
(message-goto-to)
|
||||
(message-goto-to)
|
||||
(if (not subject)
|
||||
(message-goto-subject)
|
||||
(message-goto-subject)
|
||||
(message-goto-body))))
|
||||
|
||||
;; happily, we can re-use most things from message mode
|
||||
|
@ -933,7 +933,7 @@ is supplied, or Transient Mark mode is enabled and the mark is active."
|
|||
(region-active-p)
|
||||
(push-mark))
|
||||
(let ((old-position (point))
|
||||
(message-position (save-excursion (message-goto-body) (point))))
|
||||
(message-position (save-excursion (message-goto-body) (point))))
|
||||
(goto-char (point-max))
|
||||
(when (re-search-backward message-signature-separator message-position t)
|
||||
(forward-line -1))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
||||
;;; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
||||
;;
|
||||
;; Copyright (C) 2015-2020 Dirk-Jan C. Binnema
|
||||
|
||||
|
@ -49,16 +49,16 @@ none."
|
|||
(let ((ctx mu4e~context-current))
|
||||
(when output
|
||||
(mu4e-message "Current context: %s"
|
||||
(if ctx (mu4e-context-name ctx) "<none>")))
|
||||
(if ctx (mu4e-context-name ctx) "<none>")))
|
||||
ctx))
|
||||
|
||||
(defun mu4e-context-label ()
|
||||
"Propertized string with the current context name, or \"\" if
|
||||
there is none."
|
||||
(if (mu4e-context-current)
|
||||
(concat "[" (propertize (mu4e~quote-for-modeline
|
||||
(mu4e-context-name (mu4e-context-current)))
|
||||
'face 'mu4e-context-face) "]") ""))
|
||||
(concat "[" (propertize (mu4e~quote-for-modeline
|
||||
(mu4e-context-name (mu4e-context-current)))
|
||||
'face 'mu4e-context-face) "]") ""))
|
||||
|
||||
(cl-defstruct mu4e-context
|
||||
"A mu4e context object with the following members:
|
||||
|
@ -194,9 +194,9 @@ default folders (see `make-mu4e-context' and `mu4e-context'):
|
|||
"Let user choose some context based on its name."
|
||||
(when mu4e-contexts
|
||||
(let* ((names (cl-map 'list (lambda (context)
|
||||
(cons (mu4e-context-name context) context))
|
||||
mu4e-contexts))
|
||||
(context (mu4e-read-option prompt names)))
|
||||
(cons (mu4e-context-name context) context))
|
||||
mu4e-contexts))
|
||||
(context (mu4e-read-option prompt names)))
|
||||
(or context (mu4e-error "No such context")))))
|
||||
|
||||
(defun mu4e-context-switch (&optional force name)
|
||||
|
@ -210,25 +210,25 @@ non-nil."
|
|||
(unless mu4e-contexts
|
||||
(mu4e-error "No contexts defined"))
|
||||
(let* ((names (cl-map 'list (lambda (context)
|
||||
(cons (mu4e-context-name context) context))
|
||||
mu4e-contexts))
|
||||
(context
|
||||
(if name
|
||||
(cdr-safe (assoc name names))
|
||||
(mu4e~context-ask-user "Switch to context: "))))
|
||||
(cons (mu4e-context-name context) context))
|
||||
mu4e-contexts))
|
||||
(context
|
||||
(if name
|
||||
(cdr-safe (assoc name names))
|
||||
(mu4e~context-ask-user "Switch to context: "))))
|
||||
(unless context (mu4e-error "No such context"))
|
||||
;; if new context is same as old one one switch with FORCE is set.
|
||||
(when (or force (not (eq context (mu4e-context-current))))
|
||||
(when (and (mu4e-context-current)
|
||||
(mu4e-context-leave-func mu4e~context-current))
|
||||
(funcall (mu4e-context-leave-func mu4e~context-current)))
|
||||
(mu4e-context-leave-func mu4e~context-current))
|
||||
(funcall (mu4e-context-leave-func mu4e~context-current)))
|
||||
;; enter the new context
|
||||
(when (mu4e-context-enter-func context)
|
||||
(funcall (mu4e-context-enter-func context)))
|
||||
(funcall (mu4e-context-enter-func context)))
|
||||
(when (mu4e-context-vars context)
|
||||
(mapc (lambda (cell)
|
||||
(set (car cell) (cdr cell)))
|
||||
(mu4e-context-vars context)))
|
||||
(mapc (lambda (cell)
|
||||
(set (car cell) (cdr cell)))
|
||||
(mu4e-context-vars context)))
|
||||
(setq mu4e~context-current context)
|
||||
|
||||
(run-hooks 'mu4e-context-changed-hook)
|
||||
|
@ -242,7 +242,7 @@ match, return the first. For MSG and POLICY, see `mu4e-context-determine'."
|
|||
(when (and mu4e-contexts (not mu4e~context-current))
|
||||
(let ((context (mu4e-context-determine msg policy)))
|
||||
(when context (mu4e-context-switch
|
||||
nil (mu4e-context-name context))))))
|
||||
nil (mu4e-context-name context))))))
|
||||
|
||||
(defun mu4e-context-determine (msg &optional policy)
|
||||
"Return the first context with a match-func that returns t. MSG
|
||||
|
@ -263,18 +263,18 @@ match, POLICY determines what to do:
|
|||
- otherwise, return nil. Effectively, this leaves the current context as it is."
|
||||
(when mu4e-contexts
|
||||
(if (eq policy 'always-ask)
|
||||
(mu4e~context-ask-user "Select context: ")
|
||||
(mu4e~context-ask-user "Select context: ")
|
||||
(or ;; is there a matching one?
|
||||
(cl-find-if (lambda (context)
|
||||
(when (mu4e-context-match-func context)
|
||||
(funcall (mu4e-context-match-func context) msg)))
|
||||
mu4e-contexts)
|
||||
;; no context found yet; consult policy
|
||||
(cl-case policy
|
||||
(pick-first (car mu4e-contexts))
|
||||
(ask (mu4e~context-ask-user "Select context: "))
|
||||
(ask-if-none (or (mu4e-context-current)
|
||||
(mu4e~context-ask-user "Select context: ")))
|
||||
(otherwise nil))))))
|
||||
(cl-find-if (lambda (context)
|
||||
(when (mu4e-context-match-func context)
|
||||
(funcall (mu4e-context-match-func context) msg)))
|
||||
mu4e-contexts)
|
||||
;; no context found yet; consult policy
|
||||
(cl-case policy
|
||||
(pick-first (car mu4e-contexts))
|
||||
(ask (mu4e~context-ask-user "Select context: "))
|
||||
(ask-if-none (or (mu4e-context-current)
|
||||
(mu4e~context-ask-user "Select context: ")))
|
||||
(otherwise nil))))))
|
||||
|
||||
(provide 'mu4e-context)
|
||||
|
|
|
@ -61,13 +61,13 @@
|
|||
;; Probably this can be moved to mu4e-view.el.
|
||||
(add-hook 'mu4e-view-mode-hook
|
||||
(lambda ()
|
||||
(set (make-local-variable 'bookmark-make-record-function)
|
||||
'mu4e-view-bookmark-make-record)))
|
||||
(set (make-local-variable 'bookmark-make-record-function)
|
||||
'mu4e-view-bookmark-make-record)))
|
||||
;; And this can be moved to mu4e-headers.el.
|
||||
(add-hook 'mu4e-headers-mode-hook
|
||||
(lambda ()
|
||||
(set (make-local-variable 'bookmark-make-record-function)
|
||||
'mu4e-view-bookmark-make-record)))
|
||||
(set (make-local-variable 'bookmark-make-record-function)
|
||||
'mu4e-view-bookmark-make-record)))
|
||||
|
||||
(defun mu4e-view-bookmark-make-record ()
|
||||
"Make a bookmark entry for a mu4e buffer. Note that this is an
|
||||
|
@ -81,9 +81,9 @@ emacs bookmark, not to be confused with `mu4e-bookmarks'."
|
|||
(subject (or (plist-get msg :subject) "No subject")))
|
||||
`(,subject
|
||||
,@(bookmark-make-record-default 'no-file 'no-context)
|
||||
(location . (,query . ,docid))
|
||||
(mode . ,mode)
|
||||
(handler . mu4e-bookmark-jump))))
|
||||
(location . (,query . ,docid))
|
||||
(mode . ,mode)
|
||||
(handler . mu4e-bookmark-jump))))
|
||||
|
||||
(defun mu4e-bookmark-jump (bookmark)
|
||||
"Handler function for record returned by `mu4e-view-bookmark-make-record'.
|
||||
|
@ -102,8 +102,8 @@ BOOKMARK is a bookmark name or a bookmark record."
|
|||
(run-with-timer 0.1 nil
|
||||
(lambda (bmk)
|
||||
(bookmark-default-handler
|
||||
`("" (buffer . ,(current-buffer)) .
|
||||
,(bookmark-get-bookmark-record bmk))))
|
||||
`("" (buffer . ,(current-buffer)) .
|
||||
,(bookmark-get-bookmark-record bmk))))
|
||||
bookmark))))
|
||||
|
||||
|
||||
|
@ -132,7 +132,7 @@ For example for bogofile, use \"/usr/bin/bogofilter -Sn < %s\"")
|
|||
(let* ((path (shell-quote-argument (mu4e-message-field msg :path)))
|
||||
(command (format mu4e-register-as-spam-cmd path))) ;; re-register msg as spam
|
||||
(shell-command command))
|
||||
(mu4e-mark-at-point 'delete nil))
|
||||
(mu4e-mark-at-point 'delete nil))
|
||||
|
||||
(defun mu4e-register-msg-as-ham (msg)
|
||||
"Mark message as ham."
|
||||
|
@ -140,7 +140,7 @@ For example for bogofile, use \"/usr/bin/bogofilter -Sn < %s\"")
|
|||
(let* ((path (shell-quote-argument(mu4e-message-field msg :path)))
|
||||
(command (format mu4e-register-as-ham-cmd path))) ;; re-register msg as ham
|
||||
(shell-command command))
|
||||
(mu4e-mark-at-point 'something nil))
|
||||
(mu4e-mark-at-point 'something nil))
|
||||
|
||||
;; (add-to-list 'mu4e-view-actions
|
||||
;; '("sMark as spam" . mu4e-view-register-msg-as-spam) t)
|
||||
|
@ -178,8 +178,8 @@ buffers found, compose a new message and then attach the file."
|
|||
(files-to-attach
|
||||
(delq nil (mapcar
|
||||
(lambda (f) (if (or (not (file-exists-p f)) (file-directory-p f))
|
||||
nil
|
||||
(expand-file-name f)))
|
||||
nil
|
||||
(expand-file-name f)))
|
||||
(eshell-flatten-list (reverse args))))))
|
||||
;; warn if user tries to attach without any files marked
|
||||
(if (null files-to-attach)
|
||||
|
@ -205,7 +205,7 @@ buffers found, compose a new message and then attach the file."
|
|||
;; if buffer was found, set buffer to destination buffer, and attach files
|
||||
(if (not (eq destination 'nil))
|
||||
(progn (set-buffer destination)
|
||||
(goto-char (point-max)) ;attach at end of buffer
|
||||
(goto-char (point-max)) ; attach at end of buffer
|
||||
(while files-to-attach
|
||||
(mml-attach-file (car files-to-attach)
|
||||
(or (mm-default-file-encoding (car files-to-attach))
|
||||
|
|
|
@ -56,9 +56,9 @@ This is the mu4e-specific version of
|
|||
\(i.e. the blob at the bottom of messages). This is the
|
||||
mu4e-specific version of `message-signature'."
|
||||
:type '(choice string
|
||||
(const :tag "None" nil)
|
||||
(const :tag "Contents of signature file" t)
|
||||
function sexp)
|
||||
(const :tag "None" nil)
|
||||
(const :tag "Contents of signature file" t)
|
||||
function sexp)
|
||||
:risky t
|
||||
:group 'mu4e-compose)
|
||||
|
||||
|
@ -68,7 +68,7 @@ mu4e-specific version of `message-signature'."
|
|||
:group 'mu4e-compose)
|
||||
|
||||
(make-obsolete-variable 'mu4e-compose-auto-include-date
|
||||
"This is done unconditionally now" "1.3.5")
|
||||
"This is done unconditionally now" "1.3.5")
|
||||
|
||||
(defcustom mu4e-compose-in-new-frame nil
|
||||
"Whether to compose messages in a new frame."
|
||||
|
@ -95,7 +95,7 @@ its settings apply."
|
|||
;; set the the signature separator to 'loose', since in the real world,
|
||||
;; many message don't follow the standard...
|
||||
(let ((message-signature-separator "^-- *$")
|
||||
(message-signature-insert-empty-line t))
|
||||
(message-signature-insert-empty-line t))
|
||||
(funcall mu4e-compose-cite-function))
|
||||
(pop-mark)
|
||||
(goto-char (point-min))
|
||||
|
@ -107,8 +107,8 @@ If VAL is nil, return nil."
|
|||
;; note: the propertize here is currently useless, since gnus sets its own
|
||||
;; later.
|
||||
(when val (format "%s: %s\n"
|
||||
(propertize hdr 'face 'mu4e-header-key-face)
|
||||
(propertize val 'face 'mu4e-header-value-face))))
|
||||
(propertize hdr 'face 'mu4e-header-key-face)
|
||||
(propertize val 'face 'mu4e-header-value-face))))
|
||||
|
||||
(defconst mu4e~max-reference-num 21
|
||||
"Specifies the maximum number of References:.
|
||||
|
@ -119,7 +119,7 @@ As suggested by `message-shorten-references'.")
|
|||
Beginning with CUTth
|
||||
one. Code borrowed from `message-shorten-1'."
|
||||
(setcdr (nthcdr (- cut 2) list)
|
||||
(nthcdr (+ (- cut 2) surplus 1) list)))
|
||||
(nthcdr (+ (- cut 2) surplus 1) list)))
|
||||
|
||||
(defun mu4e~draft-references-construct (msg)
|
||||
"Construct the value of the References: header based on MSG.
|
||||
|
@ -129,15 +129,15 @@ that :references includes the old in-reply-to as well) and the
|
|||
message-id. If the message-id is empty, returns the old
|
||||
References. If both are empty, return nil."
|
||||
(let* ( ;; these are the ones from the message being replied to / forwarded
|
||||
(refs (mu4e-message-field msg :references))
|
||||
(msgid (mu4e-message-field msg :message-id))
|
||||
;; now, append in
|
||||
(refs (if (and msgid (not (string= msgid "")))
|
||||
(append refs (list msgid)) refs))
|
||||
;; no doubles
|
||||
(refs (cl-delete-duplicates refs :test #'equal))
|
||||
(refnum (length refs))
|
||||
(cut 2))
|
||||
(refs (mu4e-message-field msg :references))
|
||||
(msgid (mu4e-message-field msg :message-id))
|
||||
;; now, append in
|
||||
(refs (if (and msgid (not (string= msgid "")))
|
||||
(append refs (list msgid)) refs))
|
||||
;; no doubles
|
||||
(refs (cl-delete-duplicates refs :test #'equal))
|
||||
(refnum (length refs))
|
||||
(cut 2))
|
||||
;; remove some refs when there are too many
|
||||
(when (> refnum mu4e~max-reference-num)
|
||||
(let ((surplus (- refnum mu4e~max-reference-num)))
|
||||
|
@ -154,13 +154,13 @@ 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 (addrcell)
|
||||
(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)
|
||||
"Return t if CELL1 and CELL2 have the same e-mail address.
|
||||
|
@ -168,8 +168,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 (cdr cell1) ""))
|
||||
(downcase (or (cdr cell2) ""))))
|
||||
|
||||
|
||||
(defun mu4e~draft-create-to-lst (origmsg)
|
||||
|
@ -180,16 +180,16 @@ whatever was in the To: field before, goes to the Cc:-list (if
|
|||
we're doing a reply-to-all). Special case: if we were the sender
|
||||
of the original, we simple copy the list form the original."
|
||||
(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)
|
||||
(if mu4e-compose-dont-reply-to-self
|
||||
(cl-delete-if
|
||||
(lambda (to-cell)
|
||||
(cl-member-if
|
||||
(cl-delete-if
|
||||
(lambda (to-cell)
|
||||
(cl-member-if
|
||||
(lambda (addr)
|
||||
(string= (downcase addr) (downcase (cdr to-cell))))
|
||||
(mu4e-personal-addresses)))
|
||||
reply-to)
|
||||
reply-to)
|
||||
reply-to)))
|
||||
|
||||
|
||||
|
@ -198,24 +198,24 @@ of the original, we simple copy the list form the original."
|
|||
I.e. return all the addresses in ADDRS not matching
|
||||
`mu4e-compose-reply-ignore-address'."
|
||||
(cond
|
||||
((null mu4e-compose-reply-ignore-address)
|
||||
addrs)
|
||||
((functionp mu4e-compose-reply-ignore-address)
|
||||
((null mu4e-compose-reply-ignore-address)
|
||||
addrs)
|
||||
((functionp mu4e-compose-reply-ignore-address)
|
||||
(cl-remove-if
|
||||
(lambda (elt)
|
||||
(funcall mu4e-compose-reply-ignore-address (cdr elt)))
|
||||
addrs))
|
||||
(t
|
||||
;; regexp or list of regexps
|
||||
(let* ((regexp mu4e-compose-reply-ignore-address)
|
||||
(regexp (if (listp regexp)
|
||||
(mapconcat (lambda (elt) (concat "\\(" elt "\\)"))
|
||||
regexp "\\|")
|
||||
regexp)))
|
||||
(cl-remove-if
|
||||
(lambda (elt)
|
||||
(funcall mu4e-compose-reply-ignore-address (cdr elt)))
|
||||
addrs))
|
||||
(t
|
||||
;; regexp or list of regexps
|
||||
(let* ((regexp mu4e-compose-reply-ignore-address)
|
||||
(regexp (if (listp regexp)
|
||||
(mapconcat (lambda (elt) (concat "\\(" elt "\\)"))
|
||||
regexp "\\|")
|
||||
regexp)))
|
||||
(cl-remove-if
|
||||
(lambda (elt)
|
||||
(string-match regexp (cdr elt)))
|
||||
addrs)))))
|
||||
(lambda (elt)
|
||||
(string-match regexp (cdr elt)))
|
||||
addrs)))))
|
||||
|
||||
(defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from)
|
||||
"Create a list of address for the Cc: in a new message.
|
||||
|
@ -223,37 +223,37 @@ This is based on the original message ORIGMSG, and whether it's a
|
|||
REPLY-ALL."
|
||||
(when reply-all
|
||||
(let* ((cc-lst ;; get the cc-field from the original, remove dups
|
||||
(cl-delete-duplicates
|
||||
(append
|
||||
(plist-get origmsg :to)
|
||||
(plist-get origmsg :cc)
|
||||
(when include-from(plist-get origmsg :from))
|
||||
(plist-get origmsg :list-post))
|
||||
:test #'mu4e~draft-address-cell-equal))
|
||||
;; now we have the basic list, but we must remove
|
||||
;; addresses also in the To: list
|
||||
(cc-lst
|
||||
(cl-delete-if
|
||||
(lambda (cc-cell)
|
||||
(cl-find-if
|
||||
(lambda (to-cell)
|
||||
(mu4e~draft-address-cell-equal cc-cell to-cell))
|
||||
(mu4e~draft-create-to-lst origmsg)))
|
||||
cc-lst))
|
||||
;; remove ignored addresses
|
||||
(cc-lst (mu4e~strip-ignored-addresses cc-lst))
|
||||
;; finally, we need to remove ourselves from the cc-list
|
||||
;; unless mu4e-compose-keep-self-cc is non-nil
|
||||
(cc-lst
|
||||
(if (or mu4e-compose-keep-self-cc (null user-mail-address))
|
||||
(cl-delete-duplicates
|
||||
(append
|
||||
(plist-get origmsg :to)
|
||||
(plist-get origmsg :cc)
|
||||
(when include-from(plist-get origmsg :from))
|
||||
(plist-get origmsg :list-post))
|
||||
:test #'mu4e~draft-address-cell-equal))
|
||||
;; now we have the basic list, but we must remove
|
||||
;; addresses also in the To: list
|
||||
(cc-lst
|
||||
(cl-delete-if
|
||||
(lambda (cc-cell)
|
||||
(cl-find-if
|
||||
(lambda (to-cell)
|
||||
(mu4e~draft-address-cell-equal cc-cell to-cell))
|
||||
(mu4e~draft-create-to-lst origmsg)))
|
||||
cc-lst))
|
||||
;; remove ignored addresses
|
||||
(cc-lst (mu4e~strip-ignored-addresses cc-lst))
|
||||
;; finally, we need to remove ourselves from the cc-list
|
||||
;; unless mu4e-compose-keep-self-cc is non-nil
|
||||
(cc-lst
|
||||
(if (or mu4e-compose-keep-self-cc (null user-mail-address))
|
||||
cc-lst
|
||||
(cl-delete-if
|
||||
(lambda (cc-cell)
|
||||
(cl-member-if
|
||||
(lambda (addr)
|
||||
(string= (downcase addr) (downcase (cdr cc-cell))))
|
||||
(mu4e-personal-addresses)))
|
||||
cc-lst))))
|
||||
(cl-delete-if
|
||||
(lambda (cc-cell)
|
||||
(cl-member-if
|
||||
(lambda (addr)
|
||||
(string= (downcase addr) (downcase (cdr cc-cell))))
|
||||
(mu4e-personal-addresses)))
|
||||
cc-lst))))
|
||||
cc-lst)))
|
||||
|
||||
(defun mu4e~draft-recipients-construct (field origmsg &optional reply-all include-from)
|
||||
|
@ -262,13 +262,13 @@ REPLY-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."
|
||||
(mu4e~draft-recipients-list-to-string
|
||||
(cl-case field
|
||||
(:to
|
||||
(mu4e~draft-create-to-lst origmsg))
|
||||
(:cc
|
||||
(mu4e~draft-create-cc-lst origmsg reply-all include-from))
|
||||
(otherwise
|
||||
(mu4e-error "Unsupported field")))))
|
||||
(cl-case field
|
||||
(:to
|
||||
(mu4e~draft-create-to-lst origmsg))
|
||||
(:cc
|
||||
(mu4e~draft-create-cc-lst origmsg reply-all include-from))
|
||||
(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
|
||||
|
@ -284,14 +284,14 @@ 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)
|
||||
((= (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)))
|
||||
'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.
|
||||
|
@ -299,12 +299,12 @@ 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)))))
|
||||
((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 ()
|
||||
|
@ -313,7 +313,7 @@ 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 <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address)
|
||||
(format "%s" user-mail-address))))
|
||||
|
||||
|
||||
|
@ -333,23 +333,23 @@ separator is never written to the message file. Also see
|
|||
;; 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)))
|
||||
'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
|
||||
(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))))))
|
||||
|
@ -372,15 +372,15 @@ never hits the disk. Also see
|
|||
"Ask user whether she wants to reply to *all* recipients.
|
||||
If there is just one recipient of ORIGMSG do nothing."
|
||||
(let* ((recipnum
|
||||
(+ (length (mu4e~draft-create-to-lst origmsg))
|
||||
(+ (length (mu4e~draft-create-to-lst origmsg))
|
||||
(length (mu4e~draft-create-cc-lst origmsg t))))
|
||||
(response
|
||||
(if (< recipnum 2)
|
||||
(response
|
||||
(if (< recipnum 2)
|
||||
'all ;; with less than 2 recipients, we can reply to 'all'
|
||||
(mu4e-read-option
|
||||
"Reply to "
|
||||
`( (,(format "all %d recipients" recipnum) . all)
|
||||
("sender only" . sender-only))))))
|
||||
(mu4e-read-option
|
||||
"Reply to "
|
||||
`( (,(format "all %d recipients" recipnum) . all)
|
||||
("sender only" . sender-only))))))
|
||||
(eq response 'all)))
|
||||
|
||||
(defun mu4e~draft-message-filename-construct (&optional flagstr)
|
||||
|
@ -389,25 +389,25 @@ It looks something like
|
|||
<time>-<random>.<hostname>:2,
|
||||
You can append flags."
|
||||
(let* ((sysname (if (fboundp 'system-name)
|
||||
(system-name)
|
||||
(system-name)
|
||||
(with-no-warnings system-name)))
|
||||
(sysname (if (string= sysname "") "localhost" sysname))
|
||||
(hostname (downcase
|
||||
(save-match-data
|
||||
(substring sysname
|
||||
(string-match "^[^.]+" sysname)
|
||||
(match-end 0))))))
|
||||
(sysname (if (string= sysname "") "localhost" sysname))
|
||||
(hostname (downcase
|
||||
(save-match-data
|
||||
(substring sysname
|
||||
(string-match "^[^.]+" sysname)
|
||||
(match-end 0))))))
|
||||
(format "%s.%04x%04x%04x%04x.%s:2,%s"
|
||||
(format-time-string "%s" (current-time))
|
||||
(random 65535) (random 65535) (random 65535) (random 65535)
|
||||
hostname (or flagstr ""))))
|
||||
(format-time-string "%s" (current-time))
|
||||
(random 65535) (random 65535) (random 65535) (random 65535)
|
||||
hostname (or flagstr ""))))
|
||||
|
||||
(defun mu4e~draft-common-construct ()
|
||||
"Construct the common headers for each message."
|
||||
(concat
|
||||
(when mu4e-user-agent-string
|
||||
(mu4e~draft-header "User-agent" mu4e-user-agent-string))
|
||||
(mu4e~draft-header "Date" (message-make-date))))
|
||||
(when mu4e-user-agent-string
|
||||
(mu4e~draft-header "User-agent" mu4e-user-agent-string))
|
||||
(mu4e~draft-header "Date" (message-make-date))))
|
||||
|
||||
(defconst mu4e~draft-reply-prefix "Re: "
|
||||
"String to prefix replies with.")
|
||||
|
@ -415,81 +415,81 @@ You can append flags."
|
|||
(defun mu4e~draft-reply-construct-recipients (origmsg)
|
||||
"Determine the to/cc recipients for a reply message."
|
||||
(let* ((reply-to-self (mu4e-message-contact-field-matches-me origmsg :from))
|
||||
;; reply-to-self implies reply-all
|
||||
(reply-all (or reply-to-self
|
||||
(eq mu4e-compose-reply-recipients 'all)
|
||||
(and (not (eq mu4e-compose-reply-recipients 'sender))
|
||||
(mu4e~draft-reply-all-p origmsg)))))
|
||||
;; reply-to-self implies reply-all
|
||||
(reply-all (or reply-to-self
|
||||
(eq mu4e-compose-reply-recipients 'all)
|
||||
(and (not (eq mu4e-compose-reply-recipients 'sender))
|
||||
(mu4e~draft-reply-all-p origmsg)))))
|
||||
(concat
|
||||
(if reply-to-self
|
||||
;; When we're replying to ourselves, simply keep the same headers.
|
||||
(concat
|
||||
(if reply-to-self
|
||||
;; When we're replying to ourselves, simply keep the same headers.
|
||||
(concat
|
||||
(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-message-field origmsg :cc))))
|
||||
(mu4e-message-field origmsg :cc))))
|
||||
|
||||
;; if there's no-one in To, copy the CC-list
|
||||
(if (zerop (length (mu4e~draft-create-to-lst origmsg)))
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct
|
||||
;; if there's no-one in To, copy the CC-list
|
||||
(if (zerop (length (mu4e~draft-create-to-lst origmsg)))
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct
|
||||
:cc origmsg reply-all))
|
||||
;; otherwise...
|
||||
(concat
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg))
|
||||
(mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg reply-all))))))))
|
||||
;; otherwise...
|
||||
(concat
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg))
|
||||
(mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg reply-all))))))))
|
||||
|
||||
(defun mu4e~draft-reply-construct-recipients-list (origmsg)
|
||||
"Determine the to/cc recipients for a reply message to a
|
||||
mailing-list."
|
||||
(let* ( ;; reply-to-self implies reply-all
|
||||
(list-post (plist-get origmsg :list-post))
|
||||
(from (plist-get origmsg :from))
|
||||
(recipnum
|
||||
(+ (length (mu4e~draft-create-to-lst origmsg))
|
||||
(length (mu4e~draft-create-cc-lst origmsg t t))))
|
||||
(reply-type
|
||||
(mu4e-read-option
|
||||
"Reply to mailing-list "
|
||||
`( (,(format "all %d recipient(s)" recipnum) . all)
|
||||
(,(format "list-only (%s)" (cdar list-post)) . list-only)
|
||||
(,(format "sender-only (%s)" (cdar from)) . sender-only)))))
|
||||
(list-post (plist-get origmsg :list-post))
|
||||
(from (plist-get origmsg :from))
|
||||
(recipnum
|
||||
(+ (length (mu4e~draft-create-to-lst origmsg))
|
||||
(length (mu4e~draft-create-cc-lst origmsg t t))))
|
||||
(reply-type
|
||||
(mu4e-read-option
|
||||
"Reply to mailing-list "
|
||||
`( (,(format "all %d recipient(s)" recipnum) . all)
|
||||
(,(format "list-only (%s)" (cdar list-post)) . list-only)
|
||||
(,(format "sender-only (%s)" (cdar from)) . sender-only)))))
|
||||
(cl-case reply-type
|
||||
(all
|
||||
(concat
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg))
|
||||
(mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg t t))))
|
||||
(concat
|
||||
(mu4e~draft-header "To" (mu4e~draft-recipients-construct :to origmsg))
|
||||
(mu4e~draft-header "Cc" (mu4e~draft-recipients-construct :cc origmsg t t))))
|
||||
(list-only
|
||||
(mu4e~draft-header "To"
|
||||
(mu4e~draft-recipients-list-to-string list-post)))
|
||||
(mu4e~draft-header "To"
|
||||
(mu4e~draft-recipients-list-to-string list-post)))
|
||||
(sender-only
|
||||
(mu4e~draft-header "To"
|
||||
(mu4e~draft-recipients-list-to-string from))))))
|
||||
(mu4e~draft-header "To"
|
||||
(mu4e~draft-recipients-list-to-string from))))))
|
||||
|
||||
(defun mu4e~draft-reply-construct (origmsg)
|
||||
"Create a draft message as a reply to ORIGMSG.
|
||||
Replying-to-self is special; in that case, the To and Cc fields
|
||||
will be the same as in the original."
|
||||
(let* ((old-msgid (plist-get origmsg :message-id))
|
||||
(subject (concat mu4e~draft-reply-prefix
|
||||
(message-strip-subject-re
|
||||
(or (plist-get origmsg :subject) ""))))
|
||||
(list-post (plist-get origmsg :list-post)))
|
||||
(subject (concat mu4e~draft-reply-prefix
|
||||
(message-strip-subject-re
|
||||
(or (plist-get origmsg :subject) ""))))
|
||||
(list-post (plist-get origmsg :list-post)))
|
||||
(concat
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
|
||||
(if list-post ;; mailing-lists are a bit special.
|
||||
(mu4e~draft-reply-construct-recipients-list origmsg)
|
||||
(mu4e~draft-reply-construct-recipients origmsg))
|
||||
(if list-post ;; mailing-lists are a bit special.
|
||||
(mu4e~draft-reply-construct-recipients-list origmsg)
|
||||
(mu4e~draft-reply-construct-recipients origmsg))
|
||||
|
||||
(mu4e~draft-header "Subject" subject)
|
||||
(mu4e~draft-header "References"
|
||||
(mu4e~draft-references-construct origmsg))
|
||||
(mu4e~draft-common-construct)
|
||||
(when old-msgid
|
||||
(mu4e~draft-header "In-reply-to" (format "<%s>" old-msgid)))
|
||||
"\n\n"
|
||||
(mu4e~draft-cite-original origmsg))))
|
||||
(mu4e~draft-header "Subject" subject)
|
||||
(mu4e~draft-header "References"
|
||||
(mu4e~draft-references-construct origmsg))
|
||||
(mu4e~draft-common-construct)
|
||||
(when old-msgid
|
||||
(mu4e~draft-header "In-reply-to" (format "<%s>" old-msgid)))
|
||||
"\n\n"
|
||||
(mu4e~draft-cite-original origmsg))))
|
||||
|
||||
(defconst mu4e~draft-forward-prefix "Fwd: "
|
||||
"String to prefix replies with.")
|
||||
|
@ -497,34 +497,34 @@ will be the same as in the original."
|
|||
(defun mu4e~draft-forward-construct (origmsg)
|
||||
"Create a draft forward message for original message ORIGMSG."
|
||||
(let ((subject
|
||||
(or (plist-get origmsg :subject) "")))
|
||||
(or (plist-get origmsg :subject) "")))
|
||||
(concat
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
(mu4e~draft-header "To" "")
|
||||
(mu4e~draft-common-construct)
|
||||
(mu4e~draft-header "References"
|
||||
(mu4e~draft-references-construct origmsg))
|
||||
(mu4e~draft-header "Subject"
|
||||
(concat
|
||||
;; if there's no Fwd: yet, prepend it
|
||||
(if (string-match "^Fwd:" subject)
|
||||
""
|
||||
mu4e~draft-forward-prefix)
|
||||
subject))
|
||||
(unless mu4e-compose-forward-as-attachment
|
||||
(concat
|
||||
"\n\n"
|
||||
(mu4e~draft-cite-original origmsg))))))
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
(mu4e~draft-header "To" "")
|
||||
(mu4e~draft-common-construct)
|
||||
(mu4e~draft-header "References"
|
||||
(mu4e~draft-references-construct origmsg))
|
||||
(mu4e~draft-header "Subject"
|
||||
(concat
|
||||
;; if there's no Fwd: yet, prepend it
|
||||
(if (string-match "^Fwd:" subject)
|
||||
""
|
||||
mu4e~draft-forward-prefix)
|
||||
subject))
|
||||
(unless mu4e-compose-forward-as-attachment
|
||||
(concat
|
||||
"\n\n"
|
||||
(mu4e~draft-cite-original origmsg))))))
|
||||
|
||||
(defun mu4e~draft-newmsg-construct ()
|
||||
"Create a new message."
|
||||
(concat
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
(mu4e~draft-header "To" "")
|
||||
(mu4e~draft-header "Subject" "")
|
||||
(mu4e~draft-common-construct)))
|
||||
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))
|
||||
(mu4e~draft-header "Reply-To" mu4e-compose-reply-to-address)
|
||||
(mu4e~draft-header "To" "")
|
||||
(mu4e~draft-header "Subject" "")
|
||||
(mu4e~draft-common-construct)))
|
||||
|
||||
(defvar mu4e~draft-drafts-folder nil
|
||||
"The drafts-folder for this compose buffer.
|
||||
|
@ -533,13 +533,13 @@ This is based on `mu4e-drafts-folder', which is evaluated once.")
|
|||
(defun mu4e~draft-open-file (path)
|
||||
"Open the the draft file at PATH."
|
||||
(if mu4e-compose-in-new-frame
|
||||
(find-file-other-frame path)
|
||||
(find-file-other-frame path)
|
||||
(find-file path)))
|
||||
|
||||
(defun mu4e~draft-determine-path (draft-dir)
|
||||
"Determines the path for a new draft file in DRAFT-DIR."
|
||||
(format "%s/%s/cur/%s"
|
||||
(mu4e-root-maildir) draft-dir (mu4e~draft-message-filename-construct "DS")))
|
||||
(mu4e-root-maildir) draft-dir (mu4e~draft-message-filename-construct "DS")))
|
||||
|
||||
|
||||
(defun mu4e-draft-open (compose-type &optional msg)
|
||||
|
@ -558,39 +558,39 @@ will be created from either `mu4e~draft-reply-construct', or
|
|||
(cl-case compose-type
|
||||
|
||||
(edit
|
||||
;; 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
|
||||
;; guess
|
||||
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
|
||||
(mu4e~draft-open-file (mu4e-message-field msg :path)))
|
||||
;; 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
|
||||
;; guess
|
||||
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
|
||||
(mu4e~draft-open-file (mu4e-message-field msg :path)))
|
||||
|
||||
(resend
|
||||
;; case-2: copy some exisisting message to a draft message, then edit
|
||||
;; that.
|
||||
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
|
||||
(let ((draft-path (mu4e~draft-determine-path draft-dir)))
|
||||
(copy-file (mu4e-message-field msg :path) draft-path)
|
||||
(mu4e~draft-open-file draft-path)))
|
||||
;; case-2: copy some exisisting message to a draft message, then edit
|
||||
;; that.
|
||||
(setq draft-dir (mu4e~guess-maildir (mu4e-message-field msg :path)))
|
||||
(let ((draft-path (mu4e~draft-determine-path draft-dir)))
|
||||
(copy-file (mu4e-message-field msg :path) draft-path)
|
||||
(mu4e~draft-open-file draft-path)))
|
||||
|
||||
((reply forward new)
|
||||
;; case-3: creating a new message; in this case, we can determine
|
||||
;; mu4e-get-drafts-folder
|
||||
(setq draft-dir (mu4e-get-drafts-folder msg))
|
||||
(let ((draft-path (mu4e~draft-determine-path draft-dir))
|
||||
(initial-contents
|
||||
(cl-case compose-type
|
||||
(reply (mu4e~draft-reply-construct msg))
|
||||
(forward (mu4e~draft-forward-construct msg))
|
||||
(new (mu4e~draft-newmsg-construct)))))
|
||||
(mu4e~draft-open-file draft-path)
|
||||
(insert initial-contents)
|
||||
(newline)
|
||||
;; include the message signature (if it's set)
|
||||
(if (and mu4e-compose-signature-auto-include mu4e-compose-signature)
|
||||
(let ((message-signature mu4e-compose-signature))
|
||||
(save-excursion
|
||||
(message-insert-signature)
|
||||
(mu4e~fontify-signature))))))
|
||||
;; case-3: creating a new message; in this case, we can determine
|
||||
;; mu4e-get-drafts-folder
|
||||
(setq draft-dir (mu4e-get-drafts-folder msg))
|
||||
(let ((draft-path (mu4e~draft-determine-path draft-dir))
|
||||
(initial-contents
|
||||
(cl-case compose-type
|
||||
(reply (mu4e~draft-reply-construct msg))
|
||||
(forward (mu4e~draft-forward-construct msg))
|
||||
(new (mu4e~draft-newmsg-construct)))))
|
||||
(mu4e~draft-open-file draft-path)
|
||||
(insert initial-contents)
|
||||
(newline)
|
||||
;; include the message signature (if it's set)
|
||||
(if (and mu4e-compose-signature-auto-include mu4e-compose-signature)
|
||||
(let ((message-signature mu4e-compose-signature))
|
||||
(save-excursion
|
||||
(message-insert-signature)
|
||||
(mu4e~fontify-signature))))))
|
||||
(t (mu4e-error "Unsupported compose-type %S" compose-type)))
|
||||
;; if we didn't find a draft folder yet, try some default
|
||||
(unless draft-dir
|
||||
|
|
1302
mu4e/mu4e-headers.el
1302
mu4e/mu4e-headers.el
File diff suppressed because it is too large
Load Diff
|
@ -52,34 +52,34 @@
|
|||
(cl-defmethod gnus-icalendar-event:inline-reply-buttons :around
|
||||
((event gnus-icalendar-event) handle)
|
||||
(if (and (boundp 'mu4e~view-rendering)
|
||||
(gnus-icalendar-event:rsvp event))
|
||||
(let ((method (gnus-icalendar-event:method event)))
|
||||
(when (or (string= method "REQUEST") (string= method "PUBLISH"))
|
||||
`(("Accept" mu4e-icalendar-reply (,handle accepted ,event))
|
||||
("Tentative" mu4e-icalendar-reply (,handle tentative ,event))
|
||||
("Decline" mu4e-icalendar-reply (,handle declined ,event)))))
|
||||
(gnus-icalendar-event:rsvp event))
|
||||
(let ((method (gnus-icalendar-event:method event)))
|
||||
(when (or (string= method "REQUEST") (string= method "PUBLISH"))
|
||||
`(("Accept" mu4e-icalendar-reply (,handle accepted ,event))
|
||||
("Tentative" mu4e-icalendar-reply (,handle tentative ,event))
|
||||
("Decline" mu4e-icalendar-reply (,handle declined ,event)))))
|
||||
(cl-call-next-method event handle))))
|
||||
|
||||
(defun mu4e-icalendar-reply (data)
|
||||
"Reply to the text/calendar event present in DATA."
|
||||
;; Based on `gnus-icalendar-reply'.
|
||||
(let* ((handle (car data))
|
||||
(status (cadr data))
|
||||
(event (caddr data))
|
||||
(gnus-icalendar-additional-identities (mu4e-personal-addresses))
|
||||
(reply (gnus-icalendar-with-decoded-handle handle
|
||||
(gnus-icalendar-event-reply-from-buffer
|
||||
(current-buffer) status (gnus-icalendar-identities))))
|
||||
(msg (mu4e-message-at-point 'noerror))
|
||||
(charset (cdr (assoc 'charset (mm-handle-type handle)))))
|
||||
(status (cadr data))
|
||||
(event (caddr data))
|
||||
(gnus-icalendar-additional-identities (mu4e-personal-addresses))
|
||||
(reply (gnus-icalendar-with-decoded-handle handle
|
||||
(gnus-icalendar-event-reply-from-buffer
|
||||
(current-buffer) status (gnus-icalendar-identities))))
|
||||
(msg (mu4e-message-at-point 'noerror))
|
||||
(charset (cdr (assoc 'charset (mm-handle-type handle)))))
|
||||
(when reply
|
||||
(cl-labels
|
||||
((fold-icalendar-buffer
|
||||
()
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
|
||||
(replace-match "\\1\n \\2")
|
||||
(goto-char (line-beginning-position)))))
|
||||
((fold-icalendar-buffer
|
||||
()
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
|
||||
(replace-match "\\1\n \\2")
|
||||
(goto-char (line-beginning-position)))))
|
||||
|
||||
(with-current-buffer (get-buffer-create gnus-icalendar-reply-bufname)
|
||||
(delete-region (point-min) (point-max))
|
||||
|
@ -95,7 +95,7 @@
|
|||
(gnus-icalendar--update-org-event event status))
|
||||
(when mu4e-icalendar-diary-file
|
||||
(mu4e~icalendar-insert-diary event status
|
||||
mu4e-icalendar-diary-file))))))
|
||||
mu4e-icalendar-diary-file))))))
|
||||
|
||||
(defun mu4e~icalendar-delete-citation ()
|
||||
"Function passed to `mu4e-compose-cite-function' to remove the citation."
|
||||
|
@ -107,17 +107,17 @@
|
|||
"See `mu4e-sent-handler' for DOCID and PATH."
|
||||
(mu4e-sent-handler docid path)
|
||||
(let* ((docid (mu4e-message-field original-msg :docid))
|
||||
(markdescr (assq 'trash mu4e-marks))
|
||||
(action (plist-get (cdr markdescr) :action))
|
||||
(target (mu4e-get-trash-folder original-msg)))
|
||||
(markdescr (assq 'trash mu4e-marks))
|
||||
(action (plist-get (cdr markdescr) :action))
|
||||
(target (mu4e-get-trash-folder original-msg)))
|
||||
(with-current-buffer (mu4e-get-headers-buffer)
|
||||
(run-hook-with-args 'mu4e-mark-execute-pre-hook 'trash original-msg)
|
||||
(funcall action docid original-msg target))
|
||||
(when (and (mu4e~headers-view-this-message-p docid)
|
||||
(buffer-live-p (mu4e-get-view-buffer)))
|
||||
(buffer-live-p (mu4e-get-view-buffer)))
|
||||
(switch-to-buffer (mu4e-get-view-buffer))
|
||||
(or (mu4e-view-headers-next)
|
||||
(kill-buffer-and-window))))))
|
||||
(kill-buffer-and-window))))))
|
||||
|
||||
(defun mu4e-icalendar-reply-ical (original-msg event status buffer-name)
|
||||
"Reply to ORIGINAL-MSG containing invitation EVENT with STATUS.
|
||||
|
@ -126,8 +126,8 @@ STATUS values. BUFFER-NAME is the name of the buffer holding the
|
|||
response in icalendar format."
|
||||
(let ((message-signature nil))
|
||||
(let ((mu4e-compose-cite-function #'mu4e~icalendar-delete-citation)
|
||||
(mu4e-sent-messages-behavior 'delete)
|
||||
(mu4e-compose-reply-recipients 'sender))
|
||||
(mu4e-sent-messages-behavior 'delete)
|
||||
(mu4e-compose-reply-recipients 'sender))
|
||||
(mu4e~compose-handler 'reply original-msg))
|
||||
;; Make sure the recipient is the organizer
|
||||
(let ((organizer (gnus-icalendar-event:organizer event)))
|
||||
|
@ -141,23 +141,23 @@ response in icalendar format."
|
|||
(mml-insert-multipart "alternative")
|
||||
(mml-insert-part "text/plain")
|
||||
(let ((reply-event (gnus-icalendar-event-from-buffer
|
||||
buffer-name (mu4e-personal-addresses))))
|
||||
buffer-name (mu4e-personal-addresses))))
|
||||
(insert (gnus-icalendar-event->gnus-calendar reply-event status)))
|
||||
(forward-line 1); move past closing tag
|
||||
(mml-attach-buffer buffer-name "text/calendar; method=REPLY; charset=utf-8")
|
||||
(message-remove-header "Subject")
|
||||
(message-goto-subject)
|
||||
(insert (capitalize (symbol-name status))
|
||||
": " (gnus-icalendar-event:summary event))
|
||||
": " (gnus-icalendar-event:summary event))
|
||||
(set-buffer-modified-p nil); not yet modified by user
|
||||
(when mu4e-icalendar-trash-after-reply
|
||||
;; Override `mu4e-sent-handler' set by `mu4e-compose-mode' to
|
||||
;; also trash the message (thus must be appended to hooks).
|
||||
(add-hook
|
||||
'message-sent-hook
|
||||
(lambda () (setq mu4e-sent-func
|
||||
(mu4e~icalendar-trash-message original-msg)))
|
||||
t t))))
|
||||
'message-sent-hook
|
||||
(lambda () (setq mu4e-sent-func
|
||||
(mu4e~icalendar-trash-message original-msg)))
|
||||
t t))))
|
||||
|
||||
|
||||
(defun mu4e~icalendar-insert-diary (event reply-status filename)
|
||||
|
@ -166,20 +166,20 @@ REPLY-STATUS is the status of the reply. The possible values are
|
|||
given in the doc of `gnus-icalendar-event-reply-from-buffer'."
|
||||
;; FIXME: handle recurring events
|
||||
(let* ((beg (gnus-icalendar-event:start-time event))
|
||||
(beg-date (format-time-string "%d/%m/%Y" beg))
|
||||
(beg-time (format-time-string "%H:%M" beg))
|
||||
(end (gnus-icalendar-event:end-time event))
|
||||
(end-date (format-time-string "%d/%m/%Y" end))
|
||||
(end-time (format-time-string "%H:%M" end))
|
||||
(summary (gnus-icalendar-event:summary event))
|
||||
(location (gnus-icalendar-event:location event))
|
||||
(status (capitalize (symbol-name reply-status)))
|
||||
(txt (if location
|
||||
(format "%s (%s)\n %s " summary status location)
|
||||
(format "%s (%s)" summary status))))
|
||||
(beg-date (format-time-string "%d/%m/%Y" beg))
|
||||
(beg-time (format-time-string "%H:%M" beg))
|
||||
(end (gnus-icalendar-event:end-time event))
|
||||
(end-date (format-time-string "%d/%m/%Y" end))
|
||||
(end-time (format-time-string "%H:%M" end))
|
||||
(summary (gnus-icalendar-event:summary event))
|
||||
(location (gnus-icalendar-event:location event))
|
||||
(status (capitalize (symbol-name reply-status)))
|
||||
(txt (if location
|
||||
(format "%s (%s)\n %s " summary status location)
|
||||
(format "%s (%s)" summary status))))
|
||||
(with-temp-buffer
|
||||
(if (string= beg-date end-date)
|
||||
(insert beg-date " " beg-time "-" end-time " " txt "\n")
|
||||
(insert beg-date " " beg-time "-" end-time " " txt "\n")
|
||||
(insert beg-date " " beg-time " Start of: " txt "\n")
|
||||
(insert beg-date " " end-time " End of: " txt "\n"))
|
||||
(write-region (point-min) (point-max) filename t))))
|
||||
|
|
|
@ -71,9 +71,8 @@
|
|||
"Major mode for the mu4e main screen.
|
||||
\\{mu4e-main-mode-map}."
|
||||
(use-local-map mu4e-main-mode-map)
|
||||
(setq
|
||||
truncate-lines t
|
||||
overwrite-mode 'overwrite-mode-binary)
|
||||
(setq truncate-lines t)
|
||||
(setq overwrite-mode 'overwrite-mode-binary)
|
||||
|
||||
;; show context in mode-string
|
||||
(make-local-variable 'global-mode-string)
|
||||
|
@ -88,23 +87,23 @@ when STR is clicked (using RET or mouse-2); if FUNC-OR-SHORTCUT is
|
|||
a string, execute the corresponding keyboard action when it is
|
||||
clicked."
|
||||
(let ((newstr
|
||||
(replace-regexp-in-string
|
||||
"\\[\\(..?\\)\\]"
|
||||
(lambda(m)
|
||||
(format "[%s]"
|
||||
(propertize (match-string 1 m) 'face 'mu4e-highlight-face)))
|
||||
str))
|
||||
(map (make-sparse-keymap))
|
||||
(func (if (functionp func-or-shortcut)
|
||||
func-or-shortcut
|
||||
(if (stringp func-or-shortcut)
|
||||
(lambda()(interactive)
|
||||
(execute-kbd-macro func-or-shortcut))))))
|
||||
(replace-regexp-in-string
|
||||
"\\[\\(..?\\)\\]"
|
||||
(lambda(m)
|
||||
(format "[%s]"
|
||||
(propertize (match-string 1 m) 'face 'mu4e-highlight-face)))
|
||||
str))
|
||||
(map (make-sparse-keymap))
|
||||
(func (if (functionp func-or-shortcut)
|
||||
func-or-shortcut
|
||||
(if (stringp func-or-shortcut)
|
||||
(lambda()(interactive)
|
||||
(execute-kbd-macro func-or-shortcut))))))
|
||||
(define-key map [mouse-2] func)
|
||||
(define-key map (kbd "RET") func)
|
||||
(put-text-property 0 (length newstr) 'keymap map newstr)
|
||||
(put-text-property (string-match "\\[.+$" newstr)
|
||||
(- (length newstr) 1) 'mouse-face 'highlight newstr)
|
||||
(- (length newstr) 1) 'mouse-face 'highlight newstr)
|
||||
newstr))
|
||||
|
||||
|
||||
|
@ -125,8 +124,8 @@ clicked."
|
|||
concat (concat
|
||||
;; menu entry
|
||||
(mu4e~main-action-str
|
||||
(concat "\t* [b" key "] " name)
|
||||
(concat "b" key))
|
||||
(concat "\t* [b" key "] " name)
|
||||
(concat "b" key))
|
||||
;; append all/unread numbers, if available.
|
||||
(if qcounts
|
||||
(let ((unread (plist-get (car qcounts) :unread))
|
||||
|
@ -144,99 +143,99 @@ clicked."
|
|||
(defun mu4e~key-val (key val &optional unit)
|
||||
"Return a key / value pair."
|
||||
(concat
|
||||
" * "
|
||||
(propertize (format "%-20s" key) 'face 'mu4e-header-title-face)
|
||||
": "
|
||||
(propertize val 'face 'mu4e-header-key-face)
|
||||
(if unit
|
||||
(propertize (concat " " unit) 'face 'mu4e-header-title-face)
|
||||
"")
|
||||
"\n"))
|
||||
" * "
|
||||
(propertize (format "%-20s" key) 'face 'mu4e-header-title-face)
|
||||
": "
|
||||
(propertize val 'face 'mu4e-header-key-face)
|
||||
(if unit
|
||||
(propertize (concat " " unit) 'face 'mu4e-header-title-face)
|
||||
"")
|
||||
"\n"))
|
||||
|
||||
;; NEW
|
||||
;; This is the old `mu4e~main-view' function but without
|
||||
;; buffer switching at the end.
|
||||
(defun mu4e~main-view-real (_ignore-auto _noconfirm)
|
||||
(let ((buf (get-buffer-create mu4e~main-buffer-name))
|
||||
(inhibit-read-only t))
|
||||
(inhibit-read-only t))
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(insert
|
||||
"* "
|
||||
(propertize "mu4e" 'face 'mu4e-header-key-face)
|
||||
(propertize " - mu for emacs version " 'face 'mu4e-title-face)
|
||||
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
|
||||
"\n\n"
|
||||
(propertize " Basics\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~main-action-str
|
||||
"\t* [j]ump to some maildir\n" 'mu4e-jump-to-maildir)
|
||||
(mu4e~main-action-str
|
||||
"\t* enter a [s]earch query\n" 'mu4e-search)
|
||||
(mu4e~main-action-str
|
||||
"\t* [C]ompose a new message\n" 'mu4e-compose-new)
|
||||
"\n"
|
||||
(propertize " Bookmarks\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~main-bookmarks)
|
||||
"\n"
|
||||
(propertize " Misc\n\n" 'face 'mu4e-title-face)
|
||||
"* "
|
||||
(propertize "mu4e" 'face 'mu4e-header-key-face)
|
||||
(propertize " - mu for emacs version " 'face 'mu4e-title-face)
|
||||
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
|
||||
"\n\n"
|
||||
(propertize " Basics\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~main-action-str
|
||||
"\t* [j]ump to some maildir\n" 'mu4e-jump-to-maildir)
|
||||
(mu4e~main-action-str
|
||||
"\t* enter a [s]earch query\n" 'mu4e-search)
|
||||
(mu4e~main-action-str
|
||||
"\t* [C]ompose a new message\n" 'mu4e-compose-new)
|
||||
"\n"
|
||||
(propertize " Bookmarks\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~main-bookmarks)
|
||||
"\n"
|
||||
(propertize " Misc\n\n" 'face 'mu4e-title-face)
|
||||
|
||||
(mu4e~main-action-str "\t* [;]Switch context\n" 'mu4e-context-switch)
|
||||
(mu4e~main-action-str "\t* [;]Switch context\n" 'mu4e-context-switch)
|
||||
|
||||
(mu4e~main-action-str "\t* [U]pdate email & database\n"
|
||||
'mu4e-update-mail-and-index)
|
||||
(mu4e~main-action-str "\t* [U]pdate email & database\n"
|
||||
'mu4e-update-mail-and-index)
|
||||
|
||||
;; show the queue functions if `smtpmail-queue-dir' is defined
|
||||
(if (file-directory-p smtpmail-queue-dir)
|
||||
(mu4e~main-view-queue)
|
||||
"")
|
||||
"\n"
|
||||
(mu4e~main-action-str "\t* [N]ews\n" 'mu4e-news)
|
||||
(mu4e~main-action-str "\t* [A]bout mu4e\n" 'mu4e-about)
|
||||
(mu4e~main-action-str "\t* [H]elp\n" 'mu4e-display-manual)
|
||||
(mu4e~main-action-str "\t* [q]uit\n" 'mu4e-quit)
|
||||
;; show the queue functions if `smtpmail-queue-dir' is defined
|
||||
(if (file-directory-p smtpmail-queue-dir)
|
||||
(mu4e~main-view-queue)
|
||||
"")
|
||||
"\n"
|
||||
(mu4e~main-action-str "\t* [N]ews\n" 'mu4e-news)
|
||||
(mu4e~main-action-str "\t* [A]bout mu4e\n" 'mu4e-about)
|
||||
(mu4e~main-action-str "\t* [H]elp\n" 'mu4e-display-manual)
|
||||
(mu4e~main-action-str "\t* [q]uit\n" 'mu4e-quit)
|
||||
|
||||
"\n"
|
||||
(propertize " Info\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~key-val "database-path" (mu4e-database-path))
|
||||
(mu4e~key-val "maildir" (mu4e-root-maildir))
|
||||
(mu4e~key-val "in store"
|
||||
(format "%d" (plist-get mu4e~server-props :doccount)) "messages"))
|
||||
"\n"
|
||||
(propertize " Info\n\n" 'face 'mu4e-title-face)
|
||||
(mu4e~key-val "database-path" (mu4e-database-path))
|
||||
(mu4e~key-val "maildir" (mu4e-root-maildir))
|
||||
(mu4e~key-val "in store"
|
||||
(format "%d" (plist-get mu4e~server-props :doccount)) "messages"))
|
||||
(mu4e-main-mode))))
|
||||
|
||||
(defun mu4e~main-view-queue ()
|
||||
"Display queue-related actions in the main view."
|
||||
(concat
|
||||
(mu4e~main-action-str "\t* toggle [m]ail sending mode "
|
||||
'mu4e~main-toggle-mail-sending-mode)
|
||||
"(currently "
|
||||
(propertize (if smtpmail-queue-mail "queued" "direct")
|
||||
'face 'mu4e-header-key-face)
|
||||
")\n"
|
||||
(let ((queue-size (mu4e~main-queue-size)))
|
||||
(if (zerop queue-size)
|
||||
""
|
||||
(mu4e~main-action-str
|
||||
(format "\t* [f]lush %s queued %s\n"
|
||||
(propertize (int-to-string queue-size)
|
||||
'face 'mu4e-header-key-face)
|
||||
(if (> queue-size 1) "mails" "mail"))
|
||||
'smtpmail-send-queued-mail)))))
|
||||
(mu4e~main-action-str "\t* toggle [m]ail sending mode "
|
||||
'mu4e~main-toggle-mail-sending-mode)
|
||||
"(currently "
|
||||
(propertize (if smtpmail-queue-mail "queued" "direct")
|
||||
'face 'mu4e-header-key-face)
|
||||
")\n"
|
||||
(let ((queue-size (mu4e~main-queue-size)))
|
||||
(if (zerop queue-size)
|
||||
""
|
||||
(mu4e~main-action-str
|
||||
(format "\t* [f]lush %s queued %s\n"
|
||||
(propertize (int-to-string queue-size)
|
||||
'face 'mu4e-header-key-face)
|
||||
(if (> queue-size 1) "mails" "mail"))
|
||||
'smtpmail-send-queued-mail)))))
|
||||
|
||||
(defun mu4e~main-queue-size ()
|
||||
"Return, as an int, the number of emails in the queue."
|
||||
(condition-case nil
|
||||
(with-temp-buffer
|
||||
(insert-file-contents (expand-file-name smtpmail-queue-index-file
|
||||
smtpmail-queue-dir))
|
||||
(count-lines (point-min) (point-max)))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents (expand-file-name smtpmail-queue-index-file
|
||||
smtpmail-queue-dir))
|
||||
(count-lines (point-min) (point-max)))
|
||||
(error 0)))
|
||||
|
||||
(defun mu4e~main-view ()
|
||||
"Create the mu4e main-view, and switch to it."
|
||||
(if (eq mu4e-split-view 'single-window)
|
||||
(if (buffer-live-p (mu4e-get-headers-buffer))
|
||||
(switch-to-buffer (mu4e-get-headers-buffer))
|
||||
(mu4e~main-menu))
|
||||
(if (buffer-live-p (mu4e-get-headers-buffer))
|
||||
(switch-to-buffer (mu4e-get-headers-buffer))
|
||||
(mu4e~main-menu))
|
||||
(mu4e~main-view-real nil nil)
|
||||
(switch-to-buffer mu4e~main-buffer-name)
|
||||
(goto-char (point-min)))
|
||||
|
@ -253,7 +252,7 @@ clicked."
|
|||
(mu4e-error "`smtpmail-queue-dir' does not exist"))
|
||||
(setq smtpmail-queue-mail (not smtpmail-queue-mail))
|
||||
(message (concat "Outgoing mail will now be "
|
||||
(if smtpmail-queue-mail "queued" "sent directly")))
|
||||
(if smtpmail-queue-mail "queued" "sent directly")))
|
||||
(unless (eq mu4e-split-view 'single-window)
|
||||
(let ((curpos (point)))
|
||||
(mu4e~main-view-real nil nil)
|
||||
|
@ -263,29 +262,29 @@ clicked."
|
|||
"mu4e main view in the minibuffer."
|
||||
(interactive)
|
||||
(let ((key
|
||||
(read-key
|
||||
(mu4e-format
|
||||
"%s"
|
||||
(concat
|
||||
(mu4e~main-action-str "[j]ump " 'mu4e-jump-to-maildir)
|
||||
(mu4e~main-action-str "[s]earch " 'mu4e-search)
|
||||
(mu4e~main-action-str "[C]ompose " 'mu4e-compose-new)
|
||||
(mu4e~main-action-str "[b]ookmarks " 'mu4e-headers-search-bookmark)
|
||||
(mu4e~main-action-str "[;]Switch context " 'mu4e-context-switch)
|
||||
(mu4e~main-action-str "[U]pdate " 'mu4e-update-mail-and-index)
|
||||
(mu4e~main-action-str "[N]ews " 'mu4e-news)
|
||||
(mu4e~main-action-str "[A]bout " 'mu4e-about)
|
||||
(mu4e~main-action-str "[H]elp " 'mu4e-display-manual))))))
|
||||
(read-key
|
||||
(mu4e-format
|
||||
"%s"
|
||||
(concat
|
||||
(mu4e~main-action-str "[j]ump " 'mu4e-jump-to-maildir)
|
||||
(mu4e~main-action-str "[s]earch " 'mu4e-search)
|
||||
(mu4e~main-action-str "[C]ompose " 'mu4e-compose-new)
|
||||
(mu4e~main-action-str "[b]ookmarks " 'mu4e-headers-search-bookmark)
|
||||
(mu4e~main-action-str "[;]Switch context " 'mu4e-context-switch)
|
||||
(mu4e~main-action-str "[U]pdate " 'mu4e-update-mail-and-index)
|
||||
(mu4e~main-action-str "[N]ews " 'mu4e-news)
|
||||
(mu4e~main-action-str "[A]bout " 'mu4e-about)
|
||||
(mu4e~main-action-str "[H]elp " 'mu4e-display-manual))))))
|
||||
(unless (member key '(?\C-g ?\C-\[))
|
||||
(let ((mu4e-command (lookup-key mu4e-main-mode-map (string key) t)))
|
||||
(if mu4e-command
|
||||
(condition-case err
|
||||
(let ((mu4e-hide-index-messages t))
|
||||
(call-interactively mu4e-command))
|
||||
(error (when (cadr err) (message (cadr err)))))
|
||||
(message (mu4e-format "key %s not bound to a command" (string key))))
|
||||
(when (or (not mu4e-command) (eq mu4e-command 'mu4e-context-switch))
|
||||
(sit-for 1)
|
||||
(mu4e~main-menu))))))
|
||||
(if mu4e-command
|
||||
(condition-case err
|
||||
(let ((mu4e-hide-index-messages t))
|
||||
(call-interactively mu4e-command))
|
||||
(error (when (cadr err) (message (cadr err)))))
|
||||
(message (mu4e-format "key %s not bound to a command" (string key))))
|
||||
(when (or (not mu4e-command) (eq mu4e-command 'mu4e-context-switch))
|
||||
(sit-for 1)
|
||||
(mu4e~main-menu))))))
|
||||
|
||||
(provide 'mu4e-main)
|
||||
|
|
|
@ -44,8 +44,8 @@ Value is one of the following symbols:
|
|||
- `apply' automatically apply the marks before doing anything else
|
||||
- `ignore' automatically ignore the marks without asking"
|
||||
:type '(choice (const ask :tag "ask user whether to ignore marks")
|
||||
(const apply :tag "apply marks without asking")
|
||||
(const ignore :tag "ignore marks without asking"))
|
||||
(const apply :tag "apply marks without asking")
|
||||
(const ignore :tag "ignore marks without asking"))
|
||||
:group 'mu4e-headers)
|
||||
|
||||
(defcustom mu4e-mark-execute-pre-hook nil
|
||||
|
@ -96,98 +96,98 @@ TARGET (optional) is the target directory (for 'move')")
|
|||
(defun mu4e~mark-find-headers-buffer ()
|
||||
"Find the headers buffer, if any."
|
||||
(cl-find-if
|
||||
(lambda (b)
|
||||
(with-current-buffer b
|
||||
(eq major-mode 'mu4e-headers-mode)))
|
||||
(buffer-list)))
|
||||
(lambda (b)
|
||||
(with-current-buffer b
|
||||
(eq major-mode 'mu4e-headers-mode)))
|
||||
(buffer-list)))
|
||||
|
||||
(defmacro mu4e~mark-in-context (&rest body)
|
||||
"Evaluate BODY in the context of the headers buffer.
|
||||
The current buffer must be either a headers or view buffer."
|
||||
`(cond
|
||||
((eq major-mode 'mu4e-headers-mode) ,@body)
|
||||
((eq major-mode 'mu4e-view-mode)
|
||||
(when (buffer-live-p (mu4e-get-headers-buffer))
|
||||
(let* ((msg (mu4e-message-at-point))
|
||||
(docid (mu4e-message-field msg :docid)))
|
||||
(with-current-buffer (mu4e-get-headers-buffer)
|
||||
(if (mu4e~headers-goto-docid docid)
|
||||
,@body
|
||||
(mu4e-error "Cannot find message in headers buffer"))))))
|
||||
(t
|
||||
;; even in other modes (e.g. mu4e-main-mode we try to find
|
||||
;; the headers buffer
|
||||
(let ((hbuf (mu4e~mark-find-headers-buffer)))
|
||||
(if (buffer-live-p hbuf)
|
||||
(with-current-buffer hbuf ,@body)
|
||||
,@body)))))
|
||||
((eq major-mode 'mu4e-headers-mode) ,@body)
|
||||
((eq major-mode 'mu4e-view-mode)
|
||||
(when (buffer-live-p (mu4e-get-headers-buffer))
|
||||
(let* ((msg (mu4e-message-at-point))
|
||||
(docid (mu4e-message-field msg :docid)))
|
||||
(with-current-buffer (mu4e-get-headers-buffer)
|
||||
(if (mu4e~headers-goto-docid docid)
|
||||
,@body
|
||||
(mu4e-error "Cannot find message in headers buffer"))))))
|
||||
(t
|
||||
;; even in other modes (e.g. mu4e-main-mode we try to find
|
||||
;; the headers buffer
|
||||
(let ((hbuf (mu4e~mark-find-headers-buffer)))
|
||||
(if (buffer-live-p hbuf)
|
||||
(with-current-buffer hbuf ,@body)
|
||||
,@body)))))
|
||||
|
||||
(defconst mu4e-marks
|
||||
'((refile
|
||||
:char ("r" . "▶")
|
||||
:prompt "refile"
|
||||
:dyn-target (lambda (target msg) (mu4e-get-refile-folder msg))
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid (mu4e~mark-check-target target) "-N")))
|
||||
(delete
|
||||
:char ("D" . "x")
|
||||
:prompt "Delete"
|
||||
:show-target (lambda (target) "delete")
|
||||
:action (lambda (docid msg target) (mu4e~proc-remove docid)))
|
||||
(flag
|
||||
:char ("+" . "✚")
|
||||
:prompt "+flag"
|
||||
:show-target (lambda (target) "flag")
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid nil "+F-u-N")))
|
||||
(move
|
||||
:char ("m" . "▷")
|
||||
:prompt "move"
|
||||
:ask-target mu4e~mark-get-move-target
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid (mu4e~mark-check-target target) "-N")))
|
||||
(read
|
||||
:char ("!" . "◼")
|
||||
:prompt "!read"
|
||||
:show-target (lambda (target) "read")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "+S-u-N")))
|
||||
(trash
|
||||
:char ("d" . "▼")
|
||||
:prompt "dtrash"
|
||||
:dyn-target (lambda (target msg) (mu4e-get-trash-folder msg))
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid
|
||||
(mu4e~mark-check-target target) "+T-N")))
|
||||
(unflag
|
||||
:char ("-" . "➖")
|
||||
:prompt "-unflag"
|
||||
:show-target (lambda (target) "unflag")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-F-N")))
|
||||
(untrash
|
||||
:char ("=" . "▲")
|
||||
:prompt "=untrash"
|
||||
:show-target (lambda (target) "untrash")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-T")))
|
||||
(unread
|
||||
:char ("?" . "◻")
|
||||
:prompt "?unread"
|
||||
:show-target (lambda (target) "unread")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-S+u-N")))
|
||||
(unmark
|
||||
:char " "
|
||||
:prompt "unmark"
|
||||
:action (mu4e-error "No action for unmarking"))
|
||||
(action
|
||||
:char ( "a" . "◯")
|
||||
:prompt "action"
|
||||
:ask-target (lambda () (mu4e-read-option "Action: " mu4e-headers-actions))
|
||||
:action (lambda (docid msg actionfunc)
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-headers-action actionfunc)))))
|
||||
(something
|
||||
:char ("*" . "✱")
|
||||
:prompt "*something"
|
||||
:action (mu4e-error "No action for deferred mark")))
|
||||
'((refile
|
||||
:char ("r" . "▶")
|
||||
:prompt "refile"
|
||||
:dyn-target (lambda (target msg) (mu4e-get-refile-folder msg))
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid (mu4e~mark-check-target target) "-N")))
|
||||
(delete
|
||||
:char ("D" . "x")
|
||||
:prompt "Delete"
|
||||
:show-target (lambda (target) "delete")
|
||||
:action (lambda (docid msg target) (mu4e~proc-remove docid)))
|
||||
(flag
|
||||
:char ("+" . "✚")
|
||||
:prompt "+flag"
|
||||
:show-target (lambda (target) "flag")
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid nil "+F-u-N")))
|
||||
(move
|
||||
:char ("m" . "▷")
|
||||
:prompt "move"
|
||||
:ask-target mu4e~mark-get-move-target
|
||||
:action (lambda (docid msg target)
|
||||
(mu4e~proc-move docid (mu4e~mark-check-target target) "-N")))
|
||||
(read
|
||||
:char ("!" . "◼")
|
||||
:prompt "!read"
|
||||
:show-target (lambda (target) "read")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "+S-u-N")))
|
||||
(trash
|
||||
:char ("d" . "▼")
|
||||
:prompt "dtrash"
|
||||
:dyn-target (lambda (target msg) (mu4e-get-trash-folder msg))
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid
|
||||
(mu4e~mark-check-target target) "+T-N")))
|
||||
(unflag
|
||||
:char ("-" . "➖")
|
||||
:prompt "-unflag"
|
||||
:show-target (lambda (target) "unflag")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-F-N")))
|
||||
(untrash
|
||||
:char ("=" . "▲")
|
||||
:prompt "=untrash"
|
||||
:show-target (lambda (target) "untrash")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-T")))
|
||||
(unread
|
||||
:char ("?" . "◻")
|
||||
:prompt "?unread"
|
||||
:show-target (lambda (target) "unread")
|
||||
:action (lambda (docid msg target) (mu4e~proc-move docid nil "-S+u-N")))
|
||||
(unmark
|
||||
:char " "
|
||||
:prompt "unmark"
|
||||
:action (mu4e-error "No action for unmarking"))
|
||||
(action
|
||||
:char ( "a" . "◯")
|
||||
:prompt "action"
|
||||
:ask-target (lambda () (mu4e-read-option "Action: " mu4e-headers-actions))
|
||||
:action (lambda (docid msg actionfunc)
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-headers-action actionfunc)))))
|
||||
(something
|
||||
:char ("*" . "✱")
|
||||
:prompt "*something"
|
||||
:action (mu4e-error "No action for deferred mark")))
|
||||
|
||||
"The list of all the possible marks.
|
||||
This is an alist mapping mark symbols to their properties. The
|
||||
|
@ -223,76 +223,76 @@ The following marks are available, and the corresponding props:
|
|||
|
||||
MARK TARGET description
|
||||
----------------------------------------------------------
|
||||
`refile' y mark this message for archiving
|
||||
`something' n mark this message for *something* (decided later)
|
||||
`delete' n remove the message
|
||||
`flag' n mark this message for flagging
|
||||
`move' y move the message to some folder
|
||||
`read' n mark the message as read
|
||||
`trash' y trash the message to some folder
|
||||
`unflag' n mark this message for unflagging
|
||||
`untrash' n remove the 'trashed' flag from a message
|
||||
`unmark' n unmark this message
|
||||
`unread' n mark the message as unread
|
||||
`refile' y mark this message for archiving
|
||||
`something' n mark this message for *something* (decided later)
|
||||
`delete' n remove the message
|
||||
`flag' n mark this message for flagging
|
||||
`move' y move the message to some folder
|
||||
`read' n mark the message as read
|
||||
`trash' y trash the message to some folder
|
||||
`unflag' n mark this message for unflagging
|
||||
`untrash' n remove the 'trashed' flag from a message
|
||||
`unmark' n unmark this message
|
||||
`unread' n mark the message as unread
|
||||
`action' y mark the message for some action."
|
||||
(interactive)
|
||||
(let* ((msg (mu4e-message-at-point))
|
||||
(docid (mu4e-message-field msg :docid))
|
||||
;; get a cell with the mark char and the 'target' 'move' already has a
|
||||
;; target (the target folder) the other ones get a pseudo "target", as
|
||||
;; info for the user.
|
||||
(markdesc (cdr (or (assq mark mu4e-marks)
|
||||
(mu4e-error "Invalid mark %S" mark))))
|
||||
(get-markkar
|
||||
(lambda (char)
|
||||
(if (listp char)
|
||||
(if mu4e-use-fancy-chars (cdr char) (car char))
|
||||
char)))
|
||||
(markkar (funcall get-markkar (plist-get markdesc :char)))
|
||||
(target (mu4e~mark-get-dyn-target mark target))
|
||||
(show-fct (plist-get markdesc :show-target))
|
||||
(shown-target (if show-fct
|
||||
(funcall show-fct target)
|
||||
(if target (format "%S" target)))))
|
||||
(docid (mu4e-message-field msg :docid))
|
||||
;; get a cell with the mark char and the 'target' 'move' already has a
|
||||
;; target (the target folder) the other ones get a pseudo "target", as
|
||||
;; info for the user.
|
||||
(markdesc (cdr (or (assq mark mu4e-marks)
|
||||
(mu4e-error "Invalid mark %S" mark))))
|
||||
(get-markkar
|
||||
(lambda (char)
|
||||
(if (listp char)
|
||||
(if mu4e-use-fancy-chars (cdr char) (car char))
|
||||
char)))
|
||||
(markkar (funcall get-markkar (plist-get markdesc :char)))
|
||||
(target (mu4e~mark-get-dyn-target mark target))
|
||||
(show-fct (plist-get markdesc :show-target))
|
||||
(shown-target (if show-fct
|
||||
(funcall show-fct target)
|
||||
(if target (format "%S" target)))))
|
||||
(unless docid (mu4e-warn "No message on this line"))
|
||||
(unless (eq major-mode 'mu4e-headers-mode)
|
||||
(mu4e-error "Not in headers-mode"))
|
||||
(save-excursion
|
||||
(when (mu4e~headers-mark docid markkar)
|
||||
;; update the hash -- remove everything current, and if add the new
|
||||
;; stuff, unless we're unmarking
|
||||
(remhash docid mu4e~mark-map)
|
||||
;; remove possible overlays
|
||||
(remove-overlays (line-beginning-position) (line-end-position))
|
||||
;; now, let's set a mark (unless we were unmarking)
|
||||
(unless (eql mark 'unmark)
|
||||
(puthash docid (cons mark target) mu4e~mark-map)
|
||||
;; when we have a target (ie., when moving), show the target folder in
|
||||
;; an overlay
|
||||
(when (and shown-target mu4e-headers-show-target)
|
||||
(let* ((targetstr (propertize (concat "-> " shown-target " ")
|
||||
'face 'mu4e-system-face))
|
||||
;; mu4e~headers-goto-docid docid t \will take us just after
|
||||
;; the docid cookie and then we skip the mu4e~mark-fringe
|
||||
(start (+ (length mu4e~mark-fringe)
|
||||
(mu4e~headers-goto-docid docid t)))
|
||||
(overlay (make-overlay start (+ start (length targetstr)))))
|
||||
(overlay-put overlay 'display targetstr)
|
||||
docid)))))))
|
||||
;; update the hash -- remove everything current, and if add the new
|
||||
;; stuff, unless we're unmarking
|
||||
(remhash docid mu4e~mark-map)
|
||||
;; remove possible overlays
|
||||
(remove-overlays (line-beginning-position) (line-end-position))
|
||||
;; now, let's set a mark (unless we were unmarking)
|
||||
(unless (eql mark 'unmark)
|
||||
(puthash docid (cons mark target) mu4e~mark-map)
|
||||
;; when we have a target (ie., when moving), show the target folder in
|
||||
;; an overlay
|
||||
(when (and shown-target mu4e-headers-show-target)
|
||||
(let* ((targetstr (propertize (concat "-> " shown-target " ")
|
||||
'face 'mu4e-system-face))
|
||||
;; mu4e~headers-goto-docid docid t \will take us just after
|
||||
;; the docid cookie and then we skip the mu4e~mark-fringe
|
||||
(start (+ (length mu4e~mark-fringe)
|
||||
(mu4e~headers-goto-docid docid t)))
|
||||
(overlay (make-overlay start (+ start (length targetstr)))))
|
||||
(overlay-put overlay 'display targetstr)
|
||||
docid)))))))
|
||||
|
||||
(defun mu4e~mark-get-move-target ()
|
||||
"Ask for a move target, and propose to create it if it does not exist."
|
||||
(interactive)
|
||||
;; (mu4e-message-at-point) ;; raises error if there is none
|
||||
(let* ((target (mu4e-ask-maildir "Move message to: "))
|
||||
(target (if (string= (substring target 0 1) "/")
|
||||
target
|
||||
(concat "/" target)))
|
||||
(fulltarget (concat (mu4e-root-maildir) target)))
|
||||
(target (if (string= (substring target 0 1) "/")
|
||||
target
|
||||
(concat "/" target)))
|
||||
(fulltarget (concat (mu4e-root-maildir) target)))
|
||||
(when (or (file-directory-p fulltarget)
|
||||
(and (yes-or-no-p
|
||||
(format "%s does not exist. Create now?" fulltarget))
|
||||
(mu4e~proc-mkdir fulltarget)))
|
||||
(and (yes-or-no-p
|
||||
(format "%s does not exist. Create now?" fulltarget))
|
||||
(mu4e~proc-mkdir fulltarget)))
|
||||
target)))
|
||||
|
||||
(defun mu4e~mark-ask-target (mark)
|
||||
|
@ -305,7 +305,7 @@ The following marks are available, and the corresponding props:
|
|||
The result may depend on the message at point."
|
||||
(let ((getter (plist-get (cdr (assq mark mu4e-marks)) :dyn-target)))
|
||||
(if getter
|
||||
(funcall getter target (mu4e-message-at-point))
|
||||
(funcall getter target (mu4e-message-at-point))
|
||||
target)))
|
||||
|
||||
(defun mu4e-mark-set (mark &optional target)
|
||||
|
@ -314,37 +314,37 @@ Optionally, provide TARGET (for moves)."
|
|||
(unless target
|
||||
(setq target (mu4e~mark-ask-target mark)))
|
||||
(if (not (use-region-p))
|
||||
;; single message
|
||||
(mu4e-mark-at-point mark target)
|
||||
;; single message
|
||||
(mu4e-mark-at-point mark target)
|
||||
;; mark all messages in the region.
|
||||
(save-excursion
|
||||
(let ((cant-go-further) (eor (region-end)))
|
||||
(goto-char (region-beginning))
|
||||
(while (and (< (point) eor) (not cant-go-further))
|
||||
(mu4e-mark-at-point mark target)
|
||||
(setq cant-go-further (not (mu4e-headers-next))))))))
|
||||
(goto-char (region-beginning))
|
||||
(while (and (< (point) eor) (not cant-go-further))
|
||||
(mu4e-mark-at-point mark target)
|
||||
(setq cant-go-further (not (mu4e-headers-next))))))))
|
||||
|
||||
(defun mu4e-mark-restore (docid)
|
||||
"Restore the visual mark for the message with DOCID."
|
||||
(let ((markcell (gethash docid mu4e~mark-map)))
|
||||
(when markcell
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-at-point (car markcell) (cdr markcell)))))))
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-at-point (car markcell) (cdr markcell)))))))
|
||||
|
||||
(defun mu4e~mark-get-markpair (prompt &optional allow-something)
|
||||
"Ask user with PROMPT for a mark and return (MARK . TARGET).
|
||||
If ALLOW-SOMETHING is non-nil, allow the 'something' pseudo mark
|
||||
as well."
|
||||
(let* ((marks (mapcar (lambda (markdescr)
|
||||
(cons (plist-get (cdr markdescr) :prompt)
|
||||
(car markdescr)))
|
||||
mu4e-marks))
|
||||
(marks
|
||||
(if allow-something
|
||||
marks (cl-remove-if (lambda (m) (eq 'something (cdr m))) marks)))
|
||||
(mark (mu4e-read-option prompt marks))
|
||||
(target (mu4e~mark-ask-target mark)))
|
||||
(cons (plist-get (cdr markdescr) :prompt)
|
||||
(car markdescr)))
|
||||
mu4e-marks))
|
||||
(marks
|
||||
(if allow-something
|
||||
marks (cl-remove-if (lambda (m) (eq 'something (cdr m))) marks)))
|
||||
(mark (mu4e-read-option prompt marks))
|
||||
(target (mu4e~mark-ask-target mark)))
|
||||
(cons mark target)))
|
||||
|
||||
(defun mu4e-mark-resolve-deferred-marks ()
|
||||
|
@ -353,24 +353,24 @@ If there are such marks, replace them with a _real_ mark (ask the
|
|||
user which one)."
|
||||
(interactive)
|
||||
(mu4e~mark-in-context
|
||||
(let ((markpair))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let ((mark (car val)))
|
||||
(when (eql mark 'something)
|
||||
(unless markpair
|
||||
(setq markpair
|
||||
(mu4e~mark-get-markpair "Set deferred mark(s) to: " nil)))
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-set (car markpair) (cdr markpair)))))))
|
||||
mu4e~mark-map))))
|
||||
(let ((markpair))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let ((mark (car val)))
|
||||
(when (eql mark 'something)
|
||||
(unless markpair
|
||||
(setq markpair
|
||||
(mu4e~mark-get-markpair "Set deferred mark(s) to: " nil)))
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-set (car markpair) (cdr markpair)))))))
|
||||
mu4e~mark-map))))
|
||||
|
||||
(defun mu4e~mark-check-target (target)
|
||||
"Check if TARGET exists; if not, offer to create it."
|
||||
(let ((fulltarget (concat (mu4e-root-maildir) target)))
|
||||
(if (not (mu4e-create-maildir-maybe fulltarget))
|
||||
(mu4e-error "Target dir %s does not exist " fulltarget)
|
||||
(mu4e-error "Target dir %s does not exist " fulltarget)
|
||||
target)))
|
||||
|
||||
(defun mu4e-mark-execute-all (&optional no-confirmation)
|
||||
|
@ -387,30 +387,30 @@ work well.
|
|||
If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
||||
(interactive)
|
||||
(mu4e~mark-in-context
|
||||
(let* ((marknum (hash-table-count mu4e~mark-map))
|
||||
(prompt (format "Are you sure you want to execute %d mark%s?"
|
||||
marknum (if (> marknum 1) "s" ""))))
|
||||
(let* ((marknum (hash-table-count mu4e~mark-map))
|
||||
(prompt (format "Are you sure you want to execute %d mark%s?"
|
||||
marknum (if (> marknum 1) "s" ""))))
|
||||
(if (zerop marknum)
|
||||
(mu4e-warn "Nothing is marked")
|
||||
(mu4e-warn "Nothing is marked")
|
||||
(mu4e-mark-resolve-deferred-marks)
|
||||
(when (or no-confirmation (y-or-n-p prompt))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let* ((mark (car val)) (target (cdr val))
|
||||
(markdescr (assq mark mu4e-marks))
|
||||
(msg (save-excursion
|
||||
(mu4e~headers-goto-docid docid)
|
||||
(mu4e-message-at-point))))
|
||||
;; note: whenever you do something with the message,
|
||||
;; it looses its N (new) flag
|
||||
(if markdescr
|
||||
(progn
|
||||
(run-hook-with-args
|
||||
'mu4e-mark-execute-pre-hook mark msg)
|
||||
(funcall (plist-get (cdr markdescr) :action)
|
||||
docid msg target))
|
||||
(mu4e-error "Unrecognized mark %S" mark))))
|
||||
mu4e~mark-map))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let* ((mark (car val)) (target (cdr val))
|
||||
(markdescr (assq mark mu4e-marks))
|
||||
(msg (save-excursion
|
||||
(mu4e~headers-goto-docid docid)
|
||||
(mu4e-message-at-point))))
|
||||
;; note: whenever you do something with the message,
|
||||
;; it looses its N (new) flag
|
||||
(if markdescr
|
||||
(progn
|
||||
(run-hook-with-args
|
||||
'mu4e-mark-execute-pre-hook mark msg)
|
||||
(funcall (plist-get (cdr markdescr) :action)
|
||||
docid msg target))
|
||||
(mu4e-error "Unrecognized mark %S" mark))))
|
||||
mu4e~mark-map))
|
||||
(mu4e-mark-unmark-all)
|
||||
(message nil)))))
|
||||
|
||||
|
@ -418,16 +418,16 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
|||
"Unmark all marked messages."
|
||||
(interactive)
|
||||
(mu4e~mark-in-context
|
||||
(when (or (null mu4e~mark-map) (zerop (hash-table-count mu4e~mark-map)))
|
||||
(mu4e-warn "Nothing is marked"))
|
||||
(maphash
|
||||
(lambda (docid _val)
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-set 'unmark))))
|
||||
mu4e~mark-map)
|
||||
;; in any case, clear the marks map
|
||||
(mu4e~mark-clear)))
|
||||
(when (or (null mu4e~mark-map) (zerop (hash-table-count mu4e~mark-map)))
|
||||
(mu4e-warn "Nothing is marked"))
|
||||
(maphash
|
||||
(lambda (docid _val)
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-set 'unmark))))
|
||||
mu4e~mark-map)
|
||||
;; in any case, clear the marks map
|
||||
(mu4e~mark-clear)))
|
||||
|
||||
(defun mu4e-mark-docid-marked-p (docid)
|
||||
"Is the given DOCID marked?"
|
||||
|
@ -437,7 +437,7 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
|||
(defun mu4e-mark-marks-num ()
|
||||
"Return the number of mark-instances in the current buffer."
|
||||
(mu4e~mark-in-context
|
||||
(if mu4e~mark-map (hash-table-count mu4e~mark-map) 0)))
|
||||
(if mu4e~mark-map (hash-table-count mu4e~mark-map) 0)))
|
||||
|
||||
(defun mu4e-mark-handle-when-leaving ()
|
||||
"Handle any mark-instances in the current buffer when leaving.
|
||||
|
@ -446,18 +446,18 @@ function is to be called before any further action (like searching,
|
|||
quitting the buffer) is taken; returning t means 'take the following
|
||||
action', return nil means 'don't do anything'."
|
||||
(mu4e~mark-in-context
|
||||
(let ((marknum (mu4e-mark-marks-num))
|
||||
(what mu4e-headers-leave-behavior))
|
||||
(unless (zerop marknum) ;; nothing to do?
|
||||
(when (eq what 'ask)
|
||||
(setq what (mu4e-read-option
|
||||
(format "There are %d existing mark(s); should we: "
|
||||
marknum)
|
||||
'( ("apply marks" . apply)
|
||||
("ignore marks?" . ignore)))))
|
||||
;; we determined what to do... now do it
|
||||
(when (eq what 'apply)
|
||||
(mu4e-mark-execute-all t))))))
|
||||
(let ((marknum (mu4e-mark-marks-num))
|
||||
(what mu4e-headers-leave-behavior))
|
||||
(unless (zerop marknum) ;; nothing to do?
|
||||
(when (eq what 'ask)
|
||||
(setq what (mu4e-read-option
|
||||
(format "There are %d existing mark(s); should we: "
|
||||
marknum)
|
||||
'( ("apply marks" . apply)
|
||||
("ignore marks?" . ignore)))))
|
||||
;; we determined what to do... now do it
|
||||
(when (eq what 'apply)
|
||||
(mu4e-mark-execute-all t))))))
|
||||
|
||||
(provide 'mu4e-mark)
|
||||
;;; mu4e-mark.el ends here
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
(defcustom mu4e-html2text-command
|
||||
(if (fboundp 'shr-insert-document)
|
||||
'mu4e-shr2text
|
||||
'mu4e-shr2text
|
||||
(progn (require 'html2text) 'html2text))
|
||||
"Either a shell command or a function that converts from html to plain text.
|
||||
|
||||
|
@ -124,7 +124,7 @@ Some notes on the format:
|
|||
Message view use the actual message file, and do include these fields."
|
||||
;; after all this documentation, the spectacular implementation
|
||||
(if msg
|
||||
(plist-get msg field)
|
||||
(plist-get msg field)
|
||||
(mu4e-error "Message must be non-nil")))
|
||||
|
||||
(defsubst mu4e-message-field (msg field)
|
||||
|
@ -136,16 +136,16 @@ Like `mu4e-message-field-nil', but will sanitize nil values:
|
|||
Thus, function will return nil for empty lists, non-existing body-txt or body-html."
|
||||
(let ((val (mu4e-message-field-raw msg field)))
|
||||
(cond
|
||||
(val
|
||||
val) ;; non-nil -> just return it
|
||||
((member field '(:subject :message-id :path :maildir :in-reply-to))
|
||||
"") ;; string fields except body-txt, body-html: nil -> ""
|
||||
((member field '(:body-html :body-txt))
|
||||
val)
|
||||
((member field '(:docid :size))
|
||||
0) ;; numeric type: nil -> 0
|
||||
(t
|
||||
val)))) ;; otherwise, just return nil
|
||||
(val
|
||||
val) ;; non-nil -> just return it
|
||||
((member field '(:subject :message-id :path :maildir :in-reply-to))
|
||||
"") ;; string fields except body-txt, body-html: nil -> ""
|
||||
((member field '(:body-html :body-txt))
|
||||
val)
|
||||
((member field '(:docid :size))
|
||||
0) ;; numeric type: nil -> 0
|
||||
(t
|
||||
val)))) ;; otherwise, just return nil
|
||||
|
||||
(defsubst mu4e-message-has-field (msg field)
|
||||
"If MSG has a FIELD return t, nil otherwise."
|
||||
|
@ -158,7 +158,7 @@ no such message. If optional NOERROR is non-nil, do not raise an
|
|||
error when there is no message at point."
|
||||
(let ((msg (or (get-text-property (point) 'msg) mu4e~view-message)))
|
||||
(if msg
|
||||
msg
|
||||
msg
|
||||
(unless noerror (mu4e-warn "No message at point")))))
|
||||
|
||||
(defsubst mu4e-message-field-at-point (field)
|
||||
|
@ -176,19 +176,19 @@ Determine whether we want
|
|||
to use html or text. The decision is based on PREFER-HTML and
|
||||
whether the message supports the given representation."
|
||||
(let* ((txt (mu4e-message-field msg :body-txt))
|
||||
(html (mu4e-message-field msg :body-html))
|
||||
(txt-len (length txt))
|
||||
(html-len (length html))
|
||||
(txt-limit (* mu4e-view-html-plaintext-ratio-heuristic txt-len))
|
||||
(txt-limit (if (>= txt-limit 0) txt-limit most-positive-fixnum)))
|
||||
(html (mu4e-message-field msg :body-html))
|
||||
(txt-len (length txt))
|
||||
(html-len (length html))
|
||||
(txt-limit (* mu4e-view-html-plaintext-ratio-heuristic txt-len))
|
||||
(txt-limit (if (>= txt-limit 0) txt-limit most-positive-fixnum)))
|
||||
(cond
|
||||
; user prefers html --> use html if there is
|
||||
(prefer-html (> html-len 0))
|
||||
;; otherwise (user prefers text) still use html if there is not enough
|
||||
;; text
|
||||
((< txt-limit html-len) t)
|
||||
;; otherwise, use text
|
||||
(t nil))))
|
||||
; user prefers html --> use html if there is
|
||||
(prefer-html (> html-len 0))
|
||||
;; otherwise (user prefers text) still use html if there is not enough
|
||||
;; text
|
||||
((< txt-limit html-len) t)
|
||||
;; otherwise, use text
|
||||
(t nil))))
|
||||
|
||||
(defun mu4e~message-body-has-content-type-param (msg param)
|
||||
"Does the MSG have a content-type parameter PARAM?"
|
||||
|
@ -207,29 +207,29 @@ will use that. Normally, this function prefers the text part,
|
|||
unless PREFER-HTML is non-nil."
|
||||
(setq mu4e~message-body-html (mu4e~message-use-html-p msg prefer-html))
|
||||
(let ((body
|
||||
(if mu4e~message-body-html
|
||||
;; use an htmml body
|
||||
(cond
|
||||
((stringp mu4e-html2text-command)
|
||||
(mu4e~html2text-shell msg mu4e-html2text-command))
|
||||
((functionp mu4e-html2text-command)
|
||||
(if (help-function-arglist mu4e-html2text-command)
|
||||
(funcall mu4e-html2text-command msg)
|
||||
;; oldskool parameterless mu4e-html2text-command
|
||||
(mu4e~html2text-wrapper mu4e-html2text-command msg)))
|
||||
(t (mu4e-error "Invalid `mu4e-html2text-command'")))
|
||||
;; use a text body
|
||||
(or (with-temp-buffer
|
||||
(insert (or (mu4e-message-field msg :body-txt) ""))
|
||||
(if (mu4e~safe-iequal "flowed"
|
||||
(mu4e~message-body-has-content-type-param
|
||||
msg "format"))
|
||||
(fill-flowed nil
|
||||
(mu4e~safe-iequal
|
||||
"yes"
|
||||
(mu4e~message-body-has-content-type-param
|
||||
msg "delsp"))))
|
||||
(buffer-string)) ""))))
|
||||
(if mu4e~message-body-html
|
||||
;; use an htmml body
|
||||
(cond
|
||||
((stringp mu4e-html2text-command)
|
||||
(mu4e~html2text-shell msg mu4e-html2text-command))
|
||||
((functionp mu4e-html2text-command)
|
||||
(if (help-function-arglist mu4e-html2text-command)
|
||||
(funcall mu4e-html2text-command msg)
|
||||
;; oldskool parameterless mu4e-html2text-command
|
||||
(mu4e~html2text-wrapper mu4e-html2text-command msg)))
|
||||
(t (mu4e-error "Invalid `mu4e-html2text-command'")))
|
||||
;; use a text body
|
||||
(or (with-temp-buffer
|
||||
(insert (or (mu4e-message-field msg :body-txt) ""))
|
||||
(if (mu4e~safe-iequal "flowed"
|
||||
(mu4e~message-body-has-content-type-param
|
||||
msg "format"))
|
||||
(fill-flowed nil
|
||||
(mu4e~safe-iequal
|
||||
"yes"
|
||||
(mu4e~message-body-has-content-type-param
|
||||
msg "delsp"))))
|
||||
(buffer-string)) ""))))
|
||||
(dolist (func mu4e-message-body-rewrite-functions)
|
||||
(setq body (funcall func msg body)))
|
||||
body))
|
||||
|
@ -245,10 +245,10 @@ replace with."
|
|||
(goto-char (point-min))
|
||||
(while (re-search-forward "[
]" nil t)
|
||||
(replace-match
|
||||
(cond
|
||||
((string= (match-string 0) "") "'")
|
||||
((string= (match-string 0) " ") " ")
|
||||
(t ""))))
|
||||
(cond
|
||||
((string= (match-string 0) "") "'")
|
||||
((string= (match-string 0) " ") " ")
|
||||
(t ""))))
|
||||
(buffer-string)))
|
||||
|
||||
(defun mu4e-message-contact-field-matches (msg cfield rx)
|
||||
|
@ -260,22 +260,22 @@ 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 (car cfield) rx)
|
||||
(mu4e-message-contact-field-matches msg (cdr cfield) rx))
|
||||
(when cfield
|
||||
(if (listp rx)
|
||||
;; if rx is a list, try each one of them for a match
|
||||
(cl-find-if
|
||||
(lambda (a-rx) (mu4e-message-contact-field-matches msg cfield a-rx))
|
||||
rx)
|
||||
;; not a list, check the rx
|
||||
(cl-find-if
|
||||
(lambda (ct)
|
||||
(let ((name (car ct)) (email (cdr ct)))
|
||||
(or
|
||||
(and name (string-match rx name))
|
||||
(and email (string-match rx email)))))
|
||||
(mu4e-message-field msg cfield))))))
|
||||
;; if rx is a list, try each one of them for a match
|
||||
(cl-find-if
|
||||
(lambda (a-rx) (mu4e-message-contact-field-matches msg cfield a-rx))
|
||||
rx)
|
||||
;; not a list, check the rx
|
||||
(cl-find-if
|
||||
(lambda (ct)
|
||||
(let ((name (car ct)) (email (cdr ct)))
|
||||
(or
|
||||
(and name (string-match rx name))
|
||||
(and email (string-match rx email)))))
|
||||
(mu4e-message-field msg cfield))))))
|
||||
|
||||
(defun mu4e-message-contact-field-matches-me (msg cfield)
|
||||
"Does contact-field CFIELD in MSG match me?
|
||||
|
@ -285,12 +285,12 @@ that is, any of the e-mail address in
|
|||
`(mu4e-personal-addresses)'. Returns the contact cell that
|
||||
matched, or nil."
|
||||
(cl-find-if
|
||||
(lambda (cc-cell)
|
||||
(cl-member-if
|
||||
(lambda (addr)
|
||||
(string= (downcase addr) (downcase (cdr cc-cell))))
|
||||
(mu4e-personal-addresses)))
|
||||
(mu4e-message-field msg cfield)))
|
||||
(lambda (cc-cell)
|
||||
(cl-member-if
|
||||
(lambda (addr)
|
||||
(string= (downcase addr) (downcase (cdr cc-cell))))
|
||||
(mu4e-personal-addresses)))
|
||||
(mu4e-message-field msg cfield)))
|
||||
|
||||
(defsubst mu4e-message-part-field (msgpart field)
|
||||
"Get some FIELD from MSGPART.
|
||||
|
@ -322,27 +322,27 @@ Return the buffer contents."
|
|||
This can be used in `mu4e-html2text-command' in a new enough
|
||||
Emacs. Based on code by Titus von der Malsburg."
|
||||
(mu4e~html2text-wrapper
|
||||
(lambda ()
|
||||
(let (
|
||||
;; When HTML emails contain references to remote images,
|
||||
;; retrieving these images leaks information. For example,
|
||||
;; the sender can see when I openend the email and from which
|
||||
;; computer (IP address). For this reason, it is preferrable
|
||||
;; to not retrieve images.
|
||||
;; See this discussion on mu-discuss:
|
||||
;; https://groups.google.com/forum/#!topic/mu-discuss/gr1cwNNZnXo
|
||||
(shr-inhibit-images t))
|
||||
(shr-render-region (point-min) (point-max)))) msg))
|
||||
(lambda ()
|
||||
(let (
|
||||
;; When HTML emails contain references to remote images,
|
||||
;; retrieving these images leaks information. For example,
|
||||
;; the sender can see when I openend the email and from which
|
||||
;; computer (IP address). For this reason, it is preferrable
|
||||
;; to not retrieve images.
|
||||
;; See this discussion on mu-discuss:
|
||||
;; https://groups.google.com/forum/#!topic/mu-discuss/gr1cwNNZnXo
|
||||
(shr-inhibit-images t))
|
||||
(shr-render-region (point-min) (point-max)))) msg))
|
||||
|
||||
(defun mu4e~html2text-shell (msg _cmd)
|
||||
"Convert html2 text in MSG using a shell function CMD."
|
||||
(mu4e~html2text-wrapper
|
||||
(lambda ()
|
||||
(let* ((tmp-file (mu4e-make-temp-file "html")))
|
||||
(write-region (point-min) (point-max) tmp-file)
|
||||
(erase-buffer)
|
||||
(call-process-shell-command mu4e-html2text-command tmp-file t t)
|
||||
(delete-file tmp-file))) msg))
|
||||
(lambda ()
|
||||
(let* ((tmp-file (mu4e-make-temp-file "html")))
|
||||
(write-region (point-min) (point-max) tmp-file)
|
||||
(erase-buffer)
|
||||
(call-process-shell-command mu4e-html2text-command tmp-file t t)
|
||||
(delete-file tmp-file))) msg))
|
||||
|
||||
(provide 'mu4e-message)
|
||||
;;; mu4e-message ends here
|
||||
|
|
|
@ -64,46 +64,46 @@ Example usage:
|
|||
(defun mu4e~org-store-link-query ()
|
||||
"Store a link to a mu4e query."
|
||||
(let* ((query (mu4e-last-query))
|
||||
(date (format-time-string (org-time-stamp-format)))
|
||||
;; seems we get an error when there's no date...
|
||||
(link (concat "mu4e:query:" query)))
|
||||
(date (format-time-string (org-time-stamp-format)))
|
||||
;; seems we get an error when there's no date...
|
||||
(link (concat "mu4e:query:" query)))
|
||||
(org-store-link-props
|
||||
:type "mu4e"
|
||||
:query query
|
||||
:date date)
|
||||
:type "mu4e"
|
||||
:query query
|
||||
:date date)
|
||||
(org-add-link-props
|
||||
:link link
|
||||
:description (format "mu4e-query: '%s'" query))
|
||||
:link link
|
||||
:description (format "mu4e-query: '%s'" query))
|
||||
link))
|
||||
|
||||
(defun mu4e~org-first-address (msg field)
|
||||
"Get address field FIELD from MSG as a string or nil."
|
||||
(let* ((val (plist-get msg field))
|
||||
(name (when val (car (car val))))
|
||||
(addr (when val (cdr (car val)))))
|
||||
(name (when val (car (car val))))
|
||||
(addr (when val (cdr (car val)))))
|
||||
(when val
|
||||
(if name
|
||||
(format "%s <%s>" name addr)
|
||||
(format "%s <%s>" name addr)
|
||||
(format "%s" addr)))))
|
||||
|
||||
(defun mu4e~org-store-link-message ()
|
||||
"Store a link to a mu4e message."
|
||||
(let* ((msg (mu4e-message-at-point))
|
||||
(msgid (or (plist-get msg :message-id) "<none>"))
|
||||
(date (plist-get msg :date))
|
||||
(date (format-time-string (org-time-stamp-format) date))
|
||||
;; seems we get an error when there's no date...
|
||||
(link (concat "mu4e:msgid:" msgid)))
|
||||
(msgid (or (plist-get msg :message-id) "<none>"))
|
||||
(date (plist-get msg :date))
|
||||
(date (format-time-string (org-time-stamp-format) date))
|
||||
;; seems we get an error when there's no date...
|
||||
(link (concat "mu4e:msgid:" msgid)))
|
||||
(org-store-link-props
|
||||
:type "mu4e"
|
||||
:message-id msgid
|
||||
:to (mu4e~org-first-address msg :to)
|
||||
:from (mu4e~org-first-address msg :from)
|
||||
:date date
|
||||
:subject (plist-get msg :subject))
|
||||
:type "mu4e"
|
||||
:message-id msgid
|
||||
:to (mu4e~org-first-address msg :to)
|
||||
:from (mu4e~org-first-address msg :from)
|
||||
:date date
|
||||
:subject (plist-get msg :subject))
|
||||
(org-add-link-props
|
||||
:link link
|
||||
:description (funcall mu4e-org-link-desc-func msg))
|
||||
:link link
|
||||
:description (funcall mu4e-org-link-desc-func msg))
|
||||
link))
|
||||
|
||||
(defun mu4e-org-store-link ()
|
||||
|
@ -113,8 +113,8 @@ It links to the last known query when in `mu4e-headers-mode' with
|
|||
a specific message, based on its message-id, so that links stay
|
||||
valid even after moving the message around."
|
||||
(if (and (eq major-mode 'mu4e-headers-mode)
|
||||
mu4e-org-link-query-in-headers-mode)
|
||||
(mu4e~org-store-link-query)
|
||||
mu4e-org-link-query-in-headers-mode)
|
||||
(mu4e~org-store-link-query)
|
||||
(when (mu4e-message-at-point t)
|
||||
(mu4e~org-store-link-message))))
|
||||
|
||||
|
@ -122,8 +122,8 @@ valid even after moving the message around."
|
|||
;; org-link-set-parameters method
|
||||
(if (fboundp 'org-link-set-parameters)
|
||||
(org-link-set-parameters "mu4e"
|
||||
:follow #'mu4e-org-open
|
||||
:store #'mu4e-org-store-link)
|
||||
:follow #'mu4e-org-open
|
||||
:store #'mu4e-org-store-link)
|
||||
(org-add-link-type "mu4e" 'mu4e-org-open)
|
||||
(add-hook 'org-store-link-functions 'mu4e-org-store-link))
|
||||
|
||||
|
@ -133,11 +133,11 @@ Open the mu4e message (for links starting with 'msgid:') or run
|
|||
the query (for links starting with 'query:')."
|
||||
(require 'mu4e)
|
||||
(cond
|
||||
((string-match "^msgid:\\(.+\\)" link)
|
||||
(mu4e-view-message-with-message-id (match-string 1 link)))
|
||||
((string-match "^query:\\(.+\\)" link)
|
||||
(mu4e-headers-search (match-string 1 link) current-prefix-arg))
|
||||
(t (mu4e-error "Unrecognized link type '%s'" link))))
|
||||
((string-match "^msgid:\\(.+\\)" link)
|
||||
(mu4e-view-message-with-message-id (match-string 1 link)))
|
||||
((string-match "^query:\\(.+\\)" link)
|
||||
(mu4e-headers-search (match-string 1 link) current-prefix-arg))
|
||||
(t (mu4e-error "Unrecognized link type '%s'" link))))
|
||||
|
||||
(make-obsolete 'org-mu4e-open 'mu4e-org-open "1.3.6")
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"Each expression starts with a length cookie:
|
||||
<`mu4e~cookie-pre'><length-in-hex><`mu4e~cookie-post'>.")
|
||||
(defconst mu4e~cookie-post "\377"
|
||||
"Each expression starts with a length cookie:
|
||||
"Each expression starts with a length cookie:
|
||||
<`mu4e~cookie-pre'><length-in-hex><`mu4e~cookie-post'>.")
|
||||
(defconst mu4e~cookie-matcher-rx
|
||||
(concat mu4e~cookie-pre "\\([[:xdigit:]]+\\)" mu4e~cookie-post)
|
||||
|
@ -57,8 +57,8 @@ Match 1 will be the length (in hex).")
|
|||
(defun mu4e~proc-running-p ()
|
||||
"Whether the mu process is running."
|
||||
(when (and mu4e~proc-process
|
||||
(memq (process-status mu4e~proc-process)
|
||||
'(run open listen connect stop)))
|
||||
(memq (process-status mu4e~proc-process)
|
||||
'(run open listen connect stop)))
|
||||
t))
|
||||
|
||||
(defsubst mu4e~proc-eat-sexp-from-buf ()
|
||||
|
@ -73,23 +73,23 @@ removed."
|
|||
;; mu4e~cookie-matcher-rx:
|
||||
;; (concat mu4e~cookie-pre "\\([[:xdigit:]]+\\)]" mu4e~cookie-post)
|
||||
(let ((b (string-match mu4e~cookie-matcher-rx mu4e~proc-buf))
|
||||
(sexp-len) (objcons))
|
||||
(sexp-len) (objcons))
|
||||
(when b
|
||||
(setq sexp-len (string-to-number (match-string 1 mu4e~proc-buf) 16))
|
||||
;; does mu4e~proc-buf contain the full sexp?
|
||||
(when (>= (length mu4e~proc-buf) (+ sexp-len (match-end 0)))
|
||||
;; clear-up start
|
||||
(setq mu4e~proc-buf (substring mu4e~proc-buf (match-end 0)))
|
||||
;; note: we read the input in binary mode -- here, we take the part
|
||||
;; that is the sexp, and convert that to utf-8, before we interpret
|
||||
;; it.
|
||||
(setq objcons (read-from-string
|
||||
(decode-coding-string
|
||||
(substring mu4e~proc-buf 0 sexp-len)
|
||||
'utf-8 t)))
|
||||
(when objcons
|
||||
(setq mu4e~proc-buf (substring mu4e~proc-buf sexp-len))
|
||||
(car objcons)))))))
|
||||
(setq sexp-len (string-to-number (match-string 1 mu4e~proc-buf) 16))
|
||||
;; does mu4e~proc-buf contain the full sexp?
|
||||
(when (>= (length mu4e~proc-buf) (+ sexp-len (match-end 0)))
|
||||
;; clear-up start
|
||||
(setq mu4e~proc-buf (substring mu4e~proc-buf (match-end 0)))
|
||||
;; note: we read the input in binary mode -- here, we take the part
|
||||
;; that is the sexp, and convert that to utf-8, before we interpret
|
||||
;; it.
|
||||
(setq objcons (read-from-string
|
||||
(decode-coding-string
|
||||
(substring mu4e~proc-buf 0 sexp-len)
|
||||
'utf-8 t)))
|
||||
(when objcons
|
||||
(setq mu4e~proc-buf (substring mu4e~proc-buf sexp-len))
|
||||
(car objcons)))))))
|
||||
|
||||
|
||||
(defun mu4e~proc-filter (_proc str)
|
||||
|
@ -154,81 +154,81 @@ The server output is as follows:
|
|||
(let ((sexp (mu4e~proc-eat-sexp-from-buf)))
|
||||
(with-local-quit
|
||||
(while sexp
|
||||
(mu4e-log 'from-server "%S" sexp)
|
||||
(cond
|
||||
;; a header plist can be recognized by the existence of a :date field
|
||||
((plist-get sexp :date)
|
||||
(funcall mu4e-header-func sexp))
|
||||
(mu4e-log 'from-server "%S" sexp)
|
||||
(cond
|
||||
;; a header plist can be recognized by the existence of a :date field
|
||||
((plist-get sexp :date)
|
||||
(funcall mu4e-header-func sexp))
|
||||
|
||||
;; the found sexp, we receive after getting all the headers
|
||||
((plist-get sexp :found)
|
||||
(funcall mu4e-found-func (plist-get sexp :found)))
|
||||
;; the found sexp, we receive after getting all the headers
|
||||
((plist-get sexp :found)
|
||||
(funcall mu4e-found-func (plist-get sexp :found)))
|
||||
|
||||
;; viewing a specific message
|
||||
((plist-get sexp :view)
|
||||
(funcall mu4e-view-func (plist-get sexp :view)))
|
||||
;; viewing a specific message
|
||||
((plist-get sexp :view)
|
||||
(funcall mu4e-view-func (plist-get sexp :view)))
|
||||
|
||||
;; receive an erase message
|
||||
((plist-get sexp :erase)
|
||||
(funcall mu4e-erase-func))
|
||||
;; receive an erase message
|
||||
((plist-get sexp :erase)
|
||||
(funcall mu4e-erase-func))
|
||||
|
||||
;; receive a :sent message
|
||||
((plist-get sexp :sent)
|
||||
(funcall mu4e-sent-func
|
||||
(plist-get sexp :docid)
|
||||
(plist-get sexp :path)))
|
||||
;; receive a :sent message
|
||||
((plist-get sexp :sent)
|
||||
(funcall mu4e-sent-func
|
||||
(plist-get sexp :docid)
|
||||
(plist-get sexp :path)))
|
||||
|
||||
;; received a pong message
|
||||
((plist-get sexp :pong)
|
||||
(funcall mu4e-pong-func sexp))
|
||||
;; received a pong message
|
||||
((plist-get sexp :pong)
|
||||
(funcall mu4e-pong-func sexp))
|
||||
|
||||
;; received a contacts message
|
||||
;; note: we use 'member', to match (:contacts nil)
|
||||
((plist-member sexp :contacts)
|
||||
(funcall mu4e-contacts-func
|
||||
(plist-get sexp :contacts)
|
||||
(plist-get sexp :tstamp)))
|
||||
;; received a contacts message
|
||||
;; note: we use 'member', to match (:contacts nil)
|
||||
((plist-member sexp :contacts)
|
||||
(funcall mu4e-contacts-func
|
||||
(plist-get sexp :contacts)
|
||||
(plist-get sexp :tstamp)))
|
||||
|
||||
;; something got moved/flags changed
|
||||
((plist-get sexp :update)
|
||||
(funcall mu4e-update-func
|
||||
(plist-get sexp :update)
|
||||
(plist-get sexp :move)
|
||||
(plist-get sexp :maybe-view)))
|
||||
;; something got moved/flags changed
|
||||
((plist-get sexp :update)
|
||||
(funcall mu4e-update-func
|
||||
(plist-get sexp :update)
|
||||
(plist-get sexp :move)
|
||||
(plist-get sexp :maybe-view)))
|
||||
|
||||
;; a message got removed
|
||||
((plist-get sexp :remove)
|
||||
(funcall mu4e-remove-func (plist-get sexp :remove)))
|
||||
;; a message got removed
|
||||
((plist-get sexp :remove)
|
||||
(funcall mu4e-remove-func (plist-get sexp :remove)))
|
||||
|
||||
;; start composing a new message
|
||||
((plist-get sexp :compose)
|
||||
(funcall mu4e-compose-func
|
||||
(plist-get sexp :compose)
|
||||
(plist-get sexp :original)
|
||||
(plist-get sexp :include)))
|
||||
;; start composing a new message
|
||||
((plist-get sexp :compose)
|
||||
(funcall mu4e-compose-func
|
||||
(plist-get sexp :compose)
|
||||
(plist-get sexp :original)
|
||||
(plist-get sexp :include)))
|
||||
|
||||
;; do something with a temporary file
|
||||
((plist-get sexp :temp)
|
||||
(funcall mu4e-temp-func
|
||||
(plist-get sexp :temp) ;; name of the temp file
|
||||
(plist-get sexp :what) ;; what to do with it
|
||||
;; (pipe|emacs|open-with...)
|
||||
(plist-get sexp :docid) ;; docid of the message
|
||||
(plist-get sexp :param)));; parameter for the action
|
||||
;; do something with a temporary file
|
||||
((plist-get sexp :temp)
|
||||
(funcall mu4e-temp-func
|
||||
(plist-get sexp :temp) ;; name of the temp file
|
||||
(plist-get sexp :what) ;; what to do with it
|
||||
;; (pipe|emacs|open-with...)
|
||||
(plist-get sexp :docid) ;; docid of the message
|
||||
(plist-get sexp :param)));; parameter for the action
|
||||
|
||||
;; get some info
|
||||
((plist-get sexp :info)
|
||||
(funcall mu4e-info-func sexp))
|
||||
;; get some info
|
||||
((plist-get sexp :info)
|
||||
(funcall mu4e-info-func sexp))
|
||||
|
||||
;; receive an error
|
||||
((plist-get sexp :error)
|
||||
(funcall mu4e-error-func
|
||||
(plist-get sexp :error)
|
||||
(plist-get sexp :message)))
|
||||
;; receive an error
|
||||
((plist-get sexp :error)
|
||||
(funcall mu4e-error-func
|
||||
(plist-get sexp :error)
|
||||
(plist-get sexp :message)))
|
||||
|
||||
(t (mu4e-message "Unexpected data from server [%S]" sexp)))
|
||||
(t (mu4e-message "Unexpected data from server [%S]" sexp)))
|
||||
|
||||
(setq sexp (mu4e~proc-eat-sexp-from-buf))))))
|
||||
(setq sexp (mu4e~proc-eat-sexp-from-buf))))))
|
||||
|
||||
(defun mu4e~escape (str)
|
||||
"Escape string STR for transport.
|
||||
|
@ -252,12 +252,12 @@ Start the process if needed."
|
|||
(unless (file-executable-p mu4e-mu-binary)
|
||||
(mu4e-error (format "`mu4e-mu-binary' (%S) not found" mu4e-mu-binary)))
|
||||
(let* ((process-connection-type nil) ;; use a pipe
|
||||
(args (when mu4e-mu-home `(,(format"--muhome=%s" mu4e-mu-home))))
|
||||
(args (cons "server" args)))
|
||||
(args (when mu4e-mu-home `(,(format"--muhome=%s" mu4e-mu-home))))
|
||||
(args (cons "server" args)))
|
||||
(setq mu4e~proc-buf "")
|
||||
(setq mu4e~proc-process (apply 'start-process
|
||||
mu4e~proc-name mu4e~proc-name
|
||||
mu4e-mu-binary args))
|
||||
mu4e~proc-name mu4e~proc-name
|
||||
mu4e-mu-binary args))
|
||||
;; register a function for (:info ...) sexps
|
||||
(unless mu4e~proc-process
|
||||
(mu4e-error "Failed to start the mu4e backend"))
|
||||
|
@ -269,7 +269,7 @@ Start the process if needed."
|
|||
(defun mu4e~proc-kill ()
|
||||
"Kill the mu server process."
|
||||
(let* ((buf (get-buffer mu4e~proc-name))
|
||||
(proc (and (buffer-live-p buf) (get-buffer-process buf))))
|
||||
(proc (and (buffer-live-p buf) (get-buffer-process buf))))
|
||||
(when proc
|
||||
(let ((delete-exited-processes t))
|
||||
(mu4e~call-mu '(quit)))
|
||||
|
@ -277,8 +277,8 @@ Start the process if needed."
|
|||
(ignore-errors
|
||||
(signal-process proc 'SIGINT))))
|
||||
(setq
|
||||
mu4e~proc-process nil
|
||||
mu4e~proc-buf nil))
|
||||
mu4e~proc-process nil
|
||||
mu4e~proc-buf nil))
|
||||
|
||||
;; error codes are defined in src/mu-util
|
||||
;;(defconst mu4e-xapian-empty 19 "Error code: xapian is empty/non-existent")
|
||||
|
@ -289,20 +289,20 @@ Start the process if needed."
|
|||
(setq mu4e~proc-process nil)
|
||||
(setq mu4e~proc-buf "") ;; clear any half-received sexps
|
||||
(cond
|
||||
((eq status 'signal)
|
||||
(cond
|
||||
((or(eq code 9) (eq code 2)) (message nil))
|
||||
;;(message "the mu server process has been stopped"))
|
||||
(t (error (format "mu server process received signal %d" code)))))
|
||||
((eq status 'exit)
|
||||
(cond
|
||||
((eq code 0)
|
||||
(message nil)) ;; don't do anything
|
||||
((eq code 19)
|
||||
(error "Database is locked by another process"))
|
||||
(t (error "Mu server process ended with exit code %d" code))))
|
||||
(t
|
||||
(error "Something bad happened to the mu server process")))))
|
||||
((eq status 'signal)
|
||||
(cond
|
||||
((or(eq code 9) (eq code 2)) (message nil))
|
||||
;;(message "the mu server process has been stopped"))
|
||||
(t (error (format "mu server process received signal %d" code)))))
|
||||
((eq status 'exit)
|
||||
(cond
|
||||
((eq code 0)
|
||||
(message nil)) ;; don't do anything
|
||||
((eq code 19)
|
||||
(error "Database is locked by another process"))
|
||||
(t (error "Mu server process ended with exit code %d" code))))
|
||||
(t
|
||||
(error "Something bad happened to the mu server process")))))
|
||||
|
||||
(defun mu4e~call-mu (form)
|
||||
"Call 'mu' with some command."
|
||||
|
@ -314,7 +314,7 @@ Start the process if needed."
|
|||
(defun mu4e~docid-msgid-param (docid-or-msgid)
|
||||
"Construct a backend parameter based on DOCID-OR-MSGID."
|
||||
(if (stringp docid-or-msgid)
|
||||
`(:msgid ,(mu4e~escape docid-or-msgid))
|
||||
`(:msgid ,(mu4e~escape docid-or-msgid))
|
||||
`(:docid ,docid-or-msgid)))
|
||||
|
||||
(defun mu4e~proc-add (path)
|
||||
|
@ -332,9 +332,9 @@ editing, resending) with DOCID or nil for type `new'.
|
|||
The result is delivered to the function registered as
|
||||
`mu4e-compose-func'."
|
||||
(mu4e~call-mu `(compose
|
||||
:type ,type
|
||||
:extract-encrypted ,decrypt
|
||||
:docid ,docid)))
|
||||
:type ,type
|
||||
:extract-encrypted ,decrypt
|
||||
:docid ,docid)))
|
||||
|
||||
(defun mu4e~proc-contacts (personal after tstamp)
|
||||
"Ask for contacts with PERSONAL AFTER TSTAMP.
|
||||
|
@ -343,12 +343,12 @@ response. If PERSONAL is non-nil, only get personal contacts, if
|
|||
AFTER is non-nil, get only contacts seen AFTER (the time_t
|
||||
value)."
|
||||
(mu4e~call-mu `(contacts
|
||||
:personal ,personal
|
||||
:after ,(or after nil)
|
||||
:tstamp ,(or tstamp nil))))
|
||||
:personal ,personal
|
||||
:after ,(or after nil)
|
||||
:tstamp ,(or tstamp nil))))
|
||||
|
||||
(defun mu4e~proc-extract (action docid index decrypt
|
||||
&optional path what param)
|
||||
&optional path what param)
|
||||
"Perform ACTION on part with DOCID INDEX DECRYPT PATH WHAT PARAM.
|
||||
Use a message with DOCID and perform ACTION on it (as symbol,
|
||||
either `save', `open', `temp') which mean: * save: save the part
|
||||
|
@ -357,16 +357,16 @@ with the default application registered for doing so * temp: save
|
|||
to a temporary file, then respond with
|
||||
(:temp <path> :what <what> :param <param>)."
|
||||
(mu4e~call-mu `(extract
|
||||
:action ,action
|
||||
:docid ,docid
|
||||
:index ,index
|
||||
:decrypt ,decrypt
|
||||
:path ,path
|
||||
:what ,what
|
||||
:param ,param)))
|
||||
:action ,action
|
||||
:docid ,docid
|
||||
:index ,index
|
||||
:decrypt ,decrypt
|
||||
:path ,path
|
||||
:what ,what
|
||||
:param ,param)))
|
||||
|
||||
(defun mu4e~proc-find (query threads sortfield sortdir maxnum skip-dups
|
||||
include-related)
|
||||
include-related)
|
||||
"Run QUERY with THREADS SORTFIELD SORTDIR MAXNUM SKIP-DUPS INCLUDE-RELATED.
|
||||
If THREADS is non-nil, show results in threaded fashion, SORTFIELD
|
||||
is a symbol describing the field to sort by (or nil); see
|
||||
|
@ -383,13 +383,13 @@ kind of result. The variables `mu4e-error-func' contain the
|
|||
function that will be called for, resp., a message (header row)
|
||||
or an error."
|
||||
(mu4e~call-mu `(find
|
||||
:query ,query
|
||||
:threads ,threads
|
||||
:sortfield ,sortfield
|
||||
:reverse ,(if (eq sortdir 'descending) t nil)
|
||||
:maxnum ,maxnum
|
||||
:skip-dups ,skip-dups
|
||||
:include-related ,include-related)))
|
||||
:query ,query
|
||||
:threads ,threads
|
||||
:sortfield ,sortfield
|
||||
:reverse ,(if (eq sortdir 'descending) t nil)
|
||||
:maxnum ,maxnum
|
||||
:skip-dups ,skip-dups
|
||||
:include-related ,include-related)))
|
||||
|
||||
(defun mu4e~proc-index (&optional cleanup lazy-check)
|
||||
"Index messages with possible CLEANUP and LAZY-CHECK.
|
||||
|
@ -440,15 +440,15 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my
|
|||
(unless (or maildir flags)
|
||||
(mu4e-error "At least one of maildir and flags must be specified"))
|
||||
(unless (or (not maildir)
|
||||
(file-exists-p (concat (mu4e-root-maildir) "/" maildir "/")))
|
||||
(file-exists-p (concat (mu4e-root-maildir) "/" maildir "/")))
|
||||
(mu4e-error "Target dir does not exist"))
|
||||
(mu4e~call-mu `(move
|
||||
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
|
||||
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
|
||||
:flags ,(or flags nil)
|
||||
:maildir ,(or maildir nil)
|
||||
:rename ,(and maildir mu4e-change-filenames-when-moving)
|
||||
:noview ,no-view)))
|
||||
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
|
||||
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
|
||||
:flags ,(or flags nil)
|
||||
:maildir ,(or maildir nil)
|
||||
:rename ,(and maildir mu4e-change-filenames-when-moving)
|
||||
:noview ,no-view)))
|
||||
|
||||
(defun mu4e~proc-ping (&optional queries)
|
||||
"Sends a ping to the mu server, expecting a (:pong ...) in response.
|
||||
|
@ -477,10 +477,10 @@ attached to the message, and return them as temp files. DECRYPT
|
|||
if necessary. The result will be delivered to the function
|
||||
registered as `mu4e-view-func'."
|
||||
(mu4e~call-mu `(view
|
||||
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
|
||||
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
|
||||
:extract-images ,images
|
||||
:extract-encrypted ,decrypt)))
|
||||
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
|
||||
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
|
||||
:extract-images ,images
|
||||
:extract-encrypted ,decrypt)))
|
||||
|
||||
(defun mu4e~proc-view-path (path &optional images decrypt)
|
||||
"View message at PATH..
|
||||
|
@ -489,9 +489,9 @@ attached to the message, and return them as temp files. The
|
|||
result will be delivered to the function registered as
|
||||
`mu4e-view-func'. Optionally DECRYPT."
|
||||
(mu4e~call-mu `(view
|
||||
:path ,path
|
||||
:extract-images ,images
|
||||
:extract-encrypted ,decrypt)))
|
||||
:path ,path
|
||||
:extract-images ,images
|
||||
:extract-encrypted ,decrypt)))
|
||||
|
||||
(provide 'mu4e-proc)
|
||||
;;; mu4e-proc.el ends here
|
||||
|
|
|
@ -55,15 +55,15 @@
|
|||
(defun mu4e-speedbar-install-variables ()
|
||||
"Install those variables used by speedbar to enhance mu4e."
|
||||
(add-hook 'mu4e-context-changed-hook
|
||||
(lambda()
|
||||
(when (buffer-live-p speedbar-buffer)
|
||||
(with-current-buffer speedbar-buffer
|
||||
(let ((inhibit-read-only t))
|
||||
(mu4e-speedbar-buttons))))))
|
||||
(lambda()
|
||||
(when (buffer-live-p speedbar-buffer)
|
||||
(with-current-buffer speedbar-buffer
|
||||
(let ((inhibit-read-only t))
|
||||
(mu4e-speedbar-buttons))))))
|
||||
(dolist (keymap
|
||||
'( mu4e-main-speedbar-key-map
|
||||
mu4e-headers-speedbar-key-map
|
||||
mu4e-view-speedbar-key-map))
|
||||
'( mu4e-main-speedbar-key-map
|
||||
mu4e-headers-speedbar-key-map
|
||||
mu4e-view-speedbar-key-map))
|
||||
(unless keymap
|
||||
(setq keymap (speedbar-make-specialized-keymap))
|
||||
(define-key keymap "RET" 'speedbar-edit-line)
|
||||
|
@ -71,7 +71,7 @@
|
|||
|
||||
;; Make sure our special speedbar major mode is loaded
|
||||
(if (featurep 'speedbar)
|
||||
(mu4e-speedbar-install-variables)
|
||||
(mu4e-speedbar-install-variables)
|
||||
(add-hook 'speedbar-load-hook 'mu4e-speedbar-install-variables))
|
||||
|
||||
(defun mu4e~speedbar-render-maildir-list ()
|
||||
|
@ -80,19 +80,19 @@
|
|||
(when (buffer-live-p speedbar-buffer)
|
||||
(with-current-buffer speedbar-buffer
|
||||
(mapcar (lambda (maildir-name)
|
||||
(speedbar-insert-button
|
||||
(concat " " maildir-name)
|
||||
'mu4e-highlight-face
|
||||
'highlight
|
||||
'mu4e~speedbar-maildir
|
||||
maildir-name))
|
||||
(mu4e-get-maildirs)))))
|
||||
(speedbar-insert-button
|
||||
(concat " " maildir-name)
|
||||
'mu4e-highlight-face
|
||||
'highlight
|
||||
'mu4e~speedbar-maildir
|
||||
maildir-name))
|
||||
(mu4e-get-maildirs)))))
|
||||
|
||||
(defun mu4e~speedbar-maildir (&optional _text token _ident)
|
||||
"Jump to maildir TOKEN. TEXT and INDENT are not used."
|
||||
(dframe-with-attached-buffer
|
||||
(mu4e-headers-search (concat "\"maildir:" token "\"")
|
||||
current-prefix-arg)))
|
||||
(mu4e-headers-search (concat "\"maildir:" token "\"")
|
||||
current-prefix-arg)))
|
||||
|
||||
(defun mu4e~speedbar-render-bookmark-list ()
|
||||
"Insert the list of bookmarks in the speedbar"
|
||||
|
@ -100,17 +100,17 @@
|
|||
(mapcar (lambda (bookmark)
|
||||
(unless (plist-get bookmark :hide)
|
||||
(speedbar-insert-button
|
||||
(concat " " (plist-get bookmark :name))
|
||||
'mu4e-highlight-face
|
||||
'highlight
|
||||
'mu4e~speedbar-bookmark
|
||||
(plist-get bookmark :query))))
|
||||
(mu4e-bookmarks)))
|
||||
(concat " " (plist-get bookmark :name))
|
||||
'mu4e-highlight-face
|
||||
'highlight
|
||||
'mu4e~speedbar-bookmark
|
||||
(plist-get bookmark :query))))
|
||||
(mu4e-bookmarks)))
|
||||
|
||||
(defun mu4e~speedbar-bookmark (&optional _text token _ident)
|
||||
"Run bookmarked query TOKEN. TEXT and INDENT are not used."
|
||||
(dframe-with-attached-buffer
|
||||
(mu4e-headers-search token current-prefix-arg)))
|
||||
(mu4e-headers-search token current-prefix-arg)))
|
||||
|
||||
;;;###autoload
|
||||
(defun mu4e-speedbar-buttons (&optional _buffer)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,7 +40,7 @@
|
|||
defaults, based on the XDG Base Directory Specification."
|
||||
:group 'mu4e
|
||||
:type '(choice (const :tag "Default location" nil)
|
||||
(directory :tag "Specify location"))
|
||||
(directory :tag "Specify location"))
|
||||
:safe 'stringp)
|
||||
|
||||
(defcustom mu4e-mu-binary (executable-find "mu")
|
||||
|
@ -52,7 +52,7 @@ path."
|
|||
:safe 'stringp)
|
||||
|
||||
(make-obsolete-variable 'mu4e-maildir
|
||||
"determined by server; see `mu4e-root-maildir'." "1.3.8")
|
||||
"determined by server; see `mu4e-root-maildir'." "1.3.8")
|
||||
|
||||
(defcustom mu4e-org-support t
|
||||
"Support org-mode links."
|
||||
|
@ -103,7 +103,7 @@ corresponding message file in the filesystem.
|
|||
|
||||
Having this option as t ensures that no non-existing messages are
|
||||
shown but can also be quite slow with large message stores."
|
||||
:type 'boolean :group 'mu4e :safe 'booleanp)
|
||||
:type 'boolean :group 'mu4e :safe 'booleanp)
|
||||
|
||||
(defcustom mu4e-index-lazy-check nil
|
||||
"Whether to only use a 'lazy check' during reindexing.
|
||||
|
@ -119,7 +119,7 @@ faster." :type 'boolean :group 'mu4e :safe 'booleanp)
|
|||
If nil, don't update automatically. Note, changes in
|
||||
`mu4e-update-interval' only take effect after restarting mu4e."
|
||||
:type '(choice (const :tag "No automatic update" nil)
|
||||
(integer :tag "Seconds"))
|
||||
(integer :tag "Seconds"))
|
||||
:group 'mu4e
|
||||
:safe 'integerp)
|
||||
|
||||
|
@ -156,11 +156,11 @@ the attachment dir. See Info node `(mu4e) Attachments' for details."
|
|||
|
||||
;; don't use the older vars anymore
|
||||
(make-obsolete-variable 'mu4e-user-mail-address-regexp
|
||||
'mu4e-user-mail-address-list "0.9.9.x")
|
||||
'mu4e-user-mail-address-list "0.9.9.x")
|
||||
(make-obsolete-variable 'mu4e-my-email-addresses
|
||||
'mu4e-user-mail-address-list "0.9.9.x")
|
||||
'mu4e-user-mail-address-list "0.9.9.x")
|
||||
(make-obsolete-variable 'mu4e-user-mail-address-list
|
||||
"determined by server; see `mu4e-personal-addresses'." "1.3.8")
|
||||
"determined by server; see `mu4e-personal-addresses'." "1.3.8")
|
||||
|
||||
(defcustom mu4e-use-fancy-chars nil
|
||||
"When set, allow fancy (Unicode) characters for marks/threads.
|
||||
|
@ -200,18 +200,18 @@ are plists" "1.3.7")
|
|||
|
||||
(defcustom mu4e-bookmarks
|
||||
'(( :name "Unread messages"
|
||||
:query "flag:unread AND NOT flag:trashed"
|
||||
:key ?u)
|
||||
:query "flag:unread AND NOT flag:trashed"
|
||||
:key ?u)
|
||||
( :name "Today's messages"
|
||||
:query "date:today..now"
|
||||
:key ?t)
|
||||
:query "date:today..now"
|
||||
:key ?t)
|
||||
( :name "Last 7 days"
|
||||
:query "date:7d..now"
|
||||
:show-unread t
|
||||
:key ?w)
|
||||
:query "date:7d..now"
|
||||
:show-unread t
|
||||
:key ?w)
|
||||
( :name "Messages with images"
|
||||
:query "mime:image/*"
|
||||
:key ?p))
|
||||
:query "mime:image/*"
|
||||
:key ?p))
|
||||
"List of pre-defined queries that are shown on the main screen.
|
||||
|
||||
Each of the list elements is a plist with at least:
|
||||
|
@ -247,9 +247,9 @@ A symbol which is either:
|
|||
Also see `mu4e-headers-visible-lines'
|
||||
and `mu4e-headers-visible-columns'."
|
||||
:type '(choice (const :tag "Split horizontally" horizontal)
|
||||
(const :tag "Split vertically" vertical)
|
||||
(const :tag "Single window" single-window)
|
||||
(const :tag "Don't split" nil))
|
||||
(const :tag "Split vertically" vertical)
|
||||
(const :tag "Single window" single-window)
|
||||
(const :tag "Don't split" nil))
|
||||
:group 'mu4e-headers)
|
||||
|
||||
(defcustom mu4e-view-max-specpdl-size 4096
|
||||
|
@ -263,7 +263,7 @@ and `mu4e-headers-visible-columns'."
|
|||
:group 'mu4e-view)
|
||||
|
||||
(make-obsolete-variable 'mu4e-show-images
|
||||
'mu4e-view-show-images "0.9.9.x")
|
||||
'mu4e-view-show-images "0.9.9.x")
|
||||
|
||||
(defcustom mu4e-confirm-quit t
|
||||
"Whether to confirm to quit mu4e."
|
||||
|
@ -306,12 +306,12 @@ contexts match, we have the following choices:
|
|||
|
||||
Also see `mu4e-compose-context-policy'."
|
||||
:type '(choice
|
||||
(const :tag "Always ask what context to use, even if one matches"
|
||||
always-ask)
|
||||
(const :tag "Ask if none of the contexts match" ask)
|
||||
(const :tag "Ask when there's no context yet" ask-if-none)
|
||||
(const :tag "Pick the first context if none match" pick-first)
|
||||
(const :tag "Don't change the context when none match" nil))
|
||||
(const :tag "Always ask what context to use, even if one matches"
|
||||
always-ask)
|
||||
(const :tag "Ask if none of the contexts match" ask)
|
||||
(const :tag "Ask when there's no context yet" ask-if-none)
|
||||
(const :tag "Pick the first context if none match" pick-first)
|
||||
(const :tag "Don't change the context when none match" nil))
|
||||
:group 'mu4e)
|
||||
|
||||
;; crypto
|
||||
|
@ -331,8 +331,8 @@ The setting is a symbol:
|
|||
* `ask': ask before decrypting anything
|
||||
* nil: don't try to decrypt anything."
|
||||
:type '(choice (const :tag "Try to decrypt automatically" t)
|
||||
(const :tag "Ask before decrypting anything" ask)
|
||||
(const :tag "Don't try to decrypt anything" nil))
|
||||
(const :tag "Ask before decrypting anything" ask)
|
||||
(const :tag "Don't try to decrypt anything" nil))
|
||||
:group 'mu4e-crypto)
|
||||
|
||||
;; completion; we put them here rather than in mu4e-compose, as mu4e-utils needs
|
||||
|
@ -376,14 +376,14 @@ time-based restriction."
|
|||
"Return the name and the mail-address of a CONTACT.
|
||||
It is used as the identity function for converting contacts to
|
||||
their canonical counterpart; useful as an example."
|
||||
(let ((name (plist-get contact :name))
|
||||
(mail (plist-get contact :mail)))
|
||||
(list :name name :mail mail)))
|
||||
(let ((name (plist-get contact :name))
|
||||
(mail (plist-get contact :mail)))
|
||||
(list :name name :mail mail)))
|
||||
|
||||
(make-obsolete-variable 'mu4e-contacts-rewrite-function
|
||||
"mu4e-contact-process-function (see docstring)" "mu4e 1.3.2")
|
||||
"mu4e-contact-process-function (see docstring)" "mu4e 1.3.2")
|
||||
(make-obsolete-variable 'mu4e-compose-complete-ignore-address-regexp
|
||||
"mu4e-contact-process-function (see docstring)" "mu4e 1.3.2")
|
||||
"mu4e-contact-process-function (see docstring)" "mu4e 1.3.2")
|
||||
|
||||
(defcustom mu4e-contact-process-function nil
|
||||
"Function for processing contact information for use in auto-completion.
|
||||
|
@ -406,10 +406,10 @@ an RFC-2822-compatible e-mail address."
|
|||
This can be a regexp matching the address, a list of regexps or a
|
||||
predicate function. A value of nil keeps all the addresses."
|
||||
:type '(choice
|
||||
(const nil)
|
||||
function
|
||||
string
|
||||
(repeat string))
|
||||
(const nil)
|
||||
function
|
||||
string
|
||||
(repeat string))
|
||||
:group 'mu4e-compose)
|
||||
|
||||
(defcustom mu4e-compose-reply-recipients 'ask
|
||||
|
@ -417,8 +417,8 @@ predicate function. A value of nil keeps all the addresses."
|
|||
May be 'ask, 'all, 'sender. Note that that only applies to
|
||||
non-mailing-list message; for those, mu4e always asks."
|
||||
:type '(choice ask
|
||||
all
|
||||
sender)
|
||||
all
|
||||
sender)
|
||||
:group 'mu4e-compose)
|
||||
|
||||
(defcustom mu4e-compose-reply-to-address nil
|
||||
|
@ -434,8 +434,8 @@ Useful when this is not equal to the From: address."
|
|||
|
||||
;; backward compatibility
|
||||
(make-obsolete-variable 'mu4e-reply-to-address
|
||||
'mu4e-compose-reply-to-address
|
||||
"v0.9.9")
|
||||
'mu4e-compose-reply-to-address
|
||||
"v0.9.9")
|
||||
|
||||
(defcustom mu4e-compose-keep-self-cc nil
|
||||
"When non-nil. keep your e-mail address in Cc: when replying."
|
||||
|
@ -477,8 +477,8 @@ parameter refers to the original message being replied to / being
|
|||
forwarded / re-edited and is nil otherwise. `mu4e-drafts-folder'
|
||||
is only evaluated once."
|
||||
:type '(choice
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
:group 'mu4e-folders)
|
||||
|
||||
(defcustom mu4e-refile-folder "/archive"
|
||||
|
@ -488,8 +488,8 @@ function that takes a message (a msg plist, see
|
|||
`mu4e-message-field'), and returns a folder. Note that the
|
||||
message parameter refers to the message-at-point."
|
||||
:type '(choice
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
:group 'mu4e-folders)
|
||||
|
||||
(defcustom mu4e-sent-folder "/sent"
|
||||
|
@ -500,8 +500,8 @@ function that takes a message (a msg plist, see
|
|||
message parameter refers to the original message being replied to
|
||||
/ being forwarded / re-edited, and is nil otherwise."
|
||||
:type '(choice
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
:group 'mu4e-folders)
|
||||
|
||||
(defcustom mu4e-trash-folder "/trash"
|
||||
|
@ -516,8 +516,8 @@ message-at-point. When using it when composing a message (see
|
|||
message being replied to / being forwarded / re-edited, and is
|
||||
nil otherwise."
|
||||
:type '(choice
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
(string :tag "Folder name")
|
||||
(function :tag "Function return folder name"))
|
||||
:group 'mu4e-folders)
|
||||
|
||||
(defcustom mu4e-maildir-shortcuts nil
|
||||
|
@ -741,115 +741,115 @@ mu4e-compose-mode."
|
|||
|
||||
;; headers info
|
||||
(defconst mu4e-header-info
|
||||
'( (:attachments .
|
||||
( :name "Attachments"
|
||||
:shortname "Atts"
|
||||
:help "Message attachments"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
(:bcc .
|
||||
( :name "Bcc"
|
||||
:shortname "Bcc"
|
||||
:help "Blind Carbon-Copy recipients for the message"
|
||||
:sortable t))
|
||||
(:cc .
|
||||
( :name "Cc"
|
||||
:shortname "Cc"
|
||||
:help "Carbon-Copy recipients for the message"
|
||||
:sortable t))
|
||||
(:date .
|
||||
( :name "Date"
|
||||
:shortname "Date"
|
||||
:help "Date/time when the message was written"
|
||||
:sortable t))
|
||||
'( (:attachments
|
||||
. ( :name "Attachments"
|
||||
:shortname "Atts"
|
||||
:help "Message attachments"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
(:bcc
|
||||
. ( :name "Bcc"
|
||||
:shortname "Bcc"
|
||||
:help "Blind Carbon-Copy recipients for the message"
|
||||
:sortable t))
|
||||
(:cc
|
||||
. ( :name "Cc"
|
||||
:shortname "Cc"
|
||||
:help "Carbon-Copy recipients for the message"
|
||||
:sortable t))
|
||||
(:date
|
||||
. ( :name "Date"
|
||||
:shortname "Date"
|
||||
:help "Date/time when the message was written"
|
||||
:sortable t))
|
||||
(:human-date .
|
||||
( :name "Date"
|
||||
:shortname "Date"
|
||||
:help "Date/time when the message was written."
|
||||
:sortable :date))
|
||||
( :name "Date"
|
||||
:shortname "Date"
|
||||
:help "Date/time when the message was written."
|
||||
:sortable :date))
|
||||
(:flags .
|
||||
( :name "Flags"
|
||||
:shortname "Flgs"
|
||||
:help "Flags for the message"
|
||||
:sortable nil))
|
||||
( :name "Flags"
|
||||
:shortname "Flgs"
|
||||
:help "Flags for the message"
|
||||
:sortable nil))
|
||||
(:from .
|
||||
( :name "From"
|
||||
:shortname "From"
|
||||
:help "The sender of the message"
|
||||
:sortable t))
|
||||
( :name "From"
|
||||
:shortname "From"
|
||||
:help "The sender of the message"
|
||||
:sortable t))
|
||||
(:from-or-to .
|
||||
( :name "From/To"
|
||||
:shortname "From/To"
|
||||
:help "Sender of the message if it's not me; otherwise the recipient"
|
||||
:sortable nil))
|
||||
( :name "From/To"
|
||||
:shortname "From/To"
|
||||
:help "Sender of the message if it's not me; otherwise the recipient"
|
||||
:sortable nil))
|
||||
(:maildir .
|
||||
( :name "Maildir"
|
||||
:shortname "Maildir"
|
||||
:help "Maildir for this message"
|
||||
:sortable t))
|
||||
( :name "Maildir"
|
||||
:shortname "Maildir"
|
||||
:help "Maildir for this message"
|
||||
:sortable t))
|
||||
(:list .
|
||||
( :name "List-Id"
|
||||
:shortname "List"
|
||||
:help "Mailing list id for this message"
|
||||
:sortable t))
|
||||
( :name "List-Id"
|
||||
:shortname "List"
|
||||
:help "Mailing list id for this message"
|
||||
:sortable t))
|
||||
(:mailing-list .
|
||||
( :name "List"
|
||||
:shortname "List"
|
||||
:help "Mailing list friendly name for this message"
|
||||
:sortable :list))
|
||||
( :name "List"
|
||||
:shortname "List"
|
||||
:help "Mailing list friendly name for this message"
|
||||
:sortable :list))
|
||||
(:message-id .
|
||||
( :name "Message-Id"
|
||||
:shortname "MsgID"
|
||||
:help "Message-Id for this message"
|
||||
:sortable nil))
|
||||
( :name "Message-Id"
|
||||
:shortname "MsgID"
|
||||
:help "Message-Id for this message"
|
||||
:sortable nil))
|
||||
(:path .
|
||||
( :name "Path"
|
||||
:shortname "Path"
|
||||
:help "Full filesystem path to the message"
|
||||
:sortable t))
|
||||
( :name "Path"
|
||||
:shortname "Path"
|
||||
:help "Full filesystem path to the message"
|
||||
:sortable t))
|
||||
(:signature .
|
||||
( :name "Signature"
|
||||
:shortname "Sgn"
|
||||
:help "Check for the cryptographic signature"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
( :name "Signature"
|
||||
:shortname "Sgn"
|
||||
:help "Check for the cryptographic signature"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
(:decryption .
|
||||
( :name "Decryption"
|
||||
:shortname "Dec"
|
||||
:help "Check the cryptographic decryption status"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
( :name "Decryption"
|
||||
:shortname "Dec"
|
||||
:help "Check the cryptographic decryption status"
|
||||
:require-full t
|
||||
:sortable nil))
|
||||
(:size .
|
||||
( :name "Size"
|
||||
:shortname "Size"
|
||||
:help "Size of the message"
|
||||
:sortable t))
|
||||
( :name "Size"
|
||||
:shortname "Size"
|
||||
:help "Size of the message"
|
||||
:sortable t))
|
||||
(:subject .
|
||||
( :name "Subject"
|
||||
:shortname "Subject"
|
||||
:help "Subject of the message"
|
||||
:sortable t))
|
||||
( :name "Subject"
|
||||
:shortname "Subject"
|
||||
:help "Subject of the message"
|
||||
:sortable t))
|
||||
(:tags .
|
||||
( :name "Tags"
|
||||
:shortname "Tags"
|
||||
:help "Tags for the message"
|
||||
:sortable nil))
|
||||
( :name "Tags"
|
||||
:shortname "Tags"
|
||||
:help "Tags for the message"
|
||||
:sortable nil))
|
||||
(:thread-subject .
|
||||
( :name "Subject"
|
||||
:shortname "Subject"
|
||||
:help "Subject of the thread"
|
||||
:sortable :subject))
|
||||
( :name "Subject"
|
||||
:shortname "Subject"
|
||||
:help "Subject of the thread"
|
||||
:sortable :subject))
|
||||
(:to .
|
||||
( :name "To"
|
||||
:shortname "To"
|
||||
:help "Recipient of the message"
|
||||
:sortable t))
|
||||
( :name "To"
|
||||
:shortname "To"
|
||||
:help "Recipient of the message"
|
||||
:sortable t))
|
||||
(:user-agent .
|
||||
( :name "User-Agent"
|
||||
:shortname "UA"
|
||||
:help "Program used for writing this message"
|
||||
:require-full t
|
||||
:sortable t)))
|
||||
( :name "User-Agent"
|
||||
:shortname "UA"
|
||||
:help "Program used for writing this message"
|
||||
:require-full t
|
||||
:sortable t)))
|
||||
"An alist of all possible header fields and information about them.
|
||||
This is used in the user-interface (the column headers in the header list, and
|
||||
the fields the message view).
|
||||
|
@ -873,15 +873,15 @@ Note, `:sortable' is not supported for custom header fields.")
|
|||
|
||||
(defvar mu4e-header-info-custom
|
||||
'( (:recipnum .
|
||||
( :name "Number of recipients"
|
||||
:shortname "Recip#"
|
||||
:help "Number of recipients for this message"
|
||||
:function
|
||||
(lambda (msg)
|
||||
(format "%d"
|
||||
(+ (length (mu4e-message-field msg :to))
|
||||
(length (mu4e-message-field msg :cc))))))))
|
||||
"A list of custom (user-defined) headers.
|
||||
( :name "Number of recipients"
|
||||
:shortname "Recip#"
|
||||
:help "Number of recipients for this message"
|
||||
:function
|
||||
(lambda (msg)
|
||||
(format "%d"
|
||||
(+ (length (mu4e-message-field msg :to))
|
||||
(length (mu4e-message-field msg :cc))))))))
|
||||
"A list of custom (user-defined) headers.
|
||||
The format is similar
|
||||
to `mu4e-header-info', but adds a :function property, which
|
||||
should point to a function that takes a message p-list as
|
||||
|
@ -897,7 +897,7 @@ argument, and returns a string. See the default value of
|
|||
(defconst mu4e~headers-buffer-name "*mu4e-headers*"
|
||||
"Name of the buffer for message headers.")
|
||||
|
||||
; view
|
||||
;; view
|
||||
(defconst mu4e~view-buffer-name "*mu4e-view*"
|
||||
"Name for the message view buffer.")
|
||||
|
||||
|
@ -919,7 +919,7 @@ mu4e-compose.")
|
|||
(defun mu4e-root-maildir()
|
||||
"Get the root maildir."
|
||||
(let ((root-maildir (and mu4e~server-props
|
||||
(plist-get mu4e~server-props :root-maildir))))
|
||||
(plist-get mu4e~server-props :root-maildir))))
|
||||
(unless root-maildir
|
||||
(mu4e-error "root maildir unknown; did you start mu4e?"))
|
||||
root-maildir))
|
||||
|
@ -927,7 +927,7 @@ mu4e-compose.")
|
|||
(defun mu4e-database-path()
|
||||
"Get the mu4e database path"
|
||||
(let ((path (and mu4e~server-props
|
||||
(plist-get mu4e~server-props :database-path))))
|
||||
(plist-get mu4e~server-props :database-path))))
|
||||
(unless path
|
||||
(mu4e-error "database-path unknown; did you start mu4e?"))
|
||||
path))
|
||||
|
@ -936,7 +936,7 @@ mu4e-compose.")
|
|||
"Get the user's personal addresses, if any. If none are set on the server-side,
|
||||
fall back to the obsolete `mu4e-user-mail-address-list'."
|
||||
(let ((addrs (and mu4e~server-props
|
||||
(plist-get mu4e~server-props :personal-addresses))))
|
||||
(plist-get mu4e~server-props :personal-addresses))))
|
||||
(if addrs addrs mu4e-user-mail-address-list)))
|
||||
|
||||
(defun mu4e-server-version()
|
||||
|
|
1440
mu4e/mu4e-view.el
1440
mu4e/mu4e-view.el
File diff suppressed because it is too large
Load Diff
|
@ -60,9 +60,9 @@ window, unless BACKGROUND (prefix-argument) is non-nil."
|
|||
"Quit the mu4e session."
|
||||
(interactive)
|
||||
(if mu4e-confirm-quit
|
||||
(when (y-or-n-p (mu4e-format "Are you sure you want to quit?"))
|
||||
(mu4e~stop))
|
||||
(mu4e~stop)))
|
||||
(when (y-or-n-p (mu4e-format "Are you sure you want to quit?"))
|
||||
(mu4e~stop))
|
||||
(mu4e~stop)))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(provide 'mu4e)
|
||||
|
|
146
mu4e/org-mu4e.el
146
mu4e/org-mu4e.el
|
@ -58,21 +58,21 @@
|
|||
(defun org~mu4e-mime-file (ext path id)
|
||||
"Create a file of type EXT at PATH with ID for an attachment."
|
||||
(format (concat "<#part type=\"%s\" filename=\"%s\" "
|
||||
"disposition=inline id=\"<%s>\">\n<#/part>\n")
|
||||
ext path id))
|
||||
"disposition=inline id=\"<%s>\">\n<#/part>\n")
|
||||
ext path id))
|
||||
|
||||
(defun org~mu4e-mime-multipart (plain html &optional images)
|
||||
"Create a multipart/alternative with PLAIN and HTML alternatives.
|
||||
If the html portion of the message includes IMAGES, wrap the html
|
||||
and images in a multipart/related part."
|
||||
(concat "<#multipart type=alternative><#part type=text/plain>"
|
||||
plain
|
||||
(when images "<#multipart type=related>")
|
||||
"<#part type=text/html>"
|
||||
html
|
||||
images
|
||||
(when images "<#/multipart>\n")
|
||||
"<#/multipart>\n"))
|
||||
plain
|
||||
(when images "<#multipart type=related>")
|
||||
"<#part type=text/html>"
|
||||
html
|
||||
images
|
||||
(when images "<#/multipart>\n")
|
||||
"<#/multipart>\n"))
|
||||
|
||||
(defun org~mu4e-mime-replace-images (str current-file)
|
||||
"Replace images in html files STR in CURRENT-FILE with cid links."
|
||||
|
@ -90,7 +90,7 @@ and images in a multipart/related part."
|
|||
(ext (file-name-extension path))
|
||||
(id (replace-regexp-in-string "[\/\\\\]" "_" path)))
|
||||
(cl-pushnew (org~mu4e-mime-file
|
||||
(concat "image/" ext) path id)
|
||||
(concat "image/" ext) path id)
|
||||
html-images
|
||||
:test 'equal)
|
||||
id)))
|
||||
|
@ -102,36 +102,36 @@ and images in a multipart/related part."
|
|||
(unless (fboundp 'org-export-string-as)
|
||||
(mu4e-error "Required function 'org-export-string-as not found"))
|
||||
(let* ((begin
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward mail-header-separator)))
|
||||
(end (point-max))
|
||||
(raw-body (buffer-substring begin end))
|
||||
(tmp-file (make-temp-name (expand-file-name "mail"
|
||||
temporary-file-directory)))
|
||||
;; because we probably don't want to skip part of our mail
|
||||
(org-export-skip-text-before-1st-heading nil)
|
||||
;; because we probably don't want to export a huge style file
|
||||
(org-export-htmlize-output-type 'inline-css)
|
||||
;; makes the replies with ">"s look nicer
|
||||
(org-export-preserve-breaks t)
|
||||
;; dvipng for inline latex because MathJax doesn't work in mail
|
||||
(org-export-with-LaTeX-fragments
|
||||
(if (executable-find "dvipng") 'dvipng
|
||||
(mu4e-message "Cannot find dvipng, ignore inline LaTeX") nil))
|
||||
;; to hold attachments for inline html images
|
||||
(html-and-images
|
||||
(org~mu4e-mime-replace-images
|
||||
(org-export-string-as raw-body 'html t)
|
||||
tmp-file))
|
||||
(html-images (cdr html-and-images))
|
||||
(html (car html-and-images)))
|
||||
(delete-region begin end)
|
||||
(save-excursion
|
||||
(goto-char begin)
|
||||
(newline)
|
||||
(insert (org~mu4e-mime-multipart
|
||||
raw-body html (mapconcat 'identity html-images "\n"))))))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward mail-header-separator)))
|
||||
(end (point-max))
|
||||
(raw-body (buffer-substring begin end))
|
||||
(tmp-file (make-temp-name (expand-file-name "mail"
|
||||
temporary-file-directory)))
|
||||
;; because we probably don't want to skip part of our mail
|
||||
(org-export-skip-text-before-1st-heading nil)
|
||||
;; because we probably don't want to export a huge style file
|
||||
(org-export-htmlize-output-type 'inline-css)
|
||||
;; makes the replies with ">"s look nicer
|
||||
(org-export-preserve-breaks t)
|
||||
;; dvipng for inline latex because MathJax doesn't work in mail
|
||||
(org-export-with-LaTeX-fragments
|
||||
(if (executable-find "dvipng") 'dvipng
|
||||
(mu4e-message "Cannot find dvipng, ignore inline LaTeX") nil))
|
||||
;; to hold attachments for inline html images
|
||||
(html-and-images
|
||||
(org~mu4e-mime-replace-images
|
||||
(org-export-string-as raw-body 'html t)
|
||||
tmp-file))
|
||||
(html-images (cdr html-and-images))
|
||||
(html (car html-and-images)))
|
||||
(delete-region begin end)
|
||||
(save-excursion
|
||||
(goto-char begin)
|
||||
(newline)
|
||||
(insert (org~mu4e-mime-multipart
|
||||
raw-body html (mapconcat 'identity html-images "\n"))))))
|
||||
|
||||
;; next some functions to make the org/mu4e-compose-mode switch as smooth as
|
||||
;; possible.
|
||||
|
@ -140,10 +140,10 @@ and images in a multipart/related part."
|
|||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let* ((eoh (when (search-forward mail-header-separator)
|
||||
(match-end 0)))
|
||||
(olay (make-overlay (point-min) eoh)))
|
||||
(match-end 0)))
|
||||
(olay (make-overlay (point-min) eoh)))
|
||||
(when olay
|
||||
(overlay-put olay 'face 'font-lock-comment-face)))))
|
||||
(overlay-put olay 'face 'font-lock-comment-face)))))
|
||||
|
||||
(defun org~mu4e-mime-undecorate-headers ()
|
||||
"Don't make the headers visually distinctive.
|
||||
|
@ -151,7 +151,7 @@ and images in a multipart/related part."
|
|||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let* ((eoh (when (search-forward mail-header-separator)
|
||||
(match-end 0))))
|
||||
(match-end 0))))
|
||||
(remove-overlays (point-min) eoh))))
|
||||
|
||||
(defvar org-mu4e-convert-to-html nil
|
||||
|
@ -171,34 +171,34 @@ rich-text version of what is assumed to be an org mode body."
|
|||
or org-mode (when in the body)."
|
||||
(interactive)
|
||||
(let* ((sepapoint
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp mail-header-separator nil t))))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(search-forward-regexp mail-header-separator nil t))))
|
||||
;; only do stuff when the sepapoint exist; note that after sending the
|
||||
;; message, this function maybe called on a message with the sepapoint
|
||||
;; stripped. This is why we don't use `message-point-in-header'.
|
||||
(when sepapoint
|
||||
(cond
|
||||
;; we're in the body, but in mu4e-compose-mode?
|
||||
;; if so, switch to org-mode
|
||||
((and (> (point) sepapoint) (eq major-mode 'mu4e-compose-mode))
|
||||
(org-mode)
|
||||
(add-hook 'before-save-hook
|
||||
(lambda ()
|
||||
(mu4e-error "Switch to mu4e-compose-mode (M-m) before saving"))
|
||||
nil t)
|
||||
(org~mu4e-mime-decorate-headers)
|
||||
(local-set-key (kbd "M-m")
|
||||
(lambda (keyseq)
|
||||
(interactive "kEnter mu4e-compose-mode key sequence: ")
|
||||
(let ((func (lookup-key mu4e-compose-mode-map keyseq)))
|
||||
(if func (funcall func) (insert keyseq))))))
|
||||
;; we're in the headers, but in org-mode?
|
||||
;; if so, switch to mu4e-compose-mode
|
||||
((and (<= (point) sepapoint) (eq major-mode 'org-mode))
|
||||
(org~mu4e-mime-undecorate-headers)
|
||||
(mu4e-compose-mode)
|
||||
(add-hook 'message-send-hook 'org~mu4e-mime-convert-to-html-maybe nil t)))
|
||||
;; we're in the body, but in mu4e-compose-mode?
|
||||
;; if so, switch to org-mode
|
||||
((and (> (point) sepapoint) (eq major-mode 'mu4e-compose-mode))
|
||||
(org-mode)
|
||||
(add-hook 'before-save-hook
|
||||
(lambda ()
|
||||
(mu4e-error "Switch to mu4e-compose-mode (M-m) before saving"))
|
||||
nil t)
|
||||
(org~mu4e-mime-decorate-headers)
|
||||
(local-set-key (kbd "M-m")
|
||||
(lambda (keyseq)
|
||||
(interactive "kEnter mu4e-compose-mode key sequence: ")
|
||||
(let ((func (lookup-key mu4e-compose-mode-map keyseq)))
|
||||
(if func (funcall func) (insert keyseq))))))
|
||||
;; we're in the headers, but in org-mode?
|
||||
;; if so, switch to mu4e-compose-mode
|
||||
((and (<= (point) sepapoint) (eq major-mode 'org-mode))
|
||||
(org~mu4e-mime-undecorate-headers)
|
||||
(mu4e-compose-mode)
|
||||
(add-hook 'message-send-hook 'org~mu4e-mime-convert-to-html-maybe nil t)))
|
||||
;; and add the hook
|
||||
(add-hook 'post-command-hook 'org~mu4e-mime-switch-headers-or-body t t))))
|
||||
|
||||
|
@ -212,12 +212,12 @@ Edit the message body using org mode. DEPRECATED."
|
|||
;; post-command-hook is set; hackish...but a buffer-local variable does not
|
||||
;; seem to survive buffer switching
|
||||
(if (not (member 'org~mu4e-mime-switch-headers-or-body post-command-hook))
|
||||
(progn
|
||||
(org~mu4e-mime-switch-headers-or-body)
|
||||
(mu4e-message
|
||||
(concat
|
||||
"org-mu4e-compose-org-mode enabled; "
|
||||
"press M-m before issuing message-mode commands")))
|
||||
(progn
|
||||
(org~mu4e-mime-switch-headers-or-body)
|
||||
(mu4e-message
|
||||
(concat
|
||||
"org-mu4e-compose-org-mode enabled; "
|
||||
"press M-m before issuing message-mode commands")))
|
||||
(progn ;; otherwise, remove crap
|
||||
(remove-hook 'post-command-hook 'org~mu4e-mime-switch-headers-or-body t)
|
||||
(org~mu4e-mime-undecorate-headers) ;; shut off org-mode stuff
|
||||
|
|
Loading…
Reference in New Issue