25 June, 2012

Org Mode VM Mairix Link Type, Evolved

Almost one year ago I posted a rather crude solution on how to create and use a mairix link type in VM and Org mode. This functionality is now invaluable in my every day work. During this last year it has also evolved to be less crude, it now
  • decodes mime-encoded strings,
  • stores enough properties for
    • org-email-link-description-format to be used in full, and
    • all vm specific information, including %:fromto, to be used in org-capture-templates.
Below is the current implementation, the reset of :fromto in org-store-link-plist to expand the escape is not nice but works:
;; Add mairix as new link type in org
(org-add-link-type "mairix" 'ra/org-vm-mairix-open)
(add-hook 'org-store-link-functions 'ra/org-vm-store-mairix-link)

;; Store link as mairix search for message ID
;; Most from org-vm-store-link in org-vm.el, modded
(defun ra/org-vm-store-mairix-link ()
  "Store a link to the current VM message as a Mairix search for
  its Message ID."
  (when
      (and (or (eq major-mode 'vm-summary-mode)
               (eq major-mode 'vm-presentation-mode))
           (save-window-excursion
             (vm-select-folder-buffer) buffer-file-name))
    (and (eq major-mode 'vm-presentation-mode)
         (vm-summarize))
    (vm-follow-summary-cursor)
    (save-excursion
      (vm-select-folder-buffer)
      (let* (
             ;; Collect properties
             (message 
              (car vm-message-pointer))
             (subject 
              (vm-decode-mime-encoded-words-in-string 
               (vm-su-subject message)))
             (from 
              (vm-decode-mime-encoded-words-in-string 
               (vm-get-header-contents message "From")))
             (to 
              (vm-decode-mime-encoded-words-in-string 
               (vm-get-header-contents message "To")))
             (message-id 
              (vm-su-message-id message))
             ;; Date needed for full use of org-email-link-description
             ;; and for use in capture templates
             (date 
              (vm-get-header-contents message "Date"))
             ;; Date active/inactive in correct time stamp format for
             ;; use in capture templates
             (date-ts 
              (and date
                   (ignore-errors 
                     (format-time-string
                      (org-time-stamp-format t)
                      (date-to-time date)))))
             (date-ts-ia 
              (and date
                   (ignore-errors
                     (format-time-string
                      (org-time-stamp-format t t)
                      (date-to-time date)))))
             (link 
              (org-make-link 
               "mairix:"
               (format "m:%s"
                       (org-remove-angle-brackets message-id)))))
        (org-store-link-props 
         :type "mairix"
         :message-id message-id
         :from from
         :to to
         :subject subject
         :date date
         :date-timestamp date-ts
         :date-timestamp-inactive date-ts-ia
         :link link)
        (org-add-link-props
         :description (org-email-link-description))
        ;; It seems we need to reset :fromto with expanded escapes
        ;; after :description to use %:fromto in
        ;; org-capture-templates... bug?
        (org-add-link-props
         :fromto (org-replace-escapes 
                  (or (plist-get org-store-link-plist :fromto)
                      "from %f") ; if org-from-is-user-regexp is nil
                  (list
                   (cons 
                    "%f" 
                    (or (plist-get org-store-link-plist :fromname)
                        (plist-get org-store-link-plist :fromaddress)
                        "?"))
                   (cons 
                    "%t" 
                    (or (plist-get org-store-link-plist :toname)
                        (plist-get org-store-link-plist :toaddress)
                        "?")))))
        ;; save vm folder and update the mairix db
        (vm-save-folder)
        (mairix-update-database) ; Make sure mairix-synchronous-update
                                 ; is nil, default, so we do not have
                                 ; to wait
        link))))

;; Open the mairix link, making use of mairix.el to make the search
;; and display the results
(defun ra/org-vm-mairix-open (msearch)
  "Search for messages with message-id with mairix, and display
  them in a VM folder. This requires a proper mairix.el
  setup."
  (mairix-search msearch t))
Of course, as stated in my old blog post, a working setup of Mairix and the Emacs Mairix mode is still required.

23 June, 2012

Capture Attribute Indicator in VM for Org Mode Captured Emails

Problem -- adding an attribute indicator in the vm summary buffer for emails I have org mode-captured some action/actions from. Due to old age(?) I now and then tend to forget if I have added items on my GTD-lists from an email, which sometime generates duplicate items or more...

The quick solution I came up with was to
  1. add a user-defined label, captured, to the email I just captured some action from, and
  2. modify the vm summary format with a user defined specifier to show the character C next to the attribute indicators if the email has the captured label.
The first step was really really easy thanks to org-capture-after-finalize-hook, in .emacs I did
;; Add a hook to the label-setting-function.
(add-hook 'org-capture-after-finalize-hook
          'ra/vm-add-captured-message-label)

;; Add a label to the current email, may also reside in .vm
(defun ra/vm-add-captured-message-label ()
  "Adds the \"captured\" label to the current email."
 (if (equal "mairix" (plist-get org-store-link-plist :type))
     ;;
     ;; if you do not use mairix-type links you can
     ;; - comment out the equal-condition above, and
     ;; - comment in the or-condition below.
     ;;
     ;; (or (eq major-mode 'vm-summary-mode)
     ;;     (eq major-mode 'vm-presentation-mode))
     ;;
     (vm-add-message-labels "captured" 1)))
The second step was also quite straight forward, in .vm I added
;; VM summary template
(setq vm-summary-format
      "%n %*%a%1UC %-17.17F %-3.3m %2d %S %I\"%s\"\n")

;; VM summary function C
(defun vm-summary-function-C (message)
  "Given a VM message, returns a \"C\" if it has been labelled
  \"captured\"."
  (if (member "captured" (vm-labels-of message))
      "C"
    ""))
In the vm-summary-format template above, note the sequence %a%1UC where
  • %a is the usual attribute indicators, and 
  • %1UC is where the vm-summary-function-C is called and my custom "attribute indicator", the single C character, may be inserted.

To conclude -- I did not add a new attribute and attribute indicator, but my own custom user-defined label, captured, and my own custom user-defined label indicator, C.

This solution is far from perfect, eg capturing anything else while being in a vm summary or presentation buffer will get the current email labelled. An alternative would then be to create a new capture template and key combo for capturing emails... but that will probably mess things up for me, hitting the correct combo in the correct buffer... :P

Finally a rowshot from vm summary after capturing, indicator R for replied and C for captured:

->  6    R C Robert Adesam     Jun 21 50 "Emacs for Linguists"