changeset 100755:818664433c32

(pmail-output-decode-coding): New variable. (pmail-delete-unwanted-fields): Greatly simplified. (pmail-output-as-babyl): New function. (pmail-convert-to-babyl-format): Considerably simplified: assume just one message and don't worry about Content-Type. (pmail-output-as-mbox): New function. (pmail-output): Total rewrite. (pmail-output-as-seen): New command. (pmail-output-read-pmail-file-name): Function deleted. (pmail-output-to-babyl-file): Function deleted. (pmail-output-body-to-file): Don't set an attribute.
author Richard M. Stallman <rms@gnu.org>
date Mon, 29 Dec 2008 19:12:22 +0000
parents ac4380af5753
children d9d23e4f6b00
files lisp/mail/pmailout.el
diffstat 1 files changed, 309 insertions(+), 386 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/mail/pmailout.el	Mon Dec 29 16:56:51 2008 +0000
+++ b/lisp/mail/pmailout.el	Mon Dec 29 19:12:22 2008 +0000
@@ -29,6 +29,13 @@
 (provide 'pmailout)
 
 ;;;###autoload
+(defcustom pmail-output-decode-coding nil
+  "*If non-nil, do coding system decoding when outputting message as Babyl."
+  :type '(choice (const :tag "on" t)
+		 (const :tag "off" nil))
+  :group 'pmail)
+
+;;;###autoload
 (defcustom pmail-output-file-alist nil
   "*Alist matching regexps to suggested output Pmail files.
 This is a list of elements of the form (REGEXP . NAME-EXP).
@@ -42,39 +49,6 @@
 			       sexp)))
   :group 'pmail-output)
 
