changeset 88125:5da4d43003a3

Modify requires and evals to reduce byte compilation warnings. (rmail-ignored-headers): Ignore "from" but not "mail-from". Ignore "x-authentication-warning", "x-operating-system", and new babyl-V6 headers. (rmail-displayed-headers): Add basic headers. (rmail-message-vector, rmail-deleted-vector, rmail-msgref-vector, rmail-convert-file): Deprecated. (rmail-unix-mail-delimiter): Updated comment, anchored the "From" string to the beginning of the line. (rmail): Do not convert the buffer to Babyl format; Add support for initializing and getting mbox format mail (rmail-insert-rmail-file-header): Replace the Babyl identifier text with an X-BABYL mail header. (rmail-initialize-message): New function. (rmail-url-map): Use "B" to send a mail message body to a browser; Map "j" to (rmail-message) rather than (rmail-show-message); Map "o" to (rmail-output) rather than (rmail-output-to-rmail-file); Add support for handling embedded URLs. (rmail-mode-map): Map the "Output (inbox)" menubar item to use rmail-output. (rmail-revert): Do not convert to Babyl 5 format; Use the new initialization function. (rmail-expunge-and-save): Use (rmail-display-summary-maybe). (rmail-display-summary-maybe): New function. (rmail-duplicate-message): Use the new rmail message descriptor to access the message start and end positions. (rmail-construct-io-menu): Use (rmail-output) instead of (rmail-output-to-rmail-file). (rmail-get-new-mail): Do not do a partial initialization; add a local variable: 'current-message'; remove local variable 'success'; overhaul the Babyl 5 specific parts. (rmail-msg-is-pruned): Rewrite using the rmail message descriptor. (rmail-toggle-header): Complete rewrite. (rmail-narrow-to-non-pruned-header): Use the rmail message descriptor. (rmail-display-labels, rmail-set-attribute): Rewrite. (rmail-widen-to-current-msgbeg): Use the rmail message descriptor. (rmail-process-new-messages): New (refactored) method. (rmail-show-message): Rewrite. (rmail-redecode-body): Rewrite using rmail message descriptor. (rmail-auto-file): Make a little clearer; user (rmail-output) instead of (rmail-output-to-rmail-file). (rmail-next-undeleted-message): Slight rewrite. (rmail-first-message, rmail-last-message, rmail-search-last-regexp): Do not do partial initialization. (rmail-what-message, rmail-search-message, rmail-message-regexp-p, rmail-narrow-to-header): Use the rmail message descriptor. (rmail-first-unseen-message, rmail-next-same-subject): Rewrite. (rmail-message-deleted-p, rmail-delete-message, rmail-undelete-previous-message, rmail-delete-forward, rmail-forward): Use the rmail message descriptor. (rmail-only-expunge, rmail-expunge): Rewrite. (rmail-reply): Rewrite. (rmail-narrow-to-message): New function. (rmail-activate-urls, rmail-visit-url-at-mouse, rmail-visit-url-at-point, rmail-browse-body, rmail-get-sender): New functions.
author Paul Reilly <pmr@pajato.com>
date Sat, 15 Feb 2003 13:36:53 +0000
parents 30235d819e60
children eefd09a79efd
files lisp/mail/rmail.el
diffstat 1 files changed, 769 insertions(+), 605 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/mail/rmail.el	Fri Feb 14 16:28:39 2003 +0000
+++ b/lisp/mail/rmail.el	Sat Feb 15 13:36:53 2003 +0000
@@ -38,9 +38,19 @@
 ;;   buffers, summary by topic or by regular expression, rmail-reply-prefix
 ;;   variable, and a bury rmail buffer (wipe) command.
 ;;
