commit | author | age
|
76bbd0
|
1 |
;;; org-mhe.el --- Support for Links to MH-E Messages -*- lexical-binding: t; -*- |
C |
2 |
|
|
3 |
;; Copyright (C) 2004-2018 Free Software Foundation, Inc. |
|
4 |
|
|
5 |
;; Author: Thomas Baumann <thomas dot baumann at ch dot tum dot de> |
|
6 |
;; Keywords: outlines, hypermedia, calendar, wp |
|
7 |
;; Homepage: https://orgmode.org |
|
8 |
;; |
|
9 |
;; This file is part of GNU Emacs. |
|
10 |
;; |
|
11 |
;; GNU Emacs 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 of the License, or |
|
14 |
;; (at your option) any later version. |
|
15 |
|
|
16 |
;; GNU Emacs is distributed in the hope that it will be useful, |
|
17 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19 |
;; GNU General Public License for more details. |
|
20 |
|
|
21 |
;; You should have received a copy of the GNU General Public License |
|
22 |
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
|
23 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
24 |
;; |
|
25 |
;;; Commentary: |
|
26 |
|
|
27 |
;; This file implements links to MH-E messages from within Org. |
|
28 |
;; Org mode loads this module by default - if this is not what you want, |
|
29 |
;; configure the variable `org-modules'. |
|
30 |
|
|
31 |
;;; Code: |
|
32 |
|
|
33 |
(require 'org-macs) |
|
34 |
(require 'org) |
|
35 |
|
|
36 |
;; Customization variables |
|
37 |
|
|
38 |
(defcustom org-mhe-search-all-folders nil |
|
39 |
"Non-nil means the search for the mh-message may extend to all folders. |
|
40 |
When non-nil, the search for a message will extend to all other |
|
41 |
folders if it cannot be found in the folder given in the link. |
|
42 |
Searching all folders may be slow with the default pick based |
|
43 |
search but is very efficient with one of the other search engines |
|
44 |
supported by MH-E." |
|
45 |
:group 'org-link-follow |
|
46 |
:type 'boolean) |
|
47 |
|
|
48 |
;; Declare external functions and variables |
|
49 |
(declare-function mh-display-msg "mh-show" (msg-num folder-name)) |
|
50 |
(declare-function mh-find-path "mh-utils" ()) |
|
51 |
(declare-function mh-get-header-field "mh-utils" (field)) |
|
52 |
(declare-function mh-get-msg-num "mh-utils" (error-if-no-message)) |
|
53 |
(declare-function mh-header-display "mh-show" ()) |
|
54 |
(declare-function mh-index-previous-folder "mh-search" ()) |
|
55 |
(declare-function mh-normalize-folder-name "mh-utils" |
|
56 |
(folder &optional empty-string-okay dont-remove-trailing-slash |
|
57 |
return-nil-if-folder-empty)) |
|
58 |
(declare-function mh-search "mh-search" |
|
59 |
(folder search-regexp &optional redo-search-flag |
|
60 |
window-config)) |
|
61 |
(declare-function mh-search-choose "mh-search" (&optional searcher)) |
|
62 |
(declare-function mh-show "mh-show" (&optional message redisplay-flag)) |
|
63 |
(declare-function mh-show-buffer-message-number "mh-comp" (&optional buffer)) |
|
64 |
(declare-function mh-show-header-display "mh-show" t t) |
|
65 |
(declare-function mh-show-msg "mh-show" (msg)) |
|
66 |
(declare-function mh-show-show "mh-show" t t) |
|
67 |
(declare-function mh-visit-folder "mh-folder" (folder &optional |
|
68 |
range index-data)) |
|
69 |
(defvar mh-progs) |
|
70 |
(defvar mh-current-folder) |
|
71 |
(defvar mh-show-folder-buffer) |
|
72 |
(defvar mh-index-folder) |
|
73 |
(defvar mh-searcher) |
|
74 |
(defvar mh-search-regexp-builder) |
|
75 |
|
|
76 |
;; Install the link type |
|
77 |
(org-link-set-parameters "mhe" :follow #'org-mhe-open :store #'org-mhe-store-link) |
|
78 |
|
|
79 |
;; Implementation |
|
80 |
(defun org-mhe-store-link () |
|
81 |
"Store a link to an MH-E folder or message." |
|
82 |
(when (or (eq major-mode 'mh-folder-mode) |
|
83 |
(eq major-mode 'mh-show-mode)) |
|
84 |
(save-window-excursion |
|
85 |
(let* ((from (org-mhe-get-header "From:")) |
|
86 |
(to (org-mhe-get-header "To:")) |
|
87 |
(message-id (org-mhe-get-header "Message-Id:")) |
|
88 |
(subject (org-mhe-get-header "Subject:")) |
|
89 |
(date (org-mhe-get-header "Date:")) |
|
90 |
link desc) |
|
91 |
(org-store-link-props :type "mh" :from from :to to :date date |
|
92 |
:subject subject :message-id message-id) |
|
93 |
(setq desc (org-email-link-description)) |
|
94 |
(setq link (concat "mhe:" (org-mhe-get-message-real-folder) "#" |
|
95 |
(org-unbracket-string "<" ">" message-id))) |
|
96 |
(org-add-link-props :link link :description desc) |
|
97 |
link)))) |
|
98 |
|
|
99 |
(defun org-mhe-open (path) |
|
100 |
"Follow an MH-E message link specified by PATH." |
|
101 |
(let (folder article) |
|
102 |
(if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) |
|
103 |
(error "Error in MH-E link")) |
|
104 |
(setq folder (match-string 1 path) |
|
105 |
article (match-string 3 path)) |
|
106 |
(org-mhe-follow-link folder article))) |
|
107 |
|
|
108 |
;;; mh-e integration based on planner-mode |
|
109 |
(defun org-mhe-get-message-real-folder () |
|
110 |
"Return the name of the real folder for the current message. |
|
111 |
So if you use sequences, it will now work." |
|
112 |
(save-excursion |
|
113 |
(let* ((folder |
|
114 |
(if (eq major-mode 'mh-folder-mode) |
|
115 |
mh-current-folder |
|
116 |
;; Refer to the show buffer |
|
117 |
mh-show-folder-buffer)) |
|
118 |
(end-index |
|
119 |
(if (boundp 'mh-index-folder) |
|
120 |
(min (length mh-index-folder) (length folder)))) |
|
121 |
) |
|
122 |
;; a simple test on mh-index-data does not work, because |
|
123 |
;; mh-index-data is always nil in a show buffer. |
|
124 |
(if (and (boundp 'mh-index-folder) |
|
125 |
(string= mh-index-folder (substring folder 0 end-index))) |
|
126 |
(if (eq major-mode 'mh-show-mode) |
|
127 |
(save-window-excursion |
|
128 |
(let (pop-up-frames) |
|
129 |
(when (buffer-live-p (get-buffer folder)) |
|
130 |
(progn |
|
131 |
(pop-to-buffer folder) |
|
132 |
(org-mhe-get-message-folder-from-index) |
|
133 |
) |
|
134 |
))) |
|
135 |
(org-mhe-get-message-folder-from-index) |
|
136 |
) |
|
137 |
folder |
|
138 |
) |
|
139 |
))) |
|
140 |
|
|
141 |
(defun org-mhe-get-message-folder-from-index () |
|
142 |
"Return the name of the message folder in an index folder buffer." |
|
143 |
(save-excursion |
|
144 |
(mh-index-previous-folder) |
|
145 |
(if (re-search-forward "^\\(+.*\\)$" nil t) |
|
146 |
(message "%s" (match-string 1))))) |
|
147 |
|
|
148 |
(defun org-mhe-get-message-folder () |
|
149 |
"Return the name of the current message folder. |
|
150 |
Be careful if you use sequences." |
|
151 |
(save-excursion |
|
152 |
(if (eq major-mode 'mh-folder-mode) |
|
153 |
mh-current-folder |
|
154 |
;; Refer to the show buffer |
|
155 |
mh-show-folder-buffer))) |
|
156 |
|
|
157 |
(defun org-mhe-get-message-num () |
|
158 |
"Return the number of the current message. |
|
159 |
Be careful if you use sequences." |
|
160 |
(save-excursion |
|
161 |
(if (eq major-mode 'mh-folder-mode) |
|
162 |
(mh-get-msg-num nil) |
|
163 |
;; Refer to the show buffer |
|
164 |
(mh-show-buffer-message-number)))) |
|
165 |
|
|
166 |
(defun org-mhe-get-header (header) |
|
167 |
"Return the field for HEADER of the message in folder mode. |
|
168 |
This will create a show buffer for the corresponding message. If |
|
169 |
you have a better idea of how to do this then please let us know." |
|
170 |
(let* ((folder (org-mhe-get-message-folder)) |
|
171 |
(num (org-mhe-get-message-num)) |
|
172 |
(buffer (get-buffer-create (concat "show-" folder))) |
|
173 |
(header-field)) |
|
174 |
(with-current-buffer buffer |
|
175 |
(mh-display-msg num folder) |
|
176 |
(if (eq major-mode 'mh-folder-mode) |
|
177 |
(mh-header-display) |
|
178 |
(mh-show-header-display)) |
|
179 |
(set-buffer buffer) |
|
180 |
(setq header-field (mh-get-header-field header)) |
|
181 |
(if (eq major-mode 'mh-folder-mode) |
|
182 |
(mh-show) |
|
183 |
(mh-show-show)) |
|
184 |
(org-trim header-field)))) |
|
185 |
|
|
186 |
(defun org-mhe-follow-link (folder article) |
|
187 |
"Follow an MH-E link to FOLDER and ARTICLE. |
|
188 |
If ARTICLE is nil FOLDER is shown. If the configuration variable |
|
189 |
`org-mhe-search-all-folders' is t and `mh-searcher' is pick, |
|
190 |
ARTICLE is searched in all folders. Indexed searches (swish++, |
|
191 |
namazu, and others supported by MH-E) will always search in all |
|
192 |
folders." |
|
193 |
(require 'mh-e) |
|
194 |
(require 'mh-search) |
|
195 |
(require 'mh-utils) |
|
196 |
(mh-find-path) |
|
197 |
(if (not article) |
|
198 |
(mh-visit-folder (mh-normalize-folder-name folder)) |
|
199 |
(mh-search-choose) |
|
200 |
(if (eq mh-searcher 'pick) |
|
201 |
(progn |
|
202 |
(setq article (org-add-angle-brackets article)) |
|
203 |
(mh-search folder (list "--message-id" article)) |
|
204 |
(when (and org-mhe-search-all-folders |
|
205 |
(not (org-mhe-get-message-real-folder))) |
|
206 |
(kill-buffer) |
|
207 |
(mh-search "+" (list "--message-id" article)))) |
|
208 |
(if mh-search-regexp-builder |
|
209 |
(mh-search "+" (funcall mh-search-regexp-builder |
|
210 |
(list (cons 'message-id article)))) |
|
211 |
(mh-search "+" article))) |
|
212 |
(if (org-mhe-get-message-real-folder) |
|
213 |
(mh-show-msg 1) |
|
214 |
(kill-buffer) |
|
215 |
(error "Message not found")))) |
|
216 |
|
|
217 |
(provide 'org-mhe) |
|
218 |
|
|
219 |
;;; org-mhe.el ends here |