-(defun pmail-output-read-pmail-file-name ()
-  "Read the file name to use for `pmail-output-to-babyl-file'.
-Set `pmail-default-pmail-file' to this name as well as returning it."
-  (let ((default-file
-	  (let (answer tail)
-	    (setq tail pmail-output-file-alist)
-	    ;; Suggest a file based on a pattern match.
-	    (while (and tail (not answer))
-	      (save-excursion
-		(set-buffer pmail-buffer)
-		(goto-char (point-min))
-		(if (re-search-forward (car (car tail)) nil t)
-		    (setq answer (eval (cdr (car tail)))))
-		(setq tail (cdr tail))))
-	    ;; If no suggestions, use same file as last time.
-	    (expand-file-name (or answer pmail-default-pmail-file)))))
-    (let ((read-file
-	   (expand-file-name
-	    (read-file-name
-	     (concat "Output message to Pmail file (default "
-		     (file-name-nondirectory default-file)
-		     "): ")
-	     (file-name-directory default-file)
-	     (abbreviate-file-name default-file))
-	    (file-name-directory default-file))))
-      ;; If the user enters just a directory,
-      ;; use the name within that directory chosen by the default.
-      (setq pmail-default-pmail-file
-	    (if (file-directory-p read-file)
-		(expand-file-name (file-name-nondirectory default-file)
-				  read-file)
-	      read-file)))))
-
 (defun pmail-output-read-file-name ()
   "Read the file name to use for `pmail-output'.
 Set `pmail-default-file' to this name as well as returning it."
@@ -93,7 +67,7 @@
     (let ((read-file
 	   (expand-file-name
 	    (read-file-name
-	     (concat "Output message to Unix mail file (default "
+	     (concat "Output message to mail file (default "
 		     (file-name-nondirectory default-file)
 		     "): ")
 	     (file-name-directory default-file)
@@ -107,244 +81,137 @@
 	       (or read-file (file-name-nondirectory default-file))
 	       (file-name-directory default-file)))))))
 
-(declare-function pmail-update-summary "pmailsum" (&rest ignore))
-
-;;; There are functions elsewhere in Emacs that use this function;
-;;; look at them before you change the calling method.
 ;;;###autoload
-(defun pmail-output-to-babyl-file (file-name &optional count stay)
-  "Append the current message to a Babyl file named FILE-NAME.
-If the file does not exist, ask if it should be created.
-If file is being visited, the message is appended to the Emacs
-buffer visiting that file.
-If the file exists and is not a Babyl file, the message is
-appended in inbox format, the same way `pmail-output' does it.
-
-The default file name comes from `pmail-default-pmail-file',
-which is updated to the name you use in this command.
-
-A prefix argument COUNT says to output that many consecutive messages,
-starting with the current one.  Deleted messages are skipped and don't count.
+(defcustom pmail-fields-not-to-output nil
+  "*Regexp describing fields to exclude when outputting a message to a file."
+  :type '(choice (const :tag "None" nil)
+		 regexp)
+  :group 'pmail-output)
 
-If the optional argument STAY is non-nil, then leave the last filed
-message up instead of moving forward to the next non-deleted message."
-  (interactive
-   (list (pmail-output-read-pmail-file-name)
-	 (prefix-numeric-value current-prefix-arg)))
-  (or count (setq count 1))
-  (setq file-name
-	(expand-file-name file-name
-			  (file-name-directory pmail-default-pmail-file)))
-  (if (and (file-readable-p file-name) (not (mail-file-babyl-p file-name)))
-      (pmail-output file-name count)
-    (pmail-maybe-set-message-counters)
-    (setq file-name (abbreviate-file-name file-name))
-    (or (find-buffer-visiting file-name)
-	(file-exists-p file-name)
-	(if (yes-or-no-p
-	     (concat "\"" file-name "\" does not exist, create it? "))
-	    (let ((file-buffer (create-file-buffer file-name)))
-	      (save-excursion
-		(set-buffer file-buffer)
-		(let ((buffer-read-only nil))
-		  (insert "BABYL OPTIONS: -*- pmail -*-
-Version: 5
-Labels:
-Note:   This is the header of an pmail file.
-Note:   If you are seeing it in pmail,
-Note:    it means the file has no messages in it.\n\^_"))
-		(let ((require-final-newline nil)
-		      (coding-system-for-write
-		       (or pmail-file-coding-system
-			   'emacs-mule-unix)))
-		  (write-region (point-min) (point-max) file-name t 1)))
-	      (kill-buffer file-buffer))
-	  (error "Output file does not exist")))
-    (while (> count 0)
-      (let (redelete)
-	(unwind-protect
-	    (progn
-	      (set-buffer pmail-buffer)
-	      ;; Temporarily turn off Deleted attribute.
-	      ;; Do this outside the save-restriction, since it would
-	      ;; shift the place in the buffer where the visible text starts.
-	      (if (pmail-message-deleted-p pmail-current-message)
-		  (progn (setq redelete t)
-			 (pmail-set-attribute pmail-deleted-attr-index nil)))
-	      (let ((coding-system-for-write
-		     (or pmail-file-coding-system
-			 'emacs-mule-unix))
-		    cur beg end)
-		(pmail-swap-buffers-maybe)
-		(setq cur (current-buffer))
-		(save-restriction
-		  (save-excursion
-		    (widen)
-		    (setq beg (pmail-msgbeg pmail-current-message)
-			  end (pmail-msgend pmail-current-message))
-		    ;; Output to a file.
-		    (set-buffer (get-buffer-create " pmail-out-temp"))
-		    (insert-buffer-substring cur beg end)
-		    (if pmail-fields-not-to-output
-			(pmail-delete-unwanted-fields))
-		    ;; Convert to Babyl format.
-		    (pmail-convert-to-babyl-format)
-		    (append-to-file (point-min) (point-max) file-name)
-		    (set-buffer cur)
-		    (kill-buffer (get-buffer " pmail-out-temp")))))
-	      (pmail-set-attribute pmail-filed-attr-index t))
-	  (if redelete (pmail-set-attribute pmail-deleted-attr-index t))))
-      (setq count (1- count))
-      (if pmail-delete-after-output
-	  (unless (if (and (= count 0) stay)
-		      (pmail-delete-message)
-		    (pmail-delete-forward))
-	    (setq count 0))
-	(if (> count 0)
-	    (unless (if (not stay)
-			(pmail-next-undeleted-message 1))
-	      (setq count 0))))))
-  (pmail-show-message))
+;; Delete from the buffer header fields we don't want output.
+;; Buffer should be pre-narrowed to the header.
+;; PRESERVE is a regexp for fields NEVER to delete.
+(defun pmail-delete-unwanted-fields (preserve)
+  (if pmail-fields-not-to-output
+      (save-excursion
+	(goto-char (point-min))
+	(while (re-search-forward pmail-fields-not-to-output nil t)
+	  (beginning-of-line)
+	  (unless (looking-at preserve)
+	    (delete-region (point)
+			   (progn (forward-line 1) (point))))))))
+
+(defun pmail-output-as-babyl (file-name nomsg)
+  "Convert the current buffer's text to Babyl and output to FILE-NAME.
+It alters the current buffer's text, so it should be a temp buffer."
+  (let ((coding-system-for-write
+	 'emacs-mule-unix))
+    (save-restriction
+      (goto-char (point-min))
+      (search-forward "\n\n" nil 'move)
+      (narrow-to-region (point-min) (point))
+      (if pmail-fields-not-to-output
+	  (pmail-delete-unwanted-fields nil)))
 
-(defalias 'pmail-output-to-pmail-file 'pmail-output-to-babyl-file)
+    ;; Convert to Babyl format.
+    (pmail-convert-to-babyl-format)
+    ;; Write it into the file.
+    (write-region (point-min) (point-max) file-name t nomsg)))
 
 (defun pmail-convert-to-babyl-format ()
-  (let ((count 0) start
+  (let ((count 0) (start (point-min))
 	(case-fold-search nil)
 	(buffer-undo-list t))
     (goto-char (point-min))
     (save-restriction
-      (while (not (eobp))
-	(setq start (point))
-	(unless (looking-at "^From ")
-	  (error "Invalid mbox message"))
-	(insert "\^L\n0, unseen,,\n*** EOOH ***\n")
-	(pmail-nuke-pinhead-header)
-	;; If this message has a Content-Length field,
-	;; skip to the end of the contents.
-	(let* ((header-end (save-excursion
-			     (and (re-search-forward "\n\n" nil t)
-				  (1- (point)))))
-	       (case-fold-search t)
-	       (quoted-printable-header-field-end
-		(save-excursion
-		  (re-search-forward
-		   "^content-transfer-encoding:\\(\n?[\t ]\\)*quoted-printable\\(\n?[\t ]\\)*"
-		   header-end t)))
-	       (base64-header-field-end
-		(and
-		 ;; Don't decode non-text data.
-		 (save-excursion
-		   (re-search-forward
-		    "^content-type:\\(\n?[\t ]\\)\\(text\\|message\\)/"
-		    header-end t))
-		 (save-excursion
-		   (re-search-forward
-		    "^content-transfer-encoding:\\(\n?[\t ]\\)*base64\\(\n?[\t ]\\)*"
-		    header-end t))))
-	       (size
-		;; Get the numeric value from the Content-Length field.
-		(save-excursion
-		  ;; Back up to end of prev line,
-		  ;; in case the Content-Length field comes first.
-		  (forward-char -1)
-		  (and (search-forward "\ncontent-length: "
-				       header-end t)
-		       (let ((beg (point))
-			     (eol (progn (end-of-line) (point))))
-				(string-to-number (buffer-substring beg eol)))))))
-	  (and size
-	       (if (and (natnump size)
-			(<= (+ header-end size) (point-max))
-			;; Make sure this would put us at a position
-			;; that we could continue from.
-			(save-excursion
-			  (goto-char (+ header-end size))
-			  (skip-chars-forward "\n")
-			  (or (eobp)
-			      (and (looking-at "BABYL OPTIONS:")
-				   (search-forward "\n\^_" nil t))
-			      (and (looking-at "\^L")
-				   (search-forward "\n\^_" nil t))
-			      (let ((case-fold-search t))
-				(looking-at pmail-mmdf-delim1))
-			      (looking-at "From "))))
-		   (goto-char (+ header-end size))
-		 (message "Ignoring invalid Content-Length field")
-		 (sit-for 1 0 t)))
-	  (if (let ((case-fold-search nil))
+      (unless (looking-at "^From ")
+	(error "Invalid mbox message"))
+      (insert "\^L\n0, unseen,,\n*** EOOH ***\n")
+      (pmail-nuke-pinhead-header)
+      ;; Decode base64 or quoted printable contents, Rmail style.
+      (let* ((header-end (save-excursion
+			   (and (re-search-forward "\n\n" nil t)
+				(1- (point)))))
+	     (case-fold-search t)
+	     (quoted-printable-header-field-end
+	      (save-excursion
 		(re-search-forward
-			(concat "^[\^_]?\\("
-				pmail-unix-mail-delimiter
-				"\\|"
-				pmail-mmdf-delim1 "\\|"
-				"^BABYL OPTIONS:\\|"
-				"\^L\n[01],\\)") nil t))
-	      (goto-char (match-beginning 1))
-	    (goto-char (point-max)))
-	  (setq count (1+ count))
-	  (if quoted-printable-header-field-end
-	      (save-excursion
-		(unless (mail-unquote-printable-region
-			 header-end (point) nil t t)
-		  (message "Malformed MIME quoted-printable message"))
-		;; Change "quoted-printable" to "8bit",
-		;; to reflect the decoding we just did.
-		(goto-char quoted-printable-header-field-end)
+		 "^content-transfer-encoding:\\(\n?[\t ]\\)*quoted-printable\\(\n?[\t ]\\)*"
+		 header-end t)))
+	     (base64-header-field-end
+	      (and
+	       ;; Don't decode non-text data.
+	       (save-excursion
+		 (re-search-forward
+		  "^content-type:\\(\n?[\t ]\\)\\(text\\|message\\)/"
+		  header-end t))
+	       (save-excursion
+		 (re-search-forward
+		  "^content-transfer-encoding:\\(\n?[\t ]\\)*base64\\(\n?[\t ]\\)*"
+		  header-end t)))))
+
+	(goto-char (point-max))
+	(if quoted-printable-header-field-end
+	    (save-excursion
+	      (unless (mail-unquote-printable-region
+		       header-end (point) nil t t)
+		(message "Malformed MIME quoted-printable message"))
+	      ;; Change "quoted-printable" to "8bit",
+	      ;; to reflect the decoding we just did.
+	      (goto-char quoted-printable-header-field-end)
+	      (delete-region (point) (search-backward ":"))
+	      (insert ": 8bit")))
+	(if base64-header-field-end
+	    (save-excursion
+	      (when (condition-case nil
+			(progn
+			  (base64-decode-region
+			   (1+ header-end)
+			   (save-excursion
+			     ;; Prevent base64-decode-region
+			     ;; from removing newline characters.
+			     (skip-chars-backward "\n\t ")
+			     (point)))
+			  t)
+		      (error nil))
+		;; Change "base64" to "8bit", to reflect the
+		;; decoding we just did.
+		(goto-char base64-header-field-end)
 		(delete-region (point) (search-backward ":"))
-		(insert ": 8bit")))
-	  (if base64-header-field-end
-	      (save-excursion
-		(when (condition-case nil
-			  (progn
-			    (base64-decode-region
-			     (1+ header-end)
-			     (save-excursion
-			       ;; Prevent base64-decode-region
-			       ;; from removing newline characters.
-			       (skip-chars-backward "\n\t ")
-			       (point)))
-			    t)
-			(error nil))
-		  ;; Change "base64" to "8bit", to reflect the
-		  ;; decoding we just did.
-		  (goto-char base64-header-field-end)
-		  (delete-region (point) (search-backward ":"))
-		  (insert ": 8bit")))))
-	(save-excursion
-	  (save-restriction
-	    (narrow-to-region start (point))
-	    (goto-char (point-min))
-	    (while (search-forward "\n\^_" nil t) ; single char
-	      (replace-match "\n^_"))))	; 2 chars: "^" and "_"
-	;; This is for malformed messages that don't end in newline.
-	;; There shouldn't be any, but some users say occasionally
-	;; there are some.
-	(or (bolp) (newline))
-	(insert ?\^_)
-	(setq last-coding-system-used nil)
-	(or pmail-enable-mime
-	    (not pmail-enable-multibyte)
-	    (let ((mime-charset
-		   (if (and pmail-decode-mime-charset
-			    (save-excursion
-			      (goto-char start)
-			      (search-forward "\n\n" nil t)
-			      (let ((case-fold-search t))
-				(re-search-backward
-				 pmail-mime-charset-pattern
-				 start t))))
-		       (intern (downcase (match-string 1))))))
-	      (pmail-decode-region start (point) mime-charset)))
-	(save-excursion
-	  (goto-char start)
-	  (forward-line 3)
-	  (insert "X-Coding-System: "
-		  (symbol-name last-coding-system-used)
-		  "\n"))
-	(narrow-to-region (point) (point-max))
-	(and (= 0 (% count 10))
-	     (message "Converting to Babyl format...%d" count))))))
+		(insert ": 8bit")))))
+      ;; Transform anything within the message text
+      ;; that might appear to be the end of a Babyl-format message.
+      (save-excursion
+	(save-restriction
+	  (narrow-to-region start (point))
+	  (goto-char (point-min))
+	  (while (search-forward "\n\^_" nil t) ; single char
+	    (replace-match "\n^_"))))		; 2 chars: "^" and "_"
+      ;; This is for malformed messages that don't end in newline.
+      ;; There shouldn't be any, but some users say occasionally
+      ;; there are some.
+      (or (bolp) (newline))
+      (insert ?\^_)
+      (setq last-coding-system-used nil)
+      ;; Decode coding system, following specs in the message header,
+      ;; and record what coding system was decoded.
+      (if pmail-output-decode-coding
+	  (let ((mime-charset
+		 (if (save-excursion
+		       (goto-char start)
+		       (search-forward "\n\n" nil t)
+		       (let ((case-fold-search t))
+			 (re-search-backward
+			  pmail-mime-charset-pattern
+			  start t)))
+		     (intern (downcase (match-string 1))))))
+	    (pmail-decode-region start (point) mime-charset)))
+      (save-excursion
+	(goto-char start)
+	(forward-line 3)
+	(insert "X-Coding-System: "
+		(symbol-name last-coding-system-used)
+		"\n")))))
 
 ;; Delete the "From ..." line, creating various other headers with
 ;; information from it if they don't already exist.  Now puts the
@@ -398,31 +265,54 @@
 		      ""
 		    "From: \\1\n"))
 		t)))))))
+
+(defun pmail-output-as-mbox (file-name nomsg)
+  "Convert the current buffer's text to mbox Babyl and output to FILE-NAME.
+It alters the current buffer's text, so it should be a temp buffer."
+  (let ((case-fold-search t)
+	mail-from mime-version content-type)
 
-;;;###autoload
-(defcustom pmail-fields-not-to-output nil
-  "*Regexp describing fields to exclude when outputting a message to a file."
-  :type '(choice (const :tag "None" nil)
-		 regexp)
-  :group 'pmail-output)
+    ;; Preserve the Mail-From and MIME-Version fields
+    ;; even if they have been pruned.
+    (search-forward "\n\n" nil 'move)
+    (narrow-to-region (point-min) (point))
+
+    (pmail-delete-unwanted-fields
+     (if pmail-enable-mime "Mail-From"
+       "Mail-From\\|MIME-Version\\|Content-type"))
+
+    (widen)
 
-;; Delete from the buffer header fields we don't want output.
-;; NOT-PMAIL if t means this buffer does not have the full header
-;; and *** EOOH *** that a message in an Pmail file has.
-(defun pmail-delete-unwanted-fields (&optional not-pmail)
-  (if pmail-fields-not-to-output
-      (save-excursion
-	(goto-char (point-min))
-	;; Find the end of the header.
-	(if (and (or not-pmail (search-forward "\n*** EOOH ***\n" nil t))
-		 (search-forward "\n\n" nil t))
-	    (let ((end (point-marker)))
-	      (goto-char (point-min))
-	      (while (re-search-forward pmail-fields-not-to-output end t)
-		(beginning-of-line)
-		(delete-region (point)
-			       (progn (forward-line 1) (point)))))))))
+    ;; Make sure message ends with blank line.
+    (goto-char (point-max))
+    (unless (bolp)
+       (insert "\n"))
+    (unless (looking-back "\n\n")
+      (insert "\n"))
 
+    ;; Generate a From line from other header fields
+    ;; if necessary.
+    (goto-char (point-min))
+    (unless (looking-at "From ")
+      (insert "From "
+	      (mail-strip-quoted-names
+	       (save-excursion
+		 (save-restriction
+		   (goto-char (point-min))
+		   (narrow-to-region
+		    (point)
+		    (or (search-forward "\n\n" nil)
+			(point-max)))
+		   (or (mail-fetch-field "from")
+		       (mail-fetch-field "really-from")
+		       (mail-fetch-field "sender")
+		       "unknown"))))
+	      " " (current-time-string) "\n"))
+
+    (let ((coding-system-for-write
+	   'raw-text-unix))
+      (write-region (point-min) (point-max) file-name t nomsg))))
+
 ;;; There are functions elsewhere in Emacs that use this function;
 ;;; look at them before you change the calling method.
 ;;;###autoload
@@ -430,11 +320,9 @@
   "Append this message to system-inbox-format mail file named FILE-NAME.
 A prefix argument COUNT says to output that many consecutive messages,
 starting with the current one.  Deleted messages are skipped and don't count.
-When called from lisp code, COUNT may be omitted and defaults to 1.
+When called from Lisp code, COUNT may be omitted and defaults to 1.
 
-If the pruned message header is shown on the current message, then
-messages will be appended with pruned headers; otherwise, messages
-will be appended with their original headers.
+This outputs the complete message header even the display is pruned.
 
 The default file name comes from `pmail-default-file',
 which is updated to the name you use in this command.
@@ -451,104 +339,141 @@
 	(expand-file-name file-name
 			  (and pmail-default-file
 			       (file-name-directory pmail-default-file))))
