Commits

Anonymous committed 8b08b55

Sync with VM-6.84

  • Participants
  • Parent commits 02dae38

Comments (0)

Files changed (33)

+2000-11-16  Steve Youngs  <youngs@xemacs.org>
+
+	* Makefile (ELCS): Updated to accommodate VM-6.84.
+	(TEXI_FILES): VM now uses a *.texinfo file.
+	(vm.info): Ditto.
+
+	* Sync with VM-6.84.
+
 2000-11-14  Martin Buchholz  <martin@xemacs.org>
 
 	* vm-user.el: Doc fix.
-
+	
 2000-10-05  Martin Buchholz  <martin@xemacs.org>
 
 	* *: Mega typo fix.
 # Boston, MA 02111-1307, USA.
 
 VERSION = 1.25
-AUTHOR_VERSION = 6.75
+AUTHOR_VERSION = 6.84
 MAINTAINER = XEmacs Development Team <xemacs-beta@xemacs.org>
 PACKAGE = vm
 PKG_TYPE = regular
 # vm-version.elc needs to be first in this list, because load time
 # code needs the Emacs/XEmacs MULE/no-MULE feature stuff.
 ELCS = vm-version.elc vm-message.elc vm-misc.elc tapestry.elc \
-	vm-delete.elc vm-digest.elc vm-imap.elc \
-	vm-easymenu.elc vm-edit.elc vm-folder.elc vm-license.elc \
-	vm-loaddefs.elc vm-mark.elc vm-menu.elc vm-mime.elc vm-minibuf.elc \
-	vm-macro.elc vm-motion.elc vm-mouse.elc vm-page.elc vm-pop.elc \
-	vm-reply.elc vm-save.elc vm-search.elc vm-sort.elc vm-startup.elc \
-	vm-summary.elc vm-thread.elc vm-toolbar.elc vm-undo.elc vm-user.elc \
-	vm-vars.elc vm-virtual.elc vm-window.elc
+	vm-delete.elc vm-digest.elc vm-easymenu.elc vm-edit.elc \
+	vm-folder.elc vm-imap.elc vm-license.elc vm-macro.elc \
+	vm-mark.elc vm-menu.elc vm-mime.elc vm-minibuf.elc \
+	vm-motion.elc vm-mouse.elc vm-page.elc vm-pop.elc vm-reply.elc \
+	vm-save.elc vm-search.elc vm-sort.elc vm-startup.elc \
+	vm-summary.elc vm-thread.elc vm-toolbar.elc vm-undo.elc \
+	vm-user.elc vm-vars.elc vm-virtual.elc vm-window.elc
 
 EXTRA_SOURCES = vm.elc vm-autoload.el vm-autoload.elc Makefile-kj \
 	README.bytecompile
 	-l ./vm-macro.el -l ./vm-misc.el -l ./vm-vars.el
 
 INFO_FILES = $(PACKAGE).info*
-TEXI_FILES = $(PACKAGE).texi
+TEXI_FILES = $(PACKAGE).texinfo
 MANUAL = $(PACKAGE)
 DATA_FILES = $(shell echo etc/*.x??)
 DATA_DEST = $(PACKAGE)
 		$(ELCS:.elc=.el) >> vm-autoload.el
 
 # VM requires an installed XEmacsen instead of the usual makeinfo
-vm.info: vm.texi
-	$(XEMACS) -vanilla -batch -insert vm.texi -l texinfmt -f texinfo-format-buffer -f save-buffer
+vm.info: vm.texinfo
+	$(XEMACS) -vanilla -batch -insert vm.texinfo -l texinfmt -f texinfo-format-buffer -f save-buffer
 
 srckit: srckit-std
 
     vm-user.elc vm-vars.elc vm-virtual.elc vm-window.elc
 
 SOURCES = \
+    vm-version.el \
     vm-delete.el vm-digest.el vm-easymenu.el vm-edit.el vm-folder.el \
     vm-imap.el vm-license.el vm-macro.el vm-mark.el vm-menu.el vm-message.el \
     vm-mime.el vm-minibuf.el vm-misc.el vm-mouse.el \
     vm-motion.el vm-page.el vm-pop.el vm-reply.el vm-save.el \
     vm-search.el vm-sort.el vm-startup.el vm-summary.el vm-thread.el \
     vm-toolbar.el vm-undo.el \
-    vm-user.el vm-vars.el vm-version.el vm-virtual.el vm-window.el
+    vm-user.el vm-vars.el vm-virtual.el vm-window.el
 
 vm:	vm.elc
 

File make-autoloads

 	  (while t
 	    (setq sexp (read (current-buffer)))
 	    (if (and (consp sexp) (cdr sexp)
-		     (or (eq (car sexp) 'defun)
-			 (eq (car sexp) 'defmacro)))
+		     (memq (car sexp) '(defun defmacro defsubst)))
 		(progn
-		  (if (eq (car sexp) 'defmacro)
+		  (if (memq (car sexp) '(defmacro defsubst))
 		      (setq macro macro-flag)
 		    (setq macro nil))
 		  (setq sexp (cdr sexp)

File vm-delete.el

 The optional prefix argument ARG specifies the direction to move
 if vm-move-after-killing is non-nil.  The default direction is
 forward.  A positive prefix argument means move forward, a
-negative argument means move backward, a zero argument means
+negative arugment means move backward, a zero argument means
 don't move at all."
   (interactive "p")
   (vm-follow-summary-cursor)
 	    ;; vm-clear-expunge-invalidated-undos uses this to recognize
 	    ;; expunged messages.
 	    (vm-set-deleted-flag-of (car mp) 'expunged)
-	    ;; disable summary any summary update that may have
+	    ;; disable any summary update that may have
 	    ;; already been scheduled.
 	    (vm-set-su-start-of (car mp) nil)
 	    (vm-set-buffer-modified-p t)
 		(vm-attributes-of (vm-real-message-of (car mp))))
 	    (save-excursion
 	      (set-buffer (vm-buffer-of (vm-real-message-of (car mp))))
+	      (vm-increment vm-modification-counter)
 	      (vm-save-restriction
 	       (widen)
 	       (let ((buffer-read-only nil))

File vm-digest.el

 	(vm-save-restriction
 	 (save-excursion
 	   (widen)
-	   (setq work-buffer (generate-new-buffer "*vm-work*"))
-	   (buffer-disable-undo work-buffer)
+	   (setq work-buffer (vm-make-work-buffer))
 	   (set-buffer work-buffer)
 	   (cond ((not (vectorp layout))
 		  (error "Not a MIME message"))
        (widen)
        (unwind-protect
 	   (catch 'done
-	     (setq work-buffer (generate-new-buffer "*vm-work*"))
-	     (buffer-disable-undo work-buffer)
+	     (setq work-buffer (vm-make-work-buffer))
 	     (set-buffer work-buffer)
 	     (setq temp-marker (vm-marker (point)))
 	     (vm-insert-region-from-buffer (vm-buffer-of m)
 				     (current-buffer)
 				     (vm-number-of (car vm-message-pointer))
 				     (if (cdr mlist) " ..." ""))))
+	  (buffer-disable-undo work-buffer)
 	  (set-buffer work-buffer)
 	  (setq vm-folder-type vm-default-folder-type)
 	  (while mlist
 	m)
     (while mlist
       (setq m (vm-real-message-of (car mlist)))
+      (vm-garbage-collect-message)
       (if vm-thread-obarray
 	  (vm-unthread-message m t))
       (fillarray (vm-cache-of m) nil)

File vm-folder.el

 	(mapcar (function vm-update-message-summary)
 		vm-messages-needing-summary-update)
 	(setq vm-messages-needing-summary-update nil)))
+  (vm-do-needed-folders-summary-update)
   (vm-force-mode-line-update))
 
 (defun vm-reverse-link-messages ()
 		(setq b (vm-get-file-buffer file))
 		(if b
 		    (set-buffer b)
-		  (setq temp-buffer (generate-new-buffer "*vm-work*"))
+		  (setq temp-buffer (vm-make-work-buffer))
 		  (set-buffer temp-buffer)
 		  (if (file-readable-p file)
 		      (condition-case nil
-			  (let ((coding-system-for-read 'binary))
+			  (let ((coding-system-for-read
+				    (vm-binary-coding-system)))
 			    (insert-file-contents file nil 0 4096))
 			(wrong-number-of-arguments
 			 (call-process "sed" file temp-buffer nil
 		 (t "\014\n0, recent, unseen,,\n*** EOOH ***\n"))))))
 
 (defun vm-trailing-message-separator (&optional folder-type)
-  "Returns a leading message separator for the current folder.
+  "Returns a trailing message separator for the current folder.
 Defaults to returning a separator for the current folder type.
 
 Optional first arg FOLDER-TYPE means return a separator for that
 			       (insert-buffer-substring
 				(current-buffer)
 				(vm-headers-of message)
-				(1- (vm-text-of message)))))
-			 (setq work-buffer (generate-new-buffer "*vm-work*"))
+				(1- (vm-text-of message)))
+			       ;; Yep, messages can come in
+			       ;; without the two newlines after
+			       ;; the header section.
+			       (if (not (eq (char-after (1- (point))) ?\n))
+				   (insert ?\n))))
+			 (setq work-buffer (vm-make-work-buffer))
 			 (set-buffer work-buffer)
 			 (insert-buffer-substring
 			  folder-buffer 
       (vm-set-modflag-of (car mp) t)
       (setq mp (cdr mp)))))
 
+(defun vm-compute-totals ()
+  (save-excursion
+    (vm-select-folder-buffer)
+    (let ((mp vm-message-list)
+	  (vm-new-count 0)
+	  (vm-unread-count 0)
+	  (vm-deleted-count 0)
+	  (vm-total-count 0))
+      (while mp
+	(vm-increment vm-total-count)
+	(cond ((vm-deleted-flag (car mp))
+	       (vm-increment vm-deleted-count))
+	      ((vm-new-flag (car mp))
+	       (vm-increment vm-new-count))
+	      ((vm-unread-flag (car mp))
+	       (vm-increment vm-unread-count)))
+	(setq mp (cdr mp)))
+      (setq vm-totals (list vm-modification-counter
+			    vm-total-count
+			    vm-new-count
+			    vm-unread-count
+			    vm-deleted-count)))))
+
 (defun vm-emit-totals-blurb ()
   (save-excursion
     (vm-select-folder-buffer)
     (if (not (equal (nth 0 vm-totals) vm-modification-counter))
-	(let ((mp vm-message-list)
-	      (vm-new-count 0)
-	      (vm-unread-count 0)
-	      (vm-deleted-count 0)
-	      (vm-total-count 0))
-	  (while mp
-	    (vm-increment vm-total-count)
-	    (cond ((vm-deleted-flag (car mp))
-		   (vm-increment vm-deleted-count))
-		  ((vm-new-flag (car mp))
-		   (vm-increment vm-new-count))
-		  ((vm-unread-flag (car mp))
-		   (vm-increment vm-unread-count)))
-	    (setq mp (cdr mp)))
-	  (setq vm-totals (list vm-modification-counter
-				vm-total-count
-				vm-new-count
-				vm-unread-count
-				vm-deleted-count))))
+	(vm-compute-totals))
     (if (equal (nth 1 vm-totals) 0)
 	(message "No messages.")
       (message "%d message%s, %d new, %d unread, %d deleted"
 
 (defun vm-gobble-last-modified ()
   (let ((case-fold-search t)
+	(time nil)
 	time lim oldpoint)
     (save-excursion
       (vm-save-restriction
 	       (setq blob (cdr blob))
 	       (setq time (car blob)
 		     time2 (vm-gobble-last-modified))
-	       (if (> 0 (vm-time-difference time time2))
+	       (if (and time2 (> 0 (vm-time-difference time time2)))
 		   (throw 'done nil))
 	       (setq blob (cdr blob))
 	       (while blob
 (defun vm-generate-index-file-validity-check ()
   (save-restriction
     (widen)
-    (let ((step (/ (point-max) 11))
+    (let ((step (max 1 (/ (point-max) 11)))
 	  (pos (1- (point-max)))
 	  (lim (point-min))
 	  (blob nil))
 	    (save-excursion
 	      (set-buffer work-buffer)
 	      (condition-case data
-		  (let ((coding-system-for-write 'binary)
+		  (let ((coding-system-for-write (vm-binary-coding-system))
 			(selective-display nil))
 		    (write-region (point-min) (point-max) index-file))
 		(error
       ;; vm-display is not supposed to change the current buffer.
       ;; still it's better to be safe here.
       (set-buffer mail-buffer)
+      ;; if folder is selected in the folders summary, force
+      ;; selcetion of some other folder.
+      (if buffer-file-name
+	  (vm-mark-for-folders-summary-update buffer-file-name))
       (set-buffer-modified-p nil)
       (kill-buffer (current-buffer)))
     (vm-update-summary-and-mode-line)))
 	       (if (not (eq vm-modification-counter
 			    vm-flushed-modification-counter))
 		   (progn
+		     (vm-stuff-last-modified)
+		     (vm-stuff-pop-retrieved)
+		     (vm-stuff-imap-retrieved)
 		     (vm-stuff-summary)
 		     (vm-stuff-labels)
 		     (and vm-message-order-changed
        (vm-stuff-folder-attributes nil)
        (if vm-message-list
 	   (progn
+	     (if (and vm-folders-summary-database buffer-file-name)
+		 (progn
+		   (vm-compute-totals)
+		   (vm-store-folder-totals buffer-file-name (cdr vm-totals))))
 	     ;; get summary cache up-to-date
 	     (vm-update-summary-and-mode-line)
 	     (vm-stuff-bookmark)
   (intern (buffer-name) vm-buffers-needing-display-update)
   (setq vm-block-new-mail nil)
   (vm-display nil nil '(vm-save-buffer) '(vm-save-buffer))
+  (if (and vm-folders-summary-database buffer-file-name)
+      (progn
+	(vm-compute-totals)
+	(vm-store-folder-totals buffer-file-name (cdr vm-totals))))
   (vm-update-summary-and-mode-line)
   (vm-write-index-file-maybe))
 
   (let ((old-buffer-name (buffer-name)))
     (save-excursion
       (call-interactively 'write-file))
+    (if (and vm-folders-summary-database buffer-file-name)
+	(progn
+	  (vm-compute-totals)
+	  (vm-store-folder-totals buffer-file-name (cdr vm-totals))))
     (if (not (equal (buffer-name) old-buffer-name))
 	(progn
 	  (vm-check-for-killed-summary)
 	  (setq vm-messages-not-on-disk 0)
 	  (setq vm-block-new-mail nil)
 	  (vm-write-index-file-maybe)
+	  (if (and vm-folders-summary-database buffer-file-name)
+	      (progn
+		(vm-compute-totals)
+		(vm-store-folder-totals buffer-file-name (cdr vm-totals))))
 	  (vm-update-summary-and-mode-line)
 	  (and (zerop (buffer-size))
 	       vm-delete-empty-folders
 	(set-buffer error-buffer)
 	(erase-buffer))
       (setq status
-	    (call-process vm-movemail-program nil error-buffer t
-			  source destination))
+	    (apply 'call-process
+		   (nconc
+		    (list vm-movemail-program nil error-buffer t)
+		    (copy-sequence vm-movemail-program-switches)
+		    (list source destination))))
       (save-excursion
 	(set-buffer error-buffer)
 	(if (and (numberp status) (not (= 0 status)))
 	     ;; enable-local-variables == nil disables them for newer Emacses
 	     (let ((inhibit-local-variables t)
 		   (enable-local-variables nil)
-		   (coding-system-for-read 'no-conversion))
+		   (coding-system-for-read (vm-line-ending-coding-system)))
 	       (find-file-noselect crash-box)))
+       (if (eq (current-buffer) crash-buf)
+	   (error "folder is the same file as crash box, cannot continue"))
        (save-excursion
 	 (set-buffer crash-buf)
 	 (setq crash-folder-type (vm-get-folder-type))
        (setq got-mail (/= opoint-max (point-max)))
        (if (not got-mail)
 	   nil
-	 (let ((coding-system-for-write 'binary)
+	 (let ((coding-system-for-write (vm-binary-coding-system))
 	       (selective-display nil))
 	   (write-region opoint-max (point-max) buffer-file-name t t))
 	 (vm-increment vm-modification-counter)
 	 (let ((buffer-read-only nil)
 	       folder mcount totals-blurb)
 	   (setq folder (read-file-name "Gather mail from folder: "
-					vm-folder-directory t))
+					vm-folder-directory nil t))
 	   (if (and vm-check-folder-types
 		    (not (vm-compatible-folder-p folder)))
 	       (error "Folder %s is not the same format as this folder."
 	     (vm-save-restriction
 	      (widen)
 	      (goto-char (point-max))
-	      (let ((coding-system-for-read 'binary))
+	      (let ((coding-system-for-read (vm-binary-coding-system)))
 		(insert-file-contents folder))))
 	   (setq mcount (length vm-message-list))
 	   (if (vm-assimilate-new-messages)
       (setq new-messages (if tail-cons (cdr tail-cons) vm-message-list))
       (vm-set-numbering-redo-start-point new-messages)
       (vm-set-summary-redo-start-point new-messages))
+    ;; Only update the folders summary count here if new messages
+    ;; have arrived, not when we're reading the folder for the
+    ;; first time, and not if we cannot assume that all the arrived
+    ;; messages should be considered new.  Use gobble-order as a
+    ;; first time indicator along with the new messages being equal
+    ;; to the whole message list.
+    (if (and new-messages dont-read-attributes
+	     (or (not (eq new-messages vm-message-list))
+		 (null gobble-order)))
+	(vm-modify-folder-totals buffer-file-name 'arrived
+				 (length new-messages)))
     ;; copy the new-messages list because sorting might scramble
     ;; it.  Also something the user does when
     ;; vm-arrived-message-hook is run might affect it.
 (defun vm-display-startup-message ()
   (if (sit-for 5)
       (let ((lines vm-startup-message-lines))
-	(message "VM %s, Copyright (C) 1999 Kyle E. Jones; type ? for help"
+	(message "VM %s, Copyright (C) 2000 Kyle E. Jones; type ? for help"
 		 vm-version)
 	(setq vm-startup-message-displayed t)
 	(while (and (sit-for 4) lines)
   (use-local-map vm-mode-map)
   ;; if the user saves after M-x recover-file, let them get new
   ;; mail again.
+  (make-local-hook 'after-save-hook)
   (add-hook 'after-save-hook 'vm-unblock-new-mail)
   (and (vm-menu-support-possible-p)
        (vm-menu-install-menus))
 	auto-expunge x select source-list uid
 	can-delete read-write uid-validity
 	mailbox mailbox-count message-size response
-	n retrieved retrieved-bytes process-buffer)
+	n (retrieved 0) retrieved-bytes process-buffer)
     (setq auto-expunge (cond ((setq x (assoc source
 					     vm-imap-auto-expunge-alist))
 			      (cdr x))
 		   uid-validity))
 	    ;; loop through the maildrop retrieving and deleting
 	    ;; messages as we go.
-	    (setq n 1 retrieved 0 retrieved-bytes 0)
+	    (setq n 1 retrieved-bytes 0)
 	    (setq statblob (vm-imap-start-status-timer))
 	    (vm-set-imap-stat-x-box statblob imapdrop)
 	    (vm-set-imap-stat-x-maxmsg statblob mailbox-count)
 	      (vm-increment n))
 	    (if did-delete
 		(progn
-		  ;; CLOSE forces an expunge and avoid the EXPUNGE
+		  ;; CLOSE forces an expunge and avoids the EXPUNGE
 		  ;; responses.
 		  (vm-imap-send-command process "CLOSE")
 		  (vm-imap-read-ok-response process)))
 	    (not (equal retrieved 0)) ))
       (setq vm-imap-retrieved-messages imap-retrieved-messages)
+      (if (and (eq vm-flush-interval t) (not (equal retrieved 0)))
+	  (vm-stuff-imap-retrieved))
       (and statblob (vm-imap-stop-status-timer statblob))
       (if process
 	  (vm-imap-end-session process)))))
   (let ((process-to-shutdown nil)
 	process
 	(imapdrop (vm-safe-imapdrop-string source))
-	(coding-system-for-read 'binary)
-	(coding-system-for-write 'binary)
+	(coding-system-for-read (vm-binary-coding-system))
+	(coding-system-for-write (vm-binary-coding-system))
 	greeting timestamp
 	host port mailbox auth user pass source-list process-buffer
 	source-nopwd-nombox)
 					    vm-imap-passwords)))
 	  ;; get the trace buffer
 	  (setq process-buffer
-		(generate-new-buffer (format "trace of IMAP session to %s"
+		(vm-make-work-buffer (format "trace of IMAP session to %s"
 					     host)))
 	  (save-excursion
 	    (set-buffer process-buffer)
 	    ;; clear the trace buffer of old output
 	    (erase-buffer)
 	    ;; Tell MULE not to mess with the text.
-	    (if (or vm-xemacs-mule-p vm-fsfemacs-mule-p)
-		(set-buffer-file-coding-system 'binary t))
+	    (if (fboundp 'set-buffer-file-coding-system)
+		(set-buffer-file-coding-system (vm-binary-coding-system) t))
 	    (if (equal auth "preauth")
 		(setq process
 		      (run-hook-with-args-until-success 'vm-imap-session-preauth-hook
 	    (setq process-to-shutdown nil)
 	    process ))
       (if process-to-shutdown
-	  (vm-imap-end-session process-to-shutdown)))))
+	  (vm-imap-end-session process-to-shutdown t)))))
 
-(defun vm-imap-end-session (process)
+(defun vm-imap-end-session (process &optional keep-buffer)
   (save-excursion
     (set-buffer (process-buffer process))
     (vm-imap-send-command process "LOGOUT")
     ;; we don't care about the response
     ;;(vm-imap-read-ok-response process)
-    (if (not vm-imap-keep-trace-buffer)
-	(kill-buffer (process-buffer process)))
+    (if (not keep-buffer)
+	(kill-buffer (process-buffer process))
+      (save-excursion
+       (set-buffer (process-buffer process))
+       (rename-buffer (concat "saved " (buffer-name)) t)
+       (vm-keep-some-buffers (current-buffer) 'vm-kept-imap-buffers
+			     vm-imap-keep-failed-trace-buffers)))
     (if (fboundp 'add-async-timeout)
 	(add-async-timeout 2 'delete-process process)
       (run-at-time 2 nil 'delete-process process))))

File vm-loaddefs.el

-;;; vm-loaddefs.el --- autoloads for VM formerly in loaddefs.el
-
-;; Copyright (C) 1997 by Free Software Foundation, Inc.
-
-;; Author: SL Baur <steve@xemacs.org>
-;; Keywords: mail, dumped
-
-;; This file is part of XEmacs.
-
-;; XEmacs is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; XEmacs is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with XEmacs; see the file COPYING.  If not, write to the Free
-;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-;; 02111-1307, USA.
-
-;;; Synched up with: Not in FSF
-
-;;; Commentary:
-
-;; This file is dumped with XEmacs.
-
-;; This file contains the autoload definitions for VM formerly in loaddefs.el.
-
-;;; Code:
-
-(autoload 'vm "vm"
-   "\
-View Mail: an alternate mail reader for emacs.
-Optional first arg FOLDER specifies the folder to visit.  It defaults
-to the value of vm-primary-inbox.  The folder buffer is put into VM
-mode, a major mode for reading mail.
-
-Prefix arg or optional second arg READ-ONLY non-nil indicates
-that the folder should be considered read only.  No attribute
-changes, messages additions or deletions will be allowed in the
-visited folder.
-
-Visiting the primary inbox causes any contents of the system mailbox to
-be moved and appended to the resulting buffer.
-
-All the messages can be read by repeatedly pressing SPC.  Use `n'ext and
-`p'revious to move about in the folder.  Messages are marked for
-deletion with `d', and saved to another folder with `s'.  Quitting VM
-with `q' expunges deleted messages and saves the buffered folder to
-disk.
-
-See the documentation for vm-mode for more information."
- t)
-
-(autoload 'vm-mode "vm" 
-  "\
-View Mail: an alternate mail reader for emacs.
-
-Commands:
-   h - summarize folder contents
-   j - discard cached information about the current message
-
-   n - go to next message
-   p - go to previous message
-   N - like `n' but ignores skip-variable settings
-   P - like `p' but ignores skip-variable settings
- M-n - go to next unread message
- M-p - go to previous unread message
- RET - go to numbered message (uses prefix arg or prompts in minibuffer)
- TAB - go to last message seen
- M-s - incremental search through the folder
-
-   t - display hidden headers
- SPC - scroll forward a page (if at end of message, then display next message)
-   b - scroll backward a page
-   < - go to beginning of current message
-   > - go to end of current message
-
-   d - delete message, prefix arg deletes messages forward (flag as deleted)
- C-d - delete message, prefix arg deletes messages backward (flag as deleted)
-   u - undelete
-   k - flag for deletion all messages with same subject as the current message
-
-   r - reply (only to the sender of the message)
-   R - reply with included text for current message
- M-r - extract and resend bounced message
-   f - followup (reply to all recipients of message)
-   F - followup with included text from the current message
-   z - forward the current message
-   m - send a message
-   B - resend the current message to another user.
-   c - continue composing the most recent message you were composing
-
-   @ - digestify and mail entire folder contents (the folder is not modified)
-   * - burst a digest into individual messages, and append and assimilate these
-       message into the current folder.
-
-   G - sort messages by various keys
-
-   g - get any new mail that has arrived in the system mailbox
-       (new mail is appended to the disk and buffer copies of the
-       primary inbox.)
-   v - visit another mail folder
-   V - visit a virtual folder
-
-   e - edit the current message
-
-   s - save current message in a folder (appends if folder already exists)
-   w - write current message to a file without its headers (appends if exists)
-   S - save entire folder to disk, expunging deleted messages
-   A - save unfiled messages to their vm-auto-folder-alist specified folders
-   # - expunge deleted messages (without saving folder)
-   q - quit VM, deleted messages are expunged, folder saved to disk
-   x - exit VM with no change to the folder
-
- M N - use marks; the next vm command will affect only marked messages
-       if it makes sense for the command to do so
-
-       M M - mark the current message
-       M U - unmark the current message
-       M m - mark all messages
-       M u - unmark all messages
-       M ? - help for the mark commands
-
- W S - save the current window configuration to a name
- W D - delete a window configuration
- W W - apply a configuration
- W ? - help for the window configuration commands
-
- C-_ - undo, special undo that retracts the most recent
-             changes in message attributes.  Expunges and saves
-             cannot be undone.  C-x u is also bound to this
-             command.
-
-   L - reload your VM init file, ~/.vm
-
-   ? - help
-
-   ! - run a shell command
-   | - run a shell command with the current message as input
-
- M-C - view conditions under which you may redistribute VM
- M-W - view the details of VM's lack of a warranty
-
-Variables:
-   vm-auto-center-summary
-   vm-auto-folder-alist
-   vm-auto-folder-case-fold-search
-   vm-auto-get-new-mail
-   vm-auto-next-message
-   vm-berkeley-mail-compatibility
-   vm-check-folder-types
-   vm-convert-folder-types
-   vm-circular-folders
-   vm-confirm-new-folders
-   vm-confirm-quit
-   vm-crash-box
-   vm-delete-after-archiving
-   vm-delete-after-bursting
-   vm-delete-after-saving
-   vm-delete-empty-folders
-   vm-digest-burst-type
-   vm-digest-center-preamble
-   vm-digest-preamble-format
-   vm-digest-send-type
-   vm-folder-directory
-   vm-folder-read-only
-   vm-follow-summary-cursor
-   vm-forwarded-headers
-   vm-forwarding-digest-type
-   vm-forwarding-subject-format
-   vm-gargle-uucp
-   vm-highlighted-header-regexp
-   vm-honor-page-delimiters
-   vm-in-reply-to-format
-   vm-included-text-attribution-format
-   vm-included-text-prefix
-   vm-inhibit-startup-message
-   vm-invisible-header-regexp
-   vm-jump-to-new-messages
-   vm-jump-to-unread-messages
-   vm-keep-sent-messages
-   vm-mail-header-from
-   vm-mail-mode-hook
-   vm-mail-window-percentage
-   vm-mode-hook
-   vm-move-after-deleting
-   vm-move-after-undeleting
-   vm-mutable-windows
-   vm-preview-lines
-   vm-preview-read-messages
-   vm-primary-inbox
-   vm-recognize-pop-maildrops
-   vm-reply-ignored-addresses
-   vm-reply-subject-prefix
-   vm-resend-bounced-headers
-   vm-resend-bounced-discard-header-regexp
-   vm-resend-headers
-   vm-resend-discard-header-regexp
-   vm-retain-message-order
-   vm-rfc1153-digest-discard-header-regexp
-   vm-rfc1153-digest-headers
-   vm-rfc934-digest-discard-header-regexp
-   vm-rfc934-digest-headers
-   vm-search-using-regexps
-   vm-skip-deleted-messages
-   vm-skip-read-messages
-   vm-spool-files
-   vm-startup-with-summary
-   vm-strip-reply-headers
-   vm-summary-format
-   vm-unforwarded-header-regexp
-   vm-virtual-folder-alist
-   vm-virtual-mirror
-   vm-visible-headers
-   vm-visit-when-saving
-   vm-window-configuration-file
-"
- t)
-
-(autoload 'vm-visit-folder "vm" 
-  "\
-Visit a mail file with View Mail, an alternate mail reader for emacs.
-See the description of the `vm' and `vm-mode' functions.
-
-VM will parse and present its messages to you in the usual way.
-
-First arg FOLDER specifies the mail file to visit.  When this
-command is called interactively the file name is read from the
-minibuffer.
-
-Prefix arg or optional second arg READ-ONLY non-nil indicates
-that the folder should be considered read only.  No attribute
-changes, messages additions or deletions will be allowed in the
-visited folder."
-  t)
-
-(autoload 'vm-mail "vm"
-  "\
-Send a mail message from within View Mail, or from without."
-  t)
-
-(provide 'vm-loaddefs)
-
-;;; vm-loaddefs.el ends here
 
 (defmacro vm-assert (expression)
   (list 'or expression
-	(list 'progn
-	      (list 'setq 'debug-on-error t)
+	(list 'let
+	      (list (list 'debug-on-error t))
 	      (list 'error "assertion failed: %S"
 		    (list 'quote expression)))))
 
   (list 'setq variable (list '1- variable)))
 
 (defmacro vm-select-folder-buffer ()
-  '(and vm-mail-buffer
-	(or (buffer-name vm-mail-buffer)
-	    (error "Folder buffer has been killed."))
-	(set-buffer vm-mail-buffer)))
+  '(cond (vm-mail-buffer
+	  (or (buffer-name vm-mail-buffer)
+	      (error "Folder buffer has been killed."))
+	  (set-buffer vm-mail-buffer))
+	 ((not (memq major-mode '(vm-mode vm-virtual-mode)))
+	  (error "No VM folder buffer associated with this buffer"))))
+
+(defmacro vm-select-folder-buffer-if-possible ()
+  '(cond (vm-mail-buffer
+	  (set-buffer vm-mail-buffer))))
 
 (defmacro vm-error-if-folder-read-only ()
   '(while vm-folder-read-only
 			    body)
 		     '(set-buffer-multibyte xzx))))
    body))
+
+(defsubst vm-binary-coding-system ()
+  (cond (vm-xemacs-mule-p 'binary)
+	(vm-xemacs-file-coding-p 'binary)
+	(t 'no-conversion)))
+
+(defsubst vm-line-ending-coding-system ()
+  (cond (vm-xemacs-mule-p 'no-conversion)
+	(vm-xemacs-file-coding-p 'no-conversion)
+	(t 'raw-text)))
    ))
 
 (defconst vm-menu-dispose-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Dispose"
 			 "Dispose"
 			 "---"
   )
 
 (defconst vm-menu-mail-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Mail Commands"
 			 "Mail Commands"
 			 "---"
 	   ["Yank Original" vm-menu-yank-original vm-reply-list]
 	   "----"
 	   (append
-	    (if (vm-menu-fsfemacs-menus-p)
+	    (if (vm-menu-fsfemacs19-menus-p)
 		(list "Send Using MIME..."
 		      "Send Using MIME..."
 		      "---"
 	      :style radio
 	      :selected (not vm-send-using-mime)]))
 	   (append
-	    (if (vm-menu-fsfemacs-menus-p)
+	    (if (vm-menu-fsfemacs19-menus-p)
 		(list "Fragment Messages Larger Than ..."
 		      "Fragment Messages Larger Than ..."
 		      "---"
 		   :style radio
 		   :selected (eq vm-mime-max-message-size 2000000)]))
 	   (append
-	    (if (vm-menu-fsfemacs-menus-p)
+	    (if (vm-menu-fsfemacs19-menus-p)
 		(list "Encode 8-bit Characters Using ..."
 		      "Encode 8-bit Characters Using ..."
 		      "---"
 	   ))))
 
 (defconst vm-menu-mime-dispose-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Take Action on MIME body ..."
 			 "Take Action on MIME body ..."
 			 "---"
 	    (vm-mime-run-display-function-at-point
 	     'vm-mime-display-body-using-external-viewer) t]
 	   "---"
-	   ["Save to File" (vm-mime-run-display-function-at-point
-			    'vm-mime-send-body-to-file) t]
+	   ["Save to File" vm-mime-reader-map-save-file t]
+	   ["Save to Folder" vm-mime-reader-map-save-message
+	    (let ((layout (vm-mime-run-display-function-at-point
+			   (function
+			    (lambda (e)
+			      (vm-extent-property e 'vm-mime-layout))))))
+	      (if (null layout)
+		  nil
+		(or (vm-mime-types-match "message/rfc822"
+					 (car (vm-mm-layout-type layout)))
+		    (vm-mime-types-match "message/news"
+					 (car (vm-mm-layout-type layout))))))]
 	   ["Send to Printer" (vm-mime-run-display-function-at-point
 			       'vm-mime-send-body-to-printer) t]
 	   ["Feed to Shell Pipeline (display output)"
 	   ["Feed to Shell Pipeline (discard output)"
 	    (vm-mime-run-display-function-at-point
 	     'vm-mime-pipe-body-to-queried-command-discard-output) t]
-	   ["Delete object" 'vm-delete-mime-object t]))))
+	   ["Delete object" vm-delete-mime-object t]))))
 
 (defconst vm-menu-url-browser-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Send URL to ..."
 			 "Send URL to ..."
 			 "---"
 	    t]))))
 
 (defconst vm-menu-mailto-url-browser-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Send Mail using ..."
 			 "Send Mail using ..."
 			 "---"
      (list ["VM" (vm-mouse-send-url-at-position (point) 'ignore) t]))))
 
 (defconst vm-menu-subject-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Take Action on Subject..."
 			 "Take Action on Subject..."
 			 "---"
       ))))
 
 (defconst vm-menu-author-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Take Action on Author..."
 			 "Take Action on Author..."
 			 "---"
       ))))
 
 (defconst vm-menu-content-disposition-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "Set Content Disposition"
 			 "Set Content Disposition"
 			 "---"
 (defvar vm-menu-vm-menubar nil)
 
 (defconst vm-menu-vm-menu
-  (let ((title (if (vm-menu-fsfemacs-menus-p)
+  (let ((title (if (vm-menu-fsfemacs19-menus-p)
 		   (list "VM"
 			 "VM"
 			 "---"
 (defun vm-mm-layout-disposition (e) (aref e 5))
 (defun vm-mm-layout-qdisposition (e) (aref e 6))
 (defun vm-mm-layout-header-start (e) (aref e 7))
-(defun vm-mm-layout-body-start (e) (aref e 8))
-(defun vm-mm-layout-body-end (e) (aref e 9))
-(defun vm-mm-layout-parts (e) (aref e 10))
-(defun vm-mm-layout-cache (e) (aref e 11))
-(defun vm-mm-layout-message-symbol (e) (aref e 12))
+(defun vm-mm-layout-header-end (e) (aref e 8))
+(defun vm-mm-layout-body-start (e) (aref e 9))
+(defun vm-mm-layout-body-end (e) (aref e 10))
+(defun vm-mm-layout-parts (e) (aref e 11))
+(defun vm-mm-layout-cache (e) (aref e 12))
+(defun vm-mm-layout-message-symbol (e) (aref e 13))
 (defun vm-mm-layout-message (e)
   (symbol-value (vm-mm-layout-message-symbol e)))
 ;; if display of MIME part fails, error string will be here.
-(defun vm-mm-layout-display-error (e) (aref e 13))
+(defun vm-mm-layout-display-error (e) (aref e 14))
 
 (defun vm-set-mm-layout-type (e type) (aset e 0 type))
 (defun vm-set-mm-layout-qtype (e type) (aset e 1 type))
 (defun vm-set-mm-layout-disposition (e d) (aset e 5 d))
 (defun vm-set-mm-layout-qdisposition (e d) (aset e 6 d))
 (defun vm-set-mm-layout-header-start (e start) (aset e 7 start))
-(defun vm-set-mm-layout-body-start (e start) (aset e 8 start))
-(defun vm-set-mm-layout-body-end (e end) (aset e 9 end))
-(defun vm-set-mm-layout-parts (e parts) (aset e 10 parts))
-(defun vm-set-mm-layout-cache (e c) (aset e 11 c))
-(defun vm-set-mm-layout-display-error (e c) (aset e 13 c))
+(defun vm-set-mm-layout-header-end (e start) (aset e 8 start))
+(defun vm-set-mm-layout-body-start (e start) (aset e 9 start))
+(defun vm-set-mm-layout-body-end (e end) (aset e 10 end))
+(defun vm-set-mm-layout-parts (e parts) (aset e 11 parts))
+(defun vm-set-mm-layout-cache (e c) (aset e 12 c))
+(defun vm-set-mm-layout-display-error (e c) (aset e 14 c))
 
 (defun vm-mime-make-message-symbol (m)
   (let ((s (make-symbol "<<m>>")))
 		  (save-restriction
 		    (widen)
 		    (goto-char (vm-headers-of m))
-		    (or (re-search-forward vm-mime-encoded-word-regexp
-					   (vm-text-of m) t)
-			'none)))))
+		    (let ((case-fold-search t))
+		      (or (re-search-forward vm-mime-encoded-word-regexp
+					     (vm-text-of m) t)
+			  'none))))))
 	     (vm-mime-encoded-header-flag-of m))))
 
 (defun vm-mime-Q-decode-region (start end)
 (fset 'vm-mime-B-decode-region 'vm-mime-base64-decode-region)
 
 (defun vm-mime-Q-encode-region (start end)
-  (let ((buffer-read-only nil))
+  (let ((buffer-read-only nil)
+	(val))
+    (setq val (vm-mime-qp-encode-region start end t))
     (subst-char-in-region start end (string-to-char " ") ?_ t)
-    (vm-mime-qp-encode-region start end t)))
+    val ))
 
 (defun vm-mime-B-encode-region (start end)
   (vm-mime-base64-encode-region start end nil t))
 	  (delete-char -1)
 	  (insert "\r\n"))))))
       
+(defun vm-encode-coding-region (b-start b-end coding-system &rest foo)
+  (let ((work-buffer (vm-make-work-buffer))
+	start end
+	oldsize
+	retval
+	(b (current-buffer)))
+    (save-excursion
+      (set-buffer work-buffer)
+      (insert-buffer-substring b b-start b-end)
+      (setq oldsize (buffer-size))
+      (setq retval (apply 'encode-coding-region (point-min) (point-max)
+			  coding-system foo))
+      (setq start (point-min) end (point-max))
+      (setq retval (buffer-size))
+      (save-excursion
+	(set-buffer b)
+	(goto-char b-start)
+	(insert-buffer-substring work-buffer start end)
+	(delete-region (point) (+ (point) oldsize))
+	;; Fixup the end point.  I have found no other way to
+	;; let the calling function know where the region ends
+	;; after encode-coding-region has the scrambled markers.
+	(and (markerp b-end)
+	     (set-marker b-end (point)))
+	(kill-buffer work-buffer)
+	retval ))))
+
+(defun vm-decode-coding-region (b-start b-end coding-system &rest foo)
+  (let ((work-buffer (vm-make-work-buffer))
+	start end
+	oldsize
+	retval
+	(b (current-buffer)))
+    (save-excursion
+      (setq oldsize (- b-end b-start))
+      (set-buffer work-buffer)
+      (insert-buffer-substring b b-start b-end)
+      (setq retval (apply 'decode-coding-region (point-min) (point-max)
+			  coding-system foo))
+      (and vm-fsfemacs-p (set-buffer-multibyte t))
+      (setq start (point-min) end (point-max))
+      (save-excursion
+	(set-buffer b)
+	(goto-char b-start)
+	(delete-region (point) (+ (point) oldsize))
+	(insert-buffer-substring work-buffer start end)
+	;; Fixup the end point.  I have found no other way to
+	;; let the calling function know where the region ends
+	;; after decode-coding-region has the scrambled markers.
+	(and (markerp b-end)
+	     (set-marker b-end (point)))
+	(kill-buffer work-buffer)
+	retval ))))
+
 (defun vm-mime-charset-decode-region (charset start end)
   (or (markerp end) (setq end (vm-marker end)))
   (cond ((or vm-xemacs-mule-p vm-fsfemacs-mule-p)
 	 (if (or (and vm-xemacs-p (memq (device-type) '(x mswindows)))
-		 (and vm-fsfemacs-p (eq window-system 'x))
+		 vm-fsfemacs-p
 		 nil)
 	     (let ((buffer-read-only nil)
 		   (cell (cdr (vm-string-assoc
 			       charset
 			       vm-mime-mule-charset-to-coding-alist)))
-		   (oend (marker-position end))
 		   (opoint (point)))
 	       (if cell
 		   (progn
-		     (set-marker end (+ start
-					(or (decode-coding-region
-					     start end (car cell))
-					    (- oend start))))
+		     ;; decode 8-bit indeterminate char to correct
+		     ;; char in correct charset.
+		     (vm-decode-coding-region start end (car cell))
 		     (put-text-property start end 'vm-string t)
 		     (put-text-property start end 'vm-charset charset)
 		     (put-text-property start end 'vm-coding (car cell))))
 	   (if font
 	       (condition-case data
 		   (progn (set-face-font face font)
-			  (vm-set-extent-property e 'face face))
+			  (if vm-fsfemacs-p
+			      (put-text-property start end 'face face)
+			    (vm-set-extent-property e 'duplicable t)
+			    (vm-set-extent-property e 'face face)))
 		 (error nil)))))))
 
 (defun vm-mime-transfer-decode-region (layout start end)
 	   (vm-mime-uuencode-decode-region start end crlf)))))
 
 (defun vm-mime-base64-decode-region (start end &optional crlf)
+  (or (markerp end) (setq end (vm-marker end)))
   (and (> (- end start) 200)
        (message "Decoding base64..."))
   (let ((work-buffer nil)
 	(non-data-chars (concat "^=" vm-mime-base64-alphabet)))
     (unwind-protect
 	(save-excursion
-	  (let ((default-enable-multibyte-characters nil))
-	    (setq work-buffer (generate-new-buffer " *vm-work*")))
-	  (buffer-disable-undo work-buffer)
-	  (if vm-mime-base64-decoder-program
-	      (let* ((binary-process-output t) ; any text already has CRLFs
-		     ;; use binary coding system in FSF Emacs/MULE
-		     (coding-system-for-read 'binary)
-		     (coding-system-for-write 'binary)
-		     (status (apply 'vm-run-command-on-region
-				   start end work-buffer
-				   vm-mime-base64-decoder-program
-				   vm-mime-base64-decoder-switches)))
-		(if (not (eq status t))
-		    (vm-mime-error "%s" (cdr status))))
+	  (cond
+	   ((and (featurep 'base64)
+		 (fboundp 'base64-decode-region))
+	    (base64-decode-region start end)
+	    (and crlf (vm-mime-crlf-to-lf-region start end)))
+	   (t
+	    (setq work-buffer (vm-make-work-buffer))
+	    (if vm-mime-base64-decoder-program
+		(let* ((binary-process-output t) ; any text already has CRLFs
+		       ;; use binary coding system in FSF Emacs/MULE
+		       (coding-system-for-read (vm-binary-coding-system))
+		       (coding-system-for-write (vm-binary-coding-system))
+		       (status (apply 'vm-run-command-on-region
+				      start end work-buffer
+				      vm-mime-base64-decoder-program
+				      vm-mime-base64-decoder-switches)))
+		  (if (not (eq status t))
+		      (vm-mime-error "%s" (cdr status))))
+	      (goto-char start)
+	      (skip-chars-forward non-data-chars end)
+	      (while (not done)
+		(setq inputpos (point))
+		(cond
+		 ((> (skip-chars-forward vm-mime-base64-alphabet end) 0)
+		  (setq lim (point))
+		  (while (< inputpos lim)
+		    (setq bits (+ bits 
+				  (aref vm-mime-base64-alphabet-decoding-vector
+					(char-after inputpos))))
+		    (vm-increment counter)
+		    (vm-increment inputpos)
+		    (cond ((= counter 4)
+			   (vm-insert-char (lsh bits -16) 1 nil work-buffer)
+			   (vm-insert-char (logand (lsh bits -8) 255) 1 nil
+					   work-buffer)
+			   (vm-insert-char (logand bits 255) 1 nil work-buffer)
+			   (setq bits 0 counter 0))
+			  (t (setq bits (lsh bits 6)))))))
+		(cond
+		 ((= (point) end)
+		  (if (not (zerop counter))
+		      (vm-mime-error "at least %d bits missing at end of base64 encoding"
+				     (* (- 4 counter) 6)))
+		  (setq done t))
+		 ((= (char-after (point)) 61) ; 61 is ASCII equals
+		  (setq done t)
+		  (cond ((= counter 1)
+			 (vm-mime-error "at least 2 bits missing at end of base64 encoding"))
+			((= counter 2)
+			 (vm-insert-char (lsh bits -10) 1 nil work-buffer))
+			((= counter 3)
+			 (vm-insert-char (lsh bits -16) 1 nil work-buffer)
+			 (vm-insert-char (logand (lsh bits -8) 255)
+					 1 nil work-buffer))
+			((= counter 0) t)))
+		 (t (skip-chars-forward non-data-chars end)))))
+	    (and crlf
+		 (save-excursion
+		   (set-buffer work-buffer)
+		   (vm-mime-crlf-to-lf-region (point-min) (point-max))))
 	    (goto-char start)
-	    (skip-chars-forward non-data-chars end)
-	    (while (not done)
-	      (setq inputpos (point))
-	      (cond
-	       ((> (skip-chars-forward vm-mime-base64-alphabet end) 0)
-		(setq lim (point))
-		(while (< inputpos lim)
-		  (setq bits (+ bits 
-				(aref vm-mime-base64-alphabet-decoding-vector
-				      (char-after inputpos))))
-		  (vm-increment counter)
-		  (vm-increment inputpos)
-		  (cond ((= counter 4)
-			 (vm-insert-char (lsh bits -16) 1 nil work-buffer)
-			 (vm-insert-char (logand (lsh bits -8) 255) 1 nil
-					 work-buffer)
-			 (vm-insert-char (logand bits 255) 1 nil work-buffer)
-			 (setq bits 0 counter 0))
-			(t (setq bits (lsh bits 6)))))))
-	      (cond
-	       ((= (point) end)
-		(if (not (zerop counter))
-		    (vm-mime-error "at least %d bits missing at end of base64 encoding"
-				   (* (- 4 counter) 6)))
-		(setq done t))
-	       ((= (char-after (point)) 61) ; 61 is ASCII equals
-		(setq done t)
-		(cond ((= counter 1)
-		       (vm-mime-error "at least 2 bits missing at end of base64 encoding"))
-		      ((= counter 2)
-		       (vm-insert-char (lsh bits -10) 1 nil work-buffer))
-		      ((= counter 3)
-		       (vm-insert-char (lsh bits -16) 1 nil work-buffer)
-		       (vm-insert-char (logand (lsh bits -8) 255)
-				       1 nil work-buffer))
-		      ((= counter 0) t)))
-	       (t (skip-chars-forward non-data-chars end)))))
-	  (and crlf
-	       (save-excursion
-		 (set-buffer work-buffer)
-		 (vm-mime-crlf-to-lf-region (point-min) (point-max))))
-	  (or (markerp end) (setq end (vm-marker end)))
-	  (goto-char start)
-	  (insert-buffer-substring work-buffer)
-	  (delete-region (point) end))
+	    (insert-buffer-substring work-buffer)
+	    (delete-region (point) end))))
       (and work-buffer (kill-buffer work-buffer))))
   (and (> (- end start) 200)
        (message "Decoding base64... done")))
 
 (defun vm-mime-base64-encode-region (start end &optional crlf B-encoding)
+  (or (markerp end) (setq end (vm-marker end)))
   (and (> (- end start) 200)
        (message "Encoding base64..."))
   (let ((work-buffer nil)
 	inputpos)
     (unwind-protect
 	(save-excursion
-	  (let ((default-enable-multibyte-characters nil))
-	    (setq work-buffer (generate-new-buffer " *vm-work*")))
-	  (buffer-disable-undo work-buffer)
-	  (if crlf
-	      (progn
-		(or (markerp end) (setq end (vm-marker end)))
-		(vm-mime-lf-to-crlf-region start end)))
-	  (if vm-mime-base64-encoder-program
-	      (let ((status (apply 'vm-run-command-on-region
-				   start end work-buffer
-				   vm-mime-base64-encoder-program
-				   vm-mime-base64-encoder-switches)))
-		(if (not (eq status t))
-		    (vm-mime-error "%s" (cdr status)))
-		(if B-encoding
-		    (save-excursion
-		      (set-buffer work-buffer)
-		      ;; if we're B encoding, strip out the line breaks
-		      (goto-char (point-min))
-		      (while (search-forward "\n" nil t)
-			(delete-char -1)))))
-	    (setq inputpos start)
-	    (while (< inputpos end)
-	      (setq bits (+ bits (char-after inputpos)))
-	      (vm-increment counter)
-	      (cond ((= counter 3)
-		     (vm-insert-char (aref alphabet (lsh bits -18)) 1 nil
-				     work-buffer)
-		     (vm-insert-char (aref alphabet (logand (lsh bits -12) 63))
-				     1 nil work-buffer)
-		     (vm-insert-char (aref alphabet (logand (lsh bits -6) 63))
-				     1 nil work-buffer)
-		     (vm-insert-char (aref alphabet (logand bits 63)) 1 nil
-				     work-buffer)
-		     (setq cols (+ cols 4))
-		     (cond ((= cols 72)
-			    (setq cols 0)
-			    (if (not B-encoding)
-				(vm-insert-char ?\n 1 nil work-buffer))))
-		     (setq bits 0 counter 0))
-		    (t (setq bits (lsh bits 8))))
-	      (vm-increment inputpos))
-	    ;; write out any remaining bits with appropriate padding
-	    (if (= counter 0)
-		nil
-	      (setq bits (lsh bits (- 16 (* 8 counter))))
-	      (vm-insert-char (aref alphabet (lsh bits -18)) 1 nil
-			      work-buffer)
-	      (vm-insert-char (aref alphabet (logand (lsh bits -12) 63))
-			      1 nil work-buffer)
-	      (if (= counter 1)
-		  (vm-insert-char ?= 2 nil work-buffer)
-		(vm-insert-char (aref alphabet (logand (lsh bits -6) 63))
+	  (and crlf (vm-mime-lf-to-crlf-region start end))
+	  (cond
+	   ((and (featurep 'base64)
+		 (fboundp 'base64-encode-region))
+	    (base64-encode-region start end B-encoding))
+	   (t
+	    (setq work-buffer (vm-make-work-buffer))
+	    (if vm-mime-base64-encoder-program
+		(let ((status (apply 'vm-run-command-on-region
+				     start end work-buffer
+				     vm-mime-base64-encoder-program
+				     vm-mime-base64-encoder-switches)))
+		  (if (not (eq status t))
+		      (vm-mime-error "%s" (cdr status)))
+		  (if B-encoding
+		      (save-excursion
+			(set-buffer work-buffer)
+			;; if we're B encoding, strip out the line breaks
+			(goto-char (point-min))
+			(while (search-forward "\n" nil t)
+			  (delete-char -1)))))
+	      (setq inputpos start)
+	      (while (< inputpos end)
+		(setq bits (+ bits (char-after inputpos)))
+		(vm-increment counter)
+		(cond ((= counter 3)
+		       (vm-insert-char (aref alphabet (lsh bits -18)) 1 nil
+				       work-buffer)
+		       (vm-insert-char (aref alphabet (logand (lsh bits -12) 63))
+				       1 nil work-buffer)
+		       (vm-insert-char (aref alphabet (logand (lsh bits -6) 63))
+				       1 nil work-buffer)
+		       (vm-insert-char (aref alphabet (logand bits 63)) 1 nil
+				       work-buffer)
+		       (setq cols (+ cols 4))
+		       (cond ((= cols 72)
+			      (setq cols 0)
+			      (if (not B-encoding)
+				  (vm-insert-char ?\n 1 nil work-buffer))))
+		       (setq bits 0 counter 0))
+		      (t (setq bits (lsh bits 8))))
+		(vm-increment inputpos))
+	      ;; write out any remaining bits with appropriate padding
+	      (if (= counter 0)
+		  nil
+		(setq bits (lsh bits (- 16 (* 8 counter))))
+		(vm-insert-char (aref alphabet (lsh bits -18)) 1 nil
+				work-buffer)
+		(vm-insert-char (aref alphabet (logand (lsh bits -12) 63))
 				1 nil work-buffer)
-		(vm-insert-char ?= 1 nil work-buffer)))
-	    (if (> cols 0)
-		(vm-insert-char ?\n 1 nil work-buffer)))
-	  (or (markerp end) (setq end (vm-marker end)))
-	  (goto-char start)
-	  (insert-buffer-substring work-buffer)
-	  (delete-region (point) end)
+		(if (= counter 1)
+		    (vm-insert-char ?= 2 nil work-buffer)
+		  (vm-insert-char (aref alphabet (logand (lsh bits -6) 63))
+				  1 nil work-buffer)
+		  (vm-insert-char ?= 1 nil work-buffer)))
+	      (if (> cols 0)
+		  (vm-insert-char ?\n 1 nil work-buffer)))
+	    (or (markerp end) (setq end (vm-marker end)))
+	    (goto-char start)
+	    (insert-buffer-substring work-buffer)
+	    (delete-region (point) end)))
 	  (and (> (- end start) 200)
 	       (message "Encoding base64... done"))
 	  (- end start))
 	inputpos stop-point copy-point)
     (unwind-protect
 	(save-excursion
-	  (let ((default-enable-multibyte-characters nil))
-	    (setq work-buffer (generate-new-buffer " *vm-work*")))
-	  (buffer-disable-undo work-buffer)
+	  (setq work-buffer (vm-make-work-buffer))
 	  (if vm-mime-qp-decoder-program
 	      (let* ((binary-process-output t) ; any text already has CRLFs
 		     ;; use binary coding system in FSF Emacs/MULE
-		     (coding-system-for-read 'binary)
-		     (coding-system-for-write 'binary)
+		     (coding-system-for-read (vm-binary-coding-system))
+		     (coding-system-for-write (vm-binary-coding-system))
 		     (status (apply 'vm-run-command-on-region
 				    start end work-buffer
 				    vm-mime-qp-decoder-program
 	char inputpos)
     (unwind-protect
 	(save-excursion
-	  (let ((default-enable-multibyte-characters nil))
-	    (setq work-buffer (generate-new-buffer " *vm-work*")))
-	  (buffer-disable-undo work-buffer)
+	  (setq work-buffer (vm-make-work-buffer))
 	  (if vm-mime-qp-encoder-program
 	      (let* ((binary-process-output t) ; any text already has CRLFs
 		     ;; use binary coding system in FSF Emacs/MULE
-		     (coding-system-for-read 'binary)
-		     (coding-system-for-write 'binary)
+		     (coding-system-for-read (vm-binary-coding-system))
+		     (coding-system-for-write (vm-binary-coding-system))
 		     (status (apply 'vm-run-command-on-region
 				    start end work-buffer
 				    vm-mime-qp-encoder-program
 	(tempfile (vm-make-tempfile-name)))
     (unwind-protect
 	(save-excursion
-	  (let ((default-enable-multibyte-characters nil))
-	    (setq work-buffer (generate-new-buffer " *vm-work*")))
+	  (setq work-buffer (vm-make-work-buffer))
 	  (set-buffer work-buffer)
-	  (buffer-disable-undo work-buffer)
 	  (insert-buffer-substring region-buffer start end)
 	  (goto-char (point-min))
 	  (or (re-search-forward "^begin [0-7][0-7][0-7] " nil t)
 	  (if (stringp vm-mime-uuencode-decoder-program)
 	      (let* ((binary-process-output t) ; any text already has CRLFs
 		     ;; use binary coding system in FSF Emacs/MULE
-		     (coding-system-for-read 'binary)
-		     (coding-system-for-write 'binary)
-		     (process-coding-system-alist '(("." . binary)))
+		     (coding-system-for-read (vm-binary-coding-system))
+		     (coding-system-for-write (vm-binary-coding-system))
+		     (process-coding-system-alist
+		      (list (cons "." (vm-binary-coding-system))))
 		     (status (apply 'vm-run-command-on-region
 				    (point-min) (point-max) nil
 				    vm-mime-uuencode-decoder-program
 	(setq match-start (match-beginning 0)
 	      match-end (match-end 0)
 	      charset (buffer-substring (match-beginning 1) (match-end 1))
-	      encoding (buffer-substring (match-beginning 2) (match-end 2))
-	      start (match-beginning 3)
-	      end (vm-marker (match-end 3)))
+	      encoding (buffer-substring (match-beginning 4) (match-end 4))
+	      start (match-beginning 5)
+	      end (vm-marker (match-end 5)))
 	;; don't change anything if we can't display the
 	;; character set properly.
 	(if (not (vm-mime-charset-internally-displayable-p charset))
 			   (insert "**invalid encoded word**")
 			   (delete-region (point) end)))
 	  (vm-mime-charset-decode-region charset start end)
+	  (goto-char end)
 	  (delete-region match-start start))))))
 
 (defun vm-decode-mime-encoded-words ()
 	(setq match-start (match-beginning 0)
 	      match-end (match-end 0)
 	      charset (buffer-substring (match-beginning 1) (match-end 1))
-	      encoding (buffer-substring (match-beginning 2) (match-end 2))
-	      start (match-beginning 3)
-	      end (vm-marker (match-end 3)))
+	      encoding (buffer-substring (match-beginning 4) (match-end 4))
+	      start (match-beginning 5)
+	      end (vm-marker (match-end 5)))
 	;; don't change anything if we can't display the
 	;; character set properly.
 	(if (not (vm-mime-charset-internally-displayable-p charset))
 			   (insert "**invalid encoded word**")
 			   (delete-region (point) end)))
 	  (vm-mime-charset-decode-region charset start end)
+	  (goto-char end)
 	  (delete-region match-start start))))))
 
 (defun vm-decode-mime-encoded-words-in-string (string)
   (if (and vm-display-using-mime
-	   (string-match vm-mime-encoded-word-regexp string))
+	   (let ((case-fold-search t))
+	     (string-match vm-mime-encoded-word-regexp string)))
       (vm-with-string-as-temp-buffer string 'vm-decode-mime-encoded-words)
     string ))
 
 				  encoding id description
 				  disposition qdisposition
 				  (vm-headers-of m)
+				  (vm-marker (1- (vm-text-of m)))
 				  (vm-text-of m)
 				  (vm-text-end-of m)
 				  nil nil
 			   encoding id description
 			   disposition qdisposition
 			   (vm-marker (point-min))
+			   (vm-marker (1- (point)))
 			   (vm-marker (point))
 			   (vm-marker (point-max))
 			   nil nil
 		  ((string-match "^multipart/" (car type))
 		   (setq c-t '("text/plain" "charset=us-ascii")
 			 c-t-e "7bit")) ; below
-		  ((string-match "^message/\\(rfc822\\|news\\)" (car type))
+		  ((string-match "^message/\\(rfc822\\|news\\|external-body\\)"
+				 (car type))
 		   (setq c-t '("text/plain" "charset=us-ascii")
 			 c-t-e "7bit")
 		   (goto-char (point-min))
 			  (vector type qtype encoding id description
 				  disposition qdisposition
 				  (vm-marker (point-min))
+				  (vm-marker (1- (point)))
 				  (vm-marker (point))
 				  (vm-marker (point-max))
 				  (list
 			  (vector type qtype encoding id description
 				  disposition qdisposition
 				  (vm-marker (point-min))
+				  (vm-marker (1- (point)))
 				  (vm-marker (point))
 				  (vm-marker (point-max))
 				  nil nil
 	    (vector type qtype encoding id description
 		    disposition qdisposition
 		    (vm-marker (point-min))
+		    (vm-marker (1- (point)))
 		    (vm-marker (point))
 		    (vm-marker (point-max))
 		    (nreverse multipart-list)
 	     ;; will see the description.
 	     '("attachment") '("attachment")
 	     header
+	     (vm-marker (1- text))
 	     text
 	     text-end
 	     nil nil
 	       (= (match-end 0) match-end))
 	  (setq done t)
 	(setq param-list (cdr param-list))))
-    (and (car param-list) (car (vm-parse (car param-list) "=\\(.*\\)")))))
+    (and (car param-list)
+	 (substring (car param-list) match-end))))
 
 (defun vm-mime-get-parameter (layout name)
   (vm-mime-get-xxx-parameter layout name (cdr (vm-mm-layout-type layout))))
 				(vm-mm-layout-body-end layout)))
 
 (defun vm-mime-insert-mime-headers (layout)
-  (vm-insert-region-from-buffer (marker-buffer (vm-mm-layout-body-start layout))
+  (vm-insert-region-from-buffer (marker-buffer (vm-mm-layout-header-start layout))
 				(vm-mm-layout-header-start layout)
-				(vm-mm-layout-body-start layout))
-  (if (and (not (bobp)) (char-equal (char-after (1- (point))) ?\n))
-      (delete-char -1)))
+				(vm-mm-layout-header-end layout)))
 
 (defvar buffer-display-table)
 (defvar standard-display-table)
 	b mm
 	(real-m (vm-real-message-of m))
 	(modified (buffer-modified-p))
-	(coding-system-for-read 'binary)
-	(coding-system-for-write 'binary))
+	(coding-system-for-read (vm-binary-coding-system))
+	(coding-system-for-write (vm-binary-coding-system)))
     (cond ((or (null vm-presentation-buffer-handle)
 	       (null (buffer-name vm-presentation-buffer-handle)))
-	   (setq b (generate-new-buffer (concat (buffer-name)
-						" Presentation")))
+	   (let ((default-enable-multibyte-characters t))
+	     (setq b (generate-new-buffer (concat (buffer-name)
+						  " Presentation"))))
 	   (save-excursion
 	     (set-buffer b)
 	     (if (fboundp 'buffer-disable-undo)
 	     (defvar scroll-in-place)
 	     (make-local-variable 'scroll-in-place)
 	     (setq scroll-in-place nil)
-	     (if (or vm-xemacs-mule-p vm-fsfemacs-mule-p)
-		 (set-buffer-file-coding-system 'binary t))
-	     (cond ((and vm-fsfemacs-p (not vm-fsfemacs-mule-p))
-		    ;; need to do this outside the let because
-		    ;; loading disp-table initializes
-		    ;; standard-display-table.
-		    (require 'disp-table)
-		    (let* ((standard-display-table
-			    (copy-sequence standard-display-table)))
-		      (standard-display-european t)
-		      (setq buffer-display-table standard-display-table))))
+	     (if (fboundp 'set-buffer-file-coding-system)
+		 (set-buffer-file-coding-system (vm-binary-coding-system) t))
+	     (vm-fsfemacs-nonmule-display-8bit-chars)
 	     (if (and vm-mutable-frames vm-frame-per-folder
 		      (vm-multiple-frames-possible-p))
 		 (vm-set-hooks-for-frame-deletion))
 
 (defvar native-sound-only-on-console)
 
-(defun vm-mime-can-display-internal (layout)
+(defun vm-mime-can-display-internal (layout &optional deep)
   (let ((type (car (vm-mm-layout-type layout))))
     (cond ((vm-mime-types-match "image/jpeg" type)
 	   (and (featurep 'jpeg) (vm-images-possible-here-p)))
 			 (not native-sound-only-on-console)
 			 (eq (device-type) 'x)))))
 	  ((vm-mime-types-match "multipart" type) t)
-	  ((vm-mime-types-match "message/external-body" type) nil)
+	  ((vm-mime-types-match "message/external-body" type)
+	   (or (not deep)
+	       (vm-mime-can-display-internal
+		(car (vm-mm-layout-parts layout)) t)))
 	  ((vm-mime-types-match "message" type) t)
 	  ((vm-mime-types-match "text/html" type)
-	   (fboundp 'w3-region))
+	   (and (fboundp 'w3-region)
+		;; this because GNUS bogusly sets up autoloads
+		;; for w3-region even if W3 isn't installed.
+		(fboundp 'w3-about)))
 	  ((vm-mime-types-match "text" type)
 	   (let ((charset (or (vm-mime-get-parameter layout "charset")
 			      "us-ascii")))
 (defun vm-mime-convert-undisplayable-layout (layout)
   (let ((ooo (vm-mime-can-convert (car (vm-mm-layout-type layout)))))
     (message "Converting %s to %s..."
-			(car (vm-mm-layout-type layout))
-			(nth 1 ooo))
+	     (car (vm-mm-layout-type layout))
+	     (nth 1 ooo))
     (save-excursion
-      (set-buffer (generate-new-buffer " *mime object*"))
+      (set-buffer (vm-make-work-buffer " *mime object*"))
       ;; call-process-region calls write-region.
       ;; don't let it do CR -> LF translation.
       (setq selective-display nil)
       (setq vm-message-garbage-alist
 	    (cons (cons (current-buffer) 'kill-buffer)
 		  vm-message-garbage-alist))
-      (vm-with-unibyte-buffer
-       (vm-mime-insert-mime-body layout)
-       (vm-mime-transfer-decode-region layout (point-min) (point-max)))
+      (vm-mime-insert-mime-body layout)
+      (vm-mime-transfer-decode-region layout (point-min) (point-max))
       (call-process-region (point-min) (point-max) shell-file-name
 			   t t nil shell-command-switch (nth 2 ooo))
       (goto-char (point-min))
 	      (vm-mm-layout-disposition layout)
 	      (vm-mm-layout-qdisposition layout)
 	      (vm-marker (point-min))
+	      (vm-marker (1- (point)))
 	      (vm-marker (point))
 	      (vm-marker (point-max))
 	      nil
 
 If the variable vm-mime-display-function is set, then its value
 is called as a function with no arguments, and none of the
-actions mentioned in the preceding paragraphs are done.  At the
+actions mentioned in the preceding paragraphs are taken.  At the
 time of the call, the current buffer will be the presentation
 buffer for the folder and a copy of the current message will be
 in the buffer.  The function is expected to make the message
 				extent
 				(or (vm-mm-layout-display-error layout)
 				    "no external viewer defined for type")))
-		   (vm-mime-display-internal-application/octet-stream
-		    (or extent layout))))
+		   (if (vm-mime-types-match type "message/external-body")
+		       (if (null extent)
+			   (vm-mime-display-button-xxxx layout t)
+			 (setq extent nil))
+		     (vm-mime-display-internal-application/octet-stream
+		      (or extent layout)))))
 	  (and extent (vm-mime-delete-button-maybe extent)))
       (set-buffer-modified-p modified)))
   t )
       (condition-case error-data
 	  (let ((buffer-read-only nil)
 		(start (point))
+		(charset (or (vm-mime-get-parameter layout "charset")
+			     "us-ascii"))
 		end buffer-size)
 	    (message "Inlining text/html, be patient...")
-	    (vm-with-unibyte-buffer
-	     ;; We need to keep track of where the end of the
-	     ;; processed text is.  Best way to do this is to
-	     ;; avoid markers and save-excursion, and just use
-	     ;; buffer size changes as an indicator.
-	     (vm-mime-insert-mime-body layout)
-	     (setq end (point))
-	     (setq buffer-size (buffer-size))
-	     (vm-mime-transfer-decode-region layout start end)
-	     (setq end (+ end (- (buffer-size) buffer-size)))
-	     (setq buffer-size (buffer-size))
-	     (w3-region start end)
-	     (setq end (+ end (- (buffer-size) buffer-size)))
-	     ;; remove read-only text properties
-	     (let ((inhibit-read-only t))
-	       (remove-text-properties start end '(read-only nil)))
-	     (goto-char end))
+	    (vm-mime-insert-mime-body layout)
+	    (setq end (point-marker))
+	    (vm-mime-transfer-decode-region layout start end)
+	    (vm-mime-charset-decode-region charset start end)
+	    ;; w3-region apparently deletes all the text in the
+	    ;; region and then insert new text.  This makes the
+	    ;; end == start.  The fix is to move the end marker
+	    ;; forward with a placeholder character so that when
+	    ;; w3-region delete all the text, end will still be
+	    ;; ahead of the insertion point and so will be moved
+	    ;; forward when the new text is inserted.  We'll
+	    ;; delete the placeholder afterward.
+	    (goto-char end)
+	    (insert-before-markers "z")
+	    (w3-region start (1- end))
+	    (goto-char end)
+	    (delete-char -1)
+	    ;; remove read-only text properties
+	    (let ((inhibit-read-only t))
+	      (remove-text-properties start end '(read-only nil)))
+	    (goto-char end)
 	    (message "Inlining text/html... done")
 	    t )
 	(error (vm-set-mm-layout-display-error
     nil ))
 
 (defun vm-mime-display-internal-text/plain (layout &optional no-highlighting)
-  (let ((start (point)) end old-size
+  (let ((start (point)) end
 	(buffer-read-only nil)
 	(m (vm-mm-layout-message layout))
 	(charset (or (vm-mime-get-parameter layout "charset") "us-ascii")))
 	  (vm-set-mm-layout-display-error
 	   layout (concat "Undisplayable charset: " charset))
 	  nil)
-      (vm-with-unibyte-buffer
-       (vm-mime-insert-mime-body layout)
-       (setq end (point-marker))
-       (vm-mime-transfer-decode-region layout start end)
-       (setq old-size (buffer-size))
-       (vm-mime-charset-decode-region charset start end)
-       (set-marker end (+ end (- (buffer-size) old-size))))
+      (vm-mime-insert-mime-body layout)
+      (setq end (point-marker))
+      (vm-mime-transfer-decode-region layout start end)
+      (vm-mime-charset-decode-region charset start end)
       (or no-highlighting (vm-energize-urls-in-message-region start end))
       (if (and vm-fill-paragraphs-containing-long-lines
 	       (not no-highlighting))
   (require 'enriched)
   (let ((start (point)) end
 	(buffer-read-only nil)
-	(enriched-verbose t))
+	(enriched-verbose t)
+	(charset (or (vm-mime-get-parameter layout "charset") "us-ascii")))
     (message "Decoding text/enriched, be patient...")
-    (vm-with-unibyte-buffer
-     (vm-mime-insert-mime-body layout)
-     (setq end (point-marker))
-     (vm-mime-transfer-decode-region layout start end))
+    (vm-mime-insert-mime-body layout)
+    (setq end (point-marker))
+    (vm-mime-transfer-decode-region layout start end)
+    (vm-mime-charset-decode-region charset start end)
     ;; enriched-decode expects a couple of headers at the top of
     ;; the region and will remove anything that looks like a
     ;; header.  Put a header section here for it to eat so it
 			(car (vm-mm-layout-type layout)))))
 	(buffer-read-only nil)
 	start
-	(coding-system-for-read 'binary)
-	(coding-system-for-write 'binary)
+	(coding-system-for-read (vm-binary-coding-system))
+	(coding-system-for-write (vm-binary-coding-system))
 	(append-file t)
 	process	tempfile cache end suffix)
     (setq cache (cdr (assq 'vm-mime-display-external-generic
 		      (not (vm-mime-text-type-layout-p layout)))
 		;; Tell XEmacs/MULE not to mess with the bits unless
 		;; this is a text type.
-		(if (or vm-xemacs-mule-p vm-fsfemacs-mule-p)
+		(if (fboundp 'set-buffer-file-coding-system)
 		    (if (vm-mime-text-type-layout-p layout)
-			(set-buffer-file-coding-system 'no-conversion nil)
-		      (set-buffer-file-coding-system 'binary t)))
+			(set-buffer-file-coding-system
+			 (vm-line-ending-coding-system) nil)
+		      (set-buffer-file-coding-system
+		       (vm-binary-coding-system) t)))
 		;; Write an empty tempfile out to disk and set its
 		;; permissions to 0600, then write the actual buffer
 		;; contents to tempfile.
 		(vm-select-folder-buffer)
 		(setq vm-message-garbage-alist
 		      (cons (cons tempfile 'delete-file)
-			    vm-folder-garbage-alist))))))
+			    vm-message-garbage-alist))))))
 
       ;; expand % specs
       (let ((p program-list)
 		   part-list (nreverse (copy-sequence part-list)))
 	     (while (and part-list (not done))
 	       (setq type (car (vm-mm-layout-type (car part-list))))
-	       (if (or (vm-mime-can-display-internal (car part-list))
+	       (if (or (vm-mime-can-display-internal (car part-list) t)
 		       (vm-mime-find-external-viewer type))
 		   (setq best (car part-list)
 			 done t)
 		   part-list (nreverse (copy-sequence part-list)))
 	     (while (and part-list (not done))
 	       (setq type (car (vm-mm-layout-type (car part-list))))
-	       (cond ((and (vm-mime-can-display-internal (car part-list))
+	       (cond ((and (vm-mime-can-display-internal (car part-list) t)
 			   (vm-mime-should-display-internal (car part-list)
 							    nil))
 		      (setq best (car part-list)
 (defun vm-mime-display-internal-message/delivery-status (layout)
   (vm-mime-display-internal-text/plain layout t))
 
+(defun vm-mime-display-internal-message/external-body (layout)
+  (let ((child-layout (car (vm-mm-layout-parts layout)))
+	(access-method (downcase (vm-mime-get-parameter layout "access-type")))
+	ob
+	(work-buffer nil))
+    ;; Normal objects have the header and body in the same
+    ;; buffer.  A retrieved external-body has the body in a
+    ;; different buffer from the header, so we use this as an
+    ;; indicator of whether the retrieval work has been dnoe
+    ;; yet.
+    (unwind-protect
+	(cond
+	 ((and (eq access-method "mail-server")
+	       (vm-mm-layout-id child-layout)
+	       (setq ob (vm-mime-find-leaf-content-id-in-layout-folder
+			 layout (vm-mm-layout-id child-layout))))
+	  (setq child-layout ob))
+	 ((eq (marker-buffer (vm-mm-layout-header-start child-layout))
+	      (marker-buffer (vm-mm-layout-body-start child-layout)))
+	  (condition-case data
+	      (save-excursion
+		(setq work-buffer
+		      (vm-make-work-buffer
+		       (format "*%s mime object*"
+			       (car (vm-mm-layout-type child-layout)))))
+		(set-buffer work-buffer)
+		(cond
+		 ((string= access-method "local-file")
+		  (let ((name (vm-mime-get-parameter layout "name")))
+		    (if (null name)
+			(vm-mime-error
+			 "%s access type missing `name' parameter"
+			 access-method))
+		    (if (not (file-exists-p name))
+			(vm-mime-error "file %s does not exist" name))
+		    (condition-case data
+			(insert-file-contents name)
+		      (error (signal 'vm-mime-error (cdr data))))))
+		 ((and (string= access-method "url")
+		       vm-url-retrieval-methods)
+		  (defvar w3-configuration-directory) ; for bytecompiler
+		  (let ((url (vm-mime-get-parameter layout "url"))
+			;; needed or url-retrieve will bitch
+			(w3-configuration-directory
+			 (if (boundp 'w3-configuration-directory)
+			     w3-configuration-directory
+			   "~"))
+			(url-work-buffer (buffer-name work-buffer)))
+		    (if (null url)
+			(vm-mime-error
+			 "%s access type missing `url' parameter"
+			 access-method))
+		    (setq url (vm-with-string-as-temp-buffer
+			       url
+			       (function
+				(lambda ()
+				  (goto-char (point-min))
+				  (while (re-search-forward "[ \t\n]" nil t)
+				    (delete-char -1))))))
+		    (cond
+		     ((vm-mime-fetch-url-with-programs url work-buffer) t)
+		     ((and (fboundp 'url-retrieve)
+			   (memq 'url-w3 vm-url-retrieval-methods))
+		      (condition-case data
+			  (progn
+			    (url-retrieve url)
+			    ;; url-retrieve kills the buffer before
+			    ;; starting so work-buffer must be set
+			    ;; to the buffer object again.
+			    (setq work-buffer (get-buffer url-work-buffer))
+			    (if (zerop (buffer-size))
+				(error "file empty or URL retrieval failed")))
+			(error (signal 'vm-mime-error (cdr data)))))
+		     (t nil))))
+		 ((and (or (string= access-method "ftp")
+			   (string= access-method "anon-ftp"))
+		       (or (fboundp 'efs-file-handler-function)
+			   (fboundp 'ange-ftp-hook-function)))
+		  (let ((name (vm-mime-get-parameter layout "name"))
+			(directory (vm-mime-get-parameter layout
+							  "directory"))
+			(site (vm-mime-get-parameter layout "site"))
+			user)
+		    (if (null name)
+			(vm-mime-error
+			 "%s access type missing `name' parameter"
+			 access-method))
+		    (if (null site)
+			(vm-mime-error
+			 "%s access type missing `site' parameter"
+			 access-method))
+		    (cond ((string= access-method "ftp")
+			   (setq user (read-string
+				       (format "User name to access %s: "
+					       site)
+				       (user-login-name))))
+			  (t (setq user "anonymous")))
+		    (if (and (string= access-method "ftp")
+			     vm-url-retrieval-methods
+			     (vm-mime-fetch-url-with-programs
+			      (if directory
+				  (concat "ftp:////" site "/"
+					  directory "/" name)
+				(concat "ftp:////" site "/" name))
+			      work-buffer))
+			t
+		      (cond (directory
+			     (setq directory
+				   (concat "/" user "@" site ":" directory))
+			     (setq name (expand-file-name name directory)))
+			    (t
+			     (setq name (concat "/" user "@" site ":"
+						name))))
+		      (condition-case data
+			  (insert-file-contents name)
+			(error (signal 'vm-mime-error
+				       (format "%s" (cdr data))))))))
+		 ((string= access-method "mail-server")
+		  (let ((server (vm-mime-get-parameter layout "server"))
+			(subject (vm-mime-get-parameter layout "subject")))
+		    (if (null server)
+			(vm-mime-error
+			 "%s access type missing `server' parameter"
+			 access-method))
+		    (if (not
+			 (y-or-n-p
+			  (format
+			   "Send message to %s to retrieve external body? "
+			   server)))
+			(error "Aborted"))
+		    (vm-mail-internal
+		     (format "mail to MIME mail server %s" server)
+		     server subject)
+		    (mail-text)
+		    (vm-mime-insert-mime-body child-layout)
+		    (let ((vm-confirm-mail-send nil))
+		      (vm-mail-send))))
+		 (t
+		  (vm-mime-error "unsupported access method: %s"
+				 access-method)))
+		(cond (child-layout
+		       (setq work-buffer nil)
+		       (vm-set-mm-layout-body-end child-layout
+						  (vm-marker (point-max)))
+		       (vm-set-mm-layout-body-start child-layout
+						    (vm-marker
+						     (point-min))))))
+	    (vm-mime-error
+	     (vm-set-mm-layout-display-error layout (cdr data))
+	     (setq child-layout nil)))))
+      (and work-buffer (kill-buffer work-buffer)))
+    (and child-layout (vm-decode-mime-layout child-layout))))
+
+(defun vm-mime-fetch-url-with-programs (url buffer)
+  (and
+   (eq t (cond ((and (memq 'wget vm-url-retrieval-methods)
+		     (condition-case data
+			 (vm-run-command-on-region (point) (point)
+						   buffer
+						   vm-wget-program
+						   "-q" "-O" "-" url)
+		       (error nil))))
+	       ((and (memq 'lynx vm-url-retrieval-methods)
+		     (condition-case data
+			 (vm-run-command-on-region (point) (point)
+						   buffer
+						   vm-lynx-program
+						   "-source" url)
+		       (error nil))))))
+   (save-excursion
+     (set-buffer buffer)
+     (not (zerop (buffer-size))))))
+
 (defun vm-mime-display-internal-message/partial (layout)
   (if (vectorp layout)
       (let ((buffer-read-only nil))
 				   ':data
 				   (format "[%s image]\n" name))))))
 	   (message "")
+	   ;; XEmacs 21.2 can pixel scroll images if the entire
+	   ;; image is above the baseline.
+	   (set-glyph-baseline g 100)
 	   (vm-set-mm-layout-cache
 	    layout
 	    (nconc (vm-mm-layout-cache layout)
 
 (defun vm-mime-reader-map-save-file ()
   (interactive)
-  (vm-mime-run-display-function-at-point 'vm-mime-send-body-to-file))
+  ;; make sure point doesn't move, we need it to stay on the tag
+  ;; if the user wants to delete after saving.
+  (let (file)
+    (save-excursion
+      (setq file (vm-mime-run-display-function-at-point
+		  'vm-mime-send-body-to-file)))
+    (if vm-mime-delete-after-saving
+	(let ((vm-mime-confirm-delete nil))
+	  ;; we don't care if the delete fails
+	  (condition-case nil
+	      (vm-delete-mime-object (expand-file-name file))
+	    (error nil))))))
+
+(defun vm-mime-reader-map-save-message ()
+  (interactive)
+  ;; make sure point doesn't move, we need it to stay on the tag
+  ;; if the user wants to delete after saving.
+  (let (folder)
+    (save-excursion
+      (setq folder (vm-mime-run-display-function-at-point
+		    'vm-mime-send-body-to-folder)))
+    (if vm-mime-delete-after-saving
+	(let ((vm-mime-confirm-delete nil))
+	  ;; we don't care if the delete fails
+	  (condition-case nil
+	      (vm-delete-mime-object folder)
+	    (error nil))))))
 
 (defun vm-mime-reader-map-pipe-to-command ()
   (interactive)
 	      done t)))
     (save-excursion
       (unwind-protect
-	  (let ((coding-system-for-read 'binary)
-		(coding-system-for-write 'binary))
-	    (let ((default-enable-multibyte-characters nil))
-	      (setq work-buffer (generate-new-buffer " *vm-work*")))
-	    (buffer-disable-undo work-buffer)
+	  (let ((coding-system-for-read (vm-binary-coding-system))
+		(coding-system-for-write (vm-binary-coding-system)))
+	    (setq work-buffer (vm-make-work-buffer))
 	    (set-buffer work-buffer)
 	    (setq selective-display nil)
 	    ;; Tell DOS/Windows NT whether the file is binary
 	    (setq buffer-file-type (not (vm-mime-text-type-layout-p layout)))
 	    ;; Tell XEmacs/MULE not to mess with the bits unless
 	    ;; this is a text type.
-	    (if (or vm-xemacs-mule-p vm-fsfemacs-mule-p)
+	    (if (fboundp 'set-buffer-file-coding-system)
 		(if (vm-mime-text-type-layout-p layout)
-		    (set-buffer-file-coding-system 'no-conversion nil)
-		  (set-buffer-file-coding-system 'binary t)))
+		    (set-buffer-file-coding-system
+		     (vm-line-ending-coding-system) nil)
+		  (set-buffer-file-coding-system (vm-binary-coding-system) t)))
 	    (vm-with-unibyte-buffer
 	     (vm-mime-insert-mime-body layout)
 	     (vm-mime-transfer-decode-region layout (point-min) (point-max)))
 	    ;; the bug reports for somebody else's bad code.
 	    (let ((jka-compr-compression-info-list nil))
 	      (write-region (point-min) (point-max) file nil nil))
-	    (if vm-mime-delete-after-saving
-		(vm-mime-discard-layout-contents layout
-						 (expand-file-name file))))
+	    file )
 	(and work-buffer (kill-buffer work-buffer))))))
 
+(defun vm-mime-send-body-to-folder (layout &optional default-filename)
+  (if (not (vectorp layout))
+      (setq layout (vm-extent-property layout 'vm-mime-layout)))
+  (let ((work-buffer nil)
+	(type (car (vm-mm-layout-type layout)))
+	file)
+    (if (not (or (vm-mime-types-match type "message/rfc822")
+		 (vm-mime-types-match type "message/news")))
+	(vm-mime-send-body-to-file layout default-filename)
+      (save-excursion
+	(unwind-protect
+	    (let ((coding-system-for-read (vm-binary-coding-system))
+		  (coding-system-for-write (vm-binary-coding-system)))
+	      (setq work-buffer (vm-make-work-buffer))
+	      (set-buffer work-buffer)
+	      (setq selective-display nil)
+	      ;; Tell DOS/Windows NT whether the file is binary
+	      (setq buffer-file-type (not (vm-mime-text-type-layout-p layout)))
+	      ;; Tell XEmacs/MULE not to mess with the bits unless
+	      ;; this is a text type.
+	      (if (f