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"

02 July, 2011

Orgmode Capture to Insert a Mairix Link, in VM

Problem -- inserting a Mairix type link when calling Orgmode capture in VM. Also, opening the link from an Orgmode buffer should retrieve the message thread through a Mairix search and display it in a VM folder.

I had a look at org-mairix.el, to maybe extend it with VM support, but being short on time I came up with a rather crude solution in my Emacs init file, ~/.emacs
;; 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, stripped and 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-su-subject message))
             (from (vm-get-header-contents message "From"))
             (to (vm-get-header-contents message "To"))
             (message-id (vm-su-message-id message))
             (link (org-make-link 
                    "mairix:"
                    (format "m:%s"
                            (org-remove-angle-brackets message-id)))))
        ;; TODO: Store even more properties so
        ;; org-email-link-description-format could be used in full
        (org-store-link-props :from from
                              :to to
                              :subject subject
                              :link link)
        (org-add-link-props :description (org-email-link-description))
        ;; Save mail 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
        ;; TODO: Suppress message from
        ;; mairix-sentinel-mairix-update-finished
        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 mairix, and display them in a VM folder.
  This requires a proper mairix.el setup."
  (mairix-search msearch t))
Finally I can quickly orgmode-capture something when reading a message in VM, without the referring orgmode link becomming broken as soon as I file away the message to another folder.

Of course, I was first required to install and configure Mairix, as well as setting up the Emacs Mairix mode, mairix.el. Here is the contents of my Mairix configuration file, ~/.mairixrc
base=~/mail
mbox=*...
mformat=mbox
mfolder=search
database=~/.mairixdb
nochecks
omit=.*
omit=archive
omit=search
omit=mairix
omit=from
omit=magick*
omit=**~
omit=#*
omit=stunnel.log
and the mairix.el setup in my Emacs init file
(require 'mairix)
(setq mairix-file-path "~/mail"
      mairix-mail-program (quote vm)
      mairix-search-file "search")
I also want to direct a small thank you to VM's current maintainer Uday Reddy, who suggested using Mairix links.

23 June, 2011

Issue with VM and IMAP over SSL/stunnel

Problem -- after migrating from Mac to Mac @work I could no longer get emails via imap over ssl/stunnel, using VM 8.1.1 on Emacs 23.3 and stunnel 4.35 with openssl 1.0.0d. The *Messages* buffer stated
vm-imap-protocol-error: IMAP protocol error: "unexpected char (10)"
and the trace buffer of the IMAP over SSL session showed no errors.

With help from my friend, and some ssl/stunnel debugging, I quickly found the problem in the stunnel program, so I set out to revert to the version working on my old Mac, version 4.23. Finding instructions on the Macports wiki page on how to install older ports with subversion, I did
  • jump over the part on installing subversion as a fairly new version comes with Mac OS X 10.6.7,
  • locate and check out the revision, 36499, from the Macports repository containing the old version of stunnel,
    $ svn co -r 36499 https://svn.macports.org/repository/macports/trunk/dports/security/stunnel
  • install it with the port command.
    $ cd stunnel
    $ port install
Problem solved! Now I can once again get emails to VM using IMAP over SSL, stunnel 4.23 with openssl 1.0.0d.

There are quite a few tips on how to test a ssl connection, so I will leave it out and show how I debugged stunnel by
  • creating a stunnel.conf file with
    debug = 7
    output = stunnel.log
    to be appended to the VM generated config file,
  • setting vm-stunnel-program-additional-configuration-file in the VM init file, ~/.vm, to point to to stunnel.conf file, eg
    (setq vm-stunnel-program-additional-configuration-file "/PATH/TO/STUNNEL.CONF")
  • and reloading the VM init file.
Fetching emails now created stunnel.log in the mail folder. This file showed the error
LOG5[3793:140735082364064]: Error detected on socket (read) file descriptor: Socket operation on non-socket (38)
which I could find almost no information about, even less a solution to, so the quick fix was to revert back to an old working version of stunnel as described above.

Update: Since I wrote, but not published, the above text I found out in the stunnel changelog that some Mac OS X bugs have been fixed. Downloaded the latest version, 4.37, and compiled it without any hickups. Though, when now running stunnel it segfaults in addition to the stunnel socket error above...
Update: The above error has been fixed in version 4.52 of stunnel, excellent work from MichaƂ Trojnara!

17 May, 2011

Mairix on Windows-NT Emacs

Problem -- calling Mairix under Cygwin via mairix.el on a Windows-NT Emacs 23.2 results in an error from Mairix not finding the output folder.

The Mairix setup in my Emacs init file is
(require 'mairix)
(setq mairix-file-path "~/mail"
      mairix-mail-program (quote vm)
      mairix-search-file "search")
The error message in the *mairix output* buffer shows that Mairix is looking for the output folder, search, in mail/c:/cygwin/home/robert/mail/. The first mail/ part is Mairix prefixing base to the expanded value of mairix-file-path, c:/cygwin/home/robert/mail. This prefixing is done due to the value not starting with a / or a ., see the mairixrc(5) man page.

My quick fix was to patch the function mairix-call-mairix in mairix.el to prune away the c:/cygwin part added by expand-file-name. I actually redefined the function in my Emacs init file, but also uploaded a patch for mairix.el on the EmacsWiki.

I suspect there are much nicer ways to go about this, maybe locally make expand-file-name not to expand ~ to c:/cygwin/home/robert/ but to just /home/robert/.

18 January, 2011

Emacsclient Setup on Windows 7 Starter

Problem -- not starting a new instance of Emacs but reusing an Emacs already running when opening a file with a file type associated with Emacs in Windows Explorer on my netbook @home running Windows 7 Starter. I also wanted the icons of the associated file types to have the Emacs icon.

My quick fix to this was to
  • write a bat file, runemacsclientw.bat much like the example on the EmacsWiki to start emacsclientw.exe,
  • convert the bat file to exe with a simple converter,
    • choosed the above bat file as batch file,
    • checked Invisible application (don't know if this matters...),
    • under the Versioninformation tab picked an Emacs icon file from under the etc/icons path,
    • compiled, and exited,
  • fix read/execute permissions for the users group on the new exe file, runemacsclientw.exe, placed in the emacs bin directory
  • associate file types to be opened by Emacs with runemacsclientw.exe, and
  • add (server-start) to the Emacs init file, .emacs
Done, now I pinned a link to runemacsclientw.exe on the taskbar and defined an alias, emacs, for runemacsclientw.exe in my .bashrc. I run cygwin/bash on my Windows boxes.

First Post

Ok my first blog post, should be about me right? No, you can read about me on my web site http://www.adesam.se/robert/.

Instead let's talk about what I am presumably going to write about. I think it's going to be about computers, technology in general and Emacs in particular. Maybe I will find time to post notes about GTD etc as well...

Emacs -- what is it and why do I use it? It's a way of life... or as stated in Wikipedia, it's a text editor that is higly extensible and customisable. If you know a little bit of LISP one can very quickly tweak Emacs to do what you want. I use Emacs for writing papers, programming, reading/writing emails, and organising my life. Now days I am quite comfortable with Emacs, but over the years I have tried to exchange Emacs for other tools like Eclipse, Thunderbird, Mail.app, etc but I have given up. Emacs is for me, and it works basically the same way on all systems I use: Mac OS X, Windows, Linux, Solaris...