-  (if (and (file-readable-p file-name) (mail-file-babyl-p file-name))
-      (pmail-output-to-babyl-file file-name count)
-    (set-buffer pmail-buffer)
-    (let ((orig-count count)
-	  (pmailbuf pmail-buffer)
-	  (case-fold-search t)
-	  (tembuf (get-buffer-create " pmail-output"))
-	  header-beginning
-	  mail-from mime-version content-type)
-      (while (> count 0)
-	;; Preserve the Mail-From and MIME-Version fields
-	;; even if they have been pruned.
-	(or from-gnus
-	    (save-excursion
-	      (save-restriction
-		(goto-char (if (pmail-buffers-swapped-p)
-			       (point-min)
-			     (pmail-msgbeg pmail-current-message)))
-		(setq header-beginning (point))
-		(search-forward "\n\n" nil 'move)
-		(narrow-to-region header-beginning (point))
-		(setq mail-from (mail-fetch-field "Mail-From"))
-		(unless pmail-enable-mime
-		  (setq mime-version (mail-fetch-field "MIME-Version")
-			content-type (mail-fetch-field "Content-type"))))))
-	(save-excursion
-	  (set-buffer tembuf)
-	  (erase-buffer)
-	  (insert-buffer-substring pmailbuf)
-	  (save-excursion
-	    (goto-char (min (point-min) (- (point-max) 2)))
-	    (unless (looking-at "\n\n")
-	      (goto-char (point-max))
-	      (insert "\n\n")))
-	  (when pmail-enable-mime
-	    (goto-char (point-min))
-	    (forward-line 2)
-	    (delete-region (point-min) (point))
-	    (search-forward "\n\n")
-	    (delete-region (match-beginning 0)
-			   (if (search-forward "\n\n")
-			       (1- (match-end 0))))
-	    (setq buffer-file-coding-system (or pmail-file-coding-system
-						'raw-text)))
-	  (pmail-delete-unwanted-fields t)
-	  (or (bolp) (insert "\n"))
-	  (goto-char (point-min))
-	  (if mail-from
-	      (insert mail-from "\n")
-	    (insert "From "
-		    (mail-strip-quoted-names
-		     (save-excursion
-		       (save-restriction
-			 (goto-char (point-min))
-			 (narrow-to-region
-			  (point)
-			  (or (search-forward "\n\n" nil)
-			      (point-max)))
-			 (or (mail-fetch-field "from")
-			     (mail-fetch-field "really-from")
-			     (mail-fetch-field "sender")
-			     "unknown"))))
-		    " " (current-time-string) "\n"))
-	  (when mime-version
-	    (insert "MIME-Version: " mime-version)
-	    ;; Some malformed MIME messages set content-type to nil.
-	    (when content-type
-	      (insert "\nContent-type: " content-type "\n")))
-	  ;; ``Quote'' "\nFrom " as "\n>From "
-	  ;;  (note that this isn't really quoting, as there is no requirement
-	  ;;   that "\n[>]+From " be quoted in the same transparent way.)
-	  (let ((case-fold-search nil))
-	    (while (search-forward "\nFrom " nil t)
-	      (forward-char -5)
-	      (insert ?>)))
-	  (write-region (point-min) (point-max) file-name t
-			(if noattribute 'nomsg)))
-	(or noattribute
-	    (if (equal major-mode 'pmail-mode)
-		(pmail-set-attribute pmail-filed-attr-index t)))
-	(setq count (1- count))
-	(or from-gnus
-	    (let ((next-message-p
-		   (if pmail-delete-after-output
-		       (pmail-delete-forward)
-		     (if (> count 0)
-			 (pmail-next-undeleted-message 1))))
-		  (num-appended (- orig-count count)))
-	      (if (and (> count 0) (not next-message-p))
-		  (progn
-		    (error "%s"
-		     (save-excursion
-		       (set-buffer pmailbuf)
-		       (format "Only %d message%s appended" num-appended
-			       (if (= num-appended 1) "" "s"))))
-		    (setq count 0))))))
+  (set-buffer pmail-buffer)
+
+  ;; Warn about creating new file.
+  (or (find-buffer-visiting file-name)
+      (file-exists-p file-name)
+      (yes-or-no-p
+       (concat "\"" file-name "\" does not exist, create it? "))
+      (error "Output file does not exist"))
+
+  (let ((orig-count count)
+	(case-fold-search t)
+	(tembuf (get-buffer-create " pmail-output"))
+	(babyl-format
+	 (and (file-readable-p file-name) (mail-file-babyl-p file-name))))
+
+    (unwind-protect
+	(while (> count 0)
+	  (with-current-buffer pmail-buffer
+	    (let (cur beg end)
+	      (setq beg (pmail-msgbeg pmail-current-message)
+		    end (pmail-msgend pmail-current-message))
+	      ;; All access to the buffer's local variables is now finished...
+	      (save-excursion
+		;; ... so it is ok to go to a different buffer.
+		(if (pmail-buffers-swapped-p) (set-buffer pmail-view-buffer))
+		(setq cur (current-buffer))
+		(save-restriction
+		  (widen)
+		  (with-current-buffer tembuf
+		    (insert-buffer-substring cur beg end)
+		    ;; Convert the text to one format or another and output.
+		    (if babyl-format
+			(pmail-output-as-babyl file-name (if noattribute 'nomsg))
+		      (pmail-output-as-mbox file-name 
+					    (if noattribute 'nomsg))))))))
+
+	  ;; Mark message as "filed".
+	  (unless noattribute
+	    (pmail-set-attribute pmail-filed-attr-index t))
+
+	  (setq count (1- count))
+
+	  (or from-gnus
+	      (let ((next-message-p
+		     (if pmail-delete-after-output
+			 (pmail-delete-forward)
+		       (if (> count 0)
+			   (pmail-next-undeleted-message 1))))
+		    (num-appended (- orig-count count)))
+		(if (and (> count 0) (not next-message-p))
+		    (error "Only %d message%s appended" num-appended
+			   (if (= num-appended 1) "" "s"))))))
       (kill-buffer tembuf))))
 
+(defun pmail-output-as-seen (file-name &optional count noattribute from-gnus)
+  "Append this message to system-inbox-format mail file named FILE-NAME.
+A prefix argument COUNT says to output that many consecutive messages,
+starting with the current one.  Deleted messages are skipped and don't count.
+When called from Lisp code, COUNT may be omitted and defaults to 1.
+
+This outputs the message header as you see it.
+
+The default file name comes from `pmail-default-file',
+which is updated to the name you use in this command.
+
+The optional third argument NOATTRIBUTE, if non-nil, says not
+to set the `filed' attribute, and not to display a message.
+
+The optional fourth argument FROM-GNUS is set when called from GNUS."
+  (interactive
+   (list (pmail-output-read-file-name)
+	 (prefix-numeric-value current-prefix-arg)))
+  (or count (setq count 1))
+  (setq file-name
+	(expand-file-name file-name
+			  (and pmail-default-file
+			       (file-name-directory pmail-default-file))))
+  (set-buffer pmail-buffer)
+
+  ;; Warn about creating new file.
+  (or (find-buffer-visiting file-name)
+      (file-exists-p file-name)
+      (yes-or-no-p
+       (concat "\"" file-name "\" does not exist, create it? "))
+      (error "Output file does not exist"))
+
+    (if (and (file-readable-p file-name) (mail-file-babyl-p file-name))
+	(error "Cannot output `as seen' to a Babyl file"))
+
+  (let ((orig-count count)
+	(case-fold-search t)
+	(tembuf (get-buffer-create " pmail-output")))
+
+    (unwind-protect
+	(while (> count 0)
+	  (let (cur beg end)
+	    ;; If operating from whole-mbox buffer, get message bounds.
+	    (if (not (pmail-buffers-swapped-p))
+		(setq beg (pmail-msgbeg pmail-current-message)
+		      end (pmail-msgend pmail-current-message)))
+	    ;; All access to the buffer's local variables is now finished...
+	    (save-excursion
+	      (setq cur (current-buffer))
+	      (save-restriction
+		(widen)
+		;; If operating from the view buffer, get the bounds.
+		(unless beg
+		  (setq beg (point-min)
+			end (point-max)))
+
+		(with-current-buffer tembuf
+		  (insert-buffer-substring cur beg end)
+		  ;; Convert the text to one format or another and output.
+		  (pmail-output-as-mbox file-name 
+					(if noattribute 'nomsg))))))
+
+	  ;; Mark message as "filed".
+	  (unless noattribute
+	    (pmail-set-attribute pmail-filed-attr-index t))
+
+	  (setq count (1- count))
+
+	  (or from-gnus
+	      (let ((next-message-p
+		     (if pmail-delete-after-output
+			 (pmail-delete-forward)
+		       (if (> count 0)
+			   (pmail-next-undeleted-message 1))))
+		    (num-appended (- orig-count count)))
+		(if (and (> count 0) (not next-message-p))
+		    (error "Only %d message%s appended" num-appended
+			   (if (= num-appended 1) "" "s"))))))
+      (kill-buffer tembuf))))
+
+
 ;;;###autoload
 (defun pmail-output-body-to-file (file-name)
   "Write this message body to the file FILE-NAME.
@@ -573,9 +498,7 @@
     (and (file-exists-p file-name)
 	 (not (y-or-n-p (format "File %s exists; overwrite? " file-name)))
 	 (error "Operation aborted"))
-    (write-region (point) (point-max) file-name)
-    (if (equal major-mode 'pmail-mode)
-	(pmail-set-attribute pmail-stored-attr-index t)))
+    (write-region (point) (point-max) file-name))
   (if pmail-delete-after-output
       (pmail-delete-forward)))