diff lisp/vm/vm-mime.el @ 24:4103f0995bd7 r19-15b95

Import from CVS: tag r19-15b95
author cvs
date Mon, 13 Aug 2007 08:51:03 +0200
parents 859a2309aef8
children 441bb1e64a06
line wrap: on
line diff
--- a/lisp/vm/vm-mime.el	Mon Aug 13 08:50:31 2007 +0200
+++ b/lisp/vm/vm-mime.el	Mon Aug 13 08:51:03 2007 +0200
@@ -27,17 +27,19 @@
   (put 'vm-mime-error 'error-message "MIME error"))
 
 (defun vm-mm-layout-type (e) (aref e 0))
-(defun vm-mm-layout-encoding (e) (aref e 1))
-(defun vm-mm-layout-id (e) (aref e 2))
-(defun vm-mm-layout-description (e) (aref e 3))
-(defun vm-mm-layout-disposition (e) (aref e 4))
-(defun vm-mm-layout-header-start (e) (aref e 5))
-(defun vm-mm-layout-body-start (e) (aref e 6))
-(defun vm-mm-layout-body-end (e) (aref e 7))
-(defun vm-mm-layout-parts (e) (aref e 8))
-(defun vm-mm-layout-cache (e) (aref e 9))
+(defun vm-mm-layout-qtype (e) (aref e 1))
+(defun vm-mm-layout-encoding (e) (aref e 2))
+(defun vm-mm-layout-id (e) (aref e 3))
+(defun vm-mm-layout-description (e) (aref e 4))
+(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-set-mm-layout-cache (e c) (aset e 8 c))
+(defun vm-set-mm-layout-cache (e c) (aset e 11 c))
 
 (defun vm-mm-layout (m)
   (or (vm-mime-layout-of m)
@@ -74,21 +76,10 @@
 (defun vm-mime-Q-encode-region (start end)
   (let ((buffer-read-only nil))
     (subst-char-in-region start end (string-to-char " ") ?_ t)
-    (vm-mime-qp-encode-region start end)))
-
-(fset 'vm-mime-B-encode-region 'vm-mime-base64-encode-region)
-
-(defun vm-mime-Q-decode-string (string)
-  (vm-with-string-as-region string 'vm-mime-Q-decode-region))
+    (vm-mime-qp-encode-region start end t)))
 
-(defun vm-mime-B-decode-string (string)
-  (vm-with-string-as-region string 'vm-mime-B-decode-region))
-
-(defun vm-mime-Q-encode-string (string)
-  (vm-with-string-as-region string 'vm-mime-Q-encode-region))
-
-(defun vm-mime-B-encode-string (string)
-  (vm-with-string-as-region string 'vm-mime-B-encode-region))
+(defun vm-mime-B-encode-region (start end)
+  (vm-mime-base64-encode-region start end nil t))
 
 (defun vm-mime-crlf-to-lf-region (start end)
   (let ((buffer-read-only nil))
@@ -111,13 +102,41 @@
 	  (insert "\r\n"))))))
       
 (defun vm-mime-charset-decode-region (charset start end)
-  (let ((buffer-read-only nil)
-	(cell (vm-mime-charset-internally-displayable-p charset))
-	(opoint (point)))
-    (cond ((and cell (vm-xemacs-mule-p) (eq (device-type) 'x))
-	   (decode-coding-region start end (car cell))))
-    ;; In XEmacs 20.0 beta93 decode-coding-region moves point.
-    (goto-char opoint)))
+  (or (markerp end) (setq end (vm-marker end)))
+  (cond ((vm-xemacs-mule-p)
+	 (if (eq (device-type) 'x)
+	     (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))))
+		     (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))))
+	       ;; In XEmacs 20.0 beta93 decode-coding-region moves point.
+	       (goto-char opoint))))
+	((not (vm-multiple-fonts-possible-p)) nil)
+	((vm-string-member charset vm-mime-default-face-charsets) nil)
+	(t
+	 (let ((font (cdr (vm-string-assoc
+			   charset
+			   vm-mime-charset-font-alist)))
+	       (face (make-face (make-symbol "temp-face")))
+	       (e (vm-make-extent start end)))
+	   (put-text-property start end 'vm-string t)
+	   (put-text-property start end 'vm-charset charset)
+	   (if font
+	       (condition-case data
+		   (progn (set-face-font face font)
+			  (vm-set-extent-property e 'face face))
+		 (error nil)))))))
 
 (defun vm-mime-transfer-decode-region (layout start end)
   (let ((case-fold-search t) (crlf nil))
@@ -202,8 +221,9 @@
       (and work-buffer (kill-buffer work-buffer))))
   (vm-unsaved-message "Decoding base64... done"))
 
-(defun vm-mime-base64-encode-region (start end &optional crlf)
-  (vm-unsaved-message "Encoding base64...")
+(defun vm-mime-base64-encode-region (start end &optional crlf B-encoding)
+  (and (> (- end start) 200)
+       (vm-unsaved-message "Encoding base64..."))
   (let ((work-buffer nil)
 	(counter 0)
 	(cols 0)
@@ -240,8 +260,9 @@
 				     work-buffer)
 		     (setq cols (+ cols 4))
 		     (cond ((= cols 72)
-			    (vm-insert-char ?\n 1 nil work-buffer)
-			    (setq cols 0)))
+			    (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))
@@ -263,12 +284,15 @@
 	  (or (markerp end) (setq end (vm-marker end)))
 	  (goto-char start)
 	  (insert-buffer-substring work-buffer)
-	  (delete-region (point) end))
-      (and work-buffer (kill-buffer work-buffer))))
-  (vm-unsaved-message "Encoding base64... done"))
+	  (delete-region (point) end)
+	  (and (> (- end start) 200)
+	       (vm-unsaved-message "Encoding base64... done"))
+	  (- end start))
+      (and work-buffer (kill-buffer work-buffer)))))
 
 (defun vm-mime-qp-decode-region (start end)
-  (vm-unsaved-message "Decoding quoted-printable...")
+  (and (> (- end start) 200)
+       (vm-unsaved-message "Decoding quoted-printable..."))
   (let ((work-buffer nil)
 	(buf (current-buffer))
 	(case-fold-search nil)
@@ -329,10 +353,12 @@
 	  (insert-buffer-substring work-buffer)
 	  (delete-region (point) end))
       (and work-buffer (kill-buffer work-buffer))))
-  (vm-unsaved-message "Decoding quoted-printable... done"))
+  (and (> (- end start) 200)
+       (vm-unsaved-message "Decoding quoted-printable... done")))
 
-(defun vm-mime-qp-encode-region (start end)
-  (vm-unsaved-message "Encoding quoted-printable...")
+(defun vm-mime-qp-encode-region (start end &optional Q-encoding)
+  (and (> (- end start) 200)
+       (vm-unsaved-message "Encoding quoted-printable..."))
   (let ((work-buffer nil)
 	(buf (current-buffer))
 	(cols 0)
@@ -365,16 +391,20 @@
 		  (t (vm-insert-char char 1 nil work-buffer)
 		     (vm-increment cols)))
 	    (cond ((> cols 70)
-		   (vm-insert-char ?= 1 nil work-buffer)
-		   (vm-insert-char ?\n 1 nil work-buffer)
-		   (setq cols 0)))
+		   (setq cols 0)
+		   (if Q-encoding
+		       nil
+		     (vm-insert-char ?= 1 nil work-buffer)
+		     (vm-insert-char ?\n 1 nil work-buffer))))
 	    (vm-increment inputpos))
 	  (or (markerp end) (setq end (vm-marker end)))
 	  (goto-char start)
 	  (insert-buffer-substring work-buffer)
-	  (delete-region (point) end))
-      (and work-buffer (kill-buffer work-buffer))))
-  (vm-unsaved-message "Encoding quoted-printable... done"))
+	  (delete-region (point) end)
+	  (and (> (- end start) 200)
+	       (vm-unsaved-message "Encoding quoted-printable... done"))
+	  (- end start))
+      (and work-buffer (kill-buffer work-buffer)))))
 
 (defun vm-decode-mime-message-headers (m)
   (let ((case-fold-search t)
@@ -430,13 +460,55 @@
 	  (vm-mime-charset-decode-region charset start end)
 	  (delete-region match-start start))))))
 
-(defun vm-decode-mime-encoded-words-maybe (string)
+(defun vm-decode-mime-encoded-words-in-string (string)
   (if (and vm-display-using-mime
 	   (string-match vm-mime-encoded-word-regexp string))
       (vm-with-string-as-temp-buffer string 'vm-decode-mime-encoded-words)
     string ))
 
-(defun vm-mime-parse-content-header (string &optional sepchar)
+(defun vm-reencode-mime-encoded-words ()
+  (let ((charset nil)
+	start coding pos q-encoding
+	old-size
+	(case-fold-search t)
+	(done nil))
+    (save-excursion
+      (setq start (point-min))
+      (while (not done)
+	(setq charset (get-text-property start 'vm-charset))
+	(setq pos (next-single-property-change start 'vm-charset))
+	(or pos (setq pos (point-max) done t))
+	(if charset
+	    (progn
+	      (message " pos = %d start = %d" pos start)
+	      (if (setq coding (get-text-property start 'vm-coding))
+		  (progn
+		    (setq old-size (buffer-size))
+		    (encode-coding-region start pos coding)
+		    (setq pos (+ pos (- (buffer-size) old-size)))))
+	      (message " pos = %d start = %d" pos start)
+	      (setq pos
+		    (+ start 
+		       (if (setq q-encoding
+				 (string-match "^iso-8859-\\|^us-ascii"
+					       charset))
+			   (vm-mime-Q-encode-region start pos)
+			 (vm-mime-B-encode-region start pos))))
+	      (message " pos = %d start = %d" pos start)
+	      (goto-char pos)
+	      (insert "?=")
+	      (setq pos (point))
+	      (goto-char start)
+	      (insert "=?" charset "?" (if q-encoding "Q" "B") "?")))
+	(setq start pos)))))
+
+(defun vm-reencode-mime-encoded-words-in-string (string)
+  (if (and vm-display-using-mime
+	   (text-property-any 0 (length string) 'vm-string t string))
+      (vm-with-string-as-temp-buffer string 'vm-reencode-mime-encoded-words)
+    string ))
+
+(defun vm-mime-parse-content-header (string &optional sepchar keep-quotes)
   (if (null string)
       ()
     (let ((work-buffer nil))
@@ -474,23 +546,40 @@
 		     ((looking-at " \t\n\r\f")
 		      (skip-chars-forward " \t\n\r\f"))
 		     ((= char ?\")
-		      (delete-char 1)
-		      (cond ((= (char-after (point)) ?\")
-			     (delete-char 1))
-			    ((re-search-forward "[^\\]\"" nil 0)
-			     (delete-char -1))))
+		      (let ((done nil))
+			(if keep-quotes
+			    (forward-char 1)
+			  (delete-char 1))
+			(while (not done)
+			  (if (null (re-search-forward "[\\\"]" nil t))
+			      (setq done t)
+			    (setq char (char-after (1- (point))))
+			    (cond ((char-equal char ?\\)
+				   (delete-char -1)
+				   (if (eobp)
+				       (setq done t)
+				     (forward-char 1)))
+				  (t (if (not keep-quotes)
+					 (delete-char -1))
+				     (setq done t)))))))
 		     ((= char ?\()
-		      (let ((parens 1)
-			    (pos (point)))
+		      (let ((done nil)
+			    (pos (point))
+			    (parens 1))
 			(forward-char 1)
-			(while (and (not (eobp)) (not (zerop parens)))
-			  (re-search-forward "[()]" nil 0)
-			  (cond ((or (eobp)
-				     (= (char-after (- (point) 2)) ?\\)))
-				((= (preceding-char) ?\()
-				 (setq parens (1+ parens)))
-				(t
-				 (setq parens (1- parens)))))
+			(while (not done)
+			  (if (null (re-search-forward "[\\()]" nil t))
+			      (setq done t)
+			    (setq char (char-after (1- (point))))
+			    (cond ((char-equal char ?\\)
+				   (if (eobp)
+				       (setq done t)
+				     (forward-char 1)))
+				  ((char-equal char ?\()
+				   (setq parens (1+ parens)))
+				  (t
+				   (setq parens (1- parens)
+					 done (zerop parens))))))
 			(delete-region pos (point))))))
 	     (setq s (buffer-substring start (point)))
 	     (if (and (null (string-match "^[\t\f\n\r ]+$" s))
@@ -513,8 +602,8 @@
 	  nil )))))
 
 (defun vm-mime-parse-entity (&optional m default-type default-encoding)
-  (let ((case-fold-search t) version type encoding id description
-	disposition boundary boundary-regexp start
+  (let ((case-fold-search t) version type qtype encoding id description
+	disposition qdisposition boundary boundary-regexp start
 	multipart-list c-t c-t-e done p returnval)
     (and m (vm-unsaved-message "Parsing MIME message..."))
     (prog1
@@ -531,6 +620,7 @@
 		  (setq version (vm-get-header-contents m "MIME-Version:")
 			version (car (vm-mime-parse-content-header version))
 			type (vm-get-header-contents m "Content-Type:")
+			qtype (vm-mime-parse-content-header type ?\; t)
 			type (vm-mime-parse-content-header type ?\;)
 			encoding (or (vm-get-header-contents
 				      m "Content-Transfer-Encoding:")
@@ -547,6 +637,9 @@
 					   description))
 			disposition (vm-get-header-contents
 				     m "Content-Disposition:")
+			qdisposition (and disposition
+					  (vm-mime-parse-content-header
+					   disposition ?\; t))
 			disposition (and disposition
 					 (vm-mime-parse-content-header
 					  disposition ?\;)))
@@ -554,6 +647,8 @@
 		  (narrow-to-region (vm-headers-of m) (vm-text-end-of m)))
 	      (goto-char (point-min))
 	      (setq type (vm-mime-get-header-contents "Content-Type:")
+		    qtype (or (vm-mime-parse-content-header type ?\; t)
+			      default-type)
 		    type (or (vm-mime-parse-content-header type ?\;)
 			     default-type)
 		    encoding (or (vm-mime-get-header-contents
@@ -570,6 +665,9 @@
 						   description))
 		    disposition (vm-mime-get-header-contents
 				 "Content-Disposition:")
+		    qdisposition (and disposition
+				      (vm-mime-parse-content-header
+				       disposition ?\; t))
 		    disposition (and disposition
 				     (vm-mime-parse-content-header
 				      disposition ?\;))))
@@ -581,7 +679,9 @@
 	    (cond ((and m (null type))
 		   (throw 'return-value
 			  (vector '("text/plain" "charset=us-ascii")
-				  encoding id description disposition
+				  '("text/plain" "charset=us-ascii")
+				  encoding id description
+				  disposition qdisposition
 				  (vm-headers-of m)
 				  (vm-text-of m)
 				  (vm-text-end-of m)
@@ -590,7 +690,9 @@
 		   (goto-char (point-min))
 		   (or (re-search-forward "^\n\\|\n\\'" nil t)
 		       (vm-mime-error "MIME part missing header/body separator line"))
-		   (vector default-type encoding id description disposition
+		   (vector default-type default-type
+			   encoding id description
+			   disposition qdisposition
 			   (vm-marker (point-min))
 			   (vm-marker (point))
 			   (vm-marker (point-max))
@@ -617,21 +719,24 @@
 		   (or (re-search-forward "^\n\\|\n\\'" nil t)
 		       (vm-mime-error "MIME part missing header/body separator line"))
 		   (throw 'return-value
-			  (vector type encoding id description disposition
+			  (vector type qtype encoding id description
+				  disposition qdisposition
 				  (vm-marker (point-min))
 				  (vm-marker (point))
 				  (vm-marker (point-max))
 				  (list
 				   (save-restriction
 				     (narrow-to-region (point) (point-max))
-				     (vm-mime-parse-entity nil c-t c-t-e)))
+				     (vm-mime-parse-entity-safe nil c-t
+								c-t-e)))
 				  nil )))
 		  (t
 		   (goto-char (point-min))
 		   (or (re-search-forward "^\n\\|\n\\'" nil t)
 		       (vm-mime-error "MIME part missing header/body separator line"))
 		   (throw 'return-value
-			  (vector type encoding id description disposition
+			  (vector type qtype encoding id description
+				  disposition qdisposition
 				  (vm-marker (point-min))
 				  (vm-marker (point))
 				  (vm-marker (point-max))
@@ -647,8 +752,13 @@
 		(vm-mime-error
 		 "Boundary parameter missing in %s type specification"
 		 (car type)))
-	    (setq boundary-regexp (regexp-quote boundary)
-		  boundary-regexp (concat "^--" boundary-regexp "\\(--\\)?\n"))
+	    ;; the \' in the regexp is to "be liberal" in the
+	    ;; face of broken software that does not add a line
+	    ;; break after the final boundary of a nested
+	    ;; multipart entity.
+	    (setq boundary-regexp
+		  (concat "^--" (regexp-quote boundary)
+			  "\\(--\\)?[ \t]*\\(\n\\|\\'\\)"))
 	    (goto-char (point-min))
 	    (setq start nil
 		  multipart-list nil
@@ -671,7 +781,8 @@
 	    (goto-char (point-min))
 	    (or (re-search-forward "^\n\\|\n\\'" nil t)
 		(vm-mime-error "MIME part missing header/body separator line"))
-	    (vector type encoding id description disposition
+	    (vector type qtype encoding id description
+		    disposition qdisposition
 		    (vm-marker (point-min))
 		    (vm-marker (point))
 		    (vm-marker (point-max))
@@ -699,14 +810,14 @@
 	   (text-end (if m
 			 (vm-text-end-of m)
 		       (vm-marker (point-max)))))
-     (vector c-t
+     (vector c-t c-t
 	     (vm-determine-proper-content-transfer-encoding text text-end)
 	     nil
 	     ;; cram the error message into the description slot
-	     (car error-data)
+	     (car (cdr error-data))
 	     ;; mark as an attachment to improve the chance that the user
 	     ;; will see the description.
-	     '("attachment")
+	     '("attachment") '("attachment")
 	     header
 	     text
 	     text-end)))))
@@ -766,8 +877,13 @@
 		   mode-popup-menu (and vm-use-menus vm-popup-menu-on-mouse-3
 					(vm-menu-support-possible-p)
 					(vm-menu-mode-menu))
+		   ;; Default to binary file type for DOS/NT.
+		   buffer-file-type t
+		   ;; Tell XEmacs/MULE not to mess with the text on writes.
 		   buffer-read-only t
 		   mode-line-format vm-mode-line-format)
+	     (and (fboundp 'set-file-coding-system)
+		  (set-file-coding-system 'binary t))
 	     (cond ((vm-fsfemacs-19-p)
 		    ;; need to do this outside the let because
 		    ;; loading disp-table initializes
@@ -785,14 +901,6 @@
 	     (and (vm-menu-support-possible-p)
 		  (vm-menu-install-menus)))
 	   (setq vm-presentation-buffer-handle b)))
-    ;; do this (widen) outside save-restricton intentionally.  since
-    ;; we're using the presentation buffer, make the folder
-    ;; buffer unpretty so maybe the user gets the idea.
-    ;;(widen)
-    ;; widening isn't enough.  users just complain that "I'm
-    ;; looking at the wrong message."  Curse their miserable hides.
-    ;; bury the buffer so they'll have a tough time finding it.
-    (bury-buffer (current-buffer))
     (setq b vm-presentation-buffer-handle
 	  vm-presentation-buffer vm-presentation-buffer-handle
 	  vm-mime-decoded nil)
@@ -839,15 +947,33 @@
 (fset 'vm-presentation-mode 'vm-mode)
 (put 'vm-presentation-mode 'mode-class 'special)
 
+(defvar file-coding-system)
+
 (defun vm-determine-proper-charset (beg end)
   (save-excursion
     (save-restriction
       (narrow-to-region beg end)
       (catch 'done
 	(goto-char (point-min))
-	(and (re-search-forward "[^\000-\177]" nil t)
-	     (throw 'done (or vm-mime-8bit-composition-charset "iso-8859-1")))
-	(throw 'done "us-ascii")))))
+	(if (vm-xemacs-mule-p)
+	    (let ((charsets (delq 'ascii (charsets-in-region beg end))))
+	      (cond ((null charsets)
+		     "us-ascii")
+		    ((cdr charsets)
+		     (or (car (cdr
+			       (assoc (coding-system-name file-coding-system)
+				      vm-mime-mule-coding-to-charset-alist)))
+			 "iso-2022-jp"))
+		    (t
+		     (or (car (cdr
+			       (vm-string-assoc
+				(car charsets)
+				vm-mime-mule-charset-to-charset-alist)))
+			 "unknown"))))
+	  (and (re-search-forward "[^\000-\177]" nil t)
+	       (throw 'done (or vm-mime-8bit-composition-charset
+				"iso-8859-1")))
+	  (throw 'done "us-ascii"))))))
 
 (defun vm-determine-proper-content-transfer-encoding (beg end)
   (save-excursion
@@ -923,11 +1049,15 @@
 	   (let ((charset (or (vm-mime-get-parameter layout "charset")
 			      "us-ascii")))
 	     (vm-mime-charset-internally-displayable-p charset)))
-	  ((vm-mime-types-match "text/html" type)
-	   (condition-case ()
-	       (progn (require 'w3)
-		      (fboundp 'w3-region))
-	     (error nil)))
+;; commented out until I decide whether W3 is safe to use in
+;; light of the porposed javascript extension and the possibility
+;; of executing arbitrary Emacs-Lisp code embedded in a page.
+;;
+;;	  ((vm-mime-types-match "text/html" type)
+;;	   (condition-case ()
+;;	       (progn (require 'w3)
+;;		      (fboundp 'w3-region))
+;;	     (error nil)))
 	  (t nil))))
 
 (defun vm-mime-can-convert (type)
@@ -969,10 +1099,12 @@
 			(car (vm-mm-layout-type layout))
 			(nth 1 ooo))
       (vector (list (nth 1 ooo))
+	      (list (nth 1 ooo))
 	      "binary"
 	      (vm-mm-layout-id layout)
 	      (vm-mm-layout-description layout)
 	      (vm-mm-layout-disposition layout)
+	      (vm-mm-layout-qdisposition layout)
 	      (vm-marker (point-min))
 	      (vm-marker (point))
 	      (vm-marker (point-max))
@@ -1097,6 +1229,9 @@
 	    ;; maybe user killed it
 	    (error "No presentation buffer."))
 	(set-buffer vm-presentation-buffer)
+	(if (and (interactive-p) (eq vm-system-state 'previewing))
+	    (let ((vm-display-using-mime nil))
+	      (vm-show-current-message)))
 	(setq m (car vm-message-pointer))
 	(vm-save-restriction
 	 (widen)
@@ -1180,29 +1315,33 @@
 (defun vm-mime-display-button-text (layout)
   (vm-mime-display-button-xxxx layout t))
 
-(defun vm-mime-display-internal-text/html (layout)
-  (let ((buffer-read-only nil)
-	(work-buffer nil))
-    (vm-unsaved-message "Inlining text/html, be patient...")
-    ;; w3-region is not as tame as we would like.
-    ;; make sure the yoke is firmly attached.
-    (unwind-protect
-	(progn
-	  (save-excursion
-	    (set-buffer (setq work-buffer
-			      (generate-new-buffer " *workbuf*")))
-	    (vm-mime-insert-mime-body layout)
-	    (vm-mime-transfer-decode-region layout (point-min) (point-max))
-	    (save-excursion
-	      (save-window-excursion
-		(w3-region (point-min) (point-max)))))
-	  (insert-buffer-substring work-buffer))
-      (and work-buffer (kill-buffer work-buffer)))
-    (vm-unsaved-message "Inlining text/html... done")
-    t ))
+;; commented out until I decide whether W3 is safe to use in
+;; light of the proposed javascript extension and the possibility
+;; of executing arbitrary Emacs-Lisp code embedded in a page.
+;;
+;;(defun vm-mime-display-internal-text/html (layout)
+;;  (let ((buffer-read-only nil)
+;;	(work-buffer nil))
+;;    (vm-unsaved-message "Inlining text/html, be patient...")
+;;    ;; w3-region is not as tame as we would like.
+;;    ;; make sure the yoke is firmly attached.
+;;    (unwind-protect
+;;	(progn
+;;	  (save-excursion
+;;	    (set-buffer (setq work-buffer
+;;			      (generate-new-buffer " *workbuf*")))
+;;	    (vm-mime-insert-mime-body layout)
+;;	    (vm-mime-transfer-decode-region layout (point-min) (point-max))
+;;	    (save-excursion
+;;	      (save-window-excursion
+;;		(w3-region (point-min) (point-max)))))
+;;	  (insert-buffer-substring work-buffer))
+;;      (and work-buffer (kill-buffer work-buffer)))
+;;    (vm-unsaved-message "Inlining text/html... done")
+;;    t ))
 
 (defun vm-mime-display-internal-text/plain (layout &optional ignore-urls)
-  (let ((start (point)) end
+  (let ((start (point)) end old-size
 	(buffer-read-only nil)
 	(charset (or (vm-mime-get-parameter layout "charset") "us-ascii")))
     (if (not (vm-mime-charset-internally-displayable-p charset))
@@ -1210,8 +1349,11 @@
       (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)))
       (or ignore-urls (vm-energize-urls-in-message-region start end))
+      (goto-char end)
       t )))
 
 (defun vm-mime-display-internal-text/enriched (layout)
@@ -1250,9 +1392,17 @@
 	     (setq end (point-marker))
 	     (vm-mime-transfer-decode-region layout start end)
 	     (setq tempfile (vm-make-tempfile-name))
-	     ;; Tell DOS/Windows NT whether the file is binary
-	     (setq buffer-file-type (not (vm-mime-text-type-p layout)))
-	     (write-region start end tempfile nil 0)
+	     (let ((buffer-file-type buffer-file-type)
+		   file-coding-system)
+	       ;; Tell DOS/Windows NT whether the file is binary
+	       (setq buffer-file-type (not (vm-mime-text-type-p layout)))
+	       ;; Tell XEmacs/MULE not to mess with the bits unless
+	       ;; this is a text type.
+	       (if (fboundp 'set-file-coding-system)
+		   (if (vm-mime-text-type-p layout)
+		       (set-file-coding-system 'no-conversion nil)
+		     (set-file-coding-system 'binary t)))
+	       (write-region start end tempfile nil 0))
 	     (delete-region start end)
 	     (save-excursion
 	       (vm-select-folder-buffer)
@@ -1283,7 +1433,7 @@
       (let ((buffer-read-only nil)
 	    (description (vm-mm-layout-description layout)))
 	(vm-mime-insert-button
-	 (format "%-35s [%s to save to a file]"
+	 (format "%-35.35s [%s to save to a file]"
 		 (vm-mime-layout-description layout)
 		 (if (vm-mouse-support-possible-p)
 		     "Click mouse-2"
@@ -1367,7 +1517,7 @@
 
 (defun vm-mime-display-button-multipart/parallel (layout)
   (vm-mime-insert-button
-   (format "%-35s [%s to display in parallel]"
+   (format "%-35.35s [%s to display in parallel]"
 	   (vm-mime-layout-description layout)
 	   (if (vm-mouse-support-possible-p)
 	       "Click mouse-2"
@@ -1386,7 +1536,7 @@
   (if (vectorp layout)
       (let ((buffer-read-only nil))
 	(vm-mime-insert-button
-	 (format "%-35s [%s to display]"
+	 (format "%-35.35s [%s to display]"
 		 (vm-mime-layout-description layout)
 		 (if (vm-mouse-support-possible-p)
 		     "Click mouse-2"
@@ -1418,7 +1568,7 @@
   (if (vectorp layout)
       (let ((buffer-read-only nil))
 	(vm-mime-insert-button
-	 (format "%-35s [%s to display]"
+	 (format "%-35.35s [%s to display]"
 		 (vm-mime-layout-description layout)
 		 (if (vm-mouse-support-possible-p)
 		     "Click mouse-2"
@@ -1455,7 +1605,7 @@
 	    (number (vm-mime-get-parameter layout "number"))
 	    (total (vm-mime-get-parameter layout "total")))
 	(vm-mime-insert-button
-	 (format "%-35s [%s to attempt assembly]"
+	 (format "%-35.35s [%s to attempt assembly]"
 		 (concat (vm-mime-layout-description layout)
 			 (and number (concat ", part " number))
 			 (and number total (concat " of " total)))
@@ -1595,6 +1745,7 @@
 	  (setq end (point-marker))
 	  (vm-mime-transfer-decode-region layout start end)
 	  (setq tempfile (vm-make-tempfile-name))
+	  ;; coding system for presentation buffer is binary
 	  (write-region start end tempfile nil 0)
 	  (vm-unsaved-message "Creating %s glyph..." name)
 	  (setq g (make-glyph
@@ -1646,6 +1797,7 @@
 	  (setq end (point-marker))
 	  (vm-mime-transfer-decode-region layout start end)
 	  (setq tempfile (vm-make-tempfile-name))
+	  ;; coding system for presentation buffer is binary
 	  (write-region start end tempfile nil 0)
 	  (vm-set-mm-layout-cache layout tempfile)
 	  (save-excursion
@@ -1663,7 +1815,7 @@
 (defun vm-mime-display-button-xxxx (layout disposable)
   (let ((description (vm-mime-layout-description layout)))
     (vm-mime-insert-button
-     (format "%-35s [%s to display]"
+     (format "%-35.35s [%s to display]"
 	     description
 	     (if (vm-mouse-support-possible-p) "Click mouse-2" "Press RETURN"))
      (function
@@ -1698,6 +1850,44 @@
 ;; for the karking compiler
 (defvar vm-menu-mime-dispose-menu)
 
+(defun vm-mime-set-extent-glyph-for-layout (e layout)
+  (if (and (vm-xemacs-p) (fboundp 'make-glyph)
+	   (eq (device-type) 'x) (> (device-bitplanes) 15))
+      (let ((type (car (vm-mm-layout-type layout)))
+	    (dir vm-image-directory)
+	    glyph)
+	(setq glyph
+	      (cond ((vm-mime-types-match "text" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "document.xpm" dir))))
+		    ((vm-mime-types-match "image" type)
+		     (make-glyph (vector
+				  'gif ':file
+				  (expand-file-name "mona_stamp.gif" dir))))
+		    ((vm-mime-types-match "audio" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "audio_stamp.xpm" dir))))
+		    ((vm-mime-types-match "video" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "film.xpm" dir))))
+		    ((vm-mime-types-match "message" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "message.xpm" dir))))
+		    ((vm-mime-types-match "application" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "gear.xpm" dir))))
+		    ((vm-mime-types-match "multipart" type)
+		     (make-glyph (vector
+				  'xpm ':file
+				  (expand-file-name "stuffed_box.xpm" dir))))
+		    (t nil)))
+	(and glyph (set-extent-begin-glyph e glyph)))))
+
 (defun vm-mime-insert-button (caption action layout disposable)
   (let ((start (point))	e
 	(keymap (make-sparse-keymap))
@@ -1720,6 +1910,7 @@
       (setq e (make-extent start (point)))
       (set-extent-property e 'start-open t)
       (set-extent-property e 'end-open t))
+    (vm-mime-set-extent-glyph-for-layout e layout)
     ;; for emacs
     (vm-set-extent-property e 'mouse-face 'highlight)
     (vm-set-extent-property e 'local-map keymap)
@@ -1742,17 +1933,30 @@
   (and default-filename
        (setq default-filename (file-name-nondirectory default-filename)))
   (let ((work-buffer nil)
-	;; evade the XEmacs dialox box, yeccch.
-	(should-use-dialog-box nil)
+	;; evade the XEmacs dialog box, yeccch.
+	(use-dialog-box nil)
+	(dir vm-mime-attachment-save-directory)
+	(done nil)
 	file)
-    (setq file
-	  (read-file-name
-	   (if default-filename
-	       (format "Write MIME body to file (default %s): "
-		       default-filename)
-	     "Write MIME body to file: ")
-	   vm-mime-attachment-save-directory default-filename)
-	  file (expand-file-name file vm-mime-attachment-save-directory))
+    (while (not done)
+      (setq file
+	    (read-file-name
+	     (if default-filename
+		 (format "Write MIME body to file (default %s): "
+			 default-filename)
+	       "Write MIME body to file: ")
+	     dir default-filename)
+	  file (expand-file-name file dir))
+      (if (not (file-directory-p file))
+	  (setq done t)
+	(if default-filename
+	    (message "%s is a directory" file)
+	  (error "%s is a directory" file))
+	(sit-for 2)
+	(setq dir file
+	      default-filename (if (string-match "/$" file)
+				   (concat file default-filename)
+				 (concat file "/" default-filename)))))
     (save-excursion
       (unwind-protect
 	  (progn
@@ -1761,6 +1965,12 @@
 	    (set-buffer work-buffer)
 	    ;; Tell DOS/Windows NT whether the file is binary
 	    (setq buffer-file-type (not (vm-mime-text-type-p layout)))
+	    ;; Tell XEmacs/MULE not to mess with the bits unless
+	    ;; this is a text type.
+	    (if (fboundp 'set-file-coding-system)
+		(if (vm-mime-text-type-p layout)
+		    (set-file-coding-system 'no-conversion nil)
+		  (set-file-coding-system 'binary t)))
 	    (vm-mime-insert-mime-body layout)
 	    (vm-mime-transfer-decode-region layout (point-min) (point-max))
 	    (or (not (file-exists-p file))
@@ -1878,9 +2088,9 @@
 	   (or (not (vectorp o))
 	       (and (vm-mime-types-match "text/plain"
 					 (car (vm-mm-layout-type o)))
-		    (string-match "^\\(us-ascii\\|iso-8859-1\\)$"
-				  (or (vm-mime-get-parameter o "charset")
-				      "us-ascii"))
+		    (let* ((charset (or (vm-mime-get-parameter o "charset")
+				      "us-ascii")))
+		      (vm-string-member charset vm-mime-default-face-charsets))
 		    (string-match "^\\(7bit\\|8bit\\|binary\\)$"
 				  (vm-mm-layout-encoding o))))))))
 
@@ -1890,11 +2100,12 @@
 
 (defun vm-mime-charset-internally-displayable-p (name)
   (cond ((and (vm-xemacs-mule-p) (eq (device-type) 'x))
-	 (cdr (assoc (downcase name) vm-mime-xemacs-mule-charset-alist)))
-	((vm-xemacs-p)
-	 (vm-member (downcase name) '("us-ascii" "iso-8859-1")))
-	((vm-fsfemacs-19-p)
-	 (vm-member (downcase name) '("us-ascii" "iso-8859-1")))))
+	 (vm-string-assoc name vm-mime-mule-charset-to-coding-alist))
+	((vm-multiple-fonts-possible-p)
+	 (or (vm-string-member name vm-mime-default-face-charsets)
+	     (vm-string-assoc name vm-mime-charset-font-alist)))
+	(t
+	 (vm-string-member name vm-mime-default-face-charsets))))
 
 (defun vm-mime-find-message/partials (layout id)
   (let ((list nil)
@@ -1933,7 +2144,7 @@
       (vm-increment i))
     boundary ))
 
-(defun vm-mime-attach-file (file type &optional charset)
+(defun vm-mime-attach-file (file type &optional charset description)
   "Attach a file to a VM composition buffer to be sent along with the message.
 The file is not inserted into the buffer and MIME encoded until
 you execute vm-mail-send or vm-mail-send-and-exit.  A visible tag
@@ -1945,8 +2156,9 @@
 First argument, FILE, is the name of the file to attach.  Second
 argument, TYPE, is the MIME Content-Type of the file.  Optional
 third argument CHARSET is the character set of the attached
-document.  This argument is only used for text types, and it
-is ignored for other types.
+document.  This argument is only used for text types, and it is
+ignored for other types.  Optional fourth argument DESCRIPTION
+should be a one line description of the file.
 
 When called interactively all arguments are read from the
 minibuffer.
@@ -1961,7 +2173,7 @@
    (let ((last-command last-command)
 	 (this-command this-command)
 	 (charset nil)
-	 file default-type type)
+	 description file default-type type)
      (if (null vm-send-using-mime)
 	 (error "MIME attachments disabled, set vm-send-using-mime non-nil to enable."))
      (setq file (vm-read-file-name "Attach file: " nil nil t)
@@ -1976,7 +2188,10 @@
 	 (setq charset (completing-read "Character set (default US-ASCII): "
 					vm-mime-charset-completion-alist)
 	       charset (if (> (length charset) 0) charset)))
-     (list file type charset)))
+     (setq description (read-string "One line description: "))
+     (if (string-match "^[ \t]*$" description)
+	 (setq description nil))
+     (list file type charset description)))
   (if (null vm-send-using-mime)
       (error "MIME attachments disabled, set vm-send-using-mime non-nil to enable."))
   (if (file-directory-p file)
@@ -1986,7 +2201,8 @@
   (if (not (file-readable-p file))
       (error "You don't have permission to read %s" file))
   (and charset (setq charset (list (concat "charset=" charset))))
-  (vm-mime-attach-object file type charset nil))
+  (and description (setq description (vm-mime-scrub-description description)))
+  (vm-mime-attach-object file type charset description nil))
 
 (defun vm-mime-attach-mime-file (file)
   "Attach a MIME encoded file to a VM composition buffer to be sent
@@ -2024,29 +2240,92 @@
       (error "No such file: %s" file))
   (if (not (file-readable-p file))
       (error "You don't have permission to read %s" file))
-  (vm-mime-attach-object file "MIME file" nil t))
+  (vm-mime-attach-object file nil nil nil t))
 
-(defun vm-mime-attach-object (object type params mimed)
+(defun vm-mime-attach-object (object type params description mimed)
   (if (not (eq major-mode 'mail-mode))
       (error "Command must be used in a VM Mail mode buffer."))
-  (let ((start (point))
-	e tag-string)
-    (setq tag-string (format "[ATTACHMENT %s, %s]" object type))
+  (let (start end e tag-string disposition)
+    (if (< (point) (save-excursion (mail-text) (point)))
+	(mail-text))
+    (setq start (point)
+	  tag-string (format "[ATTACHMENT %s, %s]" object
+			     (or type "MIME file")))
     (insert tag-string "\n")
-    (cond ((fboundp 'make-overlay)
-	   (setq e (make-overlay start (point) nil t nil))
-	   (overlay-put e 'face vm-mime-button-face))
+    (setq end (1- (point)))
+    ;; attach default filename for recipient if currently
+    ;; non-MIME.  if already MIME'd don't do this because it
+    ;; would override any content-disposition header already in
+    ;; the attachment.
+    (if (and (stringp object) (not mimed))
+	(progn
+	  (if (or (vm-mime-types-match "application" type)
+		  (vm-mime-types-match "model" type))
+	      (setq disposition (list "attachment"))
+	    (setq disposition (list "inline")))
+	  (setq disposition (nconc disposition
+				   (list
+				    (concat "filename=\""
+					    (file-name-nondirectory object)
+					    "\""))))))
+    (cond ((vm-fsfemacs-19-p)
+	   (put-text-property start end 'front-sticky nil)
+	   (put-text-property start end 'rear-nonsticky t)
+	   (put-text-property start end 'intangible object)
+	   (put-text-property start end 'face vm-mime-button-face)
+	   (put-text-property start end 'vm-mime-type type)
+	   (put-text-property start end 'vm-mime-object object)
+	   (put-text-property start end 'vm-mime-parameters params)
+	   (put-text-property start end 'vm-mime-description description)
+	   (put-text-property start end 'vm-mime-disposition disposition)
+	   (put-text-property start end 'vm-mime-encoded mimed)
+	   (put-text-property start end 'vm-mime-object object))
 	  ((fboundp 'make-extent)
-	   (setq e (make-extent start (1- (point))))
+	   (setq e (make-extent start end))
 	   (set-extent-property e 'start-open t)
-	   (set-extent-property e 'face vm-mime-button-face)))
-    (vm-set-extent-property e 'duplicable t)
-;; crashes XEmacs
-;;    (vm-set-extent-property e 'replicating t)
-    (vm-set-extent-property e 'vm-mime-type type)
-    (vm-set-extent-property e 'vm-mime-object object)
-    (vm-set-extent-property e 'vm-mime-params params)
-    (vm-set-extent-property e 'vm-mime-encoded mimed)))
+	   (set-extent-property e 'face vm-mime-button-face)
+	   (vm-set-extent-property e 'duplicable t)
+	   (vm-set-extent-property e 'vm-mime-type type)
+	   (vm-set-extent-property e 'vm-mime-object object)
+	   (vm-set-extent-property e 'vm-mime-parameters params)
+	   (vm-set-extent-property e 'vm-mime-description description)
+	   (vm-set-extent-property e 'vm-mime-disposition disposition)
+	   (vm-set-extent-property e 'vm-mime-encoded mimed)))))
+
+(defun vm-disallow-overlay-endpoint-insertion (overlay after start end
+					       &optional old-size)
+  (cond ((null after) nil)
+	((= start (overlay-start overlay))
+	 (move-overlay overlay end (overlay-end overlay)))
+	((= start (overlay-end overlay))
+	 (move-overlay overlay (overlay-start overlay) start))))
+
+(defun vm-mime-fake-attachment-overlays (start end)
+  (let ((o-list nil)
+	(done nil)
+	(pos start)
+	object pos props o)
+    (save-excursion
+      (save-restriction
+	(narrow-to-region start end)
+	(while (not done)
+	  (setq object (get-text-property pos 'vm-mime-object))
+	  (setq pos (next-single-property-change pos 'vm-mime-object))
+	  (or pos (setq pos (point-max) done t))
+	  (if object
+	      (progn
+		(setq o (make-overlay start pos))
+		(overlay-put o 'insert-in-front-hooks
+			     '(vm-disallow-overlay-endpoint-insertion))
+		(overlay-put o 'insert-behind-hooks
+			     '(vm-disallow-overlay-endpoint-insertion))
+		(setq props (text-properties-at start))
+		(while props
+		  (overlay-put o (car props) (car (cdr props)))
+		  (setq props (cdr (cdr props))))
+		(setq o-list (cons o o-list))))
+	  (setq start pos))
+	o-list ))))
 
 (defun vm-mime-default-type-from-filename (file)
   (let ((alist vm-mime-attachment-auto-type-alist)
@@ -2101,6 +2380,7 @@
 				    (vm-mm-layout-body-start layout)
 				    (vm-mm-layout-body-end layout)
 				    nil)))
+
 (defun vm-mime-encode-composition ()
  "MIME encode the current buffer.
 Attachment tags added to the buffer with vm-mime-attach-file are expanded
@@ -2116,11 +2396,12 @@
 	  (just-one nil)
 	  (boundary-positions nil)
 	  already-mimed layout e e-list boundary
-	  type encoding charset params object opoint-min)
+	  type encoding charset params description disposition object
+	  opoint-min)
       (mail-text)
       (setq e-list (if (fboundp 'extent-list)
 		       (extent-list nil (point) (point-max))
-		     (overlays-in (point) (point-max)))
+		     (vm-mime-fake-attachment-overlays (point) (point-max)))
 	    e-list (vm-delete (function
 			       (lambda (e)
 				 (vm-extent-property e 'vm-mime-object)))
@@ -2145,6 +2426,9 @@
 	    (narrow-to-region (point) (point-max))
 	    (setq charset (vm-determine-proper-charset (point-min)
 						       (point-max)))
+	    (if (fboundp 'encode-coding-region)
+		(encode-coding-region (point-min) (point-max)
+				      file-coding-system))
 	    (setq encoding (vm-determine-proper-content-transfer-encoding
 			    (point-min)
 			    (point-max))
@@ -2179,21 +2463,31 @@
 	    (insert "Content-Type: text/plain; charset=" charset "\n")
 	    (insert "Content-Transfer-Encoding: " encoding "\n\n")
 	    (widen))
-	  (goto-char (vm-extent-end-position e))
+	  (goto-char (vm-extent-start-position e))
 	  (narrow-to-region (point) (point))
 	  (setq object (vm-extent-property e 'vm-mime-object))
+	  ;; insert the object
 	  (cond ((bufferp object)
 		 (insert-buffer-substring object))
 		((stringp object)
-		 (insert-file-contents-literally object)))
+		 (let ((overridding-file-coding-system 'no-conversion))
+		   (insert-file-contents-literally object))))
+	  ;; gather information about the object from the extent.
 	  (if (setq already-mimed (vm-extent-property e 'vm-mime-encoded))
 	      (setq layout (vm-mime-parse-entity
 			    nil (list "text/plain" "charset=us-ascii")
 			    "7bit")
-		    type (car (vm-mm-layout-type layout))
-		    params (cdr (vm-mm-layout-type layout)))
+		    type (or (vm-extent-property e 'vm-mime-type)
+			     (car (vm-mm-layout-type layout)))
+		    params (or (vm-extent-property e 'vm-mime-parameters)
+			       (cdr (vm-mm-layout-qtype layout)))
+		    description (vm-extent-property e 'vm-mime-description)
+		    disposition (or (vm-extent-property e 'vm-mime-disposition)
+				    (vm-mm-layout-qdisposition layout)))
 	    (setq type (vm-extent-property e 'vm-mime-type)
-		  params (vm-extent-property e 'vm-mime-parameters)))
+		  params (vm-extent-property e 'vm-mime-parameters)
+		  description (vm-extent-property e 'vm-mime-description)
+		  disposition (vm-extent-property e 'vm-mime-disposition)))
 	  (cond ((vm-mime-types-match "text" type)
 		 (setq encoding
 		       (vm-determine-proper-content-transfer-encoding
@@ -2262,7 +2556,11 @@
 		nil
 	      ;; trim headers
 	      (vm-reorder-message-headers
-	       nil '("Content-Description:" "Content-ID:") nil)
+	       nil (nconc (list "Content-Disposition:" "Content-ID:")
+			  (if description
+			      (list "Content-Description:")
+			    nil))
+	       nil)
 	      ;; remove header/text separator
 	      (goto-char (1- (vm-mm-layout-body-start layout)))
 	      (if (looking-at "\n")
@@ -2273,12 +2571,24 @@
 		    (insert "; " (mapconcat 'identity params "; ") "\n")
 		  (insert ";\n\t" (mapconcat 'identity params ";\n\t") "\n"))
 	      (insert "\n"))
+	    (and description
+		 (insert "Content-Description: " description "\n"))
+	    (if disposition
+		(progn
+		  (insert "Content-Disposition: " (car disposition))
+		  (if (cdr disposition)
+		      (insert ";\n\t" (mapconcat 'identity
+						 (cdr disposition)
+						 ";\n\t")))
+		  (insert "\n")))
 	    (insert "Content-Transfer-Encoding: " encoding "\n\n"))
 	  (goto-char (point-max))
 	  (widen)
 	  (delete-region (vm-extent-start-position e)
 			 (vm-extent-end-position e))
 	  (vm-detach-extent e)
+	  (if (looking-at "\n")
+	      (delete-char 1))
 	  (setq e-list (cdr e-list)))
 	;; handle the remaining chunk of text after the last
 	;; extent, if any.
@@ -2286,6 +2596,9 @@
 	    nil
 	  (setq charset (vm-determine-proper-charset (point)
 						     (point-max)))
+	  (if (fboundp 'encode-coding-region)
+	      (encode-coding-region (point-min) (point-max)
+				    file-coding-system))
 	  (setq encoding (vm-determine-proper-content-transfer-encoding
 			  (point)
 			  (point-max))
@@ -2346,6 +2659,17 @@
 		(insert ";\n\t" (mapconcat 'identity params ";\n\t"))))
 	  (insert "\n"))
 	(if just-one
+	    (and description
+		 (insert "Content-Description: " description "\n")))
+	(if (and just-one disposition)
+	    (progn
+	      (insert "Content-Disposition: " (car disposition))
+	      (if (cdr disposition)
+		  (insert ";\n\t" (mapconcat 'identity
+					     (cdr disposition)
+					     ";\n\t")))
+	      (insert "\n")))
+	(if just-one
 	    (insert "Content-Transfer-Encoding: " encoding "\n")
 	  (if 8bit
 	      (insert "Content-Transfer-Encoding: 8bit\n")
@@ -2448,12 +2772,13 @@
 	  ;; so vm-mime-encode-composition won't complain
 	  (setq major-mode 'mail-mode)
 	  (vm-insert-region-from-buffer mail-buffer)
-	  (mapcar 'vm-copy-extent e-list)
+	  (if (vm-fsfemacs-19-p)
+	      (mapcar 'vm-copy-extent e-list))
 	  (goto-char (point-min))
 	  (or (vm-mail-mode-get-header-contents "From")
 	      (insert "From: " (or user-mail-address (user-login-name)) "\n"))
 	  (or (vm-mail-mode-get-header-contents "Message-ID")
-	      (insert "Message-ID: <fake@fake.com>\n"))
+	      (insert "Message-ID: <fake@fake.fake>\n"))
 	  (or (vm-mail-mode-get-header-contents "Date")
 	      (insert "Date: "
 		      (format-time-string "%a, %d %b %Y %H%M%S %Z"