Skip to content

Instantly share code, notes, and snippets.

@felipeochoa
Created October 2, 2017 08:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felipeochoa/63e491efd305a71dc5bfc72997036c01 to your computer and use it in GitHub Desktop.
Save felipeochoa/63e491efd305a71dc5bfc72997036c01 to your computer and use it in GitHub Desktop.
Display iCal details inline with mu4e
(defun fov-ical-mark-body-text (oldfun msg)
"Wrap (OLDFUN MSG) with (propertize * 'fov-ical-message-body-text t)."
(propertize (funcall oldfun msg) 'fov-ical-message-body-text t))
(advice-add 'mu4e-message-body-text :around 'fov-ical-mark-body-text)
(defvar mu4e~view-msg)
(defun fov-ical-insert-info ()
"Submit async requests to insert ical info the current mu4e-view buffer."
(dolist (part (mu4e-message-field mu4e~view-msg :parts))
(when (string= (mu4e-message-part-field part :mime-type) "text/calendar")
(mu4e~view-temp-action (mu4e-message-field mu4e~view-msg :docid)
(mu4e-message-part-field part :index)
"fov-ical-handler"))))
(add-hook 'mu4e-view-mode-hook 'fov-ical-insert-info)
(autoload 'gnus-icalendar-event-from-buffer "gnus-icalendar")
(defvar-local fov-ical-event nil)
(defun fov-ical-from-path (msg path)
"Return a `gnus-icalendar-event' object from an attachment on MSG.
PATH is an absolute filename where the attachment has been extracted."
(ignore msg)
(when-let ((event (with-temp-buffer
(find-file-existing path)
(prog1
(gnus-icalendar-event-from-buffer (current-buffer)
mu4e-user-mail-address-list)
(kill-buffer)))))
(setq fov-ical-event event)))
(defun fov-ical-insert-event-info (msg event)
"Summarize MSG's EVENT.
EVENT is a `gnus-icalendar-event' instance extracted from MSG's attachment."
(ignore msg)
(insert "\nMessage contains an event:\n" (gnus-icalendar-event->gnus-calendar event nil))
(let ((desc (slot-value event 'description)))
(when (search-forward desc nil t)
(delete-region (- (point) (length desc)) (point)))))
(defvar mu4e~view-buffer-name)
(defun fov-ical-temp-handler (path what docid param)
"Wrapper around `mu4e~view-temp-handler' for processing attachments.
PATH, WHAT, DOCID, and PARAM are as in `mu4e~view-temp-handler'."
(if (string= what "fov-ical-handler")
(with-current-buffer (get-buffer mu4e~view-buffer-name) ;; TODO: handle embedded msg
(when (eq (mu4e-message-field mu4e~view-msg :docid) docid)
(save-excursion
(goto-char (1- (fov-ical-get-message-body-start))) ;; 1- for extra newline
(let ((inhibit-read-only t))
(when-let ((event (fov-ical-from-path mu4e~view-msg path)))
(fov-ical-insert-event-info mu4e~view-msg event))))))
(mu4e~view-temp-handler path what docid param)))
(defvar mu4e-temp-func 'fov-ical-temp-handler)
(defun fov-ical-get-message-body-start ()
"Return the index of the first character in the buffer with 'mu4e-message-body-text set."
(let* ((lower (point-min)) (upper (1- (point-max))) (mid (floor (+ lower upper) 2)))
(while (< lower mid)
(if (get-char-property mid 'fov-ical-message-body-text)
(setq upper mid)
(setq lower mid))
(setq mid (floor (+ lower upper) 2)))
upper))
@rkanavath
Copy link

rkanavath commented May 15, 2018

error in process filter: apply: Wrong number of arguments: (lambda (oldfun msg) "Wrap (OLDFUN MSG) with (propertize * 'fov-ical-message-body-text t)." (propertize (funcall oldfun msg) (quote fov-ical-message-body-text) t)), 3
error in process filter: Wrong number of arguments: (lambda (oldfun msg) "Wrap (OLDFUN MSG) with (propertize * 'fov-ical-message-body-text t)." (propertize (funcall oldfun msg) (quote fov-ical-message-body-text) t)), 3

@killdash9
Copy link

Here's updated code that fixes the glitch pointed out by @rkanavath

(defun fov-ical-mark-body-text (oldfun msg &optional prefer-html)
  "Wrap (OLDFUN MSG) with (propertize * 'fov-ical-message-body-text t)."
  (propertize (funcall oldfun msg prefer-html) 'fov-ical-message-body-text t))

(advice-add 'mu4e-message-body-text :around 'fov-ical-mark-body-text)

(defvar mu4e~view-msg)
(defun fov-ical-insert-info ()
  "Submit async requests to insert ical info the current mu4e-view buffer."
  (dolist (part (mu4e-message-field mu4e~view-msg :parts))
    (when (string= (mu4e-message-part-field part :mime-type) "text/calendar")
      (mu4e~view-temp-action (mu4e-message-field mu4e~view-msg :docid)
                             (mu4e-message-part-field part :index)
                             "fov-ical-handler"))))

(add-hook 'mu4e-view-mode-hook 'fov-ical-insert-info)

(autoload 'gnus-icalendar-event-from-buffer "gnus-icalendar")
(defvar-local fov-ical-event nil)

(defun fov-ical-from-path (msg path)
  "Return a `gnus-icalendar-event' object from an attachment on MSG.
PATH is an absolute filename where the attachment has been extracted."
  (ignore msg)
  (when-let ((event (with-temp-buffer
                      (find-file-existing path)
                      (prog1
                          (gnus-icalendar-event-from-buffer (current-buffer)
                                                            mu4e-user-mail-address-list)
                        (kill-buffer)))))
    (setq fov-ical-event event)))

(defun fov-ical-insert-event-info (msg event)
  "Summarize MSG's EVENT.
EVENT is a `gnus-icalendar-event' instance extracted from MSG's attachment."
  (ignore msg)
  (insert "\nMessage contains an event:\n" (gnus-icalendar-event->gnus-calendar event nil))
  (let ((desc (slot-value event 'description)))
    (when (search-forward desc nil t)
      (delete-region (- (point) (length desc)) (point)))))

(defvar mu4e~view-buffer-name)

(defun fov-ical-temp-handler (path what docid param)
  "Wrapper around `mu4e~view-temp-handler' for processing attachments.
PATH, WHAT, DOCID, and PARAM are as in `mu4e~view-temp-handler'."
  (if (string= what "fov-ical-handler")
      (with-current-buffer (get-buffer mu4e~view-buffer-name) ;; TODO: handle embedded msg
        (when (eq (mu4e-message-field mu4e~view-msg :docid) docid)
          (save-excursion
            (goto-char (1- (fov-ical-get-message-body-start))) ;; 1- for extra newline
            (let ((inhibit-read-only t))
              (when-let ((event (fov-ical-from-path mu4e~view-msg path)))
                (fov-ical-insert-event-info mu4e~view-msg event))))))
    (mu4e~view-temp-handler path what docid param)))

(setq mu4e-temp-func 'fov-ical-temp-handler)

(defun fov-ical-get-message-body-start ()
  "Return the index of the first character in the buffer with 'mu4e-message-body-text set."
  (let* ((lower (point-min)) (upper (1- (point-max))) (mid (floor (+ lower upper) 2)))
    (while (< lower mid)
      (if (get-char-property mid 'fov-ical-message-body-text)
          (setq upper mid)
        (setq lower mid))
      (setq mid (floor (+ lower upper) 2)))
    upper))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment