gnus-html.el (gnus-html-schedule-image-fetching): Fix last change.
[gnus] / lisp / gnus-uu.el
index 8744e86..d4f382a 100644 (file)
@@ -1,5 +1,7 @@
 ;;; gnus-uu.el --- extract (uu)encoded files in Gnus
-;; Copyright (C) 1985,86,87,93,94,95,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998,
+;;   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Created: 2 Oct 1993
@@ -7,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs 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.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -33,6 +33,7 @@
 (require 'message)
 (require 'gnus-msg)
 (require 'mm-decode)
+(require 'yenc)
 
 (defgroup gnus-extract nil
   "Extracting encoded files."
@@ -58,8 +59,8 @@
   '(("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed 's/\r$//'")
     ("\\.pas$" "cat %s | sed 's/\r$//'")
     ("\\.[1-9]$" "groff -mandoc -Tascii %s | sed s/\b.//g")
-    ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "xv")
-    ("\\.tga$" "tgatoppm %s | xv -")
+    ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "display")
+    ("\\.tga$" "tgatoppm %s | ee -")
     ("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$"
      "sox -v .5 %s -t .au -u - > /dev/audio")
     ("\\.au$" "cat %s > /dev/audio")
@@ -73,7 +74,7 @@
     ("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$"
      "gnus-uu-archive"))
   "*Default actions to be taken when the user asks to view a file.
-To change the behaviour, you can either edit this variable or set
+To change the behavior, you can either edit this variable or set
 `gnus-uu-user-view-rules' to something useful.
 
 For example:
@@ -93,7 +94,7 @@ at that point in the command string.  If there's no \"%s\" in the
 command string, the file name will be appended to the command string
 before executing.
 
-There are several user variables to tailor the behaviour of gnus-uu to
+There are several user variables to tailor the behavior of gnus-uu to
 your needs.  First we have `gnus-uu-user-view-rules', which is the
 variable gnus-uu first consults when trying to decide how to view a
 file.  If this variable contains no matches, gnus-uu examines the
@@ -294,9 +295,12 @@ so I simply dropped them."
 
 (defcustom gnus-uu-digest-headers
   '("^Date:" "^From:" "^To:" "^Cc:" "^Subject:" "^Message-ID:" "^Keywords:"
-    "^Summary:" "^References:" "^Content-Type:" "^Content-Transfer-Encoding:")
+    "^Summary:" "^References:" "^Content-Type:" "^Content-Transfer-Encoding:"
+    "^MIME-Version:" "^Content-Disposition:" "^Content-Description:"
+    "^Content-ID:")
   "*List of regexps to match headers included in digested messages.
-The headers will be included in the sequence they are matched."
+The headers will be included in the sequence they are matched.  If nil
+include all headers."
   :group 'gnus-extract
   :type '(repeat regexp))
 
@@ -318,7 +322,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defvar gnus-uu-saved-article-name nil)
 
-(defvar gnus-uu-begin-string "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
+(defvar gnus-uu-begin-string "^begin[ \t]+0?[0-7][0-7][0-7][ \t]+\\(.*\\)$")
 (defvar gnus-uu-end-string "^end[ \t]*$")
 
 (defvar gnus-uu-body-line "^M")
@@ -331,8 +335,8 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defvar gnus-uu-shar-begin-string "^#! */bin/sh")
 
-(defvar gnus-uu-shar-file-name nil)
-(defvar gnus-uu-shar-name-marker "begin [0-7][0-7][0-7][ \t]+\\(\\(\\w\\|\\.\\)*\\b\\)")
+(defvar gnus-uu-shar-name-marker
+  "begin 0?[0-7][0-7][0-7][ \t]+\\(\\(\\w\\|[.\\:]\\)*\\b\\)")
 
 (defvar gnus-uu-postscript-begin-string "^%!PS-")
 (defvar gnus-uu-postscript-end-string "^%%EOF$")
@@ -340,6 +344,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 (defvar gnus-uu-file-name nil)
 (defvar gnus-uu-uudecode-process nil)
 (defvar gnus-uu-binhex-article-name nil)
+(defvar gnus-uu-yenc-article-name nil)
 
 (defvar gnus-uu-work-dir nil)
 
@@ -347,56 +352,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defvar gnus-uu-default-dir gnus-article-save-directory)
 (defvar gnus-uu-digest-from-subject nil)
-
-;; Keymaps
-
-(gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
-  "p" gnus-summary-mark-as-processable
-  "u" gnus-summary-unmark-as-processable
-  "U" gnus-summary-unmark-all-processable
-  "v" gnus-uu-mark-over
-  "s" gnus-uu-mark-series
-  "r" gnus-uu-mark-region
-  "g" gnus-uu-unmark-region
-  "R" gnus-uu-mark-by-regexp
-  "G" gnus-uu-unmark-by-regexp
-  "t" gnus-uu-mark-thread
-  "T" gnus-uu-unmark-thread
-  "a" gnus-uu-mark-all
-  "b" gnus-uu-mark-buffer
-  "S" gnus-uu-mark-sparse
-  "k" gnus-summary-kill-process-mark
-  "y" gnus-summary-yank-process-mark
-  "w" gnus-summary-save-process-mark
-  "i" gnus-uu-invert-processable)
-
-(gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
-  ;;"x" gnus-uu-extract-any
-  ;;"m" gnus-uu-extract-mime
-  "u" gnus-uu-decode-uu
-  "U" gnus-uu-decode-uu-and-save
-  "s" gnus-uu-decode-unshar
-  "S" gnus-uu-decode-unshar-and-save
-  "o" gnus-uu-decode-save
-  "O" gnus-uu-decode-save
-  "b" gnus-uu-decode-binhex
-  "B" gnus-uu-decode-binhex
-  "p" gnus-uu-decode-postscript
-  "P" gnus-uu-decode-postscript-and-save)
-
-(gnus-define-keys
- (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
- "u" gnus-uu-decode-uu-view
- "U" gnus-uu-decode-uu-and-save-view
- "s" gnus-uu-decode-unshar-view
- "S" gnus-uu-decode-unshar-and-save-view
- "o" gnus-uu-decode-save-view
- "O" gnus-uu-decode-save-view
- "b" gnus-uu-decode-binhex-view
- "B" gnus-uu-decode-binhex-view
- "p" gnus-uu-decode-postscript-view
- "P" gnus-uu-decode-postscript-and-save-view)
-
+(defvar gnus-uu-digest-buffer nil)
 
 ;; Commands.
 
@@ -436,7 +392,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
    (list current-prefix-arg
         (read-file-name
          (if gnus-uu-save-separate-articles
-             "Save articles is dir: "
+             "Save articles in dir: "
            "Save articles in file: ")
          gnus-uu-default-dir
          gnus-uu-default-dir)))
@@ -452,9 +408,20 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                          gnus-uu-default-dir
                          gnus-uu-default-dir))))
   (setq gnus-uu-binhex-article-name
-       (make-temp-name (concat gnus-uu-work-dir "binhex")))
+       (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
   (gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
 
+(defun gnus-uu-decode-yenc (n dir)
+  "Decode the yEnc-encoded current article."
+  (interactive
+   (list current-prefix-arg
+        (file-name-as-directory
+         (read-file-name "yEnc decode and save in dir: "
+                         gnus-uu-default-dir
+                         gnus-uu-default-dir))))
+  (setq gnus-uu-yenc-article-name nil)
+  (gnus-uu-decode-with-method 'gnus-uu-yenc-article n dir nil t))
+
 (defun gnus-uu-decode-uu-view (&optional n)
   "Uudecodes and views the current article."
   (interactive "P")
@@ -505,7 +472,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
         (read-file-name "Unbinhex, view and save in dir: "
                         gnus-uu-default-dir gnus-uu-default-dir)))
   (setq gnus-uu-binhex-article-name
-       (make-temp-name (concat gnus-uu-work-dir "binhex")))
+       (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
   (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
     (gnus-uu-decode-binhex n file)))
 
@@ -516,47 +483,65 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   "Digests and forwards all articles in this series."
   (interactive "P")
   (let ((gnus-uu-save-in-digest t)
-       (file (make-temp-name (nnheader-concat gnus-uu-tmp-dir "forward")))
-       buf subject from)
-    (gnus-setup-message 'forward
-      (setq gnus-uu-digest-from-subject nil)
-      (gnus-uu-decode-save n file)
-      (setq buf (switch-to-buffer
-                (gnus-get-buffer-create " *gnus-uu-forward*")))
-      (erase-buffer)
-      (insert-file file)
-      (let ((fs gnus-uu-digest-from-subject))
-       (when fs
-         (setq from (caar fs)
-               subject (gnus-simplify-subject-fuzzy (cdar fs))
-               fs (cdr fs))
-         (while (and fs (or from subject))
-           (when from
-             (unless (string= from (caar fs))
-               (setq from nil)))
-           (when subject
-             (unless (string= (gnus-simplify-subject-fuzzy (cdar fs))
-                              subject)
-               (setq subject nil)))
-           (setq fs (cdr fs))))
-       (unless subject
-         (setq subject "Digested Articles"))
-       (unless from
-         (setq from
-               (if (gnus-news-group-p gnus-newsgroup-name)
-                   gnus-newsgroup-name
-                 "Various"))))
-      (goto-char (point-min))
-      (when (re-search-forward "^Subject: ")
-       (delete-region (point) (gnus-point-at-eol))
-       (insert subject))
-      (goto-char (point-min))
-      (when (re-search-forward "^From: ")
-       (delete-region (point) (gnus-point-at-eol))
-       (insert from))
-      (message-forward post))
-    (delete-file file)
-    (kill-buffer buf)
+       (file (mm-make-temp-file (nnheader-concat gnus-uu-tmp-dir "forward")))
+       (message-forward-as-mime message-forward-as-mime)
+       (mail-parse-charset gnus-newsgroup-charset)
+       (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+       gnus-uu-digest-buffer subject from)
+    (if (and n (not (numberp n)))
+       (setq message-forward-as-mime (not message-forward-as-mime)
+             n nil))
+    (let ((gnus-article-reply (gnus-summary-work-articles n)))
+      (when (and (not n)
+                (= (length gnus-article-reply) 1))
+       ;; The case where neither a number of articles nor a region is
+       ;; specified.
+       (gnus-summary-top-thread)
+       (setq gnus-article-reply (nreverse (gnus-uu-find-articles-matching))))
+      (gnus-setup-message 'forward
+       (setq gnus-uu-digest-from-subject nil)
+       (setq gnus-uu-digest-buffer
+             (gnus-get-buffer-create " *gnus-uu-forward*"))
+       ;; Specify articles to be forwarded.  Note that they should be
+       ;; reversed; see `gnus-uu-get-list-of-articles'.
+       (let ((gnus-newsgroup-processable (reverse gnus-article-reply)))
+         (gnus-uu-decode-save n file)
+         (setq gnus-article-reply gnus-newsgroup-processable))
+       ;; Restore the value of `gnus-newsgroup-processable' to which
+       ;; it should be set when it is not `let'-bound.
+       (setq gnus-newsgroup-processable (reverse gnus-article-reply))
+       (switch-to-buffer gnus-uu-digest-buffer)
+       (let ((fs gnus-uu-digest-from-subject))
+         (when fs
+           (setq from (caar fs)
+                 subject (gnus-simplify-subject-fuzzy (cdar fs))
+                 fs (cdr fs))
+           (while (and fs (or from subject))
+             (when from
+               (unless (string= from (caar fs))
+                 (setq from nil)))
+             (when subject
+               (unless (string= (gnus-simplify-subject-fuzzy (cdar fs))
+                                subject)
+                 (setq subject nil)))
+             (setq fs (cdr fs))))
+         (unless subject
+           (setq subject "Digested Articles"))
+         (unless from
+           (setq from
+                 (if (gnus-news-group-p gnus-newsgroup-name)
+                     gnus-newsgroup-name
+                   "Various"))))
+       (goto-char (point-min))
+       (when (re-search-forward "^Subject: ")
+         (delete-region (point) (point-at-eol))
+         (insert subject))
+       (goto-char (point-min))
+       (when (re-search-forward "^From:")
+         (delete-region (point) (point-at-eol))
+         (insert " " from))
+       (let ((message-forward-decoded-p t))
+         (message-forward post t))))
     (setq gnus-uu-digest-from-subject nil)))
 
 (defun gnus-uu-digest-post-forward (&optional n)
@@ -566,31 +551,60 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 ;; Process marking.
 
+(defun gnus-message-process-mark (unmarkp new-marked)
+  (let ((old (- (length gnus-newsgroup-processable) (length new-marked))))
+    (gnus-message 6 "%d mark%s %s%s"
+                 (length new-marked)
+                 (if (= (length new-marked) 1) "" "s")
+                 (if unmarkp "removed" "added")
+                 (cond
+                  ((and (zerop old)
+                        (not unmarkp))
+                   "")
+                  (unmarkp
+                   (format ", %d remain marked"
+                           (length gnus-newsgroup-processable)))
+                  (t
+                   (format ", %d already marked" old))))))
+
+(defun gnus-new-processable (unmarkp articles)
+  (if unmarkp
+      (gnus-intersection gnus-newsgroup-processable articles)
+    (gnus-set-difference articles gnus-newsgroup-processable)))
+
 (defun gnus-uu-mark-by-regexp (regexp &optional unmark)
-  "Ask for a regular expression and set the process mark on all articles that match."
-  (interactive (list (read-from-minibuffer "Mark (regexp): ")))
-  (let ((articles (gnus-uu-find-articles-matching regexp)))
-    (while articles
-      (if unmark
-         (gnus-summary-remove-process-mark (pop articles))
-       (gnus-summary-set-process-mark (pop articles))))
-    (message ""))
+  "Set the process mark on articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP.
+Optional UNMARK non-nil means unmark instead of mark."
+  (interactive "sMark (regexp): \nP")
+  (save-excursion
+    (let* ((articles (gnus-uu-find-articles-matching regexp))
+          (new-marked (gnus-new-processable unmark articles)))
+      (while articles
+       (if unmark
+           (gnus-summary-remove-process-mark (pop articles))
+         (gnus-summary-set-process-mark (pop articles))))
+      (gnus-message-process-mark unmark new-marked)))
   (gnus-summary-position-point))
 
-(defun gnus-uu-unmark-by-regexp (regexp &optional unmark)
-  "Ask for a regular expression and remove the process mark on all articles that match."
-  (interactive (list (read-from-minibuffer "Mark (regexp): ")))
+(defun gnus-uu-unmark-by-regexp (regexp)
+  "Remove the process mark from articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP."
+  (interactive "sUnmark (regexp): ")
   (gnus-uu-mark-by-regexp regexp t))
 
-(defun gnus-uu-mark-series ()
+(defun gnus-uu-mark-series (&optional silent)
   "Mark the current series with the process mark."
   (interactive)
-  (let ((articles (gnus-uu-find-articles-matching)))
+  (let* ((articles (gnus-uu-find-articles-matching))
+        (l (length articles)))
     (while articles
       (gnus-summary-set-process-mark (car articles))
       (setq articles (cdr articles)))
-    (message ""))
-  (gnus-summary-position-point))
+    (unless silent
+      (gnus-message 6 "Marked %d articles" l))
+    (gnus-summary-position-point)
+    l))
 
 (defun gnus-uu-mark-region (beg end &optional unmark)
   "Set the process mark on all articles between point and mark."
@@ -622,10 +636,12 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 (defun gnus-uu-mark-thread ()
   "Marks all articles downwards in this thread."
   (interactive)
-  (let ((level (gnus-summary-thread-level)))
-    (while (and (gnus-summary-set-process-mark (gnus-summary-article-number))
-               (zerop (gnus-summary-next-subject 1))
-               (> (gnus-summary-thread-level) level))))
+  (gnus-save-hidden-threads
+    (let ((level (gnus-summary-thread-level)))
+      (while (and (gnus-summary-set-process-mark
+                  (gnus-summary-article-number))
+                 (zerop (gnus-summary-next-subject 1 nil t))
+                 (> (gnus-summary-thread-level) level)))))
   (gnus-summary-position-point))
 
 (defun gnus-uu-unmark-thread ()
@@ -654,7 +670,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 (defun gnus-uu-mark-over (&optional score)
   "Mark all articles with a score over SCORE (the prefix)."
   (interactive "P")
-  (let ((score (gnus-score-default score))
+  (let ((score (or score gnus-summary-default-score 0))
        (data gnus-newsgroup-data))
     (save-excursion
       (while data
@@ -696,14 +712,16 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   (setq gnus-newsgroup-processable nil)
   (save-excursion
     (let ((data gnus-newsgroup-data)
+         (count 0)
          number)
       (while data
        (when (and (not (memq (setq number (gnus-data-number (car data)))
                              gnus-newsgroup-processable))
                   (vectorp (gnus-data-header (car data))))
          (gnus-summary-goto-subject number)
-         (gnus-uu-mark-series))
-       (setq data (cdr data)))))
+         (setq count (+ count (gnus-uu-mark-series t))))
+       (setq data (cdr data)))
+      (gnus-message 6 "Marked %d articles" count)))
   (gnus-summary-position-point))
 
 ;; All PostScript functions written by Erik Selberg <speed@cs.washington.edu>.
@@ -808,18 +826,17 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 (defun gnus-uu-save-article (buffer in-state)
   (cond
    (gnus-uu-save-separate-articles
-    (save-excursion
-      (set-buffer buffer)
-      (gnus-write-buffer
-       (concat gnus-uu-saved-article-name gnus-current-article))
+    (with-current-buffer buffer
+      (let ((coding-system-for-write mm-text-coding-system))
+       (gnus-write-buffer
+        (concat gnus-uu-saved-article-name gnus-current-article)))
       (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
            ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
                                                 'begin 'end))
            ((eq in-state 'last) (list 'end))
            (t (list 'middle)))))
    ((not gnus-uu-save-in-digest)
-    (save-excursion
-      (set-buffer buffer)
+    (with-current-buffer buffer
       (write-region (point-min) (point-max) gnus-uu-saved-article-name t)
       (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
            ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
@@ -837,40 +854,48 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
              (eq in-state 'first-and-last))
          (progn
            (setq state (list 'begin))
-           (save-excursion
-             (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
+           (with-current-buffer (gnus-get-buffer-create "*gnus-uu-body*")
              (erase-buffer))
-           (save-excursion
-             (set-buffer (gnus-get-buffer-create "*gnus-uu-pre*"))
+           (with-current-buffer (gnus-get-buffer-create "*gnus-uu-pre*")
              (erase-buffer)
              (insert (format
-                      "Date: %s\nFrom: %s\nSubject: %s Digest\n\nTopics:\n"
-                      (current-time-string) name name))))
+                      "Date: %s\nFrom: %s\nSubject: %s Digest\n\n"
+                      (message-make-date) name name))
+             (when (and message-forward-as-mime gnus-uu-digest-buffer)
+               (insert
+                "<#mml type=message/rfc822>\nSubject: Topics\n\n<#/mml>\n")
+               (forward-line -1))
+             (insert "Topics:\n")))
        (when (not (eq in-state 'end))
          (setq state (list 'middle))))
-      (save-excursion
-       (set-buffer "*gnus-uu-body*")
+      (with-current-buffer "*gnus-uu-body*"
        (goto-char (setq beg (point-max)))
        (save-excursion
          (save-restriction
            (set-buffer buffer)
            (let (buffer-read-only)
-             (gnus-set-text-properties (point-min) (point-max) nil)
+             (set-text-properties (point-min) (point-max) nil)
              ;; These two are necessary for XEmacs 19.12 fascism.
              (put-text-property (point-min) (point-max) 'invisible nil)
              (put-text-property (point-min) (point-max) 'intangible nil))
+           (when (and message-forward-as-mime
+                      message-forward-show-mml
+                      gnus-uu-digest-buffer)
+             (mm-enable-multibyte)
+             (mime-to-mml))
            (goto-char (point-min))
-           (re-search-forward "\n\n")
-           ;; Quote all 30-dash lines.
-           (save-excursion
-             (while (re-search-forward "^-" nil t)
-               (beginning-of-line)
-               (delete-char 1)
-               (insert "- ")))
+           (search-forward "\n\n")
+           (unless (and message-forward-as-mime gnus-uu-digest-buffer)
+             ;; Quote all 30-dash lines.
+             (save-excursion
+               (while (re-search-forward "^-" nil t)
+                 (beginning-of-line)
+                 (delete-char 1)
+                 (insert "- "))))
            (setq body (buffer-substring (1- (point)) (point-max)))
            (narrow-to-region (point-min) (point))
            (if (not (setq headers gnus-uu-digest-headers))
-               (setq sorthead (buffer-substring (point-min) (point-max)))
+               (setq sorthead (buffer-string))
              (while headers
                (setq headline (car headers))
                (setq headers (cdr headers))
@@ -884,30 +909,63 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                                          (1- (point)))
                                     (progn (forward-line 1) (point)))))))))
            (widen)))
-       (insert sorthead) (goto-char (point-max))
-       (insert body) (goto-char (point-max))
-       (insert (concat "\n" (make-string 30 ?-) "\n\n"))
+       (if (and message-forward-as-mime gnus-uu-digest-buffer)
+         (if message-forward-show-mml
+             (progn
+               (insert "\n<#mml type=message/rfc822>\n")
+               (insert sorthead) (goto-char (point-max))
+               (insert body) (goto-char (point-max))
+               (insert "\n<#/mml>\n"))
+           (let ((buf (mml-generate-new-buffer " *mml*")))
+             (with-current-buffer buf
+               (insert sorthead)
+               (goto-char (point-min))
+               (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
+                 (setq subj (buffer-substring (match-beginning 1)
+                                              (match-end 1))))
+               (goto-char (point-max))
+               (insert body))
+             (insert "\n<#part type=message/rfc822"
+                     " buffer=\"" (buffer-name buf) "\">\n")))
+         (insert sorthead) (goto-char (point-max))
+         (insert body) (goto-char (point-max))
+         (insert (concat "\n" (make-string 30 ?-) "\n\n")))
        (goto-char beg)
        (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
-         (setq subj (buffer-substring (match-beginning 1) (match-end 1)))
-         (save-excursion
-           (set-buffer "*gnus-uu-pre*")
+         (setq subj (buffer-substring (match-beginning 1) (match-end 1))))
+       (when subj
+         (with-current-buffer "*gnus-uu-pre*"
            (insert (format "   %s\n" subj)))))
       (when (or (eq in-state 'last)
                (eq in-state 'first-and-last))
-       (save-excursion
-         (set-buffer "*gnus-uu-pre*")
-         (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
-         (gnus-write-buffer gnus-uu-saved-article-name))
-       (save-excursion
-         (set-buffer "*gnus-uu-body*")
-         (goto-char (point-max))
-         (insert
-          (concat (setq end-string (format "End of %s Digest" name))
-                  "\n"))
-         (insert (concat (make-string (length end-string) ?*) "\n"))
-         (write-region
-          (point-min) (point-max) gnus-uu-saved-article-name t))
+       (if (and message-forward-as-mime gnus-uu-digest-buffer)
+           (with-current-buffer gnus-uu-digest-buffer
+             (erase-buffer)
+             (insert-buffer-substring "*gnus-uu-pre*")
+             (goto-char (point-max))
+             (insert-buffer-substring "*gnus-uu-body*"))
+         (with-current-buffer "*gnus-uu-pre*"
+           (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
+           (if gnus-uu-digest-buffer
+               (with-current-buffer gnus-uu-digest-buffer
+                 (erase-buffer)
+                 (insert-buffer-substring "*gnus-uu-pre*"))
+             (let ((coding-system-for-write mm-text-coding-system))
+               (gnus-write-buffer gnus-uu-saved-article-name))))
+         (with-current-buffer "*gnus-uu-body*"
+           (goto-char (point-max))
+           (insert
+            (concat (setq end-string (format "End of %s Digest" name))
+                    "\n"))
+           (insert (concat (make-string (length end-string) ?*) "\n"))
+           (if gnus-uu-digest-buffer
+               (with-current-buffer gnus-uu-digest-buffer
+                 (goto-char (point-max))
+                 (insert-buffer-substring "*gnus-uu-body*"))
+             (let ((coding-system-for-write mm-text-coding-system)
+                   (file-name-coding-system nnmail-pathname-coding-system))
+               (write-region
+                (point-min) (point-max) gnus-uu-saved-article-name t)))))
        (gnus-kill-buffer "*gnus-uu-pre*")
        (gnus-kill-buffer "*gnus-uu-body*")
        (push 'end state))
@@ -926,8 +984,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defun gnus-uu-binhex-article (buffer in-state)
   (let (state start-char)
-    (save-excursion
-      (set-buffer buffer)
+    (with-current-buffer buffer
       (widen)
       (goto-char (point-min))
       (when (not (re-search-forward gnus-uu-binhex-begin-line nil t))
@@