0
|
1 ;; Last edited: Wed Oct 24 17:08:20 1990
|
|
2 ;; provide a simple diary facility on top of rmailsum
|
|
3 ;; Copyright (C) 1990 Henry S. Thompson
|
|
4
|
|
5 ;; This file is part of GNU Emacs.
|
|
6
|
|
7 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
8 ;; but WITHOUT ANY WARRANTY. No author or distributor
|
|
9 ;; accepts responsibility to anyone for the consequences of using it
|
|
10 ;; or for whether it serves any particular purpose or works at all,
|
|
11 ;; unless he says so in writing. Refer to the GNU Emacs General Public
|
|
12 ;; License for full details.
|
|
13
|
|
14 ;; Everyone is granted permission to copy, modify and redistribute
|
|
15 ;; GNU Emacs, but only under the conditions described in the
|
|
16 ;; GNU Emacs General Public License. A copy of this license is
|
|
17 ;; supposed to have been given to you along with GNU Emacs so you
|
|
18 ;; can know your rights and responsibilities. It should be in a
|
|
19 ;; file named COPYING. Among other things, the copyright notice
|
|
20 ;; and this notice must be preserved on all copies.
|
|
21
|
|
22 (provide 'diary)
|
|
23 (require 'mail-extras)
|
|
24
|
|
25 (autoload 'sort-subr "sort")
|
|
26
|
|
27 (defvar ht-diary-file-name "~/DIARY.babyl"
|
|
28 "default name of diary file")
|
|
29
|
|
30 (defvar ht-Calendar-directory "~/Calendar")
|
|
31
|
|
32 (defun xxx-date-lessp (date1 date2)
|
|
33 "Return T if DATE1 is earlyer than DATE2."
|
|
34 (string-lessp (gnus-comparable-date date1)
|
|
35 (gnus-comparable-date date2)))
|
|
36
|
|
37 (defun xxx-comparable-date (date)
|
|
38 "Make comparable string by string-lessp from DATE."
|
|
39 (let ((month '(("JAN" . " 1")("FEB" . " 2")("MAR" . " 3")
|
|
40 ("APR" . " 4")("MAY" . " 5")("JUN" . " 6")
|
|
41 ("JUL" . " 7")("AUG" . " 8")("SEP" . " 9")
|
|
42 ("OCT" . "10")("NOV" . "11")("DEC" . "12")))
|
|
43 (date (or date "")))
|
|
44 ;; Can understand the following styles:
|
|
45 ;; (1) 14 Apr 89 03:20:12 GMT
|
|
46 ;; (2) Fri, 17 March 89 4:01:33 GMT
|
|
47 (if (string-match
|
|
48 "\\([0-9]+\\) \\([^ ,]+\\) \\([0-9]+\\) *\\([0-9:]*\\)" date)
|
|
49 (concat
|
|
50 ;; Year
|
|
51 (substring date (match-beginning 3) (match-end 3))
|
|
52 ;; Month
|
|
53 (cdr
|
|
54 (assoc
|
|
55 (upcase (substring date
|
|
56 (match-beginning 2)
|
|
57 (+ 3 (match-beginning 2))))
|
|
58 month))
|
|
59 ;; Day
|
|
60 (format "%2d" (string-to-int
|
|
61 (substring date
|
|
62 (match-beginning 1) (match-end 1))))
|
|
63 ;; Time
|
|
64 (substring date (match-beginning 4) (match-end 4)))
|
|
65 ;; Cannot understand DATE string.
|
|
66 date
|
|
67 )
|
|
68 ))
|
|
69
|
|
70 (defun update-default-diary (arg) "update a diary - with arg, the one for
|
|
71 this file. Without arg, the default (named in ht-diary-file-name)"
|
|
72 (interactive "P")
|
|
73 (if arg
|
|
74 (update-diary (current-buffer))
|
|
75 (require-diary)
|
|
76 (update-diary (get-file-buffer ht-diary-file-name))))
|
|
77
|
|
78 (defun update-diary (buffer)
|
|
79 ;; (setq rmail-summary-buffer (get-buffer-create "*Diary*"))
|
|
80 (let ((obuf (current-buffer)))
|
|
81 (set-buffer buffer)
|
|
82 (if (not has-diary-summary)
|
|
83 (progn (make-local-variable 'has-diary-summary)
|
|
84 (setq has-diary-summary t)))
|
|
85 (rmail-summary)
|
|
86 (set-buffer obuf)))
|
|
87
|
|
88 (defun do-diary-update () "rmail-summary-mode-hook calls this"
|
|
89 (if (save-excursion (set-buffer rbuf)
|
|
90 has-diary-summary)
|
|
91 (progn
|
|
92 (make-local-variable 'diary-summary-buffer)
|
|
93 (setq diary-summary-buffer t)
|
|
94 (setq description (concat "Diary " description))
|
|
95 (setq buffer-read-only nil)
|
|
96 (sort-diary-hdrs)
|
|
97 (format-diary-hdrs)
|
|
98 (setq buffer-read-only t)
|
|
99 (not-modified)
|
|
100 (beginning-of-buffer)
|
|
101 (setq mesg nil) ; to go to earliest, not first in file
|
|
102 )))
|
|
103
|
|
104 (defun require-diary ()
|
|
105 (if (not (get-file-buffer ht-diary-file-name))
|
|
106 (progn (rmail-input ht-diary-file-name)
|
|
107 (rmail-show-message 1))
|
|
108 ))
|
|
109
|
|
110 (defvar diary-summary-buffer nil "flag to identify diary summaries")
|
|
111 (defvar has-diary-summary nil "flag to identify buffers with diary summaries")
|
|
112
|
|
113 (defun sort-diary-hdrs ()
|
|
114 (interactive)
|
|
115 (goto-char (point-min))
|
|
116 (sort-subr nil 'forward-line 'end-of-line 'get-diary-hdr-date nil))
|
|
117
|
|
118 (defun format-diary-hdrs ()
|
|
119 (goto-char (point-min))
|
|
120 (while (< (point)(point-max))
|
|
121 (forward-char 5)
|
|
122 (delete-char 35)
|
|
123 (looking-at " *\\([0-9]*\\) *\\([a-zA-Z]*\\) *\\([0-9]*\\) *\\([0-9]*\\)")
|
|
124 (if (match-beginning 0)
|
|
125 (let ((day (buffer-substring (match-beginning 1)(match-end 1)))
|
|
126 (month (capitalize (buffer-substring (match-beginning 2)
|
|
127 (min (+ (match-beginning 2)
|
|
128 3)
|
|
129 (match-end 2)))))
|
|
130 (year (buffer-substring (max
|
|
131 (- (match-end 3) 2)
|
|
132 (match-beginning 3))
|
|
133 (match-end 3)))
|
|
134 (time (buffer-substring (match-beginning 4)(match-end 4))))
|
|
135 (delete-char (+ 1
|
|
136 (if (= (match-end 4)
|
|
137 (match-beginning 4))
|
|
138 0 ; fix for no time case
|
|
139 1)
|
|
140 (- (match-end 4)(match-beginning 1))))
|
|
141 (insert (format " %2s %3s %2s %4s " day month year time))))
|
|
142 (forward-line 1))
|
|
143 (goto-char (point-min)))
|
|
144
|
|
145 (defun get-diary-hdr-date ()
|
|
146 (looking-at " *[^ ]* *[^ ]* *[^ ]* *\\(.*\\)$")
|
|
147 (xxx-comparable-date (buffer-substring (match-beginning 1)(match-end 1))))
|
|
148
|
|
149
|
|
150 (if (not (boundp 'rmail-edit-map))
|
|
151 (load-library "rmailedit"))
|
|
152 (if (not (boundp 'rmail-summary-mode-map))
|
|
153 (progn (load-library "rmailsum")
|
|
154 (rmail-summary-mode-fun1)))
|
|
155 (define-key rmail-edit-map "\C-c\C-c" 'ht-rmail-cease-edit)
|
|
156 (define-key rmail-edit-map "\C-c\C-]" 'ht-rmail-abort-edit)
|
|
157 ;(defvar diary-mode-map (copy-keymap rmail-summary-mode-map))
|
|
158 ;(define-key diary-mode-map "s" 'diary-save)
|
|
159 (define-key rmail-mode-map "h" 'ht-rmail-summarise)
|
|
160 (setq rmail-summary-mode-hook 'do-diary-update)
|
|
161
|
|
162 (defvar editing-diary-entry nil)
|
|
163
|
|
164 (defun diary-save ()
|
|
165 "save parent file and update"
|
|
166 (interactive)
|
|
167 (set-buffer rmail-buffer)
|
|
168 (rmail-expunge-and-save)
|
|
169 (if has-diary-summary (update-diary (current-buffer))))
|
|
170
|
|
171 (defun ht-rmail-summarise ()
|
|
172 "Display a summary of all messages, one line per message.
|
|
173 If file is named as ht-diary-file-name, or the summary buffer is already
|
|
174 a diary summary, make it a Diary summary (see
|
|
175 \\[describe-mode] rmail-summary-mode for info)."
|
|
176 (interactive)
|
|
177 (if (eq (current-buffer)
|
|
178 (get-file-buffer ht-diary-file-name))
|
|
179 (update-default-diary t)
|
|
180 (rmail-summary)))
|
|
181
|
|
182 (defun edit-and-move-to-diary ()
|
|
183 "try to add a date to subject field, move to diary on exit"
|
|
184 (interactive)
|
|
185 (make-local-variable 'editing-diary-entry)
|
|
186 (setq editing-diary-entry t)
|
|
187 (rmail-edit-current-message)
|
|
188 (goto-char (point-min))
|
|
189 (search-forward "\n\n")
|
|
190 (let ((try-date (and
|
|
191 (re-search-forward
|
|
192 "[0-9][-0-9 ]*[- ][a-zA-Z][a-zA-Z]*[- 0-9]*" nil t)
|
|
193 (buffer-substring (match-beginning 0)(match-end 0)))))
|
|
194 (goto-char (point-min))
|
|
195 (if (and (search-forward "Subject: " nil t)
|
|
196 try-date)
|
|
197 (progn (set-mark (point))
|
|
198 (insert try-date)))))
|
|
199
|
|
200 ;; private copy to simulate hook
|
|
201 (defun ht-rmail-cease-edit ()
|
|
202 "check if diary edit, move if so"
|
|
203 (interactive)
|
|
204 (rmail-cease-edit)
|
|
205 (if editing-diary-entry
|
|
206 (progn (setq editing-diary-entry nil)
|
|
207 (ht-output-to-Calendar)
|
|
208 (rmail-output-to-rmail-file ht-diary-file-name 1)
|
|
209 (ht-rmail-delete-forward))))
|
|
210
|
|
211 ;; try to add a diary subject field line to the appropriate caleendar file
|
|
212 (defun ht-output-to-Calendar ()
|
|
213 (goto-char (point-min))
|
|
214 (search-forward "Subject: ")
|
|
215 (or (looking-at
|
|
216 "\\([0-9]+\\) \\([A-Za-z]+\\) \\([0-9]+\\) \\([0-9:]*\\) ?\\(.*\\)\n")
|
|
217 (error "not a recognisable diary line"))
|
|
218 (let ((day (buffer-substring (match-beginning 1) (match-end 1)))
|
|
219 (month (buffer-substring (match-beginning 2) (match-end 2)))
|
|
220 (year (buffer-substring (match-beginning 3) (match-end 3)))
|
|
221 (time (buffer-substring (match-beginning 4) (match-end 4)))
|
|
222 (message (buffer-substring (match-beginning 5) (match-end 5)))
|
|
223 (mb (match-beginning 4))
|
|
224 (me (match-end 5))
|
|
225 t-month ends)
|
|
226 (if (file-exists-p ht-Calendar-directory)
|
|
227 (let* ((year (if (string-match "^19" year)
|
|
228 year
|
|
229 (concat "19" year)))
|
|
230 (dfn (concat ht-Calendar-directory
|
|
231 "/xy"
|
|
232 year
|
|
233 "/xc"
|
|
234 day
|
|
235 (setq t-month (capitalize
|
|
236 (substring month 0 3)))
|
|
237 year))
|
|
238 (buf (find-file-noselect dfn)))
|
|
239 (save-excursion
|
|
240 (set-buffer buf)
|
|
241 (goto-char (point-max))
|
|
242 (if (not (bolp))
|
|
243 (insert "\n"))
|
|
244 (if time
|
|
245 (insert time " "))
|
|
246 (if (string-match " -- \\(.*\\)$" message)
|
|
247 (progn
|
|
248 (setq ends (substring message (match-beginning 1)
|
|
249 (match-end 1)))
|
|
250 (setq message (substring message 0 (match-beginning 0)))))
|
|
251 (insert message)
|
|
252 (let ((require-final-newline nil))
|
|
253 (save-buffer)))
|
|
254 (if ends
|
|
255 ;; an end date also given
|
|
256 (if (string-match "\\([0-9]+\\) \\([A-Za-z]+\\)" ends)
|
|
257 (let ((e-day (substring ends (match-beginning 1)
|
|
258 (match-end 1)))
|
|
259 (e-month (substring ends (match-beginning 2)
|
|
260 (match-end 2)))
|
|
261 t-e-month msg)
|
|
262 (setq msg (concat
|
|
263 (substring message 0
|
|
264 (string-match " " message))
|
|
265 " continues"))
|
|
266 (if (string-equal (setq t-e-month
|
|
267 (capitalize
|
|
268 (substring e-month 0 3)))
|
|
269 t-month)
|
|
270 (fill-dates year t-month (1+ (car
|
|
271 (read-from-string day)))
|
|
272 (car
|
|
273 (read-from-string e-day))
|
|
274 msg)
|
|
275 (fill-dates year t-month (1+ (car
|
|
276 (read-from-string day)))
|
|
277 (cdr (assoc t-month
|
|
278 '(("Jan" . 31)
|
|
279 ("Feb" . 28)
|
|
280 ("Mar" . 31)
|
|
281 ("Apr" . 30)
|
|
282 ("May" . 31)
|
|
283 ("Jun" . 30)
|
|
284 ("Jul" . 31)
|
|
285 ("Aug" . 31)
|
|
286 ("Sep" . 30)
|
|
287 ("Oct" . 31)
|
|
288 ("Nov" . 30)
|
|
289 ("Dec" . 31))))
|
|
290 msg)
|
|
291 (fill-dates year t-e-month 1
|
|
292 (car (read-from-string e-day))
|
|
293 msg)))
|
|
294 (message "\C-g\C-gCouldn't parse end date: %s" ends)))
|
|
295 ))))
|
|
296
|
|
297 (defun fill-dates (year month start end mesg)
|
|
298 "fill the dates between start and end with message in the calendar"
|
|
299 (let ((day start))
|
|
300 (while (<= day end)
|
|
301 (let* ((dfn (concat ht-Calendar-directory
|
|
302 "/xy"
|
|
303 year
|
|
304 "/xc"
|
|
305 day
|
|
306 month
|
|
307 year))
|
|
308 (buf (find-file-noselect dfn)))
|
|
309 (save-excursion
|
|
310 (set-buffer buf)
|
|
311 (goto-char (point-max))
|
|
312 (if (not (bolp))
|
|
313 (insert "\n"))
|
|
314 (insert mesg)
|
|
315 (let ((require-final-newline nil))
|
|
316 (save-buffer))))
|
|
317 (setq day (1+ day)))))
|
|
318
|
|
319 ;; private copy
|
|
320 (defun ht-rmail-abort-edit ()
|
|
321 "add a hook"
|
|
322 (interactive)
|
|
323 (setq editing-diary-entry nil)
|
|
324 (rmail-abort-edit))
|
|
325
|
|
326 (defun rmail-edit-current-message ()
|
|
327 "Edit the contents of this message."
|
|
328 (interactive)
|
|
329 (rmail-edit-mode)
|
|
330 (make-local-variable 'rmail-old-text)
|
|
331 (setq rmail-old-text (buffer-substring (point-min) (point-max)))
|
|
332 (setq buffer-read-only nil)
|
|
333 (set-buffer-modified-p (buffer-modified-p))
|
|
334 ;; Make mode line update.
|
|
335 (if (and (eq (key-binding "\C-c\C-c") 'ht-rmail-cease-edit)
|
|
336 (eq (key-binding "\C-c\C-]") 'ht-rmail-abort-edit))
|
|
337 (if editing-diary-entry
|
|
338 (message "Editing: Type C-c C-c to move to diary and return to Rmail, C-c C-] to abort")
|
|
339 (message "Editing: Type C-c C-c to return to Rmail, C-c C-] to abort"))
|
|
340 (message (substitute-command-keys
|
|
341 "Editing: Type \\[rmail-cease-edit] to return to Rmail, \\[rmail-abort-edit] to abort"))))
|