-
-(require 'mail-utils)
-(eval-when-compile (require 'mule-util)) ; for detect-coding-with-priority
+(provide 'rmail)
+
+(eval-when-compile
+  (require 'font-lock)
+  (require 'mailabbrev)
+  (require 'mule-util)                ; for detect-coding-with-priority
+  (require 'rmailout)
+  (require 'rmailsum))
+
+(eval-and-compile
+  (require 'browse-url)
+  (require 'rmaildesc)
+  (require 'rmailhdr))
 
 ; These variables now declared in paths.el.
 ;(defvar rmail-spool-directory "/usr/spool/mail/"
@@ -91,7 +101,6 @@
   :prefix "rmail-edit-"
   :group 'rmail)
 
-
 (defcustom rmail-movemail-program nil
   "If non-nil, name of program for fetching new mail."
   :group 'rmail-retrieve
@@ -148,7 +157,7 @@
 
 ;;;###autoload
 (defcustom rmail-ignored-headers
-  (concat "^via:\\|^mail-from:\\|^origin:\\|^references:"
+  (concat "^via:\\|^from \\|^origin:\\|^references:"
 	  "\\|^status:\\|^received:\\|^x400-originator:\\|^x400-recipients:"
 	  "\\|^x400-received:\\|^x400-mts-identifier:\\|^x400-content-type:"
 	  "\\|^\\(resent-\\|\\)message-id:\\|^summary-line:\\|^resent-date:"
@@ -161,9 +170,11 @@
 	  "\\|^list-id:\\|^list-unsubscribe:\\|^list-archive:"
 	  "\\|^content-type:\\|^content-length:"
 	  "\\|^x-attribution:\\|^x-disclaimer:\\|^x-trace:"
-	  "\\|^x-complaints-to:\\|^nntp-posting-date:\\|^user-agent"
-	  "\\|^importance:\\|^envelope-to:\\|^delivery-date"
-	  "\\|^x.*-priority:\\|^x-mimeole:")
+	  "\\|^x-complaints-to:\\|^nntp-posting-date:\\|^user-agent:"
+	  "\\|^x-importance:\\|^envelope-to:\\|^delivery-date:"
+	  "\\|^x-importance:\\|^envelope-to:\\|^delivery-date:"
+          "\\|^x-*-priority:\\|x-mimeole:"
+	  "\\|^x-babyl-v6-attributes:\\|x-babyl-v6-keywords:")
   "*Regexp to match header fields that Rmail should normally hide.
 This variable is used for reformatting the message header,
 which normally happens once for each message,
@@ -175,7 +186,8 @@
   :group 'rmail-headers)
 
 ;;;###autoload
-(defcustom rmail-displayed-headers nil
+(defcustom rmail-displayed-headers "\
+^\\(to\\|from\\|sender\\|cc\\|date\\|subject\\|reply-to\\):[ \t]+"
   "*Regexp to match Header fields that Rmail should display.
 If nil, display all header fields except those matched by
 `rmail-ignored-headers'."
@@ -298,8 +310,9 @@
 
   (FOLDERNAME FIELD REGEXP [ FIELD REGEXP ] ... )
 
-Where FOLDERNAME is the name of a BABYL format folder to put the
-message.  If any of the field regexp's are nil, then it is ignored.
+Where FOLDERNAME is the name of a BABYL Version 6 (also known as mbox
+or Unix inbox format) folder to put the message.  If any of the field
+regexp's are nil, then it is ignored.
 
 If FOLDERNAME is \"/dev/null\", it is deleted.
 If FOLDERNAME is nil then it is deleted, and skipped.
@@ -351,12 +364,15 @@
 (defvar rmail-total-messages nil)
 (put 'rmail-total-messages 'permanent-local t)
 
+;;; mbox: deprecated. -pmr
 (defvar rmail-message-vector nil)
 (put 'rmail-message-vector 'permanent-local t)
 
+;;; mbox: deprecated. -pmr
 (defvar rmail-deleted-vector nil)
 (put 'rmail-deleted-vector 'permanent-local t)
 
+;; mbox: deprecated. -pmr
 (defvar rmail-msgref-vector nil
   "In an Rmail buffer, a vector whose Nth element is a list (N).
 When expunging renumbers messages, these lists are modified
@@ -393,10 +409,12 @@
   "*Default file name for \\[rmail-output]."
   :type 'file
   :group 'rmail-files)
+
 (defcustom rmail-default-rmail-file "~/XMAIL"
   "*Default file name for \\[rmail-output-to-rmail-file]."
   :type 'file
   :group 'rmail-files)
+
 (defcustom rmail-default-body-file "~/mailout"
   "*Default file name for \\[rmail-output-body-to-file]."
   :type 'file
@@ -488,9 +506,8 @@
 
 
 ;;; Regexp matching the delimiter of messages in UNIX mail format
-;;; (UNIX From lines), minus the initial ^.  Note that if you change
-;;; this expression, you must change the code in rmail-nuke-pinhead-header
-;;; that knows the exact ordering of the \\( \\) subexpressions.
+;;; (UNIX From lines), with an initial ^.  Used in rmail-decode-from-line,
+;;; which knows the exact ordering of the \\(...\\) subexpressions.
 (defvar rmail-unix-mail-delimiter
   (let ((time-zone-regexp
 	 (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?"
@@ -498,7 +515,7 @@
 		 "\\|"
 		 "\\) *")))
     (concat
-     "From "
+     "^From "
 
      ;; Many things can happen to an RFC 822 mailbox before it is put into
      ;; a `From' line.  The leading phrase can be stripped, e.g.
@@ -549,8 +566,8 @@
     (let* ((cite-chars "[>|}]")
 	   (cite-prefix "a-z")
 	   (cite-suffix (concat cite-prefix "0-9_.@-`'\"")))
-      (list '("^\\(From\\|Sender\\|Resent-From\\):"
-	      . font-lock-function-name-face)
+      (list '("^\\(From\\|Sender\\|Resent-[Ff]rom\\):"
+              . font-lock-function-name-face)
 	    '("^Reply-To:.*$" . font-lock-function-name-face)
 	    '("^Subject:" . font-lock-comment-face)
 	    '("^\\(To\\|Apparently-To\\|Cc\\|Newsgroups\\):"
@@ -564,7 +581,7 @@
 	       (beginning-of-line) (end-of-line)
 	       (2 font-lock-constant-face nil t)
 	       (4 font-lock-comment-face nil t)))
-	    '("^\\(X-[a-z0-9-]+\\|In-reply-to\\|Date\\):.*\\(\n[ \t]+.*\\)*$"
+	    '("^\\(X-[A-Za-z0-9-]+\\|In-reply-to\\|Date\\):.*\\(\n[ \t]+.*\\)*$"
 	      . font-lock-string-face))))
   "Additional expressions to highlight in Rmail mode.")
 
@@ -598,7 +615,7 @@
 
 (defvar rmail-enable-multibyte nil)
 
-
+;;; mbox don't care
 (defun rmail-require-mime-maybe ()
   "Require `rmail-mime-feature' if that is non-nil.
 Signal an error and set `rmail-mime-feature' to nil if the feature
@@ -612,6 +629,7 @@
        (setq rmail-enable-mime nil)))))
 
 
+;;; mbox ready
 ;;;###autoload
 (defun rmail (&optional file-name-arg)
   "Read and edit incoming mail.
@@ -674,24 +692,34 @@
       (setq run-mail-hook t)
       (rmail-mode-2)
       ;; Convert all or part to Babyl file if possible.
-      (rmail-convert-file)
+;;;      (rmail-convert-file)
       (goto-char (point-max)))
     ;; As we have read a file by raw-text, the buffer is set to
     ;; unibyte.  We must make it multibyte if necessary.
     (if (and rmail-enable-multibyte
 	     (not enable-multibyte-characters))
 	(set-buffer-multibyte t))
-    ;; If necessary, scan to find all the messages.
-    (rmail-maybe-set-message-counters)
-    (unwind-protect
-	(unless (and (not file-name-arg)
-		     (rmail-get-new-mail))
-	  (rmail-show-message (rmail-first-unseen-message)))
-      (progn
-	(if rmail-display-summary (rmail-summary))
-	(rmail-construct-io-menu)
-	(if run-mail-hook
-	    (run-hooks 'rmail-mode-hook))))))
+
+    ;; Initialize the Rmail state and process any messages in the buffer.
+    (rmail-initialize-messages)
+
+    ;; Get new mail only if there is no explicit file argument.
+    (and (not file-name-arg) (rmail-get-new-mail))
+
+    ;; Deal with the summary display.
+    (if rmail-display-summary (rmail-summary))
+
+    ;; Show the first unseen message or, if all messages have been
+    ;; seen, the last message.
+    (rmail-show-message (or (rmail-first-unseen-message)
+                            rmail-total-messages))
+
+    ;; Not sure what this is all about.
+    (rmail-construct-io-menu)
+
+    ;; Run any User callbacks.
+    (if run-mail-hook
+        (run-hooks 'rmail-mode-hook))))
 
 ;; Given the value of MAILPATH, return a list of inbox file names.
 ;; This is turned off because it is not clear that the user wants
@@ -712,6 +740,7 @@
 
 ;; This calls rmail-decode-babyl-format if the file is already Babyl.
 
+;;; mbox: DEPECATED
 (defun rmail-convert-file ()
   (let (convert)
     (widen)
@@ -756,16 +785,32 @@
 	  ;; We still have to decode BABYL part.
 	  (rmail-decode-babyl-format)))))
 
+;;;###deprecated
 (defun rmail-insert-rmail-file-header ()
-  (let ((buffer-read-only nil))
-    ;; -*-rmail-*- is here so that visiting the file normally
-    ;; recognizes it as an Rmail file.
-    (insert "BABYL OPTIONS: -*- rmail -*-
-Version: 5
+  (let ((buffer-read-only nil)
+	(header-line "X-BABYL: -*-rmail-*-"))
+    ;; Determine if the header has already been inserted.
+    (goto-char (point-min))
+    (if (not (looking-at "X-BABYL: "))
+	;; The header has not been inserted.  Insert -*-rmail-*- here
+	;; so that visiting the file normally recognizes it as an
+	;; Rmail file.
+	(insert (concat header-line "\nX-BABYL-Version: 6
+Version: 6
 Labels:
 Note:   This is the header of an rmail file.
 Note:   If you are seeing it in rmail,
-Note:    it means the file has no messages in it.\n\^_")))
+Note:    it means the file has no messages in it.")))))
+
+(defun rmail-initialize-messages ()
+  "Initialize message state and process the messages in the buffer to
+  update message state."
+  (setq rmail-total-messages 0
+        rmail-current-message 1)
+  (rmail-desc-clear-descriptors)
+  (widen)
+  (rmail-header-show-headers)
+  (setq rmail-total-messages (rmail-process-new-messages)))
 
 ;; Decode Babyl formatted part at the head of current buffer by
 ;; rmail-file-coding-system, or if it is nil, do auto conversion.
@@ -805,12 +850,14 @@
 	  (or coding-system 'undecided))))
 
 (defvar rmail-mode-map nil)
+(defvar rmail-url-map nil)
 (if rmail-mode-map
     nil
   (setq rmail-mode-map (make-keymap))
   (suppress-keymap rmail-mode-map)
   (define-key rmail-mode-map "a"      'rmail-add-label)
   (define-key rmail-mode-map "b"      'rmail-bury)
+  (define-key rmail-mode-map "B"      'rmail-browse-body)
   (define-key rmail-mode-map "c"      'rmail-continue)
   (define-key rmail-mode-map "d"      'rmail-delete-forward)
   (define-key rmail-mode-map "\C-d"   'rmail-delete-backward)
@@ -819,7 +866,7 @@
   (define-key rmail-mode-map "g"      'rmail-get-new-mail)
   (define-key rmail-mode-map "h"      'rmail-summary)
   (define-key rmail-mode-map "i"      'rmail-input)
-  (define-key rmail-mode-map "j"      'rmail-show-message)
+  (define-key rmail-mode-map "j"      'rmail-message)
   (define-key rmail-mode-map "k"      'rmail-kill-label)
   (define-key rmail-mode-map "l"      'rmail-summary-by-labels)
   (define-key rmail-mode-map "\e\C-h" 'rmail-summary)
@@ -832,7 +879,7 @@
   (define-key rmail-mode-map "n"      'rmail-next-undeleted-message)
   (define-key rmail-mode-map "\en"    'rmail-next-message)
   (define-key rmail-mode-map "\e\C-n" 'rmail-next-labeled-message)
-  (define-key rmail-mode-map "o"      'rmail-output-to-rmail-file)
+  (define-key rmail-mode-map "o"      'rmail-output)
   (define-key rmail-mode-map "\C-o"   'rmail-output)
   (define-key rmail-mode-map "p"      'rmail-previous-undeleted-message)
   (define-key rmail-mode-map "\ep"    'rmail-previous-message)
@@ -862,7 +909,13 @@
   (define-key rmail-mode-map "\C-c\C-s\C-k" 'rmail-sort-by-labels)
   (define-key rmail-mode-map "\C-c\C-n" 'rmail-next-same-subject)
   (define-key rmail-mode-map "\C-c\C-p" 'rmail-previous-same-subject)
-  )
+
+  ;; Set up a keymap derived from the standard Rmail mode keymap to
+  ;; send activated URLs to a browser.
+  (setq rmail-url-map (make-sparse-keymap))
+  (set-keymap-parent rmail-url-map rmail-mode-map)
+  (define-key rmail-url-map [mouse-2] 'rmail-visit-url-at-mouse)
+  (define-key rmail-url-map "\r" 'rmail-visit-url-at-point))
 
 (define-key rmail-mode-map [menu-bar] (make-sparse-keymap))
 
@@ -882,7 +935,7 @@
   '("Output (inbox)..." . rmail-output))
 
 (define-key rmail-mode-map [menu-bar classify output]
-  '("Output (Rmail)..." . rmail-output-to-rmail-file))
+  '("Output (Rmail)..." . rmail-output))
 
 (define-key rmail-mode-map [menu-bar classify kill-label]
   '("Kill Label..." . rmail-kill-label))
@@ -1153,18 +1206,17 @@
 	(progn
 	  (set-buffer rmail-buffer)
   	  (rmail-mode-2)
-	  ;; Convert all or part to Babyl file if possible.
-	  (rmail-convert-file)
+
 	  ;; We have read the file as raw-text, so the buffer is set to
 	  ;; unibyte.  Make it multibyte if necessary.
 	  (if (and rmail-enable-multibyte
 		   (not enable-multibyte-characters))
 	      (set-buffer-multibyte t))
-	  (goto-char (point-max))
-	  (rmail-set-message-counters)
+          (rmail-initialize-messages)
 	  (rmail-show-message rmail-total-messages)
 	  (run-hooks 'rmail-mode-hook)))))
 
+;; NOT DONE
 ;; Return a list of files from this buffer's Mail: option.
 ;; Does not assume that messages have been parsed.
 ;; Just returns nil if buffer does not look like Babyl format.
@@ -1183,15 +1235,25 @@
 		   (goto-char (point-min))
 		   (mail-parse-comma-list))))))))
 
+;;; mbox: ready
 (defun rmail-expunge-and-save ()
   "Expunge and save RMAIL file."
   (interactive)
   (rmail-expunge)
-  (set-buffer rmail-buffer)
   (save-buffer)
+  (rmail-display-summary-maybe))
+
+;;; mbox: ready
+(defun rmail-display-summary-maybe ()
+  "If a summary buffer exists then make sure it is updated and displayed."
   (if (rmail-summary-exists)
-      (rmail-select-summary (set-buffer-modified-p nil))))
-
+      (let ((current-message rmail-current-message))
+        (rmail-select-summary
+         (rmail-summary-goto-msg current-message)
+         (rmail-summary-rmail-update)
+         (set-buffer-modified-p nil)))))
+
+;;; mbox: ready
 (defun rmail-quit ()
   "Quit out of RMAIL.
 Hook `rmail-quit-hook' is run after expunging."
@@ -1215,6 +1277,7 @@
       (quit-window)
       (replace-buffer-in-windows obuf))))
 
+;;; mbox: ready
 (defun rmail-bury ()
   "Bury current Rmail buffer and its summary buffer."
   (interactive)
@@ -1228,6 +1291,7 @@
 	  (bury-buffer rmail-summary-buffer)))
     (quit-window)))
 
+;;; mbox: not ready
 (defun rmail-duplicate-message ()
   "Create a duplicated copy of the current message.
 The duplicate copy goes into the Rmail file just after the
@@ -1236,9 +1300,9 @@
   (widen)
   (let ((buffer-read-only nil)
 	(number rmail-current-message)
-	(string (buffer-substring (rmail-msgbeg rmail-current-message)
-				  (rmail-msgend rmail-current-message))))
-    (goto-char (rmail-msgend rmail-current-message))
+	(string (buffer-substring (rmail-desc-get-start rmail-current-message)
+				  (rmail-desc-get-end rmail-current-message))))
+    (goto-char (rmail-desc-get-end rmail-current-message))
     (insert string)
     (rmail-forget-messages)
     (rmail-show-message number)
@@ -1311,7 +1375,7 @@
 	    (cons "Output Rmail File"
 		  (rmail-list-to-menu "Output Rmail File"
 				      files
-				      'rmail-output-to-rmail-file))))
+				      'rmail-output))))
 
       (define-key rmail-mode-map [menu-bar classify input-menu]
 	'("Input Rmail File" . rmail-disable-menu))
@@ -1324,6 +1388,7 @@
 ;; RLK feature not added in this version:
 ;; argument specifies inbox file or files in various ways.
 
+;;; DOC NOT DONE
 (defun rmail-get-new-mail (&optional file-name)
   "Move any new mail from this RMAIL file's inbox files.
 The inbox files can be specified with the file's Mail: option.  The
@@ -1350,7 +1415,6 @@
   (or (verify-visited-file-modtime (current-buffer))
       (find-file (buffer-file-name)))
   (set-buffer rmail-buffer)
-  (rmail-maybe-set-message-counters)
   (widen)
   ;; Get rid of all undo records for this buffer.
   (or (eq buffer-undo-list t)
@@ -1358,7 +1422,7 @@
   (let ((all-files (if file-name (list file-name)
 		     rmail-inbox-list))
 	(rmail-enable-multibyte (default-value 'enable-multibyte-characters))
-	found)
+	found current-message)
     (unwind-protect
 	(progn
 	  (while all-files
@@ -1371,7 +1435,6 @@
 		  (buffer-read-only nil)
 		  ;; Don't make undo records for what we do in getting mail.
 		  (buffer-undo-list t)
-		  success
 		  ;; Files to insert this time around.
 		  files
 		  ;; Last names of those files.
@@ -1390,11 +1453,9 @@
 	      ;; Put them back in their original order.
 	      (setq files (nreverse files))
 
-	      (goto-char (point-max))
-	      (skip-chars-backward " \t\n") ; just in case of brain damage
-	      (delete-region (point) (point-max)) ; caused by require-final-newline
 	      (save-excursion
 		(save-restriction
+                  (goto-char (point-max))
 		  (narrow-to-region (point) (point))
 		  ;; Read in the contents of the inbox files,
 		  ;; renaming them as necessary,
@@ -1402,36 +1463,13 @@
 		  (if file-name
 		      (rmail-insert-inbox-text files nil)
 		    (setq delete-files (rmail-insert-inbox-text files t)))
-		  ;; Scan the new text and convert each message to babyl format.
-		  (goto-char (point-min))
-		  (unwind-protect
-		      (save-excursion
-			(setq new-messages (rmail-convert-to-babyl-format)
-			      success t))
-		    ;; Try to delete the garbage just inserted.
-		    (or success (delete-region (point-min) (point-max)))
-		    ;; If we could not convert the file's inboxes,
-		    ;; rename the files we tried to read
-		    ;; so we won't over and over again.
-		    (if (and (not file-name) (not success))
-			(let ((delfiles delete-files)
-			      (count 0))
-			  (while delfiles
-			    (while (file-exists-p (format "RMAILOSE.%d" count))
-			      (setq count (1+ count)))
-			    (rename-file (car delfiles)
-					 (format "RMAILOSE.%d" count))
-			    (setq delfiles (cdr delfiles))))))
-		  (or (zerop new-messages)
-		      (let (success)
-			(widen)
-			(search-backward "\n\^_" nil t)
-			(narrow-to-region (point) (point-max))
-			(goto-char (1+ (point-min)))
-			(rmail-count-new-messages)
-			(run-hooks 'rmail-get-new-mail-hook)
-			(save-buffer)))
-		  ;; Delete the old files, now that babyl file is saved.
+		  (unless (equal (point-min) (point-max))
+		    (setq new-messages (rmail-process-new-messages)
+                          rmail-current-message (1+ rmail-total-messages)
+                          rmail-total-messages (rmail-desc-get-count))
+		    (run-hooks 'rmail-get-new-mail-hook)
+		    (save-buffer))
+		  ;; Delete the old files, now that the RMAIL file is saved.
 		  (while delete-files
 		    (condition-case ()
 			;; First, try deleting.
@@ -1446,15 +1484,18 @@
 		  (progn (goto-char opoint)
 			 (if (or file-name rmail-inbox-list)
 			     (message "(No new mail has arrived)")))
+
+		;; Make the first unseen message the current message
+		;; and update the summary buffer, if one exists.
+		(setq current-message (rmail-first-unseen-message))
 		(if (rmail-summary-exists)
-		    (rmail-select-summary
-		     (rmail-update-summary)))
+		    (with-current-buffer rmail-summary-buffer
+                      (rmail-update-summary)
+                      (rmail-summary-goto-msg current-message))
+                  (rmail-show-message current-message))
+		(run-hooks 'rmail-after-get-new-mail-hook)
 		(message "%d new message%s read"
 			 new-messages (if (= 1 new-messages) "" "s"))
-		;; Move to the first new message
-		;; unless we have other unseen messages before it.
-		(rmail-show-message (rmail-first-unseen-message))
-		(run-hooks 'rmail-after-get-new-mail-hook)
 		(setq found t))))
 	  found)
       ;; Don't leave the buffer screwed up if we get a disk-full error.
@@ -1617,6 +1658,7 @@
   (decode-coding-region from to coding))
 
 ;; the  rmail-break-forwarded-messages  feature is not implemented
+;;; NOT DONE  but not called any more
 (defun rmail-convert-to-babyl-format ()
   (let ((count 0) start
 	(case-fold-search nil)
@@ -1745,14 +1787,14 @@
 			(message "Ignoring invalid Content-Length field")
 			(sit-for 1 0 t)))
 		 (if (let ((case-fold-search nil))
-		       (re-search-forward
-			(concat "^[\^_]?\\("
-				rmail-unix-mail-delimiter
-				"\\|"
-				rmail-mmdf-delim1 "\\|"
-				"^BABYL OPTIONS:\\|"
-				"\^L\n[01],\\)") nil t))
-		     (goto-char (match-beginning 1))
+                       (re-search-forward
+                        (concat "^[\^_]?\\("
+                                rmail-unix-mail-delimiter
+                                "\\|"
+                                rmail-mmdf-delim1 "\\|"
+                                "^BABYL OPTIONS:\\|"
+                                "\^L\n[01],\\)") nil t))
+                     (goto-char (match-beginning 1))
 		   (goto-char (point-max)))
 		 (setq count (1+ count))
 		 (if quoted-printable-header-field-end
@@ -1840,6 +1882,7 @@
 	  (t
 	   (message "Malformed MIME quoted-printable message")))))
 
+;;; DEPRECATED -pmr
 ;; Delete the "From ..." line, creating various other headers with
 ;; information from it if they don't already exist.  Now puts the
 ;; original line into a mail-from: header line for debugging and for
@@ -1961,14 +2004,11 @@
 			       (1- (point))
 			     (point-max)))))))))
 
-(defun rmail-msg-is-pruned ()
-  (rmail-maybe-set-message-counters)
-  (save-restriction
-    (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
-    (save-excursion
-      (goto-char (point-min))
-      (forward-line 1)
-      (= (following-char) ?1))))
+(defun rmail-msg-is-pruned (&optional msg)
+  "Determine if the headers for the current message are being
+  displayed. If MSG is non-nil it will be used as the message number
+  instead of the current message."
+  (rmail-desc-get-header-display-state (or msg rmail-current-message)))
 
 (defun rmail-msg-restore-non-pruned-header ()
   (let ((old-point (point))
@@ -2018,58 +2058,13 @@
 With argument ARG, show the message header pruned if ARG is greater than zero;
 otherwise, show it in full."
   (interactive "P")
-  (let* ((pruned (with-current-buffer rmail-buffer
-		   (rmail-msg-is-pruned)))
-	 (prune (if arg
-		    (> (prefix-numeric-value arg) 0)
-		  (not pruned))))
-    (if (eq pruned prune)
-	t
-      (set-buffer rmail-buffer)
-      (rmail-maybe-set-message-counters)
-      (if rmail-enable-mime
-	  (let ((buffer-read-only nil))
-	    (if pruned
-		(rmail-msg-restore-non-pruned-header)
-	      (rmail-msg-prune-header))
-	    (funcall rmail-show-mime-function))
-	(let* ((buffer-read-only nil)
-	       (window (get-buffer-window (current-buffer)))
-	       (at-point-min (= (point) (point-min)))
-	       (all-headers-visible (= (window-start window) (point-min)))
-	       (on-header
-		(save-excursion
-		  (and (not (search-backward "\n\n" nil t))
-		       (progn
-			 (end-of-line)
-			 (re-search-backward "^[-A-Za-z0-9]+:" nil t))
-		       (match-string 0))))
-	       (old-screen-line
-		(rmail-count-screen-lines (window-start window) (point))))
-	  (if pruned
-	      (rmail-msg-restore-non-pruned-header)
-	    (rmail-msg-prune-header))
-	  (cond (at-point-min
-		 (goto-char (point-min)))
-		(on-header
-		 (goto-char (point-min))
-		 (search-forward "\n\n")
-		 (or (re-search-backward
-		      (concat "^" (regexp-quote on-header)) nil t)
-		     (goto-char (point-min))))
-		(t
-		 (save-selected-window
-		   (select-window window)
-		   (recenter old-screen-line)
-		   (if (and all-headers-visible
-			    (not (= (window-start) (point-min))))
-		       (recenter (- (window-height) 2))))))))
-      (rmail-highlight-headers))))
+  (rmail-header-toggle-visibility arg)
+  (rmail-highlight-headers))
 
 (defun rmail-narrow-to-non-pruned-header ()
   "Narrow to the whole (original) header of the current message."
   (let (start end)
-    (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
+    (narrow-to-region (rmail-desc-get-start rmail-current-message) (point-max))
     (goto-char (point-min))
     (forward-line 1)
     (if (= (following-char) ?1)
@@ -2096,53 +2091,25 @@
 
 ;;;; *** Rmail Attributes and Keywords ***
 
-;; Make a string describing current message's attributes and keywords
-;; and set it up as the name of a minor mode
-;; so it will appear in the mode line.
+;; Make a string describing the current message's attributes by
+;; keywords and set it up as the name of a minor mode so it will
+;; appear in the mode line.
 (defun rmail-display-labels ()
-  (let ((blurb "") (beg (point-min-marker)) (end (point-max-marker)))
-    (save-excursion
-      (unwind-protect
-	  (progn
-	    (widen)
-	    (goto-char (rmail-msgbeg rmail-current-message))
-	    (forward-line 1)
-	    (if (looking-at "[01],")
-		(progn
-		  (narrow-to-region (point) (progn (end-of-line) (point)))
-		  ;; Truly valid BABYL format requires a space before each
-		  ;; attribute or keyword name.  Put them in if missing.
-		  (let (buffer-read-only)
-		    (goto-char (point-min))
-		    (while (search-forward "," nil t)
-		      (or (looking-at "[ ,]") (eobp)
-			  (insert " "))))
-		  (goto-char (point-max))
-		  (if (search-backward ",," nil 'move)
-		      (progn
-			(if (> (point) (1+ (point-min)))
-			    (setq blurb (buffer-substring (+ 1 (point-min)) (point))))
-			(if (> (- (point-max) (point)) 2)
-			    (setq blurb
-				  (concat blurb
-					  ";"
-					  (buffer-substring (+ (point) 3)
-							    (1- (point-max)))))))))))
-	;; Note: we don't use save-restriction because that does not work right
-	;; if changes are made outside the saved restriction
-	;; before that restriction is restored.
-	(narrow-to-region beg end)
-	(set-marker beg nil)
-	(set-marker end nil)))
-    (while (string-match " +," blurb)
-      (setq blurb (concat (substring blurb 0 (match-beginning 0)) ","
-			  (substring blurb (match-end 0)))))
-    (while (string-match ", +" blurb)
-      (setq blurb (concat (substring blurb 0 (match-beginning 0)) ","
-			  (substring blurb (match-end 0)))))
+  (let (keyword-list result)
+
+    ;; Update the keyword list for the current message.
+    (if (> rmail-current-message 0)
+        (setq keyword-list (rmail-desc-get-keywords rmail-current-message)))
+
+    ;; Generate the result string.
+    (setq result (mapconcat '(lambda (arg) arg) keyword-list " "))
+
+    ;; Update the mode line to display the keywords, the current
+    ;; message index and the total number of messages.
     (setq mode-line-process
-	  (format " %d/%d%s"
-		  rmail-current-message rmail-total-messages blurb))
+	  (format " %d/%d %s"
+		  rmail-current-message rmail-total-messages result))
+
     ;; If rmail-enable-mime is non-nil, we may have to update
     ;; `mode-line-process' of rmail-view-buffer too.
     (if (and rmail-enable-mime
@@ -2156,36 +2123,17 @@
 ;; ATTR is the name of the attribute, as a string.
 ;; MSGNUM is message number to change; nil means current message.
 (defun rmail-set-attribute (attr state &optional msgnum)
-  (set-buffer rmail-buffer)
-  (let ((omax (point-max-marker))
-	(omin (point-min-marker))
-	(buffer-read-only nil))
-    (or msgnum (setq msgnum rmail-current-message))
-    (if (> msgnum 0)
-	(unwind-protect
-	    (save-excursion
-	      (widen)
-	      (goto-char (+ 3 (rmail-msgbeg msgnum)))
-	      (let ((curstate
-		     (not
-		      (null (search-backward (concat ", " attr ",")
-					     (prog1 (point) (end-of-line)) t)))))
-		(or (eq curstate (not (not state)))
-		    (if curstate
-			(delete-region (point) (1- (match-end 0)))
-		      (beginning-of-line)
-		      (forward-char 2)
-		      (insert " " attr ","))))
-	      (if (string= attr "deleted")
-		  (rmail-set-message-deleted-p msgnum state)))
-	  ;; Note: we don't use save-restriction because that does not work right
-	  ;; if changes are made outside the saved restriction
-	  ;; before that restriction is restored.
-	  (narrow-to-region omin omax)
-	  (set-marker omin nil)
-	  (set-marker omax nil)
-	  (if (= msgnum rmail-current-message)
-	      (rmail-display-labels))))))
+  (save-excursion
+    (save-restriction
+      (let ((attr-index (rmail-desc-get-attr-index attr)))
+	(set-buffer rmail-buffer)
+	(or msgnum (setq msgnum rmail-current-message))
+	(rmail-desc-set-attribute attr-index state msgnum)
+
+        ;; Deal with the summary buffer.
+        (if rmail-summary-buffer
+            (with-current-buffer rmail-summary-buffer
+              (rmail-summary-update-attribute attr-index msgnum)))))))
 
 ;; Return t if the attributes/keywords line of msg number MSG
 ;; contains a match for the regexp LABELS.
@@ -2193,8 +2141,8 @@
   (save-excursion
     (save-restriction
       (widen)
-      (goto-char (rmail-msgbeg msg))
-      (forward-char 3)
+      (goto-char (rmail-desc-get-start msg))
+      (forward-line 1)
       (re-search-backward labels (prog1 (point) (end-of-line)) t))))
 
 ;;;; *** Rmail Message Selection And Support ***
@@ -2216,16 +2164,128 @@
   (save-excursion
     (unwind-protect
 	(progn
-	  (narrow-to-region (rmail-msgbeg rmail-current-message)
+	  (narrow-to-region (rmail-desc-get-start rmail-current-message)
 			    (point-max))
 	  (goto-char (point-min))
 	  (funcall function))
 	;; Note: we don't use save-restriction because that does not work right
 	;; if changes are made outside the saved restriction
 	;; before that restriction is restored.
-      (narrow-to-region (rmail-msgbeg rmail-current-message)
-			(rmail-msgend rmail-current-message)))))
-
+      (narrow-to-region (rmail-desc-get-start rmail-current-message)
+			(rmail-desc-get-end rmail-current-message)))))
+
+(defun rmail-process-new-messages (&optional nomsg)
+  "Process the new messages in the buffer.  The buffer has been
+narrowed to expose only the new messages.  For each new message append
+an entry to the message vector and, if necessary, add a header that
+will capture the salient BABYL information.  Return the number of new
+messages.  If NOMSG is non-nil then do not show any progress
+messages."
+  (let ((inhibit-read-only t)
+        (case-fold-search nil)
+	(new-message-counter 0)
+	(start (point-max))
+	end attributes keywords message-descriptor-list date)
+    (or nomsg (message "Processing new messages..."))
+
+    ;; Process each message in turn starting from the back and
+    ;; proceeding to the front of the region.  This is especially a
+    ;; good approach since the buffer will likely have new headers
+    ;; added.
+    (goto-char start)
+    (while (re-search-backward rmail-unix-mail-delimiter nil t)
+
+      ;; Cache the message date to facilitate generating a message
+      ;; summary later.  The format is '(DAY-OF-WEEK DAY-NUMBER MON
+      ;; YEAR TIME)
+      (setq date
+	    (list (buffer-substring (match-beginning 2) (match-end 2))
+		  (buffer-substring (match-beginning 4) (match-end 4))
+		  (buffer-substring (match-beginning 3) (match-end 3))
+		  (buffer-substring (match-beginning 7) (match-end 7))
+		  (buffer-substring (match-beginning 5) (match-end 5))))
+
+
+      ;;Set start and end to bracket this message.
+      (setq end start)
+      (setq start (point))
+      (save-excursion
+	(save-restriction
+	  (narrow-to-region start end)
+	  (goto-char start)
+
+	  ;; Bump the new message counter.
+	  (setq new-message-counter (1+ new-message-counter))
+
+	  ;; I don't understand why the following is done ... -pmr
+	  ;; Detect messages that have been added with DOS line
+	  ;; endings and convert the line endings for such messages.
+	  (if (save-excursion (end-of-line) (= (preceding-char) ?\r))
+	      (let ((buffer-read-only nil)
+		    (buffer-undo t)
+		    (end-marker (copy-marker end)))
+		(message
+                 "Processing new messages...(converting line endings)")
+		(save-excursion
+		  (goto-char (point-max))
+		  (while (search-backward "\r\n" (point-min) t)
+		    (delete-char 1)))
+		(setq end (marker-position end-marker))
+		(set-marker end-marker nil)))
+
+	  ;; Make sure we have an Rmail BABYL attribute header field.
+	  ;; All we can assume is that the Rmail BABYL header field is
+	  ;; in the header section.  It's placement can be modified by
+	  ;; another mailer.
+	  (setq attributes
+                (rmail-header-get-header rmail-header-attribute-header))
+	  (unless attributes
+
+	    ;; No suitable header exists.  Append the default BABYL
+	    ;; data header for a new message.
+	    (setq attributes (rmail-desc-get-default-attrs))
+	    (rmail-header-add-header
+             rmail-header-attribute-header attributes))
+
+          ;; Set up keywords, if any.  The keywords are provided via a
+          ;; comma separated list and returned as a list of strings.
+          (setq keywords (rmail-header-get-keywords))
+          (if keywords
+
+              ;; Keywords do exist.  Register them with the keyword
+              ;; management library.
+              (rmail-keyword-register-keywords keywords))
+                
+
+	  ;; Insure that we have From and Date headers.
+	  ;;(rmail-decode-from-line)
+	  
+	  ;; Perform User defined filtering.
+	  (save-excursion
+	    (if rmail-message-filter (funcall rmail-message-filter)))
+
+	  ;; Accumulate the message attributes along with the message
+	  ;; markers and the message date list.
+	  (setq message-descriptor-list
+		(vconcat (list (list (point-min-marker)
+				     attributes
+                                     keywords
+				     date
+                                     (count-lines start end)
+                                     (rmail-get-sender)
+                                     (rmail-header-get-header "subject")))
+			 message-descriptor-list)))))
+
+    ;; Add the new message data lists to the Rmail message descriptor
+    ;; vector.
+    (rmail-desc-add-descriptors message-descriptor-list)
+
+    ;; Unless requested otherwise, show the number of new messages.
+    ;; Return the number of new messages.
+    (or nomsg (message "Processing new messages...done (%d)" new-message-counter))
+    new-message-counter))
+
+;;; mbox: deprecated
 (defun rmail-forget-messages ()
   (unwind-protect
       (if (vectorp rmail-message-vector)
@@ -2239,6 +2299,7 @@
     (setq rmail-msgref-vector nil)
     (setq rmail-deleted-vector nil)))
 
+;;; mbox: deprecated
 (defun rmail-maybe-set-message-counters ()
   (if (not (and rmail-deleted-vector
 		rmail-message-vector
@@ -2281,6 +2342,7 @@
     (goto-char (point-min))
     (or nomsg (message "Counting new messages...done (%d)" total-messages))))
 
+;;; DEPRECATED
 (defun rmail-set-message-counters ()
   (rmail-forget-messages)
   (save-excursion
@@ -2318,6 +2380,7 @@
 	    (setq i (1+ i))))
 	(message "Counting messages...done")))))
 
+;;; DEPRECATED	
 (defun rmail-set-message-counters-counter (&optional stop)
   (let ((start (point))
 	next)
@@ -2347,6 +2410,7 @@
       (if (zerop (% (setq total-messages (1+ total-messages)) 20))
 	  (message "Counting messages...%d" total-messages)))))
 
+;;; DEPRECATED
 (defun rmail-beginning-of-message ()
   "Show current message starting from the beginning."
   (interactive)
@@ -2354,17 +2418,28 @@
 
 (defun rmail-show-message (&optional n no-summary)
   "Show message number N (prefix argument), counting from start of file.
-If summary buffer is currently displayed, update current message there also."
+If NO-SUMMARY is non-nil, then do not update the summary buffer."
   (interactive "p")
   (or (eq major-mode 'rmail-mode)
       (switch-to-buffer rmail-buffer))
-  (rmail-maybe-set-message-counters)
-  (widen)
+
+  ;; If there are no messages to display, then provide a message to
+  ;; indicate thusly.
   (if (zerop rmail-total-messages)
-      (progn (narrow-to-region (point-min) (1- (point-max)))
-	     (goto-char (point-min))
-	     (setq mode-line-process nil))
+
+      ;; There are no messages so display the Babyl boilerplate in the
+      ;; presentation buffer.  It is important to keep the boilerplate
+      ;; out of the Rmail file so as not to break other mail agents.
+      (progn
+        (message "No messages to show.  Add something better soon.")
+        (rmail-display-labels)
+        (force-mode-line-update))
+
+    ;; There are messages.  Show one.
     (let (blurb coding-system)
+      ;; Set n to the first sane message based on the sign of n:
+      ;; positive but greater than the total number of messages -> n;
+      ;; negative -> 1.
       (if (not n)
 	  (setq n rmail-current-message)
 	(cond ((<= n 0)
@@ -2377,68 +2452,95 @@
 		     blurb "No following message"))
 	      (t
 	       (setq rmail-current-message n))))
-      (let ((beg (rmail-msgbeg n)))
-	(goto-char beg)
-	(forward-line 1)
-	(save-excursion
-	  (let ((end (rmail-msgend n)))
-	    (save-restriction
-	      (if (prog1 (= (following-char) ?0)
-		    (forward-line 2)
-		    ;; If there's a Summary-line in the (otherwise empty)
-		    ;; header, we didn't yet get past the EOOH line.
-		    (if (looking-at "^\\*\\*\\* EOOH \\*\\*\\*\n")
-			(forward-line 1))
-		    (narrow-to-region (point) end))
-		  (rfc822-goto-eoh)
-		(search-forward "\n*** EOOH ***\n" end t))
-	      (narrow-to-region beg (point))
-	      (goto-char (point-min))
-	      (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
-		  (let ((coding-system (intern (match-string 1))))
-		    (condition-case nil
-			(progn
-			  (check-coding-system coding-system)
-			  (setq buffer-file-coding-system coding-system))
-		      (error
-		       (setq buffer-file-coding-system nil))))
-		(setq buffer-file-coding-system nil)))))
-	;; Clear the "unseen" attribute when we show a message.
-	(rmail-set-attribute "unseen" nil)
-	(let ((end (rmail-msgend n)))
-	  ;; Reformat the header, or else find the reformatted header.
-	  (if (= (following-char) ?0)
-	      (rmail-reformat-message beg end)
-	    (search-forward "\n*** EOOH ***\n" end t)
-	    (narrow-to-region (point) end)))
-	(goto-char (point-min))
-	(walk-windows
-	 (function (lambda (window)
-		     (if (eq (window-buffer window) (current-buffer))
-			 (set-window-point window (point)))))
-	 nil t)
+
+      ;; Index into the Rmail message vector.
+      (let ((beg (rmail-desc-get-start n))
+	    (end (rmail-desc-get-end n)))
+
+	;; Narrow the region to message N and display the headers
+	;; appropriately.
+        (rmail-header-show-headers)
+        (widen)
+	(narrow-to-region beg end)
+        (goto-char (point-min))
+
+	;; I think this is stale. -pmr
+	;;(rfc822-goto-eoh)
+	;;(narrow-to-region beg (point))
+	;;(goto-char (point-min))
+	;;(if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
+	;;    (let ((coding-system (intern (match-string 1))))
+	;;      (check-coding-system coding-system)
+	;;      (setq buffer-file-coding-system coding-system))
+        ;;  (setq buffer-file-coding-system nil))))
+
+        ;; Do something here with the coding system, I'm not sure what. -pmr
+        (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
+            (let ((coding-system (intern (match-string 1))))
+              (condition-case nil
+                  (progn
+                    (check-coding-system coding-system)
+                    (setq buffer-file-coding-system coding-system))
+                (error 
+                 (setq buffer-file-coding-system nil))))
+          (setq buffer-file-coding-system nil))
+
+        ;; Clear the "unseen" attribute when we show a message, unless
+	;; it is already cleared.
+	(if (rmail-desc-attr-p rmail-desc-unseen-index n)
+	    (rmail-desc-set-attribute rmail-desc-unseen-index nil n))
+
+;; More code that has been added that I ill understand.
+;;	(walk-windows
+;;	 (function (lambda (window)
+;;		     (if (eq (window-buffer window) (current-buffer))
+;;			 (set-window-point window (point)))))
+;;	 nil t)
+
 	(rmail-display-labels)
+
+	;; Deal with MIME
 	(if (eq rmail-enable-mime t)
 	    (funcall rmail-show-mime-function)
-	  (setq rmail-view-buffer rmail-buffer)
-	  )
+	  (setq rmail-view-buffer rmail-buffer))
+
+	;; Deal with the message headers and URLs..
+	(rmail-header-hide-headers)
 	(rmail-highlight-headers)
+        (rmail-activate-urls)
+
+	;; ?
 	(if transient-mark-mode (deactivate-mark))
+
+        ;; Make sure that point in the Rmail window is at the beginning of the buffer.
+        (set-window-point (get-buffer-window rmail-buffer) (point))
+
+	;; Run any User code.
 	(run-hooks 'rmail-show-message-hook)
+	
 	;; If there is a summary buffer, try to move to this message
 	;; in that buffer.  But don't complain if this message
 	;; is not mentioned in the summary.
 	;; Don't do this at all if we were called on behalf
 	;; of cursor motion in the summary buffer.
 	(and (rmail-summary-exists) (not no-summary)
-	     (let ((curr-msg rmail-current-message))
-	       (rmail-select-summary
-		(rmail-summary-goto-msg curr-msg t t))))
+             (save-excursion
+               (let ((curr-msg rmail-current-message))
+                 ;; Set the summary current message, disabling the
+                 ;; Rmail buffer update.
+                 (set-buffer rmail-summary-buffer)
+                 (rmail-summary-goto-msg curr-msg nil t))))
+;;;                 (rmail-summary-rmail-update))))
+
+        ;; What is going on here?
 	(with-current-buffer rmail-buffer
 	  (rmail-auto-file))
+
+        ;; Post back any status messages.
 	(if blurb
 	    (message blurb))))))
 
+;;; NOT DONE
 (defun rmail-redecode-body (coding)
   "Decode the body of the current message using coding system CODING.
 This is useful with mail messages that have malformed or missing
@@ -2460,51 +2562,45 @@
     (or (eq major-mode 'rmail-mode)
 	(switch-to-buffer rmail-buffer))
     (save-excursion
-      (let ((pruned (rmail-msg-is-pruned)))
-	(unwind-protect
-	    (let ((msgbeg (rmail-msgbeg rmail-current-message))
-		  (msgend (rmail-msgend rmail-current-message))
-		  x-coding-header)
-	      ;; We need the message headers pruned (we later restore
-	      ;; the pruned stat to what it was, see the end of
-	      ;; unwind-protect form).
-	      (or pruned
-		  (rmail-toggle-header 1))
-	      (narrow-to-region msgbeg msgend)
-	      (goto-char (point-min))
-	      (when (search-forward "\n*** EOOH ***\n" (point-max) t)
-		(narrow-to-region msgbeg (point)))
-	      (goto-char (point-min))
-	      (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
-		  (let ((old-coding (intern (match-string 1)))
-			(buffer-read-only nil))
-		    (check-coding-system old-coding)
-		    ;; Make sure the new coding system uses the same EOL
-		    ;; conversion, to prevent ^M characters from popping
-		    ;; up all over the place.
-		    (setq coding
-			  (coding-system-change-eol-conversion
-			   coding
-			   (coding-system-eol-type old-coding)))
-		    (setq x-coding-header (point-marker))
-		    (narrow-to-region msgbeg msgend)
-		    (encode-coding-region (point) msgend old-coding)
-		    (decode-coding-region (point) msgend coding)
-		    (setq last-coding-system-used coding)
-		    ;; Rewrite the coding-system header according
-		    ;; to what we did.
-		    (goto-char x-coding-header)
-		    (delete-region (point)
-				   (save-excursion
-				     (beginning-of-line)
-				     (point)))
-		    (insert "X-Coding-System: "
-			    (symbol-name last-coding-system-used))
-		    (set-marker x-coding-header nil)
-		    (rmail-show-message))
-		(error "No X-Coding-System header found")))
-	  (or pruned
-	      (rmail-toggle-header 0)))))))
+      (unwind-protect
+          (let ((msgbeg (rmail-desc-get-start rmail-current-message))
+                (msgend (rmail-desc-get-end rmail-current-message))
+                x-coding-header)
+            ;; We need the message headers pruned (we later restore
+            ;; the pruned stat to what it was, see the end of
+            ;; unwind-protect form).
+            (rmail-header-show-headers)
+            (narrow-to-region msgbeg msgend)
+            (goto-char (point-min))
+            (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
+                (let ((old-coding (intern (match-string 1)))
+                      (buffer-read-only nil))
+                  (check-coding-system old-coding)
+                  ;; Make sure the new coding system uses the same EOL
+                  ;; conversion, to prevent ^M characters from popping
+                  ;; up all over the place.
+                  (setq coding
+                        (coding-system-change-eol-conversion
+                         coding
+                         (coding-system-eol-type old-coding)))
+                  (setq x-coding-header (point-marker))
+                  (narrow-to-region msgbeg msgend)
+                  (encode-coding-region (point) msgend old-coding)
+                  (decode-coding-region (point) msgend coding)
+                  (setq last-coding-system-used coding)
+                  ;; Rewrite the coding-system header according
+                  ;; to what we did.
+                  (goto-char x-coding-header)
+                  (delete-region (point)
+                                 (save-excursion
+                                   (beginning-of-line)
+                                   (point)))
+                  (insert "X-Coding-System: "
+                          (symbol-name last-coding-system-used))
+                  (set-marker x-coding-header nil)
+                  (rmail-show-message))
+              (error "No X-Coding-System header found")))
+        (rmail-header-hide-headers)))))
 
 ;; Find all occurrences of certain fields, and highlight them.
 (defun rmail-highlight-headers ()
@@ -2549,6 +2645,7 @@
 		  (setq rmail-overlay-list
 			(cons overlay rmail-overlay-list))))))))))
 
+;;; mbox ready
 (defun rmail-auto-file ()
   "Automatically move a message into a sub-folder based on criteria.
 Called when a new message is displayed."
@@ -2561,12 +2658,12 @@
     (let ((from (mail-fetch-field "from"))
 	  (subj (mail-fetch-field "subject"))
 	  (to   (concat (mail-fetch-field "to") "," (mail-fetch-field "cc")))
-	  (d rmail-automatic-folder-directives)
+	  (directives rmail-automatic-folder-directives)
 	  (directive-loop nil)
 	  (folder nil))
-      (while d
-	(setq folder (car (car d))
-	      directive-loop (cdr (car d)))
+      (while directives
+	(setq folder (car (car directives))
+	      directive-loop (cdr (car directives)))
 	(while (and (car directive-loop)
 		    (let ((f (cond
 			      ((string= (car directive-loop) "from") from)
@@ -2581,9 +2678,9 @@
 		(rmail-delete-forward)
 	      (if (string= "/dev/null" folder)
 		  (rmail-delete-message)
-		(rmail-output-to-rmail-file folder 1 t)
-		(setq d nil))))
-	(setq d (cdr d))))))
+		(rmail-output folder 1 t)
+		(setq directives nil))))
+	(setq directives (cdr directives))))))
 
 (defun rmail-next-message (n)
   "Show following message whether deleted or not.
@@ -2606,27 +2703,39 @@
 
 Returns t if a new message is being shown, nil otherwise."
   (interactive "p")
-  (set-buffer rmail-buffer)
-  (rmail-maybe-set-message-counters)
   (let ((lastwin rmail-current-message)
 	(current rmail-current-message))
+
+    ;; Handle forward movement looking for an undeleted message.  Move
+    ;; forward a message at a time as long as there are subsequent
+    ;; messages.  Stop if the last message is encountered.
     (while (and (> n 0) (< current rmail-total-messages))
       (setq current (1+ current))
-      (if (not (rmail-message-deleted-p current))
-	  (setq lastwin current n (1- n))))
+      (if (not (rmail-desc-deleted-p current))
+	  (setq lastwin current
+		n (1- n))))
+
+    ;; Handle backward movement looking for an undeleted message.
+    ;; Move backward a message at a time as long as there are
+    ;; preceding messages.  Stop if the first message is encountered.
     (while (and (< n 0) (> current 1))
       (setq current (1- current))
-      (if (not (rmail-message-deleted-p current))
-	  (setq lastwin current n (1+ n))))
+      (if (not (rmail-desc-deleted-p current))
+	  (setq lastwin current
+		n (1+ n))))
+
+    ;; Show the message (even if no movement took place so that the
+    ;; delete attribute is marked) and determine the result value.
+    (rmail-show-message lastwin)
     (if (/= lastwin rmail-current-message)
- 	(progn (rmail-show-message lastwin)
- 	       t)
+        t
       (if (< n 0)
 	  (message "No previous nondeleted message"))
       (if (> n 0)
 	  (message "No following nondeleted message"))
       nil)))
 
+;;; mbox: ready.
 (defun rmail-previous-undeleted-message (n)
   "Show previous non-deleted message.
 With prefix argument N, moves backward N non-deleted messages,
@@ -2634,74 +2743,66 @@
   (interactive "p")
   (rmail-next-undeleted-message (- n)))
 
+;;; mbox: ready.
 (defun rmail-first-message ()
   "Show first message in file."
   (interactive)
-  (rmail-maybe-set-message-counters)
   (rmail-show-message 1))
 
+;;; mbox: ready
 (defun rmail-last-message ()
   "Show last message in file."
   (interactive)
-  (rmail-maybe-set-message-counters)
   (rmail-show-message rmail-total-messages))
 
+;;; mbox: not called
 (defun rmail-what-message ()
   (let ((where (point))
 	(low 1)
 	(high rmail-total-messages)
 	(mid (/ rmail-total-messages 2)))
     (while (> (- high low) 1)
-      (if (>= where (rmail-msgbeg mid))
+      (if (>= where (rmail-desc-get-start mid))
 	  (setq low mid)
 	(setq high mid))
       (setq mid (+ low (/ (- high low) 2))))
-    (if (>= where (rmail-msgbeg high)) high low)))
-
+    (if (>= where (rmail-desc-get-start high)) high low)))
+
+;;; mbox: ready
+(defun rmail-narrow-to-header (msg)
+  (save-excursion
+    (let ((start (rmail-desc-get-start msg))
+          (end (rmail-desc-get-end msg)))
+      (widen)
+      (goto-char start)
+    (search-forward "\n\n" end nil t)
+    (narrow-to-region start (point)))))
+
+;;; mbox: ready
 (defun rmail-message-recipients-p (msg recipients &optional primary-only)
   (save-restriction
-    (goto-char (rmail-msgbeg msg))
-    (search-forward "\n*** EOOH ***\n")
-    (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
     (or (string-match recipients (or (mail-fetch-field "To") ""))
 	(string-match recipients (or (mail-fetch-field "From") ""))
 	(if (not primary-only)
 	    (string-match recipients (or (mail-fetch-field "Cc") ""))))))
 
-(defun rmail-message-regexp-p (n regexp)
-  "Return t, if for message number N, regexp REGEXP matches in the header."
-  (let ((beg (rmail-msgbeg n))
-	(end (rmail-msgend n)))
-    (goto-char beg)
-    (forward-line 1)
-    (save-excursion
-      (save-restriction
-	(if (prog1 (= (following-char) ?0)
-	      (forward-line 2)
-	      ;; If there's a Summary-line in the (otherwise empty)
-	      ;; header, we didn't yet get past the EOOH line.
-	      (when (looking-at "^\\*\\*\\* EOOH \\*\\*\\*\n")
-		(forward-line 1))
-	      (setq beg (point))
-	      (narrow-to-region (point) end))
-	    (progn
-	      (rfc822-goto-eoh)
-	      (setq end (point)))
-	  (setq beg (point))
-	  (search-forward "\n*** EOOH ***\n" end t)
-	  (setq end (1+ (match-beginning 0)))))
-	(goto-char beg)
-	(if rmail-enable-mime
-	    (funcall rmail-search-mime-header-function n regexp end)
-	  (re-search-forward regexp end t)))))
-
+;;; mbox: ready
+(defun rmail-message-regexp-p (msg regexp)
+  "Return t, if for message number MSG, regexp REGEXP matches in the header."
+  (save-excursion
+    (save-restriction
+      (rmail-narrow-to-header msg)
+      (re-search-forward regexp nil t))))
+
+;;; mbox: ready
 (defun rmail-search-message (msg regexp)
   "Return non-nil, if for message number MSG, regexp REGEXP matches."
-  (goto-char (rmail-msgbeg msg))
+  (goto-char (rmail-desc-get-start msg))
   (if rmail-enable-mime
       (funcall rmail-search-mime-message-function msg regexp)
-    (re-search-forward regexp (rmail-msgend msg) t)))
-
+    (re-search-forward regexp (rmail-desc-get-end msg) t)))
+
+;;; mbox: ready
 (defvar rmail-search-last-regexp nil)
 (defun rmail-search (regexp &optional n)
   "Show message containing next match for REGEXP (but not the current msg).
@@ -2730,13 +2831,12 @@
 	   (if (< n 0) "Reverse " "")
 	   regexp)
   (set-buffer rmail-buffer)
-  (rmail-maybe-set-message-counters)
   (let ((omin (point-min))
 	(omax (point-max))
 	(opoint (point))
-	win
 	(reversep (< n 0))
-	(msg rmail-current-message))
+	(msg rmail-current-message)
+        win)
     (unwind-protect
 	(progn
 	  (widen)
@@ -2798,20 +2898,15 @@
 	    (prefix-numeric-value current-prefix-arg))))
   (rmail-search regexp (- (or n 1))))
 
-;; Show the first message which has the `unseen' attribute.
 (defun rmail-first-unseen-message ()
-  (rmail-maybe-set-message-counters)
+  "Show the first message which has not been seen.  If all messages
+have been seen, then show the last message."
   (let ((current 1)
 	found)
-    (save-restriction
-      (widen)
-      (while (and (not found) (<= current rmail-total-messages))
-	(if (rmail-message-labels-p current ", ?\\(unseen\\),")
-	    (setq found current))
-	(setq current (1+ current))))
-;; Let the caller show the message.
-;;    (if found
-;;	(rmail-show-message found))
+    (while (and (not found) (<= current rmail-total-messages))
+      (if (rmail-desc-attr-p rmail-desc-unseen-index current)
+	  (setq found current))
+      (setq current (1+ current)))
     found))
 
 (defun rmail-next-same-subject (n)
@@ -2836,25 +2931,26 @@
     (save-excursion
       (save-restriction
 	(widen)
-	(while (and (/= n 0)
-		    (if forward
-			(< i rmail-total-messages)
-		      (> i 1)))
-	  (let (done)
-	    (while (and (not done)
-			(if forward
-			    (< i rmail-total-messages)
-			  (> i 1)))
-	      (setq i (if forward (1+ i) (1- i)))
-	      (goto-char (rmail-msgbeg i))
-	      (search-forward "\n*** EOOH ***\n")
-	      (let ((beg (point)) end)
-		(search-forward "\n\n")
-		(setq end (point))
-		(goto-char beg)
-		(setq done (re-search-forward search-regexp end t))))
-	    (if done (setq found i)))
-	  (setq n (if forward (1- n) (1+ n))))))
+	(if forward
+	    (while (and (/= n 0) (< i rmail-total-messages))
+	      (let (done)
+		(while (and (not done)
+			    (< i rmail-total-messages))
+		  (setq i (+ i 1))
+		  (rmail-narrow-to-header i)
+		  (goto-char (point-min))
+		  (setq done (re-search-forward search-regexp (point-max) t)))
+		(if done (setq found i)))
+	      (setq n (1- n)))
+	  (while (and (/= n 0) (> i 1))
+	    (let (done)
+	      (while (and (not done) (> i 1))
+		(setq i (- i 1))
+		(rmail-narrow-to-header i)
+		(goto-char (point-min))
+		(setq done (re-search-forward search-regexp (point-max) t)))
+	      (if done (setq found i)))
+	    (setq n (1+ n))))))
     (if found
 	(rmail-show-message found)
       (error "No %s message with same subject"
@@ -2869,8 +2965,9 @@
 
 ;;;; *** Rmail Message Deletion Commands ***
 
+;;; mbox: ready
 (defun rmail-message-deleted-p (n)
-  (= (aref rmail-deleted-vector n) ?D))
+  (rmail-desc-deleted-p n))
 
 (defun rmail-set-message-deleted-p (n state)
   (aset rmail-deleted-vector n (if state ?D ?\ )))
@@ -2878,8 +2975,9 @@
 (defun rmail-delete-message ()
   "Delete this message and stay on it."
   (interactive)
-  (rmail-set-attribute "deleted" t)
-  (run-hooks 'rmail-delete-message-hook))
+  (rmail-desc-set-attribute rmail-desc-deleted-index t rmail-current-message)
+  (run-hooks 'rmail-delete-message-hook)
+  (rmail-show-message rmail-current-message))
 
 (defun rmail-undelete-previous-message ()
   "Back up to deleted message, select it, and undelete it."
@@ -2887,19 +2985,19 @@
   (set-buffer rmail-buffer)
   (let ((msg rmail-current-message))
     (while (and (> msg 0)
-		(not (rmail-message-deleted-p msg)))
+		(not (rmail-desc-attr-p rmail-desc-deleted-index msg)))
       (setq msg (1- msg)))
     (if (= msg 0)
 	(error "No previous deleted message")
-      (if (/= msg rmail-current-message)
-	  (rmail-show-message msg))
-      (rmail-set-attribute "deleted" nil)
+      (rmail-desc-set-attribute rmail-desc-deleted-index nil msg)
+      (rmail-show-message msg)
       (if (rmail-summary-exists)
 	  (save-excursion
 	    (set-buffer rmail-summary-buffer)
 	    (rmail-summary-mark-undeleted msg)))
       (rmail-maybe-display-summary))))
 
+;;; mbox: ready
 (defun rmail-delete-forward (&optional backward)
   "Delete this message and move to next nondeleted one.
 Deleted messages stay in the file until the \\[rmail-expunge] command is given.
@@ -2907,7 +3005,7 @@
 
 Returns t if a new message is displayed after the delete, or nil otherwise."
   (interactive "P")
-  (rmail-set-attribute "deleted" t)
+  (rmail-desc-set-attribute rmail-desc-deleted-index t rmail-current-message)
   (run-hooks 'rmail-delete-message-hook)
   (let ((del-msg rmail-current-message))
     (if (rmail-summary-exists)
@@ -2916,12 +3014,14 @@
     (prog1 (rmail-next-undeleted-message (if backward -1 1))
       (rmail-maybe-display-summary))))
 
+;;; mbox: ready
 (defun rmail-delete-backward ()
   "Delete this message and move to previous nondeleted one.
 Deleted messages stay in the file until the \\[rmail-expunge] command is given."
   (interactive)
   (rmail-delete-forward t))
 
+;;; mbox: deprecated
 ;; Compute the message number a given message would have after expunging.
 ;; The present number of the message is OLDNUM.
 ;; DELETEDVEC should be rmail-deleted-vector.
@@ -2947,101 +3047,52 @@
       (funcall rmail-confirm-expunge
 	       "Erase deleted messages from Rmail file? ")))
 
+;;; mbox: ready
 (defun rmail-only-expunge ()
   "Actually erase all deleted messages in the file."
   (interactive)
-  (set-buffer rmail-buffer)
   (message "Expunging deleted messages...")
+
   ;; Discard all undo records for this buffer.
-  (or (eq buffer-undo-list t)
-      (setq buffer-undo-list nil))
-  (rmail-maybe-set-message-counters)
-  (let* ((omax (- (buffer-size) (point-max)))
-	 (omin (- (buffer-size) (point-min)))
-	 (opoint (if (and (> rmail-current-message 0)
-			  (rmail-message-deleted-p rmail-current-message))
-		     0
-		   (if rmail-enable-mime
-		       (with-current-buffer rmail-view-buffer
-			 (- (point)(point-min)))
-		     (- (point) (point-min)))))
-	 (messages-head (cons (aref rmail-message-vector 0) nil))
-	 (messages-tail messages-head)
-	 ;; Don't make any undo records for the expunging.
-	 (buffer-undo-list t)
-	 (win))
-    (unwind-protect
-	(save-excursion
-	  (widen)
-	  (goto-char (point-min))
-	  (let ((counter 0)
-		(number 1)
-		(total rmail-total-messages)
-		(new-message-number rmail-current-message)
-		(new-summary nil)
-		(new-msgref (list (list 0)))
-		(rmailbuf (current-buffer))
-		(buffer-read-only nil)
-		(messages rmail-message-vector)
-		(deleted rmail-deleted-vector)
-		(summary rmail-summary-vector))
-	    (setq rmail-total-messages nil
-		  rmail-current-message nil
-		  rmail-message-vector nil
-		  rmail-deleted-vector nil
-		  rmail-summary-vector nil)
-
-	    (while (<= number total)
-	      (if (= (aref deleted number) ?D)
-		  (progn
-		    (delete-region
-		      (marker-position (aref messages number))
-		      (marker-position (aref messages (1+ number))))
-		    (move-marker (aref messages number) nil)
-		    (if (> new-message-number counter)
-			(setq new-message-number (1- new-message-number))))
-		(setq counter (1+ counter))
-		(setq messages-tail
-		      (setcdr messages-tail
-			      (cons (aref messages number) nil)))
-		(setq new-summary
-		      (cons (if (= counter number) (aref summary (1- number)))
-			    new-summary))
-		(setq new-msgref
-		      (cons (aref rmail-msgref-vector number)
-			    new-msgref))
-		(setcar (car new-msgref) counter))
-	      (if (zerop (% (setq number (1+ number)) 20))
-		  (message "Expunging deleted messages...%d" number)))
-	    (setq messages-tail
-		  (setcdr messages-tail
-			  (cons (aref messages number) nil)))
-	    (setq rmail-current-message new-message-number
-		  rmail-total-messages counter
-		  rmail-message-vector (apply 'vector messages-head)
-		  rmail-deleted-vector (make-string (1+ counter) ?\ )
-		  rmail-summary-vector (vconcat (nreverse new-summary))
-		  rmail-msgref-vector (apply 'vector (nreverse new-msgref))
-		  win t)))
-      (message "Expunging deleted messages...done")
-      (if (not win)
-	  (narrow-to-region (- (buffer-size) omin) (- (buffer-size) omax)))
-      (rmail-show-message
-       (if (zerop rmail-current-message) 1 nil))
-      (if rmail-enable-mime
-	  (goto-char (+ (point-min) opoint))
-	(goto-char (+ (point) opoint))))))
-
+  (or (eq buffer-undo-list t) (setq buffer-undo-list nil))
+
+  ;; Remove the messages from the buffer and from the Rmail message
+  ;; descriptor vector.
+  (rmail-desc-prune-deleted-messages 'rmail-expunge-callback)
+
+  ;; Update the Rmail message counter, deal with the summary buffer,
+  ;; show the current message and update the User status.
+  (setq rmail-total-messages (rmail-desc-get-count))
+  (rmail-show-message rmail-current-message t)
+  (if rmail-summary-buffer
+      (save-excursion
+        (set-buffer rmail-summary-buffer)
+        (rmail-update-summary)))
+  (message "Expunging deleted messages...done"))
+
+;;; We'll deal with this later. -pmr
+;;;    (if rmail-enable-mime
+;;;	(goto-char (+ (point-min) opoint))
+;;;      (goto-char (+ (point) opoint))))))
+
+;;; mbox: ready
+(defun rmail-expunge-callback (n)
+  "Called after message N has been pruned to update the current Rmail
+  message counter."
+  (if (< n rmail-current-message)
+      (setq rmail-current-message (1- rmail-current-message))))
+
+;;; mbox: ready
 (defun rmail-expunge ()
   "Erase deleted messages from Rmail file and summary buffer."
   (interactive)
   (when (rmail-expunge-confirmed)
-    (rmail-only-expunge)
-    (if (rmail-summary-exists)
-	(rmail-select-summary (rmail-update-summary)))))
+    (rmail-only-expunge)))
 
 ;;;; *** Rmail Mailing Commands ***
 
+;;; mbox: In progress.  I'm still not happy with the initial citation
+;;; stuff. -pmr
 (defun rmail-start-mail (&optional noerase to subject in-reply-to cc
 				   replybuffer sendactions same-window others)
   (let (yank-action)
@@ -3078,108 +3129,105 @@
   (interactive)
   (rmail-start-mail t))
 
+;;; mbox: ready -pmr
 (defun rmail-reply (just-sender)
   "Reply to the current message.
 Normally include CC: to all other recipients of original message;
 prefix argument means ignore them.  While composing the reply,
 use \\[mail-yank-original] to yank the original message into it."
   (interactive "P")
-  (let (from reply-to cc subject date to message-id references
-	     resent-to resent-cc resent-reply-to
-	     (msgnum rmail-current-message))
-    (save-excursion
-      (save-restriction
-	(if rmail-enable-mime
-	    (narrow-to-region
-	     (goto-char (point-min))
-	     (if (search-forward "\n\n" nil 'move)
-		 (1+ (match-beginning 0))
-	       (point)))
-	  (widen)
-	  (goto-char (rmail-msgbeg rmail-current-message))
-	  (forward-line 1)
-	  (if (= (following-char) ?0)
-	      (narrow-to-region
-	       (progn (forward-line 2)
-		      (point))
-	       (progn (search-forward "\n\n" (rmail-msgend rmail-current-message)
-				      'move)
-		      (point)))
-	    (narrow-to-region (point)
-			      (progn (search-forward "\n*** EOOH ***\n")
-				     (beginning-of-line) (point)))))
-	(setq from (mail-fetch-field "from")
-	      reply-to (or (mail-fetch-field "reply-to" nil t)
-			   from)
-	      cc (and (not just-sender)
-		      (mail-fetch-field "cc" nil t))
-	      subject (mail-fetch-field "subject")
-	      date (mail-fetch-field "date")
-	      to (or (mail-fetch-field "to" nil t) "")
-	      message-id (mail-fetch-field "message-id")
-	      references (mail-fetch-field "references" nil nil t)
-	      resent-reply-to (mail-fetch-field "resent-reply-to" nil t)
-	      resent-cc (and (not just-sender)
-			     (mail-fetch-field "resent-cc" nil t))
-	      resent-to (or (mail-fetch-field "resent-to" nil t) "")
+  (save-excursion
+    (save-restriction
+      (let ((msgnum rmail-current-message)
+            (display-state (rmail-desc-get-header-display-state rmail-current-message))
+            from reply-to cc subject date to message-id references
+            resent-to resent-cc resent-reply-to)
+        (rmail-header-show-headers)
+        (setq from (mail-fetch-field "from")
+              reply-to (or (mail-fetch-field "reply-to" nil t) from)
+              cc (and (not just-sender)
+                      (mail-fetch-field "cc" nil t))
+              subject (mail-fetch-field "subject")
+              date (mail-fetch-field "date")
+              to (or (mail-fetch-field "to" nil t) "")
+              message-id (mail-fetch-field "message-id")
+              references (mail-fetch-field "references" nil nil t)
+              resent-reply-to (mail-fetch-field "resent-reply-to" nil t)
+              resent-cc (and (not just-sender)
+                             (mail-fetch-field "resent-cc" nil t))
+              resent-to (or (mail-fetch-field "resent-to" nil t) ""))
 ;;;	      resent-subject (mail-fetch-field "resent-subject")
 ;;;	      resent-date (mail-fetch-field "resent-date")
 ;;;	      resent-message-id (mail-fetch-field "resent-message-id")
-	      )))
-    ;; Merge the resent-to and resent-cc into the to and cc.
-    (if (and resent-to (not (equal resent-to "")))
-	(if (not (equal to ""))
-	    (setq to (concat to ", " resent-to))
-	  (setq to resent-to)))
-    (if (and resent-cc (not (equal resent-cc "")))
-	(if (not (equal cc ""))
-	    (setq cc (concat cc ", " resent-cc))
-	  (setq cc resent-cc)))
-    ;; Add `Re: ' to subject if not there already.
-    (and (stringp subject)
-	 (setq subject
-	       (concat rmail-reply-prefix
-		       (if (let ((case-fold-search t))
-			     (string-match rmail-reply-regexp subject))
-			   (substring subject (match-end 0))
-			 subject))))
-    (rmail-start-mail
-     nil
-     ;; Using mail-strip-quoted-names is undesirable with newer mailers
-     ;; since they can handle the names unstripped.
-     ;; I don't know whether there are other mailers that still
-     ;; need the names to be stripped.
-;;;     (mail-strip-quoted-names reply-to)
-     reply-to
-     subject
-     (rmail-make-in-reply-to-field from date message-id)
-     (if just-sender
-	 nil
-       ;; mail-strip-quoted-names is NOT necessary for rmail-dont-reply-to
-       ;; to do its job.
-       (let* ((cc-list (rmail-dont-reply-to
-			(mail-strip-quoted-names
-			 (if (null cc) to (concat to ", " cc))))))
-	 (if (string= cc-list "") nil cc-list)))
-     rmail-view-buffer
-     (list (list 'rmail-mark-message
-		 rmail-buffer
-		 (with-current-buffer rmail-buffer
-		   (aref rmail-msgref-vector msgnum))
-		 "answered"))
-     nil
-     (list (cons "References" (concat (mapconcat 'identity references " ")
-				      " " message-id))))))
-
-(defun rmail-mark-message (buffer msgnum-list attribute)
-  "Give BUFFER's message number in MSGNUM-LIST the attribute ATTRIBUTE.
-This is use in the send-actions for message buffers.
-MSGNUM-LIST is a list of the form (MSGNUM)
-which is an element of rmail-msgref-vector."
+
+        ;; Merge the resent-to and resent-cc into the to and cc.
+        (if (and resent-to (not (equal resent-to "")))
+            (if (not (equal to ""))
+                (setq to (concat to ", " resent-to))
+              (setq to resent-to)))
+        (if (and resent-cc (not (equal resent-cc "")))
+            (if (not (equal cc ""))
+                (setq cc (concat cc ", " resent-cc))
+              (setq cc resent-cc)))
+        ;; Add `Re: ' to subject if not there already.
+        (and (stringp subject)
+             (setq subject
+                   (concat rmail-reply-prefix
+                           (if (let ((case-fold-search t))
+                                 (string-match rmail-reply-regexp subject))
+                               (substring subject (match-end 0))
+                             subject))))
+        ;; Reset the headers display state before switching to the
+        ;; reply buffer.
+        (rmail-header-toggle-visibility (if display-state 1 0))
+
+        ;; Now setup the mail reply buffer.
+        (rmail-start-mail
+         nil
+         ;; Using mail-strip-quoted-names is undesirable with newer mailers
+         ;; since they can handle the names unstripped.
+         ;; I don't know whether there are other mailers that still
+         ;; need the names to be stripped.
+         (mail-strip-quoted-names reply-to)
+         subject
+         (rmail-make-in-reply-to-field from date message-id)
+         (if just-sender
+             nil
+           ;; mail-strip-quoted-names is NOT necessary for rmail-dont-reply-to
+           ;; to do its job.
+           (let* ((cc-list (rmail-dont-reply-to
+                            (mail-strip-quoted-names
+                             (if (null cc) to (concat to ", " cc))))))
+             (if (string= cc-list "") nil cc-list)))
+         rmail-view-buffer
+         (list (list 'rmail-reply-callback rmail-buffer "answered" t msgnum))
+         nil
+         (list (cons "References" (concat (mapconcat 'identity references " ")
+                                          " " message-id))))))))
+
+(defun rmail-reply-callback (buffer attr state n)
+  "Mail reply callback function. Sets ATTR (a string) if STATE is
+  non-nil, otherwise clears it.  N is the message number.  BUFFER,
+  possibly narrowed, contains an mbox mail message."
   (save-excursion
     (set-buffer buffer)
-    (if (car msgnum-list)
-	(rmail-set-attribute attribute t (car msgnum-list)))))
+    (rmail-set-attribute attr state n)))
+
+(defun rmail-mark-message (msgnum-list attr-index)
+  "Set the attribute denoted by ATTRIBUTE-INDEX in the message denoted
+by the car of MSGNUM-LIST.  This is used in the send-actions for
+message buffers.  MSGNUM-LIST is a list of the form (MSGNUM)."
+  (save-excursion
+    (let ((n (car msgnum-list)))
+      (set-buffer rmail-buffer)
+      (rmail-narrow-to-message n)
+      (rmail-desc-set-attribute attr-index t n))))
+
+(defun rmail-narrow-to-message (n)
+  "Set the narrowing restriction in the current (rmail) buffer to
+  bracket message N."
+  (widen)
+  (narrow-to-region (rmail-desc-get-start n) (rmail-desc-get-end n)))
 
 (defun rmail-make-in-reply-to-field (from date message-id)
   (cond ((not from)
@@ -3240,6 +3288,7 @@
          (let ((mail-use-rfc822 t))
            (rmail-make-in-reply-to-field from date message-id)))))
 
+;;; mbox: ready
 (defun rmail-forward (resend)
   "Forward the current message to another user.
 With prefix argument, \"resend\" the message instead of forwarding it;
@@ -3262,7 +3311,7 @@
 	   (list (list 'rmail-mark-message
 		       forward-buffer
 		       (with-current-buffer rmail-buffer
-			 (aref rmail-msgref-vector msgnum))
+			 (rmail-desc-get-start msgnum))
 		       "forwarded"))
 	   ;; If only one window, use it for the mail buffer.
 	   ;; Otherwise, use another window for the mail buffer
@@ -3404,6 +3453,7 @@
 (defvar mail-mime-unsent-header "^Content-Type: message/rfc822 *$"
  "A regexp that matches the header of a MIME body part with a failed message.")
 
+;;; NOT DONE
 (defun rmail-retry-failure ()
   "Edit a mail message which is based on the contents of the current message.
 For a message rejected by the mail system, extract the interesting headers and
@@ -3753,6 +3803,120 @@
      (setq i (1+ i)))
    (concat string-vector)))
 
-(provide 'rmail)
+;;;; Browser related functions
+
+(defun rmail-activate-urls ()
+  "Highlight URLs embedded in the message body."
+  (save-excursion
+    (goto-char (point-min))
+    (search-forward "\n\n" nil t)
+    (browse-url-activate-urls (point) (point-max)
+                              'bold 'bold-italic 'highlight rmail-url-map)))
+
+;;; mbox: not ready, there is a bug here which I don't
+;;; understand. When invoked with the summary buffer as the current
+;;; buffer, the save-excursion does not seem to work.  -pmr
+(defun rmail-visit-url-at-mouse (event)
+  "Visit the URL underneath the mouse."
+  (interactive "e")
+  (save-window-excursion
+
+    ;; Determine if the function has been invoked from a summary
+    ;; buffer.
+    (if (eq major-mode 'rmail-summary-mode)
+
+        ;; It has.  DTRT.
+        (progn
+          (set-buffer rmail-buffer)
+          (save-excursion
+            (browse-url-at-mouse event)
+            (rmail-show-message rmail-current-message))
+          (switch-to-buffer rmail-summary-buffer))
+
+      ;; The function has been invoked from an Rmail buffer.  Visit the
+      ;; URL and then repaint the current message to reflect a visited
+      ;; URL.
+      (browse-url-at-mouse event)
+      (rmail-show-message rmail-current-message))))
+
+(defun rmail-visit-url-at-point ()
+  "Visit the URL at point."
+  (interactive)
+  (save-excursion
+
+    ;; Visit the URL and then repaint the current message to reflect a
+    ;; visited URL.
+    (browse-url-at-point)
+    (rmail-show-message rmail-current-message)))
+
+(defun rmail-browse-body ()
+  "Send the message body to a browser to be rendered."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (goto-char (point-min))
+      (search-forward "\n\n" (point-max) t)
+      (narrow-to-region (point) (point-max))
+      (browse-url-of-buffer))))
+
+;;; New functions that need better placement.
+(defun rmail-get-sender ()
+  "Return the message sender.
+The current buffer (possibly narrowed) contains a single message."
+  (save-excursion
+    (goto-char (point-min))
+    (if (not (re-search-forward "^From:[ \t]*" nil t))
+	"                         "
+      (let* ((from (mail-strip-quoted-names
+		    (buffer-substring
+		     (1- (point))
+		     ;; Get all the lines of the From field
+		     ;; so that we get a whole comment if there is one,
+		     ;; so that mail-strip-quoted-names can discard it.
+		     (let ((opoint (point)))
+		       (while (progn (forward-line 1)
+				     (looking-at "[ \t]")))
+		       ;; Back up over newline, then trailing spaces or tabs
+		       (forward-char -1)
+		       (skip-chars-backward " \t")
+		       (point)))))
+	     len mch lo)
+	(if (string-match (concat "^\\("
+				  (regexp-quote (user-login-name))
+				  "\\($\\|@\\)\\|"
+				  (regexp-quote
+				   ;; Don't lose if run from init file
+				   ;; where user-mail-address is not
+				   ;; set yet.
+				   (or user-mail-address
+				       (concat (user-login-name) "@"
+					       (or mail-host-address
+						   (system-name)))))
+				  "\\>\\)")
+			  from)
+	    (save-excursion
+	      (goto-char (point-min))
+	      (if (not (re-search-forward "^To:[ \t]*" nil t))
+		  nil
+		(setq from
+		      (concat "to: "
+			      (mail-strip-quoted-names
+			       (buffer-substring
+				(point)
+				(progn (end-of-line)
+				       (skip-chars-backward " \t")
+				       (point)))))))))
+	(setq len (length from))
+	(setq mch (string-match "[@%]" from))
+	(format "%25s"
+		(if (or (not mch) (<= len 25))
+		    (substring from (max 0 (- len 25)))
+		  (substring from
+			     (setq lo (cond ((< (- mch 14) 0) 0)
+					    ((< len (+ mch 11))
+					     (- len 25))
+					    (t (- mch 14))))
+			     (min len (+ lo 25)))))))))
+
 
 ;;; rmail.el ends here