From:	CRDGW2::CRDGW2::MRGATE::"SMTP::PREP.AI.MIT.EDU::INFO-GNU-EMACS-REQUEST" 13-JUL-1989 10:54
To:	MRGATE::"ARISIA::EVERHART"
Subj:	VM 4.37 (part 3 of 4)

Received: by life.ai.mit.edu (4.1/AI-4.10) id AA02062; Wed, 12 Jul 89 18:11:25 EDT
Return-Path: <talos!kjones@uunet.uu.net>
Received: from uunet.uu.net by life.ai.mit.edu (4.1/AI-4.10) id AA01720; Wed, 12 Jul 89 17:56:10 EDT
Received: from talos.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA03320; Wed, 12 Jul 89 17:55:52 -0400
Date: Wed, 12 Jul 89 17:30:33 EDT
From: talos!kjones@uunet.uu.net (Kyle Jones)
Message-Id: <8907122130.AA02141@talos.uucp>
To: info-gnu-emacs@prep.ai.mit.edu
Reply-To: kyle@cs.odu.edu
Subject: VM 4.37 (part 3 of 4)

#!/bin/sh
# this is part 3 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file vm.el continued
#
CurArch=3
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file vm.el"
sed 's/^X//' << 'SHAR_EOF' >> vm.el
X(defmacro vm-set-subject-of (message subject) (list 'aset message 17 subject))
X(defmacro vm-set-su-start-of (message start) (list 'aset message 18 start))
X(defmacro vm-set-su-end-of (message end) (list 'aset message 19 end))
X
X(defun vm-text-end-of (message)
X  (- (vm-end-of message)
X     (cond ((eq vm-folder-type 'mmdf) 5)
X	   (t 1))))
X
X;; The remaining routines in this group are part of the undo system.
X
X;; init
X(if vm-mode-map
X    ()
X  (setq vm-mode-map (make-keymap))
X  (suppress-keymap vm-mode-map)
X  (define-key vm-mode-map "h" 'vm-summarize)
X  (define-key vm-mode-map "\M-n" 'vm-next-unread-message)
X  (define-key vm-mode-map "\M-p" 'vm-previous-unread-message)
X  (define-key vm-mode-map "n" 'vm-next-message)
X  (define-key vm-mode-map "p" 'vm-previous-message)
X  (define-key vm-mode-map "N" 'vm-Next-message)
X  (define-key vm-mode-map "P" 'vm-Previous-message)
X  (define-key vm-mode-map "\t" 'vm-goto-message-last-seen)
X  (define-key vm-mode-map "\r" 'vm-goto-message)
X  (define-key vm-mode-map "t" 'vm-expose-hidden-headers)
X  (define-key vm-mode-map " " 'vm-scroll-forward)
X  (define-key vm-mode-map "b" 'vm-scroll-backward)
X  (define-key vm-mode-map "\C-?" 'vm-scroll-backward)
X  (define-key vm-mode-map "d" 'vm-delete-message)
X  (define-key vm-mode-map "u" 'vm-undelete-message)
X  (define-key vm-mode-map "k" 'vm-kill-subject)
X  (define-key vm-mode-map "f" 'vm-followup)
X  (define-key vm-mode-map "F" 'vm-followup-include-text)
X  (define-key vm-mode-map "r" 'vm-reply)
X  (define-key vm-mode-map "R" 'vm-reply-include-text)
X  (define-key vm-mode-map "z" 'vm-forward-message)
X  (define-key vm-mode-map "@" 'vm-send-digest)
X  (define-key vm-mode-map "*" 'vm-burst-digest)
X  (define-key vm-mode-map "m" 'vm-mail)
X  (define-key vm-mode-map "g" 'vm-get-new-mail)
X  (define-key vm-mode-map "G" 'vm-group-messages)
X  (define-key vm-mode-map "v" 'vm-visit-folder)
X  (define-key vm-mode-map "s" 'vm-save-message)
X  (define-key vm-mode-map "w" 'vm-save-message-sans-headers)
X  (define-key vm-mode-map "A" 'vm-auto-archive-messages)
X  (define-key vm-mode-map "S" 'vm-save-folder)
X  (define-key vm-mode-map "|" 'vm-pipe-message-to-command)
X  (define-key vm-mode-map "#" 'vm-expunge-folder)
X  (define-key vm-mode-map "q" 'vm-quit)
X  (define-key vm-mode-map "x" 'vm-quit-no-change)
X  (define-key vm-mode-map "?" 'vm-help)
X  (define-key vm-mode-map "\C-_" 'vm-undo)
X  (define-key vm-mode-map "\C-xu" 'vm-undo)
X  (define-key vm-mode-map "!" 'shell-command)
X  (define-key vm-mode-map "<" 'beginning-of-buffer)
X  (define-key vm-mode-map ">" 'vm-end-of-message)
X  (define-key vm-mode-map "\M-s" 'vm-isearch-forward)
X  (define-key vm-mode-map "=" 'vm-summarize)
X  (define-key vm-mode-map "\M-c" 'vm-show-copying-restrictions)
X  (define-key vm-mode-map "\M-w" 'vm-show-no-warranty)
X  (define-key vm-mode-map "\M-C" 'vm-show-copying-restrictions)
X  (define-key vm-mode-map "\M-W" 'vm-show-no-warranty))
X
X(defun vm-mark-for-display-update (message)
X  (if (not (memq message vm-messages-needing-display-update))
X      (setq vm-messages-needing-display-update
X	    (cons message vm-messages-needing-display-update))))
X
X(defun vm-last (list) (while (cdr-safe list) (setq list (cdr list))) list)
X
X(put 'folder-empty 'error-conditions '(folder-empty error))
X(put 'folder-empty 'error-message "Folder is empty")
X
X(defun vm-error-if-folder-empty ()
X  (while (null vm-message-list)
X    (signal 'folder-empty nil)))
X
X(defun vm-proportion-windows ()
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (if (not (one-window-p t))
X      (let ((mail-w (get-buffer-window (current-buffer)))
X	    (n (- (window-height (get-buffer-window (current-buffer)))
X		  (/ (* vm-mail-window-percentage
X			(- (screen-height)
X			   (window-height (minibuffer-window))))
X		     100)))
X	    (old-w (selected-window)))
X	(if mail-w
X	    (save-excursion
X	      (select-window mail-w)
X	      (shrink-window n)
X	      (select-window old-w))))))
X
X(defun vm-number-messages ()
X  (let ((n 1) (message-list vm-message-list))
X    (while message-list
X      (vm-set-number-of (car message-list) (int-to-string n))
X      (setq n (1+ n) message-list (cdr message-list)))
X    (setq vm-ml-highest-message-number (int-to-string (1- n)))))
X
X(defun vm-match-visible-header (alist)
X  (catch 'match
X    (while alist
X      (if (looking-at (car (car alist)))
X	  (throw 'match (car alist)))
X      (setq alist (cdr alist)))
X    nil))
X
X(defun vm-delete-header ()
X  (if (looking-at vm-generic-header-regexp)
X      (delete-region (match-beginning 0) (match-end 0))))
X
X;; Build a chain of message structures.
X;; Find the start and end of each message and fill end the relevant
X;; fields in the message structures.
X
X(defun vm-build-message-list ()
X  (save-excursion
X    (vm-build-visible-header-alist)
X    (let (tail-cons message prev-message case-fold-search marker
X	  start-regexp sep-pattern trailer-length)
X      (if (eq vm-folder-type 'mmdf)
X	  (setq start-regexp "^\001\001\001\001\n"
X		separator-string "\n\001\001\001\001\n\001\001\001\001"
X		trailer-length 6)
X	(setq start-regexp "^From "
X	      separator-string "\n\nFrom "
X	      trailer-length 2))
X      (if vm-message-list
X	  (let ((mp vm-message-list)
X		(end (point-min)))
X	    (while mp
X	      (if (< end (vm-end-of (car mp)))
X		  (setq end (vm-end-of (car mp))))
X	      (setq mp (cdr mp)))
X	    ;; move back past trailer so separator-string will match below
X	    (goto-char (- end trailer-length))
X	    (setq tail-cons (vm-last vm-message-list)))
X	(goto-char (point-min))
X	(if (looking-at start-regexp)
X	    (progn
X	      (setq message (vm-make-message) prev-message message)
X	      (vm-set-start-of message (vm-marker (match-beginning 0)))
X	      (setq vm-message-list (list message)
X		    tail-cons vm-message-list))))
X      (while (search-forward separator-string nil t)
X	(setq marker (vm-marker (+ trailer-length (match-beginning 0)))
X	      message (vm-make-message))
X	(vm-set-start-of message marker)
X	(if prev-message
X	    (vm-set-end-of prev-message marker))
X	(if tail-cons
X	    (progn
X	      (setcdr tail-cons (list message))
X	      (setq tail-cons (cdr tail-cons)
X		    prev-message message))
X	  (setq vm-message-list (list message)
X		tail-cons vm-message-list
X		prev-message message)))
X      (if prev-message
X	  (vm-set-end-of prev-message (vm-marker (point-max)))))))
X
X(defun vm-build-visible-header-alist ()
X  (let ((header-alist (cons nil nil))
X	(vheaders vm-visible-headers)
X	list)
X    (setq list header-alist)
X    (while vheaders
X      (setcdr list (cons (cons (car vheaders) nil) nil))
X      (setq list (cdr list) vheaders (cdr vheaders)))
X    (setq vm-visible-header-alist (cdr header-alist))))
X
X;; Group the headers that the user wants to see at the end of the headers
X;; section so we can narrow to them.  The vheaders field of the
X;; message struct is set.  This function is called on demand whenever
X;; a vheaders field is discovered to be nil for a particular message.
X
X(defun vm-reorder-message-headers (message)
X  (save-excursion
X    (vm-save-restriction
X     (let ((header-alist vm-visible-header-alist)
X	   list buffer-read-only match-end-0
X	   (inhibit-quit t)
X	   (old-buffer-modified-p (buffer-modified-p)))
X       (goto-char (vm-start-of message))
X       (forward-line)
X       (while (and (not (= (following-char) ?\n))
X		   (looking-at vm-generic-header-regexp))
X	 (setq match-end-0 (match-end 0)
X	       list (vm-match-visible-header header-alist))
X	 (if (null list)
X	     (goto-char match-end-0)
X	   (if (cdr list)
X	       (setcdr list 
X		       (concat
X			(cdr list)
X			(buffer-substring (point) match-end-0)))
X	     (setcdr list (buffer-substring (point) match-end-0)))
X	   (delete-region (point) match-end-0)))
X       (vm-set-vheaders-of message (point-marker))
X       (setq list header-alist)
X       (while list
X	 (if (cdr (car list))
X	     (progn
X	       (insert (cdr (car list)))
X	       (setcdr (car list) nil)))
X	 (setq list (cdr list)))
X       (set-buffer-modified-p old-buffer-modified-p)))))
X
X;; Read the attribute headers from the messages and store their contents
X;; in attributes fields of the message structures.  If a message has no
X;; attributes header assume it is new.  If a message already has
X;; attributes don't bother checking the headers.
X;;
X;; Stores the position where the message text begins in the message struct.
X
X(defun vm-read-attributes ()
X  (save-excursion
X    (let ((mp vm-message-list))
X      (setq vm-new-count 0
X	    vm-unread-count 0
X	    vm-total-count 0)
X      (while mp
X	(vm-increment vm-total-count)
X	(if (vm-attributes-of (car mp))
X	    ()
X	  (goto-char (vm-start-of (car mp)))
X	  (search-forward "\n\n" (vm-text-end-of (car mp)) 0)
X	  (vm-set-text-of (car mp) (point-marker))
X	  (goto-char (vm-start-of (car mp)))
X	  (cond ((re-search-forward vm-attributes-header-regexp
X				    (vm-text-of (car mp)) t)
X		 (goto-char (match-beginning 1))
X		 (vm-set-attributes-of (car mp)
X				       (condition-case ()
X					   (read (current-buffer))
X					 (error (vector t nil nil nil nil))))
X		 ;; If attributes are unrecogniable just assume the
X		 ;; message is new.
X		 (cond ((or (not (vectorp (vm-attributes-of (car mp))))
X			    (not (= (length (vm-attributes-of (car mp)))
X				    5)))
X			(vm-set-attributes-of (car mp)
X					      (vector t nil nil nil nil)))))
X		((and vm-berkeley-mail-compatibility
X		      (re-search-forward vm-berkeley-mail-status-header-regexp
X					 (vm-text-of (car mp)) t))
X		 (vm-set-attributes-of (car mp) (vector nil (looking-at "R")
X							nil nil nil)))
X		(t
X		 (vm-set-attributes-of (car mp) (vector t nil nil nil nil)))))
X	(cond ((vm-deleted-flag (car mp))) ; don't count deleted messages
X	      ((vm-new-flag (car mp))
X	       (vm-increment vm-new-count))
X	      ((vm-unread-flag (car mp))
X	       (vm-increment vm-unread-count)))
X	(setq mp (cdr mp))))))
X
X;; Stuff the messages attributes back into the messages as headers.
X(defun vm-stuff-attributes ()
X  (save-excursion
X    (vm-save-restriction
X     (widen)
X     (let ((mp vm-message-list) attributes buffer-read-only
X	   (old-buffer-modified-p (buffer-modified-p)))
X       (while mp
X	 (setq attributes (vm-attributes-of (car mp)))
X	 (goto-char (vm-start-of (car mp)))
X	 (if (re-search-forward vm-attributes-header-regexp
X				(vm-text-of (car mp)) t)
X	     (delete-region (match-beginning 0) (match-end 0)))
X	 (cond (vm-berkeley-mail-compatibility
X		(goto-char (vm-start-of (car mp)))
X		(if (re-search-forward vm-berkeley-mail-status-header-regexp
X				       (vm-text-of (car mp)) t)
X		    (delete-region (match-beginning 0) (match-end 0)))
X		(cond ((not (vm-new-flag (car mp)))
X		       (goto-char (vm-start-of (car mp)))
X		       (forward-line)
X		       (insert-before-markers
X			vm-berkeley-mail-status-header
X			(if (vm-unread-flag (car mp)) "" "R")
X			"O\n")))))
X	 (goto-char (vm-start-of (car mp)))
X	 (forward-line)
X	 (insert-before-markers vm-attributes-header " "
X				(prin1-to-string attributes) "\n")
X	 (setq mp (cdr mp)))
X       (set-buffer-modified-p old-buffer-modified-p)))))
X	  
X;; Remove any message marked for deletion from the buffer and the
X;; message list.
X(defun vm-gobble-deleted-messages ()
X  (save-excursion
X    (vm-save-restriction
X     (widen)
X     (let ((mp vm-message-list) prev buffer-read-only did-gobble)
X       (while mp
X	 (if (not (vm-deleted-flag (car mp)))
X	     (setq prev mp)
X	   (setq did-gobble t)
X	   (delete-region (vm-start-of (car mp))
X			  (vm-end-of (car mp)))
X	   (if (null prev)
X	       (setq vm-message-list (cdr vm-message-list))
X	     (setcdr prev (cdr mp))))
X	 (setq mp (cdr mp)))
X       (if did-gobble
X	   (progn
X	     (vm-clear-expunge-invalidated-undos)
X	     (if (null vm-message-list)
X		 (setq overlay-arrow-position nil))
X	     (cond ((and vm-last-message-pointer
X			 (vm-deleted-flag (car vm-last-message-pointer)))
X		    (setq vm-last-message-pointer nil)))
X	     (cond ((and vm-message-pointer
X			 (vm-deleted-flag (car vm-message-pointer)))
X		    (setq vm-system-state nil)
X		    (setq mp (cdr vm-message-pointer))
X		    (while (and mp (vm-deleted-flag (car mp)))
X		      (setq mp (cdr mp)))
X		    (setq vm-message-pointer
X			  (or mp (vm-last vm-message-list)))))
X	     did-gobble ))))))
X
X(defun vm-change-all-new-to-unread ()
X  (let ((mp vm-message-list))
X    (while mp
X      (if (vm-new-flag (car mp))
X	  (progn
X	    (vm-set-new-flag (car mp) nil)
X	    (vm-set-unread-flag (car mp) t)))
X      (setq mp (cdr mp)))))
X
X(defun vm-update-summary-and-mode-line ()
X  (setq vm-ml-message-number (vm-number-of (car vm-message-pointer)))
X  (cond ((vm-new-flag (car vm-message-pointer))
X	 (setq vm-ml-attributes-string "new"))
X	((vm-unread-flag (car vm-message-pointer))
X	 (setq vm-ml-attributes-string "unread"))
X	(t (setq vm-ml-attributes-string "read")))
X  (cond ((vm-filed-flag (car vm-message-pointer))
X	 (setq vm-ml-attributes-string
X	       (concat vm-ml-attributes-string " filed"))))
X  (cond ((vm-replied-flag (car vm-message-pointer))
X	 (setq vm-ml-attributes-string
X	       (concat vm-ml-attributes-string " replied"))))
X  (cond ((vm-deleted-flag (car vm-message-pointer))
X	 (setq vm-ml-attributes-string
X	       (concat vm-ml-attributes-string " deleted"))))
X  (while vm-messages-needing-display-update
X    (vm-update-message-summary vm-messages-needing-display-update)
X    (setq vm-messages-needing-display-update
X	  (cdr vm-messages-needing-display-update)))
X  (save-excursion
X    (set-buffer (other-buffer))
X    (set-buffer-modified-p (buffer-modified-p))))
X
X(defun vm-goto-message (n)
X  "Go to the message numbered N.
XInteractively N is the prefix argument.  If no prefix arg is provided
XN is prompted for in the minibuffer."
X  (interactive "NGo to message: ")
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (let ((cons (nthcdr (1- n) vm-message-list)))
X    (if (null cons)
X	(error "No such message."))
X    (if (eq vm-message-pointer cons)
X	(vm-preview-current-message)
X      (setq vm-last-message-pointer vm-message-pointer
X	    vm-message-pointer cons)
X      (vm-set-summary-pointer (car vm-message-pointer))
X      (vm-preview-current-message))))
X
X(defun vm-goto-message-last-seen ()
X  "Go to the message last previewed."
X  (interactive)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (if vm-last-message-pointer
X      (let (tmp)
X	(setq tmp vm-message-pointer
X	      vm-message-pointer vm-last-message-pointer
X	      vm-last-message-pointer tmp)
X	(vm-set-summary-pointer (car vm-message-pointer))
X	(vm-preview-current-message))))
X
X(put 'beginning-of-folder 'error-conditions '(beginning-of-folder error))
X(put 'beginning-of-folder 'error-message "Beginning of folder")
X(put 'end-of-folder 'error-conditions '(end-of-folder error))
X(put 'end-of-folder 'error-message "End of folder")
X
X(defun vm-check-count (count)
X  (if (>= count 0)
X      (if (< (length vm-message-pointer) count)
X	  (signal 'end-of-folder nil))
X    (if (< (1+ (- (length vm-message-list) (length vm-message-pointer)))
X	   (vm-abs count))
X	(signal 'beginning-of-folder nil))))
X
X(defun vm-move-message-pointer (direction)
X  (let ((mp vm-message-pointer))
X    (if (eq direction 'forward)
X	(progn
X	  (setq mp (cdr mp))
X	  (if (null mp)
X	      (if vm-circular-folders
X		  (setq mp vm-message-list)
X		(signal 'end-of-folder nil))))
X      (if (eq mp vm-message-list)
X	  (if vm-circular-folders
X	      (setq mp (vm-last vm-message-list))
X	    (signal 'beginning-of-folder nil))
X	(setq mp (let ((curr vm-message-list))
X		   (while (not (eq (cdr curr) mp))
X		     (setq curr (cdr curr)))
X		   curr))))
X    (setq vm-message-pointer mp)))
X
X(defun vm-should-skip-message (mp)
X  (or (and vm-skip-deleted-messages
X	   (vm-deleted-flag (car mp)))
X      (and vm-skip-read-messages
X	   (or (vm-deleted-flag (car mp))
X	       (not (or (vm-new-flag (car mp))
X			(vm-unread-flag (car mp))))))))
X
X(defun vm-next-message (&optional count retry)
X  "Go forward one message and preview it.
XWith prefix arg COUNT, go forward COUNT messages.  A negative COUNT
Xmeans go backward.  If the absolute value of COUNT > 1 the values of the
Xvariables vm-skip-deleted-messages and vm-skip-read-messages are
Xignored."
X  (interactive "p\np")
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (or count (setq count 1))
X  (let ((oldmp vm-message-pointer)
X	(error)
X	(direction (if (> count 0) 'forward 'backward))
X	(count (vm-abs count)))
X    (cond
X     ((null vm-message-pointer)
X      (setq vm-message-pointer vm-message-list))
X     ((/= count 1)
X      (condition-case ()
X	  (while (not (zerop count))
X	    (vm-move-message-pointer direction)
X	    (vm-decrement count))
X	(beginning-of-folder (setq error 'beginning-of-folder))
X	(end-of-folder (setq error 'end-of-folder))))
X     (t
X      (condition-case ()
X	  (progn
X	    (vm-move-message-pointer direction)
X	    (while (and (not (eq oldmp vm-message-pointer))
X			(vm-should-skip-message vm-message-pointer))
X	      (vm-move-message-pointer direction))
X	    ;; Retry the move if we've gone a complete circle and we should
X	    ;; skip the current message and there are other messages.
X	    (and (eq vm-message-pointer oldmp) retry (cdr vm-message-list)
X		 (vm-should-skip-message vm-message-pointer)
X		 (vm-move-message-pointer direction)))
X	(beginning-of-folder
X	 (setq vm-message-pointer oldmp)
X	 (if retry
X	     (vm-move-message-pointer direction)
X	   (setq error 'beginning-of-folder)))
X	(end-of-folder
X	 (setq vm-message-pointer oldmp)
X	 (if retry
X	     (vm-move-message-pointer direction)
X	   (setq error 'end-of-folder))))))
X    (if (not (eq vm-message-pointer oldmp))
X	(progn
X	  (setq vm-last-message-pointer oldmp)
X	  (vm-set-summary-pointer (car vm-message-pointer))
X	  (vm-preview-current-message)))
X    (if error
X	(signal error nil))))
X
X(defun vm-previous-message (&optional count retry)
X  "Go back one message and preview it.
XWith prefix arg COUNT, go backward COUNT messages.  A negative COUNT
Xmeans go forward.  If the absolute value of COUNT > 1 the values of the
Xvariables vm-skip-deleted-messages and vm-skip-read-messages are
Xignored."
X  (interactive "p\np")
X  (or count (setq count 1))
X  (vm-next-message (- count) retry))
X
X(defun vm-Next-message (&optional count)
X  "Like vm-next-message but will not skip messages."
X  (interactive "p")
X  (let (vm-skip-deleted-messages vm-skip-read-messages)
X    (vm-next-message count)))
X
X(defun vm-Previous-message (&optional count)
X  "Like vm-previous-message but will not skip messages."
X  (interactive "p")
X  (let (vm-skip-deleted-messages vm-skip-read-messages)
X    (vm-previous-message count)))
X
X(defun vm-next-unread-message ()
X  "Move forward to the nearest new or unread message, if there is one."
X  (interactive)
X  (condition-case ()
X      (let ((vm-skip-read-messages t)
X	    (oldmp vm-message-pointer))
X	(vm-next-message)
X	;; in case vm-circular-folder is non-nil
X	(and (eq vm-message-pointer oldmp) (signal 'end-of-folder nil)))
X    (end-of-folder (error "No next unread message"))))
X
X(defun vm-previous-unread-message ()
X  "Move backward to the nearest new or unread message, if there is one."
X  (interactive)
X  (condition-case ()
X      (let ((vm-skip-read-messages t)
X	    (oldmp vm-message-pointer))
X	(vm-previous-message)
X	;; in case vm-circular-folder is non-nil
X	(and (eq vm-message-pointer oldmp) (signal 'beginning-of-folder nil)))
X    (beginning-of-folder (error "No previous unread message"))))
X
X(defun vm-preview-current-message ()
X  (setq vm-system-state 'previewing)
X  (widen)
X  (narrow-to-region
X   (vm-vheaders-of (car vm-message-pointer))
X   (if vm-preview-lines
X       (min
X	(vm-text-end-of (car vm-message-pointer))
X	(save-excursion
X	  (goto-char (vm-text-of (car vm-message-pointer)))
X	  (forward-line (if (natnump vm-preview-lines) vm-preview-lines 0))
X	  (point)))
X     (vm-text-of (car vm-message-pointer))))
X  (let ((w (get-buffer-window (current-buffer))))
X    (and w (progn (set-window-start w (point-min))
X		  (set-window-point w (point-max))))
X    (and w vm-highlighted-header-regexp
X	 (progn
X	   (save-restriction
X	     (narrow-to-region (point) (point))
X	     (sit-for 0))
X	   (goto-char (point-min))
X	   (while (re-search-forward vm-highlighted-header-regexp nil t)
X	     (save-restriction
X	       (goto-char (match-beginning 0))
X	       (looking-at vm-generic-header-regexp)
X	       (goto-char (match-beginning 1))
X	       (narrow-to-region (point-min) (point))
X	       (sit-for 0)
X	       (setq inverse-video t)
X	       (widen)
X	       (narrow-to-region (point-min) (match-end 1))
X	       (sit-for 0)
X	       (setq inverse-video nil)
X	       (goto-char (match-end 0)))))))
X  (goto-char (point-max))
X  ;; De Morgan's Theorems could clear away most of the following negations,
X  ;; but the resulting code would be horribly obfuscated.
X  (if (or (null vm-preview-lines)
X	  (and (not vm-preview-read-messages)
X	       (not (vm-new-flag (car vm-message-pointer)))
X	       (not (vm-unread-flag (car vm-message-pointer)))))
X      ;; Don't sit and howl unless the mail buffer is visible.
X      (vm-show-current-message (get-buffer-window (current-buffer)))
X    (vm-update-summary-and-mode-line)))
X
X(defun vm-show-current-message (&optional sit-and-howl)
X  (setq vm-system-state 'reading)
X  (save-excursion
X    (goto-char (point-min))
X    (widen)
X    (narrow-to-region (point) (vm-text-end-of (car vm-message-pointer))))
X  (cond ((vm-new-flag (car vm-message-pointer))
X	 (vm-set-new-flag (car vm-message-pointer) nil))
X	((vm-unread-flag (car vm-message-pointer))
X	 (vm-set-unread-flag (car vm-message-pointer) nil)))
X  (vm-update-summary-and-mode-line)
X  (cond (sit-and-howl
X	 (sit-for 0)
X	 (vm-howl-if-eom-visible))))
X
X(defun vm-expose-hidden-headers ()
X  "Expose headers omitted from vm-visible-headers."
X  (interactive)
X  (vm-follow-summary-cursor)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (save-excursion
X    (goto-char (point-max))
X    (widen)
X    (narrow-to-region (point) (vm-start-of (car vm-message-pointer)))
X    (let (w)
X      (and (setq w (get-buffer-window (current-buffer)))
X	   (= (window-start w) (vm-vheaders-of (car vm-message-pointer)))
X	   (set-window-start w (vm-start-of (car vm-message-pointer)))))))
X
X(defun vm-howl-if-eom-visible ()
X  (let ((w (get-buffer-window (current-buffer))))
X    (and w (pos-visible-in-window-p (point-max) w)
X	 (message "End of message %s from %s"
X		  (vm-number-of (car vm-message-pointer))
X		  (vm-su-full-name (car vm-message-pointer))))))
X
X;; message-changed is an old-fashoined local variable.
X(defun vm-scroll-forward (&optional arg message-changed)
X  "Scroll forward a screenful of text.
XIf the current message is being previewed, the message body is revealed.
XIf at the end of the current message, move to the next message."
X  (interactive "P")
X  (setq message-changed (vm-follow-summary-cursor))
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (if (null (get-buffer-window (current-buffer)))
X      (progn
X	(if vm-mutable-windows
X	    (let ((pop-up-windows
X		   (and pop-up-windows (eq vm-mutable-windows t))))
X	      (display-buffer (current-buffer)))
X	  (switch-to-buffer (current-buffer)))
X	(if (and vm-summary-buffer (get-buffer-window vm-summary-buffer)
X		 (eq vm-mutable-windows t))
X	    (vm-proportion-windows))
X	(if (eq vm-system-state 'previewing)
X	    (vm-show-current-message t)
X	  (vm-howl-if-eom-visible)))
X    (if (eq vm-system-state 'previewing)
X	(vm-show-current-message t)
X      (if message-changed
X	  (vm-howl-if-eom-visible)
X	(let ((w (get-buffer-window (current-buffer)))
X	      (old-w (selected-window)))
X	  (unwind-protect
X	      (progn
X		(select-window w)
X		(if (not (eq (condition-case () (scroll-up arg)
X			       (end-of-buffer (if (null arg)
X						  (progn
X						    (vm-next-message)
X						    'next-message))))
X			     'next-message))
X		    (vm-howl-if-eom-visible)))
X	    (select-window old-w)))))))
X
X(defun vm-scroll-backward (&optional arg)
X  "Scroll backward a screenful of text."
X  (interactive "P")
X  (vm-follow-summary-cursor)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (if (null (get-buffer-window (current-buffer)))
X      (progn
X	(if vm-mutable-windows
X	    (let ((pop-up-windows
X		   (and pop-up-windows (eq vm-mutable-windows t))))
X	      (display-buffer (current-buffer)))
X	  (switch-to-buffer (current-buffer)))
X	(if (and vm-summary-buffer (get-buffer-window vm-summary-buffer)
X		 (eq vm-mutable-windows t))
X	    (vm-proportion-windows)))
X    (let ((w (get-buffer-window (current-buffer)))
X	  (old-w (selected-window)))
X      (unwind-protect
X	  (progn
X	    (select-window w)
X	    (scroll-down arg))
X	(select-window old-w)))))
X
X(defun vm-end-of-message ()
X  "Displays the end of the current message, exposing and marking it read
Xas necessary."
X  (interactive)
X  (vm-follow-summary-cursor)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm-error-if-folder-empty)
X  (if (eq vm-system-state 'previewing)
X      (vm-show-current-message))
X  (goto-char (point-max))
X  (vm-howl-if-eom-visible))
X
X(defun vm-quit-no-change ()
X  "Exit VM without saving changes made to the folder."
X  (interactive)
X  (vm-quit t))
X
X(defun vm-quit (&optional no-change)
X  "Quit VM, saving changes and expunging messages marked for deletion.
XNew messages are changed to unread."
X  (interactive)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (and no-change (buffer-modified-p)
X       (not (zerop vm-messages-not-on-disk))
X       ;; Folder may have been saved with C-x C-s and atriutes may have
X       ;; been changed after that; in that case vm-messages-not-on-disk
X       ;; would not have been zeroed.  However, all modification flag
X       ;; undos are cleared if VM actually modifies the folder buffer
X       ;; (as opposed to the folder's attributes), so this can be used
X       ;; to verify that there are indeed unsaved messages.
X       (null (assq 'set-buffer-modified-p vm-undo-record-list))
X       (not (y-or-n-p
X	     (format "%d message%s have not been saved to disk, exit anyway? "
X		     vm-messages-not-on-disk
X		     (if (= 1 vm-messages-not-on-disk) "" "s"))))
X       (error "Aborted"))
X  (let ((inhibit-quit t))
X    (if (not no-change)
X	(vm-change-all-new-to-unread))
X    (if (and (buffer-modified-p) (not no-change))
X	(vm-save-folder t))
X    (let ((summary-buffer vm-summary-buffer)
X	  (mail-buffer (current-buffer)))
X      (if summary-buffer
X	  (progn
X	    (setq overlay-arrow-position nil)
X	    (if (eq vm-mutable-windows t)
X		(delete-windows-on vm-summary-buffer))
X	    (kill-buffer summary-buffer)))
X      (set-buffer mail-buffer)
X      (set-buffer-modified-p nil)
X      (kill-buffer (current-buffer)))
X    ;; Make sure we are now dealing with the buffer and window that
X    ;; would be selected were we to give up control now.
X    (set-buffer (window-buffer (selected-window)))
X    ;; If we land on a buffer that VM knows about
X    ;; do some nice things for the user, if we're allowed.
X    (cond ((and (eq major-mode 'vm-mode) (eq vm-mutable-windows t))
X	   (if (null vm-startup-with-summary)
X	       (delete-other-windows)
X	     (condition-case () (vm-summarize t) (error nil))
X	     (and (not (eq major-mode 'vm-summary-mode))
X		  (eq vm-startup-with-summary t)
X		  (not (one-window-p t))
X		  vm-summary-buffer
X		  (get-buffer-window vm-summary-buffer)
X		  (progn
X		    (select-window (get-buffer-window vm-summary-buffer))
X		    (delete-other-windows)))))
X	  ((eq major-mode 'vm-summary-mode)
X	   (cond ((eq vm-startup-with-summary nil)
X		  (switch-to-buffer vm-mail-buffer)
X		  (and (not (one-window-p t)) (eq vm-mutable-windows t)
X		       (delete-other-windows)))
X		 ((not (eq vm-startup-with-summary t))
X		  (let ((pop-up-windows
X			 (and pop-up-windows (eq vm-mutable-windows t))))
X		    (display-buffer vm-mail-buffer))
X		  (if (eq vm-mutable-windows t)
X		      (if (eq major-mode 'vm-summary-mode)
X			  (vm-proportion-windows)
X			(switch-to-buffer vm-summary-buffer))))
X		 ((eq vm-mutable-windows t)
X		  (delete-other-windows)))))))
X
X;; This allows C-x C-s to do the right thing for VM mail buffers.
X;; Note that deleted messages are not expunged.
X(defun vm-write-file-hook ()
X  (if (not (eq major-mode 'vm-mode))
X      ()
X    (if vm-inhibit-write-file-hook
X	()
X      ;; The vm-save-restriction isn't really necessary here (since
X      ;; vm-stuff-atributes cleans up after itself) but should remain
X      ;; as a safeguard against the time when other stuff is added here.
X      (vm-save-restriction
X       (let ((inhibit-quit t)
X	     (buffer-read-only))
X	 (vm-stuff-attributes)
X	 nil )))))
X
X(defun vm-save-folder (&optional quitting)
X  "Save current folder to disk."
X  (interactive)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (if (buffer-modified-p)
X      (let ((inhibit-quit t))
X	;; may get error if folder is emptied by the expunge.
X	(condition-case ()
X	    (vm-expunge-folder quitting t)
X	  (error nil))
X	(vm-stuff-attributes)
X	(let ((vm-inhibit-write-file-hook t))
X	  (save-buffer))
X	(setq vm-messages-not-on-disk 0)
X	(and (zerop (buffer-size)) vm-delete-empty-folders
X	     (condition-case ()
X		 (progn
X		   (delete-file buffer-file-name)
X		   (message "%s removed" buffer-file-name))
X	       (error nil)))
X	(if (not quitting)
X	    (if vm-message-pointer
X		(vm-update-summary-and-mode-line)
X	      (vm-next-message))))))
X
X(defun vm-visit-folder (folder)
X  "Visit a mail file.
XVM will parse and present its messages to you in the usual way."
X  (interactive
X   (list (read-file-name
X	  "Visit folder: " (if vm-folder-directory
X			       (expand-file-name vm-folder-directory)
X			     default-directory) nil t)))
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (vm folder))
X
X(defun vm-help ()
X  "Display VM command and variable information."
X  (interactive)
X  (if (and vm-mail-buffer (get-buffer-window vm-mail-buffer))
X      (set-buffer vm-mail-buffer))
X  (let ((pop-up-windows (and pop-up-windows (eq vm-mutable-windows t))))
X    (cond
X     ((eq last-command 'vm-help)
X      (describe-mode))
X     ((eq vm-system-state 'previewing)
X      (message "Type SPC to read message, n previews next message   (? gives more help)"))
X     ((eq vm-system-state 'reading)
X      (message "SPC and b scroll, (d)elete, (s)ave, (n)ext, (r)eply   (? gives more help)"))
X     (t (describe-mode)))))
X
X(defun vm-move-mail (source destination)
X  (call-process "movemail" nil nil nil (expand-file-name source)
X		(expand-file-name destination)))
X
X(defun vm-gobble-crash-box ()
X  (save-excursion
X    (vm-save-restriction
X     (widen)
X     (let ((opoint-max (point-max)) crash-buf buffer-read-only
X	   (old-buffer-modified-p (buffer-modified-p)))
X       (setq crash-buf (find-file-noselect vm-crash-box))
X       (goto-char (point-max))
X       (insert-buffer-substring crash-buf
X				1 (1+ (save-excursion
X					(set-buffer crash-buf)
X					(widen)
X					(buffer-size))))
X       (write-region opoint-max (point-max) buffer-file-name t t)
X       (backup-buffer)
X       ;; make sure primary inbox is private.  384 = octal 600
X       (condition-case () (set-file-modes buffer-file-name 384) (error nil))
X       (set-buffer-modified-p old-buffer-modified-p)
X       (kill-buffer crash-buf)
X       (condition-case () (delete-file vm-crash-box)
X	 (error nil))))))
X
X(defun vm-get-spooled-mail ()
X  (let ((spool-files (or vm-spool-files
X			 (list (concat vm-spool-directory (user-login-name)))))
X	(inhibit-quit t)
X	(got-mail))
X    (if (file-exists-p vm-crash-box)
X	(progn
X	  (message "Recovering messages from crash box...")
X	  (vm-gobble-crash-box)
X	  (message "Recovering messages from crash box... done")
X	  (setq got-mail t)))
X    (while spool-files
X      (if (file-readable-p (car spool-files))
X	  (progn
X	    (message "Getting new mail from %s..." (car spool-files))
X	    (vm-move-mail (car spool-files) vm-crash-box)
X	    (vm-gobble-crash-box)
X	    (message "Getting new mail from %s... done" (car spool-files))
X	    (setq got-mail t)))
X      (setq spool-files (cdr spool-files)))
X    got-mail ))
X
X(defun vm-get-new-mail ()
X  "Move any new mail that has arrived in the system mailbox into the
Xprimary inbox.  New mail is appended to the disk and buffer copies of
Xthe primary inbox.
X
XThis command is valid only from the primary inbox buffer."
X  (interactive)
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (if (not vm-primary-inbox-p)
X      (error "This is not your primary inbox."))
X  (if (not (and (vm-get-spooled-mail) (vm-assimilate-new-messages)))
X      (message "No new mail.")
X    (vm-emit-totals-blurb)
X    ;; If there's a current grouping, then the summary has already
X    ;; been redone in vm-group-messages.
X    (if (and vm-summary-buffer (not vm-current-grouping))
X	(progn
X	  (vm-do-summary)
X	  (vm-emit-totals-blurb)))
X    (vm-thoughtfully-select-message)
X    (if vm-summary-buffer
X	(vm-set-summary-pointer (car vm-message-pointer)))))
X
X(defun vm-emit-totals-blurb ()
X  (message "%d message%s, %d new, %d unread."
X	   vm-total-count (if (= vm-total-count 1) "" "s")
X	   vm-new-count vm-unread-count))
X
X(defun vm-find-first-unread-message ()
X  (let (mp unread-mp)
X    (setq mp vm-message-list)
X    (while mp
X      (if (and (vm-new-flag (car mp)) (not (vm-deleted-flag (car mp))))
X	  (setq unread-mp mp mp nil)
X	(setq mp (cdr mp))))
X    (if (null unread-mp)
X	(progn
X	  (setq mp vm-message-list)
X	  (while mp
X	    (if (and (vm-unread-flag (car mp))
X		     (not (vm-deleted-flag (car mp))))
X		(setq unread-mp mp mp nil)
X	      (setq mp (cdr mp))))))
X    unread-mp))
X
X;; returns non-nil if there were any new messages
X(defun vm-assimilate-new-messages ()
X  (let ((tail-cons (vm-last vm-message-list))
X	(new-messages-p (null vm-message-pointer)))
X    (vm-save-restriction
X     (widen)
X     (vm-build-message-list)
X     (vm-read-attributes)
X     (setq new-messages-p (or new-messages-p (cdr tail-cons)))
X     (if (and vm-current-grouping new-messages-p)
X	 (condition-case data
X	     (vm-group-messages vm-current-grouping)
X	   ;; presumably an unsupported grouping
X	   (error (message (car (cdr data)))
X		  (sleep-for 2)
X		  (vm-number-messages)))
X       (vm-number-messages)))
X    new-messages-p ))
X
X(defun vm-thoughtfully-select-message ()
X  ;; This is called after new messages have been assimilated in a folder.
X  ;; We move to a new message only if the user is not "reading" the current
X  ;; message, or if there is no current message.
X  ;;
X  ;; Most of the complications in the `if' test below are due to the presence
X  ;; of the variables vm-preview-lines and vm-preview-read-messages.
X  ;; These can cause previewing never to be done, or not be done for
X  ;; specific messages.  In these cases VM assumes a user is "reading"
X  ;; an exposed message if the top of the message is not visible in the
X  ;; folder buffer window.
X  (if (or (null vm-message-pointer)
X	  (not (eq vm-system-state 'reading))
X	  (and (or (null vm-preview-lines)
X		   (and (not vm-preview-read-messages)
X			(not (vm-new-flag (car vm-message-pointer)))
X			(not (vm-unread-flag (car vm-message-pointer)))))
X	       (let ((w (get-buffer-window (current-buffer))))
X		 (and w (pos-visible-in-window-p (point-min) w)))))
X      (let ((mp (vm-find-first-unread-message)))
X	(if mp
X	    (progn
X	      (if vm-message-pointer
X		  (setq vm-last-message-pointer vm-message-pointer
X			vm-message-pointer mp)
X		(setq vm-message-pointer mp))
X	      (vm-preview-current-message))
X	  (if (null vm-message-pointer)
X	      (vm-Next-message))))))
X
X(defun vm-display-startup-message ()
X  (if (sit-for 5)
X      (let ((lines
X	     '(
X"You may give out copies of VM.  Type \\[vm-show-copying-restrictions] to see the conditions"
X"VM comes with ABSOLUTELY NO WARRANTY; type \\[vm-show-no-warranty] for full details"
X	       )))
X	(message "VM %s, Copyright (C) 1989 Kyle E. Jones; type ? for help"
X		 vm-version)
X	(while (and (sit-for 4) lines)
X	  (message (substitute-command-keys (car lines)))
X	  (setq lines (cdr lines)))))
X  (message ""))
X
X(defun vm (&optional folder)
X  "Read mail under Emacs.
XOptional first arg FOLDER specifies the folder to visit.  It defaults
Xto the value of vm-primary-inbox.  The folder buffer is put into VM
Xmode, a major mode for reading mail.
X
XVisiting the primary inbox causes any contents of the system mailbox to
Xbe moved and appended to the resulting buffer.
X
XAll the messages can be read by repeatedly pressing SPC.  Messages are
Xmarked for deletion with `d', and saved to a folder with `s'.  Quitting
XVM with `q' expunges messages marked for deletion and saves the buffered
Xfolder to disk.
X
XSee the documentation for vm-mode for more information."
X  (interactive)
X  (if vm-session-beginning
X      (progn
X	(random t)
X	(load "vm-undo")
X	(load "vm-summary")))
X  (if vm-mail-buffer
X      (set-buffer vm-mail-buffer))
X  (let ((mail-buffer (find-file-noselect
X		      (or folder (expand-file-name vm-primary-inbox)))))
X    (set-buffer mail-buffer)
X    (or (buffer-modified-p) (setq vm-messages-not-on-disk 0))
X    (let ((first-time (not (eq major-mode 'vm-mode)))
X	  (inhibit-quit t))
X      (if first-time
X	  (progn
X	    (buffer-flush-undo (current-buffer))
X	    (abbrev-mode 0)
X	    (auto-fill-mode 0)
X	    (vm-mode)))
X      (if (or (and vm-primary-inbox-p (vm-get-spooled-mail)) first-time)
X	  (progn
X	    (vm-assimilate-new-messages)
X	    ;; Can't allow a folder-empty error here because execution
X	    ;; would abort before the session startup code below.
X	    (if (null vm-message-list)
X		(message "Folder is empty.")
X	      (vm-emit-totals-blurb)
X	      ;; If there's a current grouping, then the summary has already
X	      ;; been redone in vm-group-messages.
X	      (if (and vm-summary-buffer (not vm-current-grouping))
X		  (progn
X		    (vm-do-summary)
X		    ;; The summary update messages erased this info
X		    ;; from the echo area.
X		    (vm-emit-totals-blurb)))
X	      (save-window-excursion
X		;; Make sure the mail buffer is not visible.  This is
X		;; needed to insure that if vm-preview-lines is nil, the
X		;; mail window won't be momentarily displayed and then
X		;; disappear behind the summary window, if
X		;; vm-startup-with-summary is t.
X		(if (get-buffer-window mail-buffer)
X		    (if (one-window-p)
X			(switch-to-buffer (other-buffer))
X		      (delete-windows-on mail-buffer)))
X		(set-buffer mail-buffer)
X		(vm-thoughtfully-select-message))
X	      (if vm-summary-buffer
X		  (vm-set-summary-pointer (car vm-message-pointer))))))
X      (switch-to-buffer mail-buffer)
X      (if (and vm-message-list vm-startup-with-summary)
X	  (progn
X	    (vm-summarize t)
X	    (vm-emit-totals-blurb)
X	    (and (eq vm-startup-with-summary t)
X		 (eq vm-mutable-windows t)
X		 (if (eq major-mode 'vm-summary-mode)
X		     (delete-other-windows)
X		   (select-window (get-buffer-window vm-summary-buffer))
X		   (delete-other-windows))))
X	(if (eq vm-mutable-windows t)
X	    (delete-other-windows)))
X      (if vm-session-beginning
X	  (progn
X	    (setq vm-session-beginning nil)
X	    (or vm-inhibit-startup-message folder
X		(vm-display-startup-message))
X	    (if (and vm-message-list (not (input-pending-p)))
X		(vm-emit-totals-blurb)))))))
X
X(defun vm-mode ()
X  "Major mode for reading mail.
X
XCommands:
X   h - summarize folder contents
X
X   n - go to next message
X   p - go to previous message
X   N - like `n' but ignores skip-variable settings
X   P - like `p' but ignores skip-variable settings
X M-n - go to next unread message
X M-p - go to previous unread message
X RET - go to numbered message (uses prefix arg or prompts in minibuffer)
X TAB - go to last message seen
X M-s - incremental search through the folder
X
X   t - display hidden headers
X SPC - scroll forward a page (if at end of message, then display next message)
X   b - scroll backward a page
X   > - go to end of current message
X
X   d - delete current message (mark as deleted)
X   u - undelete
X   k - mark for deletion all messages with same subject as the current message
X
X   r - reply (only to the sender of the message)
X   R - reply with included text for current message
X   f - followup (reply to all recipients of message)
X   F - followup with included text from the current message
X   z - forward the current message
X   m - send a message
X
X   @ - digestify and mail entire folder contents (the folder is not modified)
X   * - burst a digest into indivdual messages, and append and assimilate these
X       message into the current folder.
X
X   G - group messages according to some criteria
X
X   g - get any new mail that has arrived in the system mailbox
X       (new mail is appended to the disk and buffer copies of the
X       primary inbox.)
X   v - visit another mail folder
X
X   s - save current message in a folder (appends if folder already exists)
X   w - write current message to a file without its headers (appends if exists)
X   S - save entire folder to disk, expunging deleted messages
X   A - save unfiled messages to their vm-auto-folder-alist specified folders
X   # - expunge deleted messages (without saving folder)
X   q - quit VM, deleted messages are expunged, folder saved to disk
X   x - exit VM with no change to the folder
X
X C-_ - undo, special undo that retracts the most recent
X             changes in message attributes.  Expunges and saves
X             cannot be undone.
X
X   ? - help
X
X   ! - run a shell command
X   | - run a shell command with the current message as input
X
X M-c - view conditions under which youmay redistribute of VM
X M-w - view the details of VM's lack of a warranty
X
XVariables:
X   vm-auto-folder-alist
X   vm-berkeley-mail-compatibility
X   vm-circular-folders
X   vm-confirm-new-folders
X   vm-crash-box
X   vm-delete-after-saving
X   vm-delete-empty-folders
X   vm-folder-directory
X   vm-folder-type
X   vm-follow-summary-cursor
X   vm-forwarding-subject-format
X   vm-gargle-uucp
X   vm-group-by
X   vm-highlighted-header-regexp
X   vm-in-reply-to-format
X   vm-included-text-attribution-format
X   vm-included-text-prefix
X   vm-inhibit-startup-message
X   vm-mail-window-percentage
X   vm-mode-hooks
X   vm-move-after-deleting
X   vm-mutable-windows
X   vm-preview-lines
X   vm-preview-read-messages
X   vm-primary-inbox
X   vm-rfc934-forwarding
X   vm-search-using-regexps
X   vm-skip-deleted-messages
X   vm-skip-read-messages
X   vm-spool-files
X   vm-startup-with-summary
X   vm-strip-reply-headers
X   vm-summary-format
X   vm-visible-headers
X   vm-visit-when-saving"
X  (widen)
X  (make-local-variable 'require-final-newline)
X  (make-local-variable 'file-precious-flag)
X  (setq
X   buffer-read-only nil
X   case-fold-search t
X   file-precious-flag t
X   major-mode 'vm-mode
X   mode-line-format
X   '("" mode-line-modified mode-line-buffer-identification "   "
X     global-mode-string
X     (vm-message-list
X      ("   %[(" vm-ml-attributes-string ")%]----")
X      ("   %[()%]----"))
X     (-3 . "%p") "-%-")
X   mode-line-buffer-identification
X   '("VM " vm-version ": %b"
X     (vm-message-list
X      ("   " vm-ml-message-number
X       " (of " vm-ml-highest-message-number ")")
X      "  (no messages)"))
X   mode-name "VM"
X   require-final-newline nil
X   vm-current-grouping vm-group-by
X   vm-primary-inbox-p (equal buffer-file-name
X			     (expand-file-name vm-primary-inbox)))
X  (use-local-map vm-mode-map)
X  (run-hooks 'vm-mode-hooks))
X
X(put 'vm-mode 'mode-class 'special)
X
X(autoload 'vm-group-messages "vm-group" nil t)
X
X(autoload 'vm-reply "vm-reply" nil t)
X(autoload 'vm-reply-include-text "vm-reply" nil t)
X(autoload 'vm-followup "vm-reply" nil t)
X(autoload 'vm-followup-include-text "vm-reply" nil t)
X(autoload 'vm-mail "vm-reply" nil t)
X(autoload 'vm-forward-message "vm-reply" nil t)
X(autoload 'vm-send-digest "vm-reply" nil t)
X
X(autoload 'vm-isearch-forward "vm-search" nil t)
X
X(autoload 'vm-burst-digest "vm-digest" nil t)
X(autoload 'vm-rfc934-char-stuff-region "vm-digest")
X(autoload 'vm-digestify-region "vm-digest")
X
X(autoload 'vm-show-no-warranty "vm-license" nil t)
X(autoload 'vm-show-copying-restrictions "vm-license" nil t)
X
X(autoload 'vm-auto-archive-messages "vm-save" nil t)
X(autoload 'vm-save-message "vm-save" nil t)
X(autoload 'vm-save-message-sans-headers "vm-save" nil t)
X(autoload 'vm-pipe-message-to-command "vm-save" nil t)
X
X(autoload 'vm-delete-message "vm-delete" nil t)
X(autoload 'vm-undelete-message "vm-delete" nil t)
X(autoload 'vm-kill-subject "vm-delete" nil t)
X(autoload 'vm-expunge-folder "vm-delete" nil t)
X
X(if (not (memq 'vm-write-file-hook write-file-hooks))
X    (setq write-file-hooks
X	  (cons 'vm-write-file-hook write-file-hooks)))
SHAR_EOF
echo "File vm.el is complete"
chmod 0664 vm.el || echo "restore of vm.el fails"
echo "x - extracting vm.texinfo (Text)"
sed 's/^X//' << 'SHAR_EOF' > vm.texinfo &&
X\input texinfo  @comment -*-Texinfo-*-
X@setfilename vm.info
X@settitle VM User's Manual
X@iftex
X@finalout
X@end iftex
X@c @setchapternewpage odd		% For book style double sided manual.
X@c      @smallbook
X@tex
X\overfullrule=0pt
X%\global\baselineskip 30pt      % For printing in double spaces
X@end tex
X@ifinfo
XThis file documents the VM mail reader.
X
XCopyright (C) 1989 Kyle E. Jones
X
XPermission is granted to make and distribute verbatim copies of
Xthis manual provided the copyright notice and this permission notice
Xare preserved on all copies.
X
X@ignore
XPermission is granted to process this file through Tex and print the
Xresults, provided the printed document carries copying permission
Xnotice identical to this one except for the removal of this paragraph
X(this paragraph not being relevant to the printed manual).
X
X@end ignore
X@end ifinfo
X@c
X@titlepage
X@sp 6
X@center @titlefont{VM User's Manual}
X@sp 4
X@center First Edition, VM Version 4
X@sp 1
X@center June 1989
X@sp 5
X@center Kyle E. Jones
X@center @t{kyle@@cs.odu.edu}
X@page
X@vskip 0pt plus 1filll
XCopyright @copyright{} 1989 Kyle E. Jones
X
XPermission is granted to make and distribute verbatim copies of
Xthis manual provided the copyright notice and this permission notice
Xare preserved on all copies.
X
X@end titlepage
X@page
X@ifinfo
X@node Top, Introduction,, (DIR)
X
XThis manual documents the VM mail reader which runs as a subsystem under
XEmacs.  The manual is divided into the following chapters.
X
X@menu
X* Introduction::	Overview of the VM interface.
X* Starting Up::		What happens when your start VM.
X* Selecting Messages::	How to select messages for reading.
X* Sending Messages::	How to send messages from within VM.
X* Saving Messages::	How to save messages.
X* Deleting Messages::	How to delete, undelete and expunge messages
X* Undoing::		How to undo changes to message attributes.
X* Grouping Messages::	How to make VM present messages
X* Reading Digests::	How to read digests under VM.
X* Summaries::		How to view and customize the summary of a folder.
X* Miscellaneous::	Various customization variables undescribed elsewhere.
X
XIndices:
X
X* Key Index::		Menus of command keys and their references.
X* Command Index::	Menus of commands and their references.
X* Variable Index::	Menus of variables and their references.
X@end menu
X@end ifinfo
X
X@node Introduction, Starting Up, Variable Index, Top
X@unnumbered Introduction
X
XVM (View Mail) is an Emacs subsystem that allows UNIX mail to be read
Xand disposed of within Emacs.  Commands exist to do the normal things
Xexpected of a mail user agent, such as generating replies, saving
Xmessages to folders, deleting messages and so on.  There are other more
Xadvanced commands that do tasks like bursting and creating digests,
Xmessage forwarding, and organizing message presentation according to
Xvarious criteria.
X
XTo invoke VM simply type @kbd{M-x vm}.  VM gathers any mail that has
Xarrived in your system mailbox and appends it to a file known as your
X@dfn{primary inbox}, and visits that file for reading.  @xref{Starting Up}.
XA file visited for reading by VM is called the @dfn{current folder}.@refill
X
X@findex vm-scroll-forward
X@findex vm-scroll-backward
X@kindex SPC
X@kindex b
XIf there are any messages in the primary inbox, VM selects the first new
Xor unread message, and previews it.  @dfn{Previewing} is VM's way of
Xshowing you part of message and allowing you to decide whether you want
Xto read it.  @xref{Previewing}.  By default VM shows you the message's
Xsender, recipient, subject and date headers.  Typing @key{SPC}
X(@code{vm-scroll-forward}) exposes the body of the message and marks the
Xmessage as read.  Subsequent @key{SPC}'s scroll forward through the
Xmessage, @kbd{b} scrolls backward.  When you reach the end of a message,
Xtyping a @key{SPC} or @kbd{n} moves you forward to preview the next
Xmessage.@refill
X
XIf you do not want to read a message that's being previewed, just type
X@kbd{n} and VM will move on to the next message (if there is one).
X@xref{Selecting Messages}.@refill
X
XTo save a message to a mail folder use @kbd{s} (@code{vm-save-message}).
XVM will prompt you for the folder name in the minibuffer.
X@xref{Saving Messages}.@refill
X
XMessages are deleted by typing @kbd{d} (@code{vm-delete-message}) while
Xpreviewing or reading them.  The message is not deleted right away; it
Xis simply marked for deletion.  If you change your mind about deleting a
Xmessage just select it and type @kbd{u} (@code{vm-undelete-message}),
Xand the message will be undeleted.  @xref{Deleting Messages}.  The
Xactual removal of deleted messages from the current folder is called
X@dfn{expunging} and it is accomplished by typing @kbd{#}
X(@code{vm-expunge-folder}).  The message is still present in the on-disk
Xversion of the folder until the folder is saved.@refill
X
XTyping @kbd{h} (@code{vm-summarize}) causes VM to pop up a window
Xcontaining a summary of contents of the current folder.  The summary is
Xpresented one line per message, by message number, listing each message's
Xauthor, date sent, line and byte count, and subject.  Also various
Xletters appear beside the message number to indicate that a message is
Xnew, unread, marked for deletion, etc.  An arrow @samp{->} appears to
Xthe left of the line summarizing the current message.  The summary
Xformat is user configurable, @pxref{Summaries}.@refill
X
X@findex vm-save-folder
X@kindex S
XWhen you are finished reading mail the current folder must be saved, so
Xthat the next time the folder is visited VM will know which messages have
Xbeen already read, replied to and so on.  Typing @kbd{S}
X(@code{vm-save-folder}) expunges all deleted messages and saves the
Xfolder.  @kbd{C-x C-s} saves the folder without expunging deleted
Xmessages but the messages are still marked deleted.  The next time the
Xfolder is visited these messages will still be marked for deletion.@refill
X
X@findex vm-quit
X@findex vm-quit-no-change
X@kindex q
X@kindex x
XTo quit VM you can type @kbd{q} (@code{vm-quit}) or @kbd{x}
X(@code{vm-quit-no-change}).  Typing @kbd{q} expunges and saves the
Xcurrent folder before quitting.  Also, any messages marked new are
Xchanged to be marked unread, before saving.  The @kbd{x} command quits
XVM without expunging, saving or otherwise modifying the current folder.
XQuitting is not required; you can simply switch to another Emacs buffer
Xwhen you've finished reading mail.@refill
X
X@findex vm-get-new-mail
X@kindex g
XAt any time while reading mail in the primary inbox you can type @kbd{g}
X(@code{vm-get-new-mail}) to check to see if new mail has arrived.  If
Xnew mail has arrived it will be merged into the primary inbox.  If you
Xare not in the middle of another message, VM will also jump to the first
Xnew message.
X
X@node Starting Up, Selecting Messages, Introduction, Top
X@chapter Starting Up
X
XThere are two ways to start VM: @kbd{M-x vm} and @kbd{M-x vm-visit-folder}.
X
X@findex vm
X@vindex vm-primary-inbox
X@kbd{M-x vm} causes VM to gather any mail present in your system mailbox
Xand append it to a file known as your @dfn{primary inbox}, creating
Xthis file if necessary.  The default name of this file is
X@file{~/INBOX}, but VM will use whatever file is named by the variable
X@code{vm-primary-inbox}.@refill
X
X@vindex vm-crash-box
XVM transfers the mail from the system mailbox to the primary inbox via a
Xtemporary file known as the @dfn{crash box}.  The variable
X@code{vm-crash-box} names the crash box file.  VM first copies the mail
Xto the crash box, deletes the system mailbox, merges the crash box
Xcontents into the primary inbox, and then deletes the crash box.  If the
Xsystem or Emacs should crash in the midst of this transfer, any message
Xnot present in the primary inbox will be either in the system mailbox or
Xthe crash box.  Some messages may be duplicated but no mail will be
Xlost.@refill
X
XIf the file named by @code{vm-crash-box} already exists when VM is
Xstarted up, VM will merge that with the primary inbox before getting any
Xnew messages from the system mailbox.@refill
X
X@vindex vm-spool-files
XBy default, the location of the system mailbox is determined
Xheuristically by VM based on what type of system you're using.  VM can
Xbe told explicitly where the system mailbox is through the variable
X@code{vm-spool-files}.  The value of this variable should be a list of
Xstrings naming files VM should try when searching for newly arrived
Xmail.  Multiple mailboxes can be specified if you receive mail in
Xmore than one place.@refill
X
X@findex vm-visit-folder
X@kindex v
X@kbd{M-x vm-visit-folder} (@kbd{v} from within VM) allows you to visit
Xsome other mail folder than the primary inbox.  The folder name will be
Xprompted for in the minibuffer.@refill
X
XOnce VM has read the folder, the first new or unread message will be
Xselected.  If there is no such message, the first message in the folder
Xis selected.
X
X@vindex vm-startup-with-summary
XThe variable @code{vm-startup-with-summary} controls whether VM
Xautomatically displays a summary of the folder's contents at startup.  A
SHAR_EOF
echo "End of part 3"
echo "File vm.texinfo is continued in part 4"
echo "4" > s2_seq_.tmp
exit 0
