mu4e (ical): Allow to reply to icalendar invitations

Fixes https://github.com/djcb/mu/issues/994
This commit is contained in:
Christophe Troestler 2019-04-13 00:53:36 +02:00
parent c639a939f4
commit 1078fee2c5
5 changed files with 114 additions and 9 deletions

View File

@ -28,6 +28,7 @@ dist_lisp_LISP= \
mu4e-contrib.el \
mu4e-draft.el \
mu4e-headers.el \
mu4e-icalendar.el \
mu4e-lists.el \
mu4e-main.el \
mu4e-mark.el \

View File

@ -413,14 +413,17 @@ You can append flags."
Replying-to-self is special; in that case, the To and Cc fields
will be the same as in the original."
(let* ((reply-to-self (mu4e-message-contact-field-matches-me origmsg :from))
(recipnum
(+ (length (mu4e~draft-create-to-lst origmsg))
(length (mu4e~draft-create-cc-lst origmsg t))))
;; reply-to-self implies reply-all
(reply-all (or reply-to-self (mu4e~draft-reply-all-p origmsg)))
(old-msgid (plist-get origmsg :message-id))
(subject (concat mu4e~draft-reply-prefix
(message-strip-subject-re
(recipnum
(+ (length (mu4e~draft-create-to-lst origmsg))
(length (mu4e~draft-create-cc-lst origmsg t))))
;; 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))))
(old-msgid (plist-get origmsg :message-id))
(subject (concat mu4e~draft-reply-prefix
(message-strip-subject-re
(or (plist-get origmsg :subject) "")))))
(concat
(mu4e~draft-header "From" (or (mu4e~draft-from-construct) ""))

92
mu4e/mu4e-icalendar.el Normal file
View File

@ -0,0 +1,92 @@
;;; mu4e-icalendar.el --- reply to iCalendar meeting requests
;;; Commentary:
;; To install:
;; (require 'gnus-icalendar)
;; (gnus-icalendar-setup)
;; to enable optional iCalendar->Org sync functionality
;; NOTE: both the capture file and the headline(s) inside must already exist
;; (setq gnus-icalendar-org-capture-file "~/org/notes.org")
;; (setq gnus-icalendar-org-capture-headline '("Calendar"))
;; (gnus-icalendar-org-setup)
(require 'mu4e)
(require 'gnus-icalendar)
(eval-when-compile (require 'cl))
(defun mu4e-icalendar-setup ()
(gnus-icalendar-setup)
(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))
`(("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 a text/calendar event."
;; Based on `gnus-icalendar-reply'.
(let* ((handle (car data))
(status (cadr data))
(event (caddr data))
(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)))
(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)))))
(let ((subject (concat (capitalize (symbol-name status))
": " (gnus-icalendar-event:summary event))))
(with-current-buffer (get-buffer-create gnus-icalendar-reply-bufname)
(delete-region (point-min) (point-max))
(insert reply)
(fold-icalendar-buffer)
(mu4e-icalendar-reply-with-buffer msg subject (buffer-name)))
;; Back in article buffer
(setq-local gnus-icalendar-reply-status status)
(when gnus-icalendar-org-enabled-p
(gnus-icalendar--update-org-event event status)
;; refresh article buffer to update the reply status
(with-current-buffer mu4e~headers-buffer-name
(mu4e-headers-rerun-search))))))))
(defun mu4e~icalendar-delete-citation ()
(delete-region (point-min) (point-max)))
(defun mu4e-icalendar-reply-with-buffer (original-msg subject buffer-name)
(let ((message-signature nil))
(let ((mu4e-compose-cite-function #'mu4e~icalendar-delete-citation)
(mu4e-sent-messages-behavior 'delete)
(mu4e-compose-reply-recipients 'sender))
;; FIXME: only reply to the original sender (do not ask)
(mu4e~compose-handler 'reply original-msg))
(message-goto-body)
(insert "\n\n")
(mml-insert-multipart "alternative")
(mml-insert-empty-tag 'part 'type "text/plain")
(mml-attach-buffer buffer-name "text/calendar; method=REPLY; charset=UTF-8")
(message-goto-subject)
(delete-region (line-beginning-position) (line-end-position))
(insert "Subject: " subject)
; (message-send-and-exit)
))
(provide 'mu4e-icalendar)
;;; mu4e-icalendar.el ends here

View File

@ -405,6 +405,14 @@ predicate function. A value of nil keeps all the addresses."
(repeat string))
:group 'mu4e-compose)
(defcustom mu4e-compose-reply-recipients 'ask
"Which recipients to use when replying to a message.
May be 'ask, 'all, 'sender."
:type '(choice ask
all
sender)
:group 'mu4e-compose)
(defcustom mu4e-compose-reply-to-address nil
"The Reply-To address.
Useful when this is not equal to the From: address."

View File

@ -381,7 +381,8 @@ article-mode."
gnus-summary-buffer (get-buffer-create " *appease-gnus*")
gnus-original-article-buffer (current-buffer))
(run-hooks 'gnus-article-decode-hook)
(let ((max-specpdl-size mu4e-view-max-specpdl-size))
(let ((mu4e~view-rendering t) ; customize gnus in mu4e
(max-specpdl-size mu4e-view-max-specpdl-size))
(gnus-article-prepare-display))
(mu4e-view-mode)
(setq mu4e~view-message msg)