org-mairix.el 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. ;;; org-mairix.el - Support for hooking mairix search into Org for different MUAs
  2. ;;
  3. ;; Copyright (C) 2007 Georg C. F. Greve
  4. ;;
  5. ;; Author: Georg C. F. Greve <greve at fsfeurope dot org>
  6. ;; Keywords: outlines, hypermedia, calendar, wp, email, mairix
  7. ;; Purpose: Integrate mairix email searching into Org mode
  8. ;; See http://orgmode.org and http://www.rpcurnow.force9.co.uk/mairix/
  9. ;; Version: 0.4
  10. ;;
  11. ;; This file is Free Software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 3, or (at your option)
  14. ;; any later version.
  15. ;; It is distributed in the hope that it will be useful, but WITHOUT
  16. ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. ;; License for more details.
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  21. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  22. ;; Boston, MA 02110-1301, USA.
  23. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  24. ;; USAGE NOTE
  25. ;;
  26. ;; You will need to configure mairix first, which involves setting up your
  27. ;; .mairixrc in your home directory. Once it is working, you should set up
  28. ;; your way to display results in your favorite way -- usually a MUA, in my
  29. ;; case gnus.
  30. ;;
  31. ;; After both steps are done, all you should need to hook mairix, org
  32. ;; and your MUA together is to do (require 'org-mairix) in your
  33. ;; startup file. Everything can then be configured normally through
  34. ;; Emacs customisation.
  35. ;;
  36. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  37. (require 'org)
  38. ;;; The custom variables
  39. (defgroup org-mairix nil
  40. "Mairix support/integration in org."
  41. :tag "Org Mairix"
  42. :group 'org-links)
  43. (defcustom org-mairix-threaded-links t
  44. "Should new links be created as threaded links?
  45. If t, links will be stored as threaded searches.
  46. If nil, links will be stored as non-threaded searches."
  47. :group 'org-mairix
  48. :type 'boolean)
  49. (defcustom org-mairix-augmented-links nil
  50. "Should new links be created as augmenting searches?
  51. If t, links will be stored as augmenting searches.
  52. If nil, links will be stored as normal searches.
  53. Attention: When activating this option, you will need
  54. to remove old articles from your mairix results group
  55. in some other way, mairix will not do it for you."
  56. :group 'org-mairix
  57. :type 'boolean)
  58. (defcustom org-mairix-display-hook 'org-mairix-gnus-display-results
  59. "Hook to call to display the results of a successful mairix search.
  60. Defaults to Gnus, feel free to add your own MUAs or methods."
  61. :group 'org-mairix
  62. :type 'hook)
  63. (defcustom org-mairix-executable "mairix"
  64. "The mairix executable to call. If your paths are set up
  65. correctly, you should not need to change this."
  66. :group 'org-mairix
  67. :type 'string)
  68. (defgroup org-mairix-gnus nil
  69. "Use gnus for mairix support in org."
  70. :tag "Org Mairix Gnus"
  71. :group 'org-mairix)
  72. (defcustom org-mairix-gnus-results-group "nnmaildir:mairix"
  73. "The group that is configured to hold the mairix search results,
  74. which needs to be setup independently of the org-mairix integration,
  75. along with general mairix configuration."
  76. :group 'org-mairix-gnus
  77. :type 'string)
  78. (defcustom org-mairix-gnus-select-display-group-function 'org-mairix-gnus-select-display-group-function-gg
  79. "Hook to call to select the group that contains the matching articles.
  80. We should not need this, it is owed to a problem of gnus that people were
  81. not yet able to figure out, see
  82. http://article.gmane.org/gmane.emacs.gnus.general/65248
  83. http://article.gmane.org/gmane.emacs.gnus.general/65265
  84. http://article.gmane.org/gmane.emacs.gnus.user/9596
  85. for reference.
  86. It seems gnus needs a 'forget/ignore everything you think you
  87. know about that group' function. Volunteers?"
  88. :group 'org-mairix-gnus
  89. :type 'hook)
  90. ;;; The hooks to integrate mairix into org
  91. (org-add-link-type "mairix" 'org-mairix-open)
  92. (add-hook 'org-store-link-functions 'org-mairix-store-link)
  93. ;;; Generic org-mairix functions
  94. (defun org-mairix-store-link ()
  95. "Store a link to the current message as a Mairix search for its
  96. Message ID."
  97. ;; gnus integration
  98. (when (memq major-mode '(gnus-summary-mode gnus-article-mode))
  99. (and (eq major-mode 'gnus-article-mode) (gnus-article-show-summary))
  100. (let* ((article (gnus-summary-article-number))
  101. (header (gnus-summary-article-header article))
  102. (from (mail-header-from header))
  103. (message-id (mail-header-id header))
  104. (subject (gnus-summary-subject-string)))
  105. (org-store-link-props :type "mairix" :from from :subject subject
  106. :message-id message-id)
  107. (setq cpltxt (org-email-link-description))
  108. (org-store-link-props :link (concat "mairix:"
  109. (if org-mairix-threaded-links "t:")
  110. (if org-mairix-augmented-links "a:")
  111. "@@" (org-remove-angle-brackets message-id))
  112. :description cpltxt))))
  113. (defun org-mairix-message-send-and-exit-with-link ()
  114. "Function that can be assigned as an alternative sending function,
  115. it sends the message and then stores a mairix link to it before burying
  116. the buffer just like 'message-send-and-exit' does."
  117. (interactive)
  118. (message-send)
  119. (let* ((message-id (message-fetch-field "Message-Id"))
  120. (subject (message-fetch-field "Subject"))
  121. (link (concat "mairix:"
  122. (if org-mairix-threaded-links "t:")
  123. (if org-mairix-augmented-links "a:")
  124. "@@" (org-remove-angle-brackets message-id)))
  125. (desc (concat "Email: '" subject "'")))
  126. (setq org-stored-links
  127. (cons (list link desc) org-stored-links)))
  128. (message-bury (current-buffer)))
  129. (defun org-mairix-open (path)
  130. "Function to open mairix link.
  131. We first need to split it into its individual parts, and then
  132. extract the message-id to be passed on to the display function
  133. before call mairix, evaluate the number of matches returned, and
  134. make sure to only call display of mairix succeeded in matching."
  135. (let* ((cmdline org-mairix-executable))
  136. (if (string< "t:" path)
  137. (progn (setq path (substring path 2 nil))
  138. (setq cmdline (concat cmdline " --threads"))))
  139. (if (string< "a:" path)
  140. (progn (setq path (substring path 2 nil))
  141. (setq cmdline (concat cmdline " --augment"))))
  142. (let* ((message-id (substring path 2 nil)))
  143. (setq cmdline (concat cmdline " m:" message-id))
  144. (print cmdline)
  145. (setq retval (shell-command-to-string
  146. (concat cmdline " m:" message-id)))
  147. (string-match "\[0-9\]+" retval)
  148. (setq matches (string-to-number (match-string 0 retval)))
  149. (if (eq matches 0) (message "Link failed: no matches, sorry")
  150. (message "Link returned %d matches" matches)
  151. (run-hook-with-args 'org-mairix-display-hook message-id)))))
  152. ;;; Functions necessary for gnus integration
  153. (defun org-mairix-gnus-display-results (message-id)
  154. "Display results of mairix search in Gnus.
  155. Note: This does not work as cleanly as I would like it to. The
  156. problem being that Gnus should simply reread the group cleanly,
  157. without remembering anything. At the moment it seems to be unable
  158. to do that -- so you're likely to see zombies floating around.
  159. If you can improve this, please do!"
  160. (require 'gnus)
  161. (require 'gnus-sum)
  162. ;; FIXME: (bzg/gg) We might need to make sure gnus is running here,
  163. ;; and to start it in case it isn't running already. Does
  164. ;; anyone know a function to do that? It seems main org mode
  165. ;; does not do this, either.
  166. (funcall (cdr (assq 'gnus org-link-frame-setup)))
  167. (if gnus-other-frame-object (select-frame gnus-other-frame-object))
  168. ;; FIXME: This is horribly broken. Please see
  169. ;; http://article.gmane.org/gmane.emacs.gnus.general/65248
  170. ;; http://article.gmane.org/gmane.emacs.gnus.general/65265
  171. ;; http://article.gmane.org/gmane.emacs.gnus.user/9596
  172. ;; for reference.
  173. ;;
  174. ;; It seems gnus needs a "forget/ignore everything you think you
  175. ;; know about that group" function. Volunteers?
  176. ;;
  177. ;; For now different methods seem to work differently well for
  178. ;; different people. So we're playing hook-selection here to make
  179. ;; it easy to play around until we found a proper solution.
  180. (run-hook-with-args 'org-mairix-gnus-select-display-group-function)
  181. (gnus-summary-select-article
  182. nil t t (car (gnus-find-matching-articles "message-id" message-id))))
  183. (provide 'org-mairix)
  184. (defun org-mairix-gnus-select-display-group-function-gg ()
  185. "Georg's hack to select a group that gnus (falsely) believes to be
  186. empty to then call rebuilding of the summary. It leaves zombies of
  187. old searches around, though."
  188. (gnus-group-quick-select-group 0 org-mairix-gnus-results-group)
  189. (gnus-group-clear-data)
  190. (gnus-summary-reselect-current-group t t))
  191. (defun org-mairix-gnus-select-display-group-function-bzg ()
  192. "This is the classic way the org mode is using, and it seems to be
  193. using better for Bastien, so it may work for you."
  194. (gnus-group-clear-data org-mairix-gnus-results-group)
  195. (gnus-group-read-group t nil org-mairix-gnus-results-group))
  196. ;;; org-mairix.el ends here