diff lisp/mail/mspools.el @ 17905:07602ad4416d

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Tue, 20 May 1997 21:48:58 +0000
parents
children 073e0019f9d9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mail/mspools.el	Tue May 20 21:48:58 1997 +0000
@@ -0,0 +1,394 @@
+;;; MSPOOLS.EL --- Show mail spools waiting to be read
+
+;; Copyright (C) 1997 Stephen Eglen
+
+;; Author: Stephen Eglen <stephene@cogs.susx.ac.uk>
+;; Maintainer: Stephen Eglen <stephene@cogs.susx.ac.uk>
+;; Created: 22 Jan 1997
+;; Version: 1.0
+;; Keywords:
+
+ 
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; If you use a mail filter (e.g. procmail, filter) to put mail messages in
+;; folders, this file will let you see which folders have mail waiting
+;; to be read in them.  It assumes that new mail for the file `folder'
+;; is written by the filter to a file called `folder.spool'.  (If the
+;; file writes directly to `folder' you may lose mail if new mail
+;; arrives whilst you are reading the folder in emacs, hence the use
+;; of a spool file.)  For example, the following procmail recipe puts
+;; any mail with `emacs' in the subject line into the spool file
+;; `apple.spool', ready to go into the folder `emacs'.
+;:0:
+;* ^Subject.*emacs
+;emacs.spool
+
+;; It also assumes that all of your spool files and mail folders live
+;; in the directory pointed to by `mspools-folder-directory', so you must
+;; set this (see Installation).
+
+;; When you run `mspools-show', it creates a *spools* buffer containing
+;; all of the spools in the folder directory that are waiting to be
+;; read.  On each line is the spool name and its size in bytes.  Move
+;; to the line of the folder that you would like to read, and then
+;; press return or space.  The mailer (VM or RMAIL) should then read
+;; that folder and get the new mail for you.  When you return to the
+;; *spools* buffer, you will either see "*" to indicate that the spool
+;; has been read, or the remaining unread spools, depending on the
+;; value of `mspools-update'.
+
+;; This file should work with both VM and RMAIL.  See the variable
+;; `mspools-using-vm' for details.
+
+
+;;; Installation
+
+;; Basic
+;(autoload 'mspools-show "mspools" "Show outstanding mail spools." t)
+; Point to directory where spool files and folders are:
+; (setq mspools-folder-directory "~/MAIL/")
+
+;; Extras
+; possibly bind it to a key:
+;(global-set-key  '[S-f1] 'mspools-show)
+;(setq mspools-update t)
+
+;; Interface with the mail filter
+; We assume that the mail filter drops new mail into the spool
+; `folder.spool'.  If your spool files are something like folder.xyz
+; for inbox `folder', then do
+; (setq spool-suffix "xyz")
+; If you use other conventions for your spool files, this code will
+; need rewriting.
+
+;;; Warning for VM users
+;; Dont use if you are not sure what you are doing!  The value of
+;; vm-spool-files is altered, so you may not be able to read incoming
+;; mail with VM if this is incorrectly set.
+
+;; Useful settings for VM
+;vm-auto-get-new-mail should be t (default t)
+
+;;; Acknowledgements
+;; The code for setting up vm-spool-files came from 
+;;http://www-users.informatik.rwth-aachen.de/~berg/archive/procmail/0047.html
+;;  Thanks to jond@mitre.org (Jonathan Doughty)
+
+;;; TODO
+
+;; What if users have mail spools in more than one directory?  Extend
+;; mspools-folder-directory to be a list of files?
+
+;; I was going to add mouse support so that you could click on a line
+;; to visit the buffer.  Tell me if you want it, and I can put the
+;; code in (I dont use the mouse much, so I havent bothered with it so
+;; far).
+
+
+;; Rather than showing size in bytes, could we see the number of msgs
+;; waiting?  (Could be more time demanding / system dependent).
+;; Perl script counts the number of /^From / occurences.
+;; ?
+;; Include date
+;; (substring  (current-time-string (nth 4 (file-attributes "~/INBOX")))  4 19)
+;; Maybe just call a perl script to do all the hard work, and
+;; visualise the results in the buffer.
+
+;; Shrink wrap the buffer to remove excess white-space?
+
+
+;;; User Variables
+
+
+(defvar mspools-update nil
+  "*Non-nil means update *spools* buffer after visiting any folder.")
+
+(defvar mspools-suffix "spool"
+  "*Extension used for spool files (not including full stop).")
+
+;;; Internal Variables
+
+(defvar mspools-vm-system-mail (getenv "MAIL")
+  "Main mailbox used.  Only used by VM.")
+
+(defvar mspools-vm-system-mail-crash 
+  (concat mspools-vm-system-mail ".crash")
+  "Crash box for main mailbox.  See also `mspools-vm-system-mail'.  
+Only used by VM." )
+
+
+(defvar mspools-files nil
+  "List of entries (SPOOL . SIZE) giving spool name and file size.")
+
+(defvar mspools-files-len nil
+  "Length of `mspools-files' list.")
+
+(defvar mspools-buffer "*spools*"
+  "Name of buffer for displaying spool info.")
+
+(defvar mspools-mode-map nil
+  "Keymap for the *spools* buffer.")
+
+(defvar mspools-folder-directory 
+  (if (boundp 'vm-folder-directory)
+      vm-folder-directory
+    nil)
+  "Directory where mail folders are kept.  Defaults to
+`vm-folder-directory' if bound else nil.  Make sure it has a trailing /
+at the end. ")
+
+
+(defvar mspools-using-vm 
+  (fboundp 'vm)
+  "*Non-nil if VM is used as mail reader, otherwise RMAIL is used.")
+
+
+;;; Code
+
+;;; VM Specific code
+(if mspools-using-vm
+    (require 'vm-vars))
+
+(defun mspools-set-vm-spool-files ()
+  "Set value of `vm-spool-files'.  Only needed for VM."
+  (setq		
+   vm-spool-files 
+   (append
+    (list
+     ;; Main mailbox
+     (list vm-primary-inbox
+	   mspools-vm-system-mail; your mailbox
+	   mspools-vm-system-mail-crash ; crash for mailbox
+	   ))
+    
+    ;; Mailing list inboxes
+    (mapcar '(lambda (s)
+	       "make the appropriate entry for vm-spool-files"
+	       (list
+		(concat vm-folder-directory s)
+		(concat vm-folder-directory s "." mspools-suffix)
+		(concat vm-folder-directory s ".crash")))
+	    ;; So I create a vm-spool-files entry for each of those mail drops
+	    (mapcar 'file-name-sans-extension 
+		    (directory-files vm-folder-directory nil 
+				     (format "^[^.]+\\.%s" mspools-suffix)))
+	    ))
+   ))
+
+
+
+;;; MSPOOLS-SHOW -- the main function
+(defun mspools-show ( &optional noshow) 
+  "Show the list of non-empty spool files in the *spools* buffer.
+Buffer is not displayed if SHOW is non-nil."
+  (interactive)
+  (if (get-buffer mspools-buffer)
+      ;; buffer exists
+      (progn
+	(set-buffer mspools-buffer)	
+	(setq buffer-read-only nil)      
+	(delete-region (point-min) (point-max)))
+    ;; else buff. doesnt exist so create it
+    (get-buffer-create mspools-buffer))
+  
+  ;; generate the list of spool files
+  (if mspools-using-vm
+      (mspools-set-vm-spool-files))
+  
+  (mspools-get-spool-files)
+  (if (not noshow) (pop-to-buffer mspools-buffer))
+  
+  (setq buffer-read-only t)
+  (mspools-mode)
+  )
+
+
+
+
+(defun mspools-visit-spool ()
+  "Visit the folder on the current line of the *spools* buffer."
+  (interactive)
+  (let ( spool-name folder-name)
+    (setq spool-name (mspools-get-spool-name))
+    (setq folder-name (mspools-get-folder-from-spool spool-name))
+
+    ;; put in a little "*" to indicate spool file has been read.
+    (if (not mspools-update)
+	(save-excursion
+	  (setq buffer-read-only nil)
+	  (beginning-of-line)
+	  (insert "*")
+	  (delete-char 1)
+	  (setq buffer-read-only t)
+	  ))
+    
+
+    (message "folder %s spool %s" folder-name spool-name)
+    (if (eq (count-lines (point-min) 
+			 (save-excursion
+			   (end-of-line)
+			   (point)))
+	    mspools-files-len)
+	(next-line (- 1 mspools-files-len)) ;back to top of list
+      ;; else just on to next line
+      (next-line 1))
+
+    ;; Choose whether to use VM or RMAIL for reading folder.
+    (if mspools-using-vm 
+	(vm-visit-folder (concat mspools-folder-directory folder-name))
+      ;; else using RMAIL 
+      (rmail (concat mspools-folder-directory folder-name))
+      (setq rmail-inbox-list 
+	    (list (concat mspools-folder-directory spool-name)))
+      (rmail-get-new-mail))
+    
+    
+    (if mspools-update
+	;; generate new list of spools.
+	(save-excursion 
+	  (mspools-show-again 'noshow)))
+    ))
+
+
+
+
+(defun mspools-get-folder-from-spool (name)
+  "Return folder name corresponding to the spool file NAME."
+  ;; Simply strip of the extension.
+  (file-name-sans-extension name))
+
+;; Alternative version if you have more complicated mapping of spool name
+;; to file name.
+;(defun get-folder-from-spool-safe (name)
+;  "Return the folder name corresponding to the spool file NAME."
+;  (if (string-match "^\\(.*\\)\.spool$" name)
+;      (substring name (match-beginning 1) (match-end 1))
+;    (error "Could not extract folder name from spool name %s" name)))
+
+; test
+;(mspools-get-folder-from-spool "happy.spool")
+;(mspools-get-folder-from-spool "happy.sp")
+
+
+
+(defun mspools-get-spool-name ()
+  "Return the name of the spool on the current line."
+  (let ((line-num (1- (count-lines (point-min)
+				   (save-excursion
+				     (end-of-line)
+				     (point))
+				   ))))
+    (car (nth line-num mspools-files))))
+
+;;; Keymap
+
+(if mspools-mode-map
+    ()
+  (setq mspools-mode-map (make-sparse-keymap))
+  
+  (define-key mspools-mode-map "\C-c\C-c" 'mspools-visit-spool)
+  (define-key mspools-mode-map "\C-m" 'mspools-visit-spool)
+  (define-key mspools-mode-map " " 'mspools-visit-spool)
+  (define-key mspools-mode-map "?" 'mspools-help)
+  (define-key mspools-mode-map "q" 'mspools-quit)
+  (define-key mspools-mode-map "g" 'revert-buffer))
+
+
+;;; Spools mode functions  
+
+(defun mspools-revert-buffer (ignore noconfirm)
+  "Re-run mspools-show to revert the *spools* buffer."
+  (mspools-show 'noshow))
+
+(defun mspools-show-again (&optional noshow)
+  "Update the *spools* buffer.  This is useful if mspools-update is
+nil."
+  (interactive)
+  (mspools-show noshow))
+  
+(defun mspools-help ()
+  "Show help for `mspools-mode'."
+  (interactive)
+  (describe-function 'mspools-mode))
+
+(defun mspools-quit ()
+  "Quit the *spools* buffer."
+  (interactive)
+  (kill-buffer mspools-buffer))
+  
+
+(defun mspools-mode ()
+  "Major mode for output from mspools-show.
+\\<mspools-mode-map>Move point to one of the items in this buffer, then use
+\\[mspools-visit-spool] to go to the spool that the current line refers to.
+\\[mspools-show-again] to regenerate the list of spools.
+\\{mspools-mode-map}"
+  (kill-all-local-variables)
+  (make-local-variable 'revert-buffer-function)
+  (setq revert-buffer-function 'mspools-revert-buffer)
+  (use-local-map mspools-mode-map)
+  (setq major-mode 'mspools-mode)
+  (setq mode-name "MSpools")
+  )
+
+
+(defun mspools-get-spool-files ()
+  "Find the list of spool files and display them in *spools* buffer."
+  (let (folders head spool len beg end any)
+    (setq folders (directory-files mspools-folder-directory nil 
+				   (format "^[^.]+\\.%s" mspools-suffix)))
+    
+    
+    (setq folders (mapcar 'mspools-size-folder folders))
+    (setq folders (delq nil folders))
+    (setq mspools-files folders)
+    (setq mspools-files-len (length mspools-files))
+    (set-buffer mspools-buffer)
+    (while folders
+      (setq any t)
+      (setq head (car folders))
+      (setq spool (car head))
+      (setq len (cdr head))
+      (setq folders (cdr folders))
+      (setq beg (point))
+      (insert (format " %10d %s" len spool))
+      (setq end (point))
+      (insert "\n")
+      ;;(put-text-property beg end 'mouse-face 'highlight)
+      )
+    (if any
+	(delete-char -1))			;delete last RET
+    (goto-char (point-min))
+    ))
+
+
+
+(defun mspools-size-folder (spool)
+  "Return (SPOOL . SIZE ) iff SIZE of spool file is non-zero."
+  ;; 7th file attribute is the size of the file in bytes.
+  (let ((size (nth 7 
+		   (file-attributes (concat mspools-folder-directory spool)))))
+    ;; todo (if (and (not (null size)) (> size 0))
+    (if (> size 0)
+	(cons spool  size)
+      ;; else SPOOL is empty
+      nil)))
+
+(provide 'mspools)
+;;; MSPOOLS.EL ends here