]> code.delx.au - gnu-emacs/blob - lisp/mail/mspools.el
(webjump-to-javaapi): Function deleted.
[gnu-emacs] / lisp / mail / mspools.el
1 ;;; MSPOOLS.EL --- Show mail spools waiting to be read
2
3 ;; Copyright (C) 1997 Stephen Eglen
4
5 ;; Author: Stephen Eglen <stephene@cogs.susx.ac.uk>
6 ;; Maintainer: Stephen Eglen <stephene@cogs.susx.ac.uk>
7 ;; Created: 22 Jan 1997
8 ;; Version: 1.0
9 ;; Keywords:
10
11
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Commentary:
28
29 ;; If you use a mail filter (e.g. procmail, filter) to put mail messages in
30 ;; folders, this file will let you see which folders have mail waiting
31 ;; to be read in them. It assumes that new mail for the file `folder'
32 ;; is written by the filter to a file called `folder.spool'. (If the
33 ;; file writes directly to `folder' you may lose mail if new mail
34 ;; arrives whilst you are reading the folder in emacs, hence the use
35 ;; of a spool file.) For example, the following procmail recipe puts
36 ;; any mail with `emacs' in the subject line into the spool file
37 ;; `apple.spool', ready to go into the folder `emacs'.
38 ;:0:
39 ;* ^Subject.*emacs
40 ;emacs.spool
41
42 ;; It also assumes that all of your spool files and mail folders live
43 ;; in the directory pointed to by `mspools-folder-directory', so you must
44 ;; set this (see Installation).
45
46 ;; When you run `mspools-show', it creates a *spools* buffer containing
47 ;; all of the spools in the folder directory that are waiting to be
48 ;; read. On each line is the spool name and its size in bytes. Move
49 ;; to the line of the folder that you would like to read, and then
50 ;; press return or space. The mailer (VM or RMAIL) should then read
51 ;; that folder and get the new mail for you. When you return to the
52 ;; *spools* buffer, you will either see "*" to indicate that the spool
53 ;; has been read, or the remaining unread spools, depending on the
54 ;; value of `mspools-update'.
55
56 ;; This file should work with both VM and RMAIL. See the variable
57 ;; `mspools-using-vm' for details.
58
59
60 ;;; Installation
61
62 ;; Basic
63 ;(autoload 'mspools-show "mspools" "Show outstanding mail spools." t)
64 ; Point to directory where spool files and folders are:
65 ; (setq mspools-folder-directory "~/MAIL/")
66
67 ;; Extras
68 ; possibly bind it to a key:
69 ;(global-set-key '[S-f1] 'mspools-show)
70 ;(setq mspools-update t)
71
72 ;; Interface with the mail filter
73 ; We assume that the mail filter drops new mail into the spool
74 ; `folder.spool'. If your spool files are something like folder.xyz
75 ; for inbox `folder', then do
76 ; (setq spool-suffix "xyz")
77 ; If you use other conventions for your spool files, this code will
78 ; need rewriting.
79
80 ;;; Warning for VM users
81 ;; Dont use if you are not sure what you are doing! The value of
82 ;; vm-spool-files is altered, so you may not be able to read incoming
83 ;; mail with VM if this is incorrectly set.
84
85 ;; Useful settings for VM
86 ;vm-auto-get-new-mail should be t (default t)
87
88 ;;; Acknowledgements
89 ;; The code for setting up vm-spool-files came from
90 ;;http://www-users.informatik.rwth-aachen.de/~berg/archive/procmail/0047.html
91 ;; Thanks to jond@mitre.org (Jonathan Doughty)
92
93 ;;; TODO
94
95 ;; What if users have mail spools in more than one directory? Extend
96 ;; mspools-folder-directory to be a list of files?
97
98 ;; I was going to add mouse support so that you could click on a line
99 ;; to visit the buffer. Tell me if you want it, and I can put the
100 ;; code in (I dont use the mouse much, so I havent bothered with it so
101 ;; far).
102
103
104 ;; Rather than showing size in bytes, could we see the number of msgs
105 ;; waiting? (Could be more time demanding / system dependent).
106 ;; Perl script counts the number of /^From / occurences.
107 ;; ?
108 ;; Include date
109 ;; (substring (current-time-string (nth 4 (file-attributes "~/INBOX"))) 4 19)
110 ;; Maybe just call a perl script to do all the hard work, and
111 ;; visualise the results in the buffer.
112
113 ;; Shrink wrap the buffer to remove excess white-space?
114
115
116 ;;; User Variables
117
118
119 (defvar mspools-update nil
120 "*Non-nil means update *spools* buffer after visiting any folder.")
121
122 (defvar mspools-suffix "spool"
123 "*Extension used for spool files (not including full stop).")
124
125 ;;; Internal Variables
126
127 (defvar mspools-vm-system-mail (getenv "MAIL")
128 "Main mailbox used. Only used by VM.")
129
130 (defvar mspools-vm-system-mail-crash
131 (concat mspools-vm-system-mail ".crash")
132 "Crash box for main mailbox. See also `mspools-vm-system-mail'.
133 Only used by VM." )
134
135
136 (defvar mspools-files nil
137 "List of entries (SPOOL . SIZE) giving spool name and file size.")
138
139 (defvar mspools-files-len nil
140 "Length of `mspools-files' list.")
141
142 (defvar mspools-buffer "*spools*"
143 "Name of buffer for displaying spool info.")
144
145 (defvar mspools-mode-map nil
146 "Keymap for the *spools* buffer.")
147
148 (defvar mspools-folder-directory
149 (if (boundp 'vm-folder-directory)
150 vm-folder-directory
151 nil)
152 "Directory where mail folders are kept. Defaults to
153 `vm-folder-directory' if bound else nil. Make sure it has a trailing /
154 at the end. ")
155
156
157 (defvar mspools-using-vm
158 (fboundp 'vm)
159 "*Non-nil if VM is used as mail reader, otherwise RMAIL is used.")
160
161
162 ;;; Code
163
164 ;;; VM Specific code
165 (if mspools-using-vm
166 (require 'vm-vars))
167
168 (defun mspools-set-vm-spool-files ()
169 "Set value of `vm-spool-files'. Only needed for VM."
170 (setq
171 vm-spool-files
172 (append
173 (list
174 ;; Main mailbox
175 (list vm-primary-inbox
176 mspools-vm-system-mail; your mailbox
177 mspools-vm-system-mail-crash ; crash for mailbox
178 ))
179
180 ;; Mailing list inboxes
181 (mapcar '(lambda (s)
182 "make the appropriate entry for vm-spool-files"
183 (list
184 (concat vm-folder-directory s)
185 (concat vm-folder-directory s "." mspools-suffix)
186 (concat vm-folder-directory s ".crash")))
187 ;; So I create a vm-spool-files entry for each of those mail drops
188 (mapcar 'file-name-sans-extension
189 (directory-files vm-folder-directory nil
190 (format "^[^.]+\\.%s" mspools-suffix)))
191 ))
192 ))
193
194
195
196 ;;; MSPOOLS-SHOW -- the main function
197 (defun mspools-show ( &optional noshow)
198 "Show the list of non-empty spool files in the *spools* buffer.
199 Buffer is not displayed if SHOW is non-nil."
200 (interactive)
201 (if (get-buffer mspools-buffer)
202 ;; buffer exists
203 (progn
204 (set-buffer mspools-buffer)
205 (setq buffer-read-only nil)
206 (delete-region (point-min) (point-max)))
207 ;; else buff. doesnt exist so create it
208 (get-buffer-create mspools-buffer))
209
210 ;; generate the list of spool files
211 (if mspools-using-vm
212 (mspools-set-vm-spool-files))
213
214 (mspools-get-spool-files)
215 (if (not noshow) (pop-to-buffer mspools-buffer))
216
217 (setq buffer-read-only t)
218 (mspools-mode)
219 )
220
221
222
223
224 (defun mspools-visit-spool ()
225 "Visit the folder on the current line of the *spools* buffer."
226 (interactive)
227 (let ( spool-name folder-name)
228 (setq spool-name (mspools-get-spool-name))
229 (setq folder-name (mspools-get-folder-from-spool spool-name))
230
231 ;; put in a little "*" to indicate spool file has been read.
232 (if (not mspools-update)
233 (save-excursion
234 (setq buffer-read-only nil)
235 (beginning-of-line)
236 (insert "*")
237 (delete-char 1)
238 (setq buffer-read-only t)
239 ))
240
241
242 (message "folder %s spool %s" folder-name spool-name)
243 (if (eq (count-lines (point-min)
244 (save-excursion
245 (end-of-line)
246 (point)))
247 mspools-files-len)
248 (next-line (- 1 mspools-files-len)) ;back to top of list
249 ;; else just on to next line
250 (next-line 1))
251
252 ;; Choose whether to use VM or RMAIL for reading folder.
253 (if mspools-using-vm
254 (vm-visit-folder (concat mspools-folder-directory folder-name))
255 ;; else using RMAIL
256 (rmail (concat mspools-folder-directory folder-name))
257 (setq rmail-inbox-list
258 (list (concat mspools-folder-directory spool-name)))
259 (rmail-get-new-mail))
260
261
262 (if mspools-update
263 ;; generate new list of spools.
264 (save-excursion
265 (mspools-show-again 'noshow)))
266 ))
267
268
269
270
271 (defun mspools-get-folder-from-spool (name)
272 "Return folder name corresponding to the spool file NAME."
273 ;; Simply strip of the extension.
274 (file-name-sans-extension name))
275
276 ;; Alternative version if you have more complicated mapping of spool name
277 ;; to file name.
278 ;(defun get-folder-from-spool-safe (name)
279 ; "Return the folder name corresponding to the spool file NAME."
280 ; (if (string-match "^\\(.*\\)\.spool$" name)
281 ; (substring name (match-beginning 1) (match-end 1))
282 ; (error "Could not extract folder name from spool name %s" name)))
283
284 ; test
285 ;(mspools-get-folder-from-spool "happy.spool")
286 ;(mspools-get-folder-from-spool "happy.sp")
287
288
289
290 (defun mspools-get-spool-name ()
291 "Return the name of the spool on the current line."
292 (let ((line-num (1- (count-lines (point-min)
293 (save-excursion
294 (end-of-line)
295 (point))
296 ))))
297 (car (nth line-num mspools-files))))
298
299 ;;; Keymap
300
301 (if mspools-mode-map
302 ()
303 (setq mspools-mode-map (make-sparse-keymap))
304
305 (define-key mspools-mode-map "\C-c\C-c" 'mspools-visit-spool)
306 (define-key mspools-mode-map "\C-m" 'mspools-visit-spool)
307 (define-key mspools-mode-map " " 'mspools-visit-spool)
308 (define-key mspools-mode-map "?" 'mspools-help)
309 (define-key mspools-mode-map "q" 'mspools-quit)
310 (define-key mspools-mode-map "g" 'revert-buffer))
311
312
313 ;;; Spools mode functions
314
315 (defun mspools-revert-buffer (ignore noconfirm)
316 "Re-run mspools-show to revert the *spools* buffer."
317 (mspools-show 'noshow))
318
319 (defun mspools-show-again (&optional noshow)
320 "Update the *spools* buffer. This is useful if mspools-update is
321 nil."
322 (interactive)
323 (mspools-show noshow))
324
325 (defun mspools-help ()
326 "Show help for `mspools-mode'."
327 (interactive)
328 (describe-function 'mspools-mode))
329
330 (defun mspools-quit ()
331 "Quit the *spools* buffer."
332 (interactive)
333 (kill-buffer mspools-buffer))
334
335
336 (defun mspools-mode ()
337 "Major mode for output from mspools-show.
338 \\<mspools-mode-map>Move point to one of the items in this buffer, then use
339 \\[mspools-visit-spool] to go to the spool that the current line refers to.
340 \\[mspools-show-again] to regenerate the list of spools.
341 \\{mspools-mode-map}"
342 (kill-all-local-variables)
343 (make-local-variable 'revert-buffer-function)
344 (setq revert-buffer-function 'mspools-revert-buffer)
345 (use-local-map mspools-mode-map)
346 (setq major-mode 'mspools-mode)
347 (setq mode-name "MSpools")
348 )
349
350
351 (defun mspools-get-spool-files ()
352 "Find the list of spool files and display them in *spools* buffer."
353 (let (folders head spool len beg end any)
354 (setq folders (directory-files mspools-folder-directory nil
355 (format "^[^.]+\\.%s" mspools-suffix)))
356
357
358 (setq folders (mapcar 'mspools-size-folder folders))
359 (setq folders (delq nil folders))
360 (setq mspools-files folders)
361 (setq mspools-files-len (length mspools-files))
362 (set-buffer mspools-buffer)
363 (while folders
364 (setq any t)
365 (setq head (car folders))
366 (setq spool (car head))
367 (setq len (cdr head))
368 (setq folders (cdr folders))
369 (setq beg (point))
370 (insert (format " %10d %s" len spool))
371 (setq end (point))
372 (insert "\n")
373 ;;(put-text-property beg end 'mouse-face 'highlight)
374 )
375 (if any
376 (delete-char -1)) ;delete last RET
377 (goto-char (point-min))
378 ))
379
380
381
382 (defun mspools-size-folder (spool)
383 "Return (SPOOL . SIZE ) iff SIZE of spool file is non-zero."
384 ;; 7th file attribute is the size of the file in bytes.
385 (let ((size (nth 7
386 (file-attributes (concat mspools-folder-directory spool)))))
387 ;; todo (if (and (not (null size)) (> size 0))
388 (if (> size 0)
389 (cons spool size)
390 ;; else SPOOL is empty
391 nil)))
392
393 (provide 'mspools)
394 ;;; MSPOOLS.EL ends here