changeset 31716:9968f55ad26e

Update to emacs-21-branch of the Gnus CVS repository.
author Gerd Moellmann <gerd@gnu.org>
date Tue, 19 Sep 2000 13:37:09 +0000
parents 7c896543d225
children 6b20b7e85e3c
files lisp/gnus/earcon.el lisp/gnus/gnus-agent.el lisp/gnus/gnus-art.el lisp/gnus/gnus-async.el lisp/gnus/gnus-audio.el lisp/gnus/gnus-bcklg.el lisp/gnus/gnus-cache.el lisp/gnus/gnus-cite.el lisp/gnus/gnus-cus.el lisp/gnus/gnus-demon.el lisp/gnus/gnus-draft.el lisp/gnus/gnus-dup.el lisp/gnus/gnus-eform.el lisp/gnus/gnus-ems.el lisp/gnus/gnus-gl.el lisp/gnus/gnus-group.el lisp/gnus/gnus-int.el lisp/gnus/gnus-kill.el lisp/gnus/gnus-logic.el lisp/gnus/gnus-mh.el lisp/gnus/gnus-move.el lisp/gnus/gnus-msg.el lisp/gnus/gnus-nocem.el lisp/gnus/gnus-range.el lisp/gnus/gnus-salt.el lisp/gnus/gnus-score.el lisp/gnus/gnus-setup.el lisp/gnus/gnus-soup.el lisp/gnus/gnus-spec.el lisp/gnus/gnus-srvr.el lisp/gnus/gnus-start.el lisp/gnus/gnus-sum.el lisp/gnus/gnus-topic.el lisp/gnus/gnus-undo.el lisp/gnus/gnus-util.el lisp/gnus/gnus-uu.el lisp/gnus/gnus-vm.el lisp/gnus/gnus-win.el lisp/gnus/gnus.el lisp/gnus/message.el lisp/gnus/messcompat.el lisp/gnus/nnagent.el lisp/gnus/nnbabyl.el lisp/gnus/nndir.el lisp/gnus/nndoc.el lisp/gnus/nndraft.el lisp/gnus/nneething.el lisp/gnus/nnfolder.el lisp/gnus/nngateway.el lisp/gnus/nnheader.el lisp/gnus/nnkiboze.el lisp/gnus/nnlistserv.el lisp/gnus/nnmail.el lisp/gnus/nnmbox.el lisp/gnus/nnmh.el lisp/gnus/nnml.el lisp/gnus/nnoo.el lisp/gnus/nnsoup.el lisp/gnus/nnspool.el lisp/gnus/nntp.el lisp/gnus/nnvirtual.el lisp/gnus/nnweb.el lisp/gnus/parse-time.el lisp/gnus/pop3.el lisp/gnus/score-mode.el
diffstat 65 files changed, 10750 insertions(+), 5972 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/gnus/earcon.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/earcon.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,7 +1,11 @@
 ;;; earcon.el --- Sound effects for messages
-;; Copyright (C) 1996 Free Software Foundation
+
+;; Copyright (C) 1996, 2000 Free Software Foundation
 
 ;; Author: Steven L. Baur <steve@miranova.com>
+
+;; This file is part of GNU Emacs.
+
 ;; 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)
@@ -16,8 +20,10 @@
 ;; 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.
+;; This file is part of GNU Emacs.
 
 ;;; Commentary:
+
 ;; This file provides access to sound effects in Gnus.
 
 ;;; Code:
@@ -74,8 +80,6 @@
 (defvar earcon-button-marker-list nil)
 (make-variable-buffer-local 'earcon-button-marker-list)
 
-
-
 ;;; FIXME!! clone of code from gnus-vis.el FIXME!!
 (defun earcon-article-push-button (event)
   "Check text under the mouse pointer for a callback function.
@@ -156,7 +160,6 @@
 	(setq entry nil)))
     entry))
 
-
 (defun earcon-button-push (marker)
   ;; Push button starting at MARKER.
   (save-excursion
--- a/lisp/gnus/gnus-agent.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-agent.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; gnus-agent.el --- unplugged support for Gnus
-;; Copyright (C) 1997,98 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; This file is part of GNU Emacs.
@@ -27,7 +27,10 @@
 (require 'gnus-cache)
 (require 'nnvirtual)
 (require 'gnus-sum)
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'timer)
+  (require 'cl)
+  (require 'gnus-score))
 
 (defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
   "Where the Gnus agent will store its files."
@@ -75,9 +78,12 @@
   :group 'gnus-agent
   :type 'hook)
 
-;;; Internal variables
+(defcustom gnus-agent-confirmation-function 'y-or-n-p
+  "Function to confirm when error happens."
+  :group 'gnus-agent
+  :type 'function)
 
-(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
+;;; Internal variables
 
 (defvar gnus-agent-history-buffers nil)
 (defvar gnus-agent-buffer-alist nil)
@@ -92,7 +98,11 @@
 (defvar gnus-agent-spam-hashtb nil)
 (defvar gnus-agent-file-name nil)
 (defvar gnus-agent-send-mail-function nil)
-(defvar gnus-agent-file-coding-system 'no-conversion)
+(defvar gnus-agent-file-coding-system 'raw-text)
+
+(defconst gnus-agent-scoreable-headers
+  '("subject" "from" "date" "message-id" "references" "chars" "lines" "xref")
+  "Headers that are considered when scoring articles for download via the Agent.")
 
 ;; Dynamic variables
 (defvar gnus-headers)
@@ -106,12 +116,20 @@
   (setq gnus-agent t)
   (gnus-agent-read-servers)
   (gnus-category-read)
-  (setq gnus-agent-overview-buffer
-	(gnus-get-buffer-create " *Gnus agent overview*"))
+  (gnus-agent-create-buffer)
   (add-hook 'gnus-group-mode-hook 'gnus-agent-mode)
   (add-hook 'gnus-summary-mode-hook 'gnus-agent-mode)
   (add-hook 'gnus-server-mode-hook 'gnus-agent-mode))
 
+(defun gnus-agent-create-buffer ()
+  (if (gnus-buffer-live-p gnus-agent-overview-buffer)
+      t
+    (setq gnus-agent-overview-buffer
+	  (gnus-get-buffer-create " *Gnus agent overview*"))
+    (with-current-buffer gnus-agent-overview-buffer
+      (mm-enable-multibyte))
+    nil))
+
 (gnus-add-shutdown 'gnus-close-agent 'gnus)
 
 (defun gnus-close-agent ()
@@ -127,7 +145,7 @@
 
 (defun gnus-agent-read-file (file)
   "Load FILE and do a `read' there."
-  (nnheader-temp-write nil
+  (with-temp-buffer
     (ignore-errors
       (nnheader-insert-file-contents file)
       (goto-char (point-min))
@@ -153,7 +171,8 @@
 (defun gnus-agent-start-fetch ()
   "Initialize data structures for efficient fetching."
   (gnus-agent-open-history)
-  (setq gnus-agent-current-history (gnus-agent-history-buffer)))
+  (setq gnus-agent-current-history (gnus-agent-history-buffer))
+  (gnus-agent-create-buffer))
 
 (defun gnus-agent-stop-fetch ()
   "Save all data structures and clean up."
@@ -214,8 +233,10 @@
   "Jc" gnus-enter-category-buffer
   "Jj" gnus-agent-toggle-plugged
   "Js" gnus-agent-fetch-session
+  "JY" gnus-agent-synchronize
   "JS" gnus-group-send-drafts
-  "Ja" gnus-agent-add-group)
+  "Ja" gnus-agent-add-group
+  "Jr" gnus-agent-remove-group)
 
 (defun gnus-agent-group-make-menu-bar ()
   (unless (boundp 'gnus-agent-group-menu)
@@ -334,7 +355,7 @@
      (concat "^" (regexp-quote mail-header-separator) "\n"))
     (replace-match "\n")
     (gnus-agent-insert-meta-information 'mail)
-    (gnus-request-accept-article "nndraft:queue")))
+    (gnus-request-accept-article "nndraft:queue" nil t t)))
 
 (defun gnus-agent-insert-meta-information (type &optional method)
   "Insert meta-information into the message that says how it's to be posted.
@@ -357,11 +378,15 @@
 (defun gnus-agent-fetch-groups (n)
   "Put all new articles in the current groups into the Agent."
   (interactive "P")
+  (unless gnus-plugged
+    (error "Groups can't be fetched when Gnus is unplugged"))
   (gnus-group-iterate n 'gnus-agent-fetch-group))
 
 (defun gnus-agent-fetch-group (group)
   "Put all new articles in GROUP into the Agent."
   (interactive (list (gnus-group-group-name)))
+  (unless gnus-plugged
+    (error "Groups can't be fetched when Gnus is unplugged"))
   (unless group
     (error "No group on the current line"))
   (let ((gnus-command-method (gnus-find-method-for-group group)))
@@ -390,6 +415,38 @@
     (setf (cadddr cat) (nconc (cadddr cat) groups))
     (gnus-category-write)))
 
+(defun gnus-agent-remove-group (arg)
+  "Remove the current group from its agent category, if any."
+  (interactive "P")
+  (let (c)
+    (gnus-group-iterate arg
+      (lambda (group)
+	(when (cadddr (setq c (gnus-group-category group)))
+	  (setf (cadddr c) (delete group (cadddr c))))))
+    (gnus-category-write)))
+
+(defun gnus-agent-synchronize ()
+  "Synchronize local, unplugged, data with backend.
+Currently sends flag setting requests, if any."
+  (interactive)
+  (save-excursion
+    (dolist (gnus-command-method gnus-agent-covered-methods)
+      (when (file-exists-p (gnus-agent-lib-file "flags"))
+	(set-buffer (get-buffer-create " *Gnus Agent flag synchronize*"))
+	(erase-buffer)
+	(nnheader-insert-file-contents (gnus-agent-lib-file "flags"))
+	(if (null (gnus-check-server gnus-command-method))
+	    (message "Couldn't open server %s" (nth 1 gnus-command-method))
+	  (while (not (eobp))
+	    (if (null (eval (read (current-buffer))))
+		(progn (forward-line)
+		       (kill-line -1))
+	      (write-file (gnus-agent-lib-file "flags"))
+	      (error "Couldn't set flags from file %s"
+		     (gnus-agent-lib-file "flags"))))
+	  (write-file (gnus-agent-lib-file "flags")))
+        (kill-buffer nil)))))
+
 ;;;
 ;;; Server mode commands
 ;;;
@@ -427,8 +484,11 @@
 
 (defun gnus-agent-write-servers ()
   "Write the alist of covered servers."
-  (nnheader-temp-write (nnheader-concat gnus-agent-directory "lib/servers")
-    (prin1 gnus-agent-covered-methods (current-buffer))))
+  (gnus-make-directory (nnheader-concat gnus-agent-directory "lib"))
+  (let ((coding-system-for-write nnheader-file-coding-system)
+	(file-name-coding-system nnmail-pathname-coding-system))
+    (with-temp-file (nnheader-concat gnus-agent-directory "lib/servers")
+      (prin1 gnus-agent-covered-methods (current-buffer)))))
 
 ;;;
 ;;; Summary commands
@@ -492,12 +552,24 @@
     (when (and (not gnus-plugged)
 	       (gnus-agent-method-p gnus-command-method))
       (gnus-agent-load-alist gnus-newsgroup-name)
-      (let ((articles gnus-newsgroup-unreads)
+      ;; First mark all undownloaded articles as undownloaded.
+      (let ((articles (append gnus-newsgroup-unreads
+			      gnus-newsgroup-marked
+			      gnus-newsgroup-dormant))
 	    article)
 	(while (setq article (pop articles))
 	  (unless (or (cdr (assq article gnus-agent-article-alist))
-		  (memq article gnus-newsgroup-downloadable))
-	    (push article gnus-newsgroup-undownloaded)))))))
+		      (memq article gnus-newsgroup-downloadable)
+		      (memq article gnus-newsgroup-cached))
+	    (push article gnus-newsgroup-undownloaded))))
+      ;; Then mark downloaded downloadable as not-downloadable,
+      ;; if you get my drift.
+      (let ((articles gnus-newsgroup-downloadable)
+	    article)
+	(while (setq article (pop articles))
+	  (when (cdr (assq article gnus-agent-article-alist))
+	    (setq gnus-newsgroup-downloadable
+		  (delq article gnus-newsgroup-downloadable))))))))
 
 (defun gnus-agent-catchup ()
   "Mark all undownloaded articles as read."
@@ -513,53 +585,86 @@
 ;;;
 
 (defun gnus-agent-save-active (method)
+  (gnus-agent-save-active-1 method 'gnus-active-to-gnus-format))
+
+(defun gnus-agent-save-active-1 (method function)
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method method)
+	   (new (gnus-make-hashtable (count-lines (point-min) (point-max))))
 	   (file (gnus-agent-lib-file "active")))
-      (gnus-make-directory (file-name-directory file))
-      (let ((coding-system-for-write gnus-agent-file-coding-system))
-	(write-region (point-min) (point-max) file nil 'silent))
-      (when (file-exists-p (gnus-agent-lib-file "groups"))
-	(delete-file (gnus-agent-lib-file "groups"))))))
+      (funcall function nil new)
+      (gnus-agent-write-active file new)
+      (erase-buffer)
+      (nnheader-insert-file-contents file))))
+
+(defun gnus-agent-write-active (file new)
+  (let ((orig (gnus-make-hashtable (count-lines (point-min) (point-max))))
+	(file (gnus-agent-lib-file "active"))
+	elem osym)
+    (when (file-exists-p file)
+      (with-temp-buffer
+	(nnheader-insert-file-contents file)
+	(gnus-active-to-gnus-format nil orig))
+      (mapatoms
+       (lambda (sym)
+	 (when (and sym (boundp sym))
+	   (if (and (boundp (setq osym (intern (symbol-name sym) orig)))
+		    (setq elem (symbol-value osym)))
+	       (setcdr elem (cdr (symbol-value sym)))
+	     (set (intern (symbol-name sym) orig) (symbol-value sym)))))
+       new))
+    (gnus-make-directory (file-name-directory file))
+    (let ((coding-system-for-write gnus-agent-file-coding-system))
+      ;; The hashtable contains real names of groups,  no more prefix
+      ;; removing, so set `full' to `t'.
+      (gnus-write-active-file file orig t))))
 
 (defun gnus-agent-save-groups (method)
-  (let* ((gnus-command-method method)
-	 (file (gnus-agent-lib-file "groups")))
-    (gnus-make-directory (file-name-directory file))
-    (let ((coding-system-for-write gnus-agent-file-coding-system))
-      (write-region (point-min) (point-max) file nil 'silent))
-    (when (file-exists-p (gnus-agent-lib-file "active"))
-      (delete-file (gnus-agent-lib-file "active")))))
+  (gnus-agent-save-active-1 method 'gnus-groups-to-gnus-format))
 
 (defun gnus-agent-save-group-info (method group active)
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method method)
-	   (file (if nntp-server-list-active-group
-		     (gnus-agent-lib-file "active")
-		   (gnus-agent-lib-file "groups"))))
+	   (coding-system-for-write nnheader-file-coding-system)
+	   (file-name-coding-system nnmail-pathname-coding-system)
+	   (file (gnus-agent-lib-file "active"))
+	   oactive)
       (gnus-make-directory (file-name-directory file))
-      (nnheader-temp-write file
+      (with-temp-file file
+	;; Emacs got problem to match non-ASCII group in multibyte buffer.
+	(mm-disable-multibyte) 
 	(when (file-exists-p file)
 	  (nnheader-insert-file-contents file))
 	(goto-char (point-min))
-	(if nntp-server-list-active-group
-	    (progn
-	      (when (re-search-forward
-		     (concat "^" (regexp-quote group) " ") nil t)
-		(gnus-delete-line))
-	      (insert group " " (number-to-string (cdr active)) " "
-		      (number-to-string (car active)) " y\n"))
-	  (when (re-search-forward (concat (regexp-quote group) " ") nil t)
-	    (gnus-delete-line))
-	  (insert-buffer-substring nntp-server-buffer))))))
+	(when (re-search-forward
+	       (concat "^" (regexp-quote group) " ") nil t)
+	  (save-excursion
+	    (save-restriction
+	      (narrow-to-region (match-beginning 0)
+				(progn
+				  (forward-line 1)
+				  (point)))
+	      (setq oactive (car (nnmail-parse-active)))))
+	  (gnus-delete-line))
+	(insert (format "%S %d %d y\n" (intern group)
+			(cdr active)
+			(or (car oactive) (car active))))
+	(goto-char (point-max))
+	(while (search-backward "\\." nil t)
+	  (delete-char 1))))))
 
 (defun gnus-agent-group-path (group)
   "Translate GROUP into a path."
   (if nnmail-use-long-file-names
       (gnus-group-real-name group)
-    (nnheader-replace-chars-in-string
-     (nnheader-translate-file-chars (gnus-group-real-name group))
-     ?. ?/)))
+    (nnheader-translate-file-chars
+     (nnheader-replace-chars-in-string
+      (nnheader-replace-duplicate-chars-in-string
+       (nnheader-replace-chars-in-string 
+	(gnus-group-real-name group)
+	?/ ?_)
+       ?. ?_)
+      ?. ?/))))
 
 
 
@@ -587,11 +692,12 @@
 			     (format " *Gnus agent %s history*"
 				     (gnus-agent-method)))))
 	  gnus-agent-history-buffers)
+    (mm-disable-multibyte) ;; everything is binary
     (erase-buffer)
     (insert "\n")
     (let ((file (gnus-agent-lib-file "history")))
       (when (file-exists-p file)
-	(insert-file file))
+	(nnheader-insert-file-contents file))
       (set (make-local-variable 'gnus-agent-file-name) file))))
 
 (defun gnus-agent-save-history ()
@@ -613,11 +719,15 @@
   (save-excursion
     (set-buffer gnus-agent-current-history)
     (goto-char (point-max))
-    (insert id "\t" (number-to-string date) "\t")
-    (while group-arts
-      (insert (caar group-arts) " " (number-to-string (cdr (pop group-arts)))
-	      " "))
-    (insert "\n")))
+    (let ((p (point)))
+      (insert id "\t" (number-to-string date) "\t")
+      (while group-arts
+	(insert (format "%S" (intern (caar group-arts)))
+		" " (number-to-string (cdr (pop group-arts)))
+		" "))
+      (insert "\n")
+      (while (search-backward "\\." p t)
+	(delete-char 1)))))
 
 (defun gnus-agent-article-in-history-p (id)
   (save-excursion
@@ -646,7 +756,7 @@
     ;; Prune off articles that we have already fetched.
     (while (and articles
 		(cdr (assq (car articles) gnus-agent-article-alist)))
-     (pop articles))
+      (pop articles))
     (let ((arts articles))
       (while (cdr arts)
 	(if (cdr (assq (cadr arts) gnus-agent-article-alist))
@@ -656,7 +766,7 @@
       (let ((dir (concat
 		  (gnus-agent-directory)
 		  (gnus-agent-group-path group) "/"))
-	    (date (gnus-time-to-day (current-time)))
+	    (date (time-to-days (current-time)))
 	    (case-fold-search t)
 	    pos crosses id elem)
 	(gnus-make-directory dir)
@@ -664,10 +774,13 @@
 	;; Fetch the articles from the backend.
 	(if (gnus-check-backend-function 'retrieve-articles group)
 	    (setq pos (gnus-retrieve-articles articles group))
-	  (nnheader-temp-write nil
+	  (with-temp-buffer
 	    (let (article)
 	      (while (setq article (pop articles))
-		(when (gnus-request-article article group)
+		(when (or 
+		       (gnus-backlog-request-article group article 
+						     nntp-server-buffer)
+		       (gnus-request-article article group))
 		  (goto-char (point-max))
 		  (push (cons article (point)) pos)
 		  (insert-buffer-substring nntp-server-buffer)))
@@ -726,7 +839,7 @@
       (setcdr alist (cons (cons (cdar crosses) t) (cdr alist)))
       (save-excursion
 	(set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*"
-					       group)))
+						    group)))
 	(when (= (point-max) (point-min))
 	  (push (cons group (current-buffer)) gnus-agent-buffer-alist)
 	  (ignore-errors
@@ -749,43 +862,65 @@
 		      nil 'silent))
       (pop gnus-agent-buffer-alist))
     (while gnus-agent-group-alist
-      (nnheader-temp-write (caar gnus-agent-group-alist)
+      (with-temp-file (caar gnus-agent-group-alist)
 	(princ (cdar gnus-agent-group-alist))
 	(insert "\n"))
       (pop gnus-agent-group-alist))))
 
+(if (fboundp 'union)
+    (defalias 'gnus-agent-union 'union)
+  (defun gnus-agent-union (l1 l2)
+    "Set union of lists L1 and L2."
+    (cond ((null l1) l2)
+	  ((null l2) l1)
+	  ((equal l1 l2) l1)
+	  (t
+	   (or (>= (length l1) (length l2))
+	       (setq l1 (prog1 l2 (setq l2 l1))))
+	   (while l2
+	     (or (memq (car l2) l1)
+		 (push (car l2) l1))
+	     (pop l2))
+	   l1))))
+
 (defun gnus-agent-fetch-headers (group &optional force)
-  (let ((articles (if (gnus-agent-load-alist group)
-		      (gnus-sorted-intersection
-		       (gnus-list-of-unread-articles group)
-		       (gnus-uncompress-range
-			(cons (1+ (caar (last gnus-agent-article-alist)))
-			      (cdr (gnus-active group)))))
-		    (gnus-list-of-unread-articles group))))
+  (let ((articles (gnus-list-of-unread-articles group))
+	(gnus-decode-encoded-word-function 'identity)
+	(file (gnus-agent-article-name ".overview" group)))
+    ;; Add article with marks to list of article headers we want to fetch.
+    (dolist (arts (gnus-info-marks (gnus-get-info group)))
+      (setq articles (gnus-agent-union (gnus-uncompress-sequence (cdr arts))
+			    articles)))
+    (setq articles (sort articles '<))
+    ;; Remove known articles.
+    (when (gnus-agent-load-alist group)
+      (setq articles (gnus-sorted-intersection
+		      articles
+		      (gnus-uncompress-range
+		       (cons (1+ (caar (last gnus-agent-article-alist)))
+			     (cdr (gnus-active group)))))))
     ;; Fetch them.
+    (gnus-make-directory (nnheader-translate-file-chars
+			  (file-name-directory file) t))
     (when articles
       (gnus-message 7 "Fetching headers for %s..." group)
       (save-excursion
-	(set-buffer nntp-server-buffer)
-	(unless (eq 'nov (gnus-retrieve-headers articles group))
-	  (nnvirtual-convert-headers))
-	;; Save these headers for later processing.
-	(copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
-	(let (file)
-	  (when (file-exists-p
-		 (setq file (gnus-agent-article-name ".overview" group)))
-	    (gnus-agent-braid-nov group articles file))
-	  (gnus-make-directory (nnheader-translate-file-chars
-				(file-name-directory file)))
- 	  (let ((coding-system-for-write
- 		 gnus-agent-file-coding-system))
- 	    (write-region (point-min) (point-max) file nil 'silent))
-	  (gnus-agent-save-alist group articles nil)
-	  (gnus-agent-enter-history
-	   "last-header-fetched-for-session"
-	   (list (cons group (nth (- (length  articles) 1) articles)))
-	   (gnus-time-to-day (current-time)))
-	  articles)))))
+ 	(set-buffer nntp-server-buffer)
+ 	(unless (eq 'nov (gnus-retrieve-headers articles group))
+ 	  (nnvirtual-convert-headers))
+ 	;; Save these headers for later processing.
+ 	(copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
+	(when (file-exists-p file)
+	  (gnus-agent-braid-nov group articles file))
+	(let ((coding-system-for-write
+	       gnus-agent-file-coding-system))
+	  (write-region (point-min) (point-max) file nil 'silent))
+	(gnus-agent-save-alist group articles nil)
+	(gnus-agent-enter-history
+	 "last-header-fetched-for-session"
+	 (list (cons group (nth (- (length  articles) 1) articles)))
+	 (time-to-days (current-time)))
+	articles))))
 
 (defsubst gnus-agent-copy-nov-line (article)
   (let (b e)
@@ -846,26 +981,33 @@
 
 (defun gnus-agent-save-alist (group &optional articles state dir)
   "Save the article-state alist for GROUP."
-  (nnheader-temp-write (if dir
-			   (concat dir ".agentview")
-			 (gnus-agent-article-name ".agentview" group))
-    (princ (setq gnus-agent-article-alist
-		 (nconc gnus-agent-article-alist
-			(mapcar (lambda (article) (cons article state))
-				articles)))
-	   (current-buffer))
-    (insert "\n")))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+      (with-temp-file (if dir
+			  (concat dir ".agentview")
+			(gnus-agent-article-name ".agentview" group))
+	(princ (setq gnus-agent-article-alist
+		     (nconc gnus-agent-article-alist
+			    (mapcar (lambda (article) (cons article state))
+				    articles)))
+	       (current-buffer))
+	(insert "\n"))))
 
 (defun gnus-agent-article-name (article group)
   (concat (gnus-agent-directory) (gnus-agent-group-path group) "/"
 	  (if (stringp article) article (string-to-number article))))
 
+(defun gnus-agent-batch-confirmation (msg)
+  "Show error message and return t."
+  (gnus-message 1 msg)
+  t)
+
 ;;;###autoload
 (defun gnus-agent-batch-fetch ()
   "Start Gnus and fetch session."
   (interactive)
   (gnus)
-  (gnus-agent-fetch-session)
+  (let ((gnus-agent-confirmation-function 'gnus-agent-batch-confirmation))
+    (gnus-agent-fetch-session))
   (gnus-group-exit))
 
 (defun gnus-agent-fetch-session ()
@@ -879,51 +1021,108 @@
 	groups group gnus-command-method)
     (save-excursion
       (while methods
-	(setq gnus-command-method (car methods))
-	(when (or (gnus-server-opened gnus-command-method)
-		  (gnus-open-server gnus-command-method))
-	  (setq groups (gnus-groups-from-server (car methods)))
-	  (gnus-agent-with-fetch
-	    (while (setq group (pop groups))
-	      (when (<= (gnus-group-level group) gnus-agent-handle-level)
-		(gnus-agent-fetch-group-1 group gnus-command-method)))))
+	(condition-case err
+	    (progn
+	      (setq gnus-command-method (car methods))
+	      (when (or (gnus-server-opened gnus-command-method)
+			(gnus-open-server gnus-command-method))
+		(setq groups (gnus-groups-from-server (car methods)))
+		(gnus-agent-with-fetch
+		  (while (setq group (pop groups))
+		    (when (<= (gnus-group-level group) gnus-agent-handle-level)
+		      (gnus-agent-fetch-group-1 group gnus-command-method))))))
+	  (error 
+	   (unless (funcall gnus-agent-confirmation-function
+			    (format "Error (%s).  Continue? " err))
+	     (error "Cannot fetch articles into the Gnus agent."))))
 	(pop methods))
       (gnus-message 6 "Finished fetching articles into the Gnus agent"))))
 
 (defun gnus-agent-fetch-group-1 (group method)
   "Fetch GROUP."
   (let ((gnus-command-method method)
+	(gnus-newsgroup-name group)
 	gnus-newsgroup-dependencies gnus-newsgroup-headers
 	gnus-newsgroup-scored gnus-headers gnus-score
 	gnus-use-cache articles arts
-	category predicate info marks score-param)
+	category predicate info marks score-param
+	(gnus-summary-expunge-below gnus-summary-expunge-below)
+	(gnus-summary-mark-below gnus-summary-mark-below)
+	(gnus-orphan-score gnus-orphan-score)
+	;; Maybe some other gnus-summary local variables should also
+	;; be put here.
+	)
+    (unless (gnus-check-group group)
+      (error "Can't open server for %s" group))
     ;; Fetch headers.
     (when (and (or (gnus-active group) (gnus-activate-group group))
-	       (setq articles (gnus-agent-fetch-headers group)))
-      ;; Parse them and see which articles we want to fetch.
-      (setq gnus-newsgroup-dependencies
-	    (make-vector (length articles) 0))
-      (setq gnus-newsgroup-headers
-	    (gnus-get-newsgroup-headers-xover articles nil nil group))
+	       (setq articles (gnus-agent-fetch-headers group))
+	       (progn
+		 ;; Parse them and see which articles we want to fetch.
+		 (setq gnus-newsgroup-dependencies
+		       (make-vector (length articles) 0))
+		 ;; No need to call `gnus-get-newsgroup-headers-xover' with
+		 ;; the entire .overview for group as we still have the just
+		 ;; downloaded headers in `gnus-agent-overview-buffer'.
+		 (let ((nntp-server-buffer gnus-agent-overview-buffer))
+		   (setq gnus-newsgroup-headers
+			 (gnus-get-newsgroup-headers-xover articles nil nil 
+							   group)))
+		 ;; `gnus-agent-overview-buffer' may be killed for
+		 ;; timeout reason.  If so, recreate it.
+		 (gnus-agent-create-buffer)))
       (setq category (gnus-group-category group))
       (setq predicate
 	    (gnus-get-predicate
-	     (or (gnus-group-get-parameter group 'agent-predicate)
+	     (or (gnus-group-find-parameter group 'agent-predicate t)
 		 (cadr category))))
-      (setq score-param
-	    (or (gnus-group-get-parameter group 'agent-score)
-		(caddr category)))
-      (when score-param
-	(gnus-score-headers (list (list score-param))))
-      (setq arts nil)
-      (while (setq gnus-headers (pop gnus-newsgroup-headers))
-	(setq gnus-score
-	      (or (cdr (assq (mail-header-number gnus-headers)
-			     gnus-newsgroup-scored))
-		  gnus-summary-default-score))
-	(when (funcall predicate)
-	  (push (mail-header-number gnus-headers)
-		arts)))
+      ;; Do we want to download everything, or nothing?
+      (if (or (eq (caaddr predicate) 'gnus-agent-true)
+	      (eq (caaddr predicate) 'gnus-agent-false))
+	  ;; Yes.
+	  (setq arts (symbol-value
+		      (cadr (assoc (caaddr predicate)
+				   '((gnus-agent-true articles)
+				     (gnus-agent-false nil))))))
+	;; No, we need to decide what we want.
+	(setq score-param
+	      (let ((score-method
+		     (or
+		      (gnus-group-find-parameter group 'agent-score t)
+		      (caddr category))))
+		(when score-method
+		  (require 'gnus-score)
+		  (if (eq score-method 'file)
+		      (let ((entries
+			     (gnus-score-load-files
+			      (gnus-all-score-files group)))
+			    list score-file)
+			(while (setq list (car entries))
+			  (push (car list) score-file)
+			  (setq list (cdr list))
+			  (while list
+			    (when (member (caar list)
+					  gnus-agent-scoreable-headers)
+			      (push (car list) score-file))
+			    (setq list (cdr list)))
+			  (setq score-param
+				(append score-param (list (nreverse score-file)))
+				score-file nil entries (cdr entries)))
+			(list score-param))
+		    (if (stringp (car score-method))
+			score-method
+		      (list (list score-method)))))))
+	(when score-param
+	  (gnus-score-headers score-param))
+	(setq arts nil)
+	(while (setq gnus-headers (pop gnus-newsgroup-headers))
+	  (setq gnus-score
+		(or (cdr (assq (mail-header-number gnus-headers)
+			       gnus-newsgroup-scored))
+		    gnus-summary-default-score))
+	  (when (funcall predicate)
+	    (push (mail-header-number gnus-headers)
+		  arts))))
       ;; Fetch the articles.
       (when arts
 	(gnus-agent-fetch-articles group arts)))
@@ -934,7 +1133,11 @@
       (gnus-agent-fetch-articles
        group (gnus-uncompress-range (cdr arts)))
       (setq marks (delq arts (gnus-info-marks info)))
-      (gnus-info-set-marks info marks))))
+      (gnus-info-set-marks info marks)
+      (gnus-dribble-enter
+       (concat "(gnus-group-set-info '"
+	       (gnus-prin1-to-string info)
+	       ")")))))
 
 ;;;
 ;;; Agent Category Mode
@@ -1036,7 +1239,7 @@
   (gnus-set-default-directory)
   (setq mode-line-process nil)
   (use-local-map gnus-category-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq truncate-lines t)
   (setq buffer-read-only t)
   (gnus-run-hooks 'gnus-category-mode-hook))
@@ -1093,7 +1296,8 @@
   "Write the category alist."
   (setq gnus-category-predicate-cache nil
 	gnus-category-group-cache nil)
-  (nnheader-temp-write (nnheader-concat gnus-agent-directory "lib/categories")
+  (gnus-make-directory (nnheader-concat gnus-agent-directory "lib"))
+  (with-temp-file (nnheader-concat gnus-agent-directory "lib/categories")
     (prin1 gnus-category-alist (current-buffer))))
 
 (defun gnus-category-edit-predicate (category)
@@ -1103,7 +1307,7 @@
     (gnus-edit-form
      (cadr info) (format "Editing the predicate for category %s" category)
      `(lambda (predicate)
-	(setf (cadr (assq ',category gnus-category-alist)) predicate)
+	(setcar (cdr (assq ',category gnus-category-alist)) predicate)
 	(gnus-category-write)
 	(gnus-category-list)))))
 
@@ -1115,7 +1319,7 @@
      (caddr info)
      (format "Editing the score expression for category %s" category)
      `(lambda (groups)
-	(setf (caddr (assq ',category gnus-category-alist)) groups)
+	(setcar (cddr (assq ',category gnus-category-alist)) groups)
 	(gnus-category-write)
 	(gnus-category-list)))))
 
@@ -1126,7 +1330,7 @@
     (gnus-edit-form
      (cadddr info) (format "Editing the group list for category %s" category)
      `(lambda (groups)
-	(setf (cadddr (assq ',category gnus-category-alist)) groups)
+	(setcar (nthcdr 3 (assq ',category gnus-category-alist)) groups)
 	(gnus-category-write)
 	(gnus-category-list)))))
 
@@ -1136,8 +1340,8 @@
   (let ((info (assq category gnus-category-alist))
 	(buffer-read-only nil))
     (gnus-delete-line)
-    (gnus-category-write)
-    (setq gnus-category-alist (delq info gnus-category-alist))))
+    (setq gnus-category-alist (delq info gnus-category-alist))
+    (gnus-category-write)))
 
 (defun gnus-category-copy (category to)
   "Copy the current category."
@@ -1154,7 +1358,7 @@
   (interactive "SCategory name: ")
   (when (assq category gnus-category-alist)
     (error "Category %s already exists" category))
-  (push (list category 'true nil nil)
+  (push (list category 'false nil nil)
 	gnus-category-alist)
   (gnus-category-write)
   (gnus-category-list))
@@ -1267,145 +1471,169 @@
   "Expire all old articles."
   (interactive)
   (let ((methods gnus-agent-covered-methods)
-	(day (- (gnus-time-to-day (current-time)) gnus-agent-expire-days))
+	(day (- (time-to-days (current-time)) gnus-agent-expire-days))
 	gnus-command-method sym group articles
 	history overview file histories elem art nov-file low info
-	unreads marked article)
+	unreads marked article orig lowest highest)
     (save-excursion
       (setq overview (gnus-get-buffer-create " *expire overview*"))
       (while (setq gnus-command-method (pop methods))
-	(let ((expiry-hashtb (gnus-make-hashtable 1023)))
-	(gnus-agent-open-history)
-	(set-buffer
-	 (setq gnus-agent-current-history
-	       (setq history (gnus-agent-history-buffer))))
-	(goto-char (point-min))
-	(when (> (buffer-size) 1)
-	  (goto-char (point-min))
-	  (while (not (eobp))
-	    (skip-chars-forward "^\t")
-	    (if (> (read (current-buffer)) day)
-		;; New article; we don't expire it.
-		(forward-line 1)
-	      ;; Old article.  Schedule it for possible nuking.
-	      (while (not (eolp))
-		(setq sym (let ((obarray expiry-hashtb))
-			    (read (current-buffer))))
-		(if (boundp sym)
-		    (set sym (cons (cons (read (current-buffer)) (point))
-				   (symbol-value sym)))
-		  (set sym (list (cons (read (current-buffer)) (point)))))
-		(skip-chars-forward " "))
-	      (forward-line 1)))
-	  ;; We now have all articles that can possibly be expired.
-	  (mapatoms
-	   (lambda (sym)
-	     (setq group (symbol-name sym)
-		   articles (sort (symbol-value sym) 'car-less-than-car)
-		   low (car (gnus-active group))
-		   info (gnus-get-info group)
-		   unreads (ignore-errors (gnus-list-of-unread-articles group))
-		   marked (nconc (gnus-uncompress-range
-				  (cdr (assq 'tick (gnus-info-marks info))))
-				 (gnus-uncompress-range
-				  (cdr (assq 'dormant
-					     (gnus-info-marks info)))))
-		   nov-file (gnus-agent-article-name ".overview" group))
-	     (when info
-	       (gnus-agent-load-alist group)
-	       (gnus-message 5 "Expiring articles in %s" group)
-	       (set-buffer overview)
-	       (erase-buffer)
-	       (when (file-exists-p nov-file)
-		 (nnheader-insert-file-contents nov-file))
-	       (goto-char (point-min))
-	       (setq article 0)
-	       (while (setq elem (pop articles))
-		 (setq article (car elem))
-		 (when (or (null low)
-			   (< article low)
-			   gnus-agent-expire-all
-			   (and (not (memq article unreads))
-				(not (memq article marked))))
-		   ;; Find and nuke the NOV line.
-		   (while (and (not (eobp))
-			       (or (not (numberp
-					 (setq art (read (current-buffer)))))
-				   (< art article)))
-		     (if (file-exists-p
-			  (gnus-agent-article-name
-			   (number-to-string art) group))
-			 (forward-line 1)
-		       ;; Remove old NOV lines that have no articles.
-		       (gnus-delete-line)))
-		   (if (or (eobp)
-			   (/= art article))
-		       (beginning-of-line)
-		     (gnus-delete-line))
-		   ;; Nuke the article.
-		   (when (file-exists-p (setq file (gnus-agent-article-name
-						    (number-to-string article)
-						    group)))
-		     (delete-file file))
-		   ;; Schedule the history line for nuking.
-		   (push (cdr elem) histories)))
-	       (gnus-make-directory (file-name-directory nov-file))
-	       (let ((coding-system-for-write
-		      gnus-agent-file-coding-system))
-		 (write-region (point-min) (point-max) nov-file nil 'silent))
-	       ;; Delete the unwanted entries in the alist.
-	       (setq gnus-agent-article-alist
-		     (sort gnus-agent-article-alist 'car-less-than-car))
-	       (let* ((alist gnus-agent-article-alist)
-		      (prev (cons nil alist))
-		      (first prev)
-		      expired)
-		 (while (and alist
-			     (<= (caar alist) article))
-		   (if (or (not (cdar alist))
-			   (not (file-exists-p
+	(when (file-exists-p (gnus-agent-lib-file "active"))
+	  (with-temp-buffer
+	    (nnheader-insert-file-contents (gnus-agent-lib-file "active"))
+	    (gnus-active-to-gnus-format 
+	     gnus-command-method
+	     (setq orig (gnus-make-hashtable
+			 (count-lines (point-min) (point-max))))))
+	  (let ((expiry-hashtb (gnus-make-hashtable 1023)))
+	    (gnus-agent-open-history)
+	    (set-buffer
+	     (setq gnus-agent-current-history
+		   (setq history (gnus-agent-history-buffer))))
+	    (goto-char (point-min))
+	    (when (> (buffer-size) 1)
+	      (goto-char (point-min))
+	      (while (not (eobp))
+		(skip-chars-forward "^\t")
+		(if (> (read (current-buffer)) day)
+		    ;; New article; we don't expire it.
+		    (forward-line 1)
+		  ;; Old article.  Schedule it for possible nuking.
+		  (while (not (eolp))
+		    (setq sym (let ((obarray expiry-hashtb) s)
+				(setq s (read (current-buffer)))
+				(if (stringp s) (intern s) s)))
+		    (if (boundp sym)
+			(set sym (cons (cons (read (current-buffer)) (point))
+				       (symbol-value sym)))
+		      (set sym (list (cons (read (current-buffer)) (point)))))
+		    (skip-chars-forward " "))
+		  (forward-line 1)))
+	      ;; We now have all articles that can possibly be expired.
+	      (mapatoms
+	       (lambda (sym)
+		 (setq group (symbol-name sym)
+		       articles (sort (symbol-value sym) 'car-less-than-car)
+		       low (car (gnus-active group))
+		       info (gnus-get-info group)
+		       unreads (ignore-errors
+				 (gnus-list-of-unread-articles group))
+		       marked (nconc
+			       (gnus-uncompress-range
+				(cdr (assq 'tick (gnus-info-marks info))))
+			       (gnus-uncompress-range
+				(cdr (assq 'dormant
+					   (gnus-info-marks info)))))
+		       nov-file (gnus-agent-article-name ".overview" group)
+		       lowest nil
+		       highest nil)
+		 (gnus-agent-load-alist group)
+		 (gnus-message 5 "Expiring articles in %s" group)
+		 (set-buffer overview)
+		 (erase-buffer)
+		 (when (file-exists-p nov-file)
+		   (nnheader-insert-file-contents nov-file))
+		 (goto-char (point-min))
+		 (setq article 0)
+		 (while (setq elem (pop articles))
+		   (setq article (car elem))
+		   (when (or (null low)
+			     (< article low)
+			     gnus-agent-expire-all
+			     (and (not (memq article unreads))
+				  (not (memq article marked))))
+		     ;; Find and nuke the NOV line.
+		     (while (and (not (eobp))
+				 (or (not (numberp
+					   (setq art (read (current-buffer)))))
+				     (< art article)))
+		       (if (and (numberp art) 
+				(file-exists-p
 				 (gnus-agent-article-name
-				  (number-to-string
-				   (caar alist))
-				  group))))
-		       (progn
-			 (push (caar alist) expired)
-			 (setcdr prev (setq alist (cdr alist))))
-		     (setq prev alist
-			   alist (cdr alist))))
-		 (setq gnus-agent-article-alist (cdr first))
-		 (gnus-agent-save-alist group)
-		 ;; Mark all articles up to the first article
-		 ;; in `gnus-article-alist' as read.
-		 (when (and info (caar gnus-agent-article-alist))
-		   (setcar (nthcdr 2 info)
-			   (gnus-range-add
-			    (nth 2 info)
-			    (cons 1 (- (caar gnus-agent-article-alist) 1)))))
-		 ;; Maybe everything has been expired from `gnus-article-alist'
-		 ;; and so the above marking as read could not be conducted,
-		 ;; or there are expired article within the range of the alist.
-		 (when (and (car expired)
-			    (or (not (caar gnus-agent-article-alist))
-				(> (car expired)
-				   (caar gnus-agent-article-alist))) )
-		   (setcar (nthcdr 2 info)
-			   (gnus-add-to-range
-			    (nth 2 info)
-			    (nreverse expired))))
-		 (gnus-dribble-enter
-		  (concat "(gnus-group-set-info '"
-			  (gnus-prin1-to-string info)
-			  ")")))))
-	   expiry-hashtb)
-	  (set-buffer history)
-	  (setq histories (nreverse (sort histories '<)))
-	  (while histories
-	    (goto-char (pop histories))
-	    (gnus-delete-line))
-	  (gnus-agent-save-history)
-	  (gnus-agent-close-history))
-	(gnus-message 4 "Expiry...done"))))))
+				  (number-to-string art) group)))
+			   (progn
+			     (unless lowest
+			       (setq lowest art))
+			     (setq highest art)
+			     (forward-line 1))
+			 ;; Remove old NOV lines that have no articles.
+			 (gnus-delete-line)))
+		     (if (or (eobp)
+			     (/= art article))
+			 (beginning-of-line)
+		       (gnus-delete-line))
+		     ;; Nuke the article.
+		     (when (file-exists-p
+			    (setq file (gnus-agent-article-name
+					(number-to-string article)
+					group)))
+		       (delete-file file))
+		     ;; Schedule the history line for nuking.
+		     (push (cdr elem) histories)))
+		 (gnus-make-directory (file-name-directory nov-file))
+		 (let ((coding-system-for-write
+			gnus-agent-file-coding-system))
+		   (write-region (point-min) (point-max) nov-file nil 'silent))
+		 ;; Delete the unwanted entries in the alist.
+		 (setq gnus-agent-article-alist
+		       (sort gnus-agent-article-alist 'car-less-than-car))
+		 (let* ((alist gnus-agent-article-alist)
+			(prev (cons nil alist))
+			(first prev)
+			expired)
+		   (while (and alist
+			       (<= (caar alist) article))
+		     (if (or (not (cdar alist))
+			     (not (file-exists-p
+				   (gnus-agent-article-name
+				    (number-to-string
+				     (caar alist))
+				    group))))
+			 (progn
+			   (push (caar alist) expired)
+			   (setcdr prev (setq alist (cdr alist))))
+		       (setq prev alist
+			     alist (cdr alist))))
+		   (setq gnus-agent-article-alist (cdr first))
+		   (gnus-agent-save-alist group)
+		   ;; Mark all articles up to the first article
+		   ;; in `gnus-article-alist' as read.
+		   (when (and info (caar gnus-agent-article-alist))
+		     (setcar (nthcdr 2 info)
+			     (gnus-range-add
+			      (nth 2 info)
+			      (cons 1 (- (caar gnus-agent-article-alist) 1)))))
+		   ;; Maybe everything has been expired from `gnus-article-alist'
+		   ;; and so the above marking as read could not be conducted,
+		   ;; or there are expired article within the range of the alist.
+		   (when (and info
+			      expired
+			      (or (not (caar gnus-agent-article-alist))
+				  (> (car expired)
+				     (caar gnus-agent-article-alist))))
+		     (setcar (nthcdr 2 info)
+			     (gnus-add-to-range
+			      (nth 2 info)
+			      (nreverse expired))))
+		   (gnus-dribble-enter
+		    (concat "(gnus-group-set-info '"
+			    (gnus-prin1-to-string info)
+			    ")")))
+		 (when lowest
+		   (if (gnus-gethash group orig)
+		       (setcar (gnus-gethash group orig) lowest)
+		     (gnus-sethash group (cons lowest highest) orig))))
+	       expiry-hashtb)
+	      (set-buffer history)
+	      (setq histories (nreverse (sort histories '<)))
+	      (while histories
+		(goto-char (pop histories))
+		(gnus-delete-line))
+	      (gnus-agent-save-history)
+	      (gnus-agent-close-history)
+	      (gnus-write-active-file
+	       (gnus-agent-lib-file "active") orig))
+	    (gnus-message 4 "Expiry...done")))))))
 
 ;;;###autoload
 (defun gnus-agent-batch ()
--- a/lisp/gnus/gnus-art.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-art.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,20 +27,27 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
-(require 'custom)
 (require 'gnus)
 (require 'gnus-sum)
 (require 'gnus-spec)
 (require 'gnus-int)
-(require 'browse-url)
+(require 'mm-bodies)
+(require 'mail-parse)
+(require 'mm-decode)
+(require 'mm-view)
+(require 'wid-edit)
+(require 'mm-uu)
 
 (defgroup gnus-article nil
   "Article display."
   :link '(custom-manual "(gnus)The Article Buffer")
   :group 'gnus)
 
+(defgroup gnus-article-treat nil
+  "Treating article parts."
+  :link '(custom-manual "(gnus)Article Hiding")
+  :group 'gnus-article)
+
 (defgroup gnus-article-hiding nil
   "Hiding article parts."
   :link '(custom-manual "(gnus)Article Hiding")
@@ -107,11 +114,19 @@
     "^Originator:" "^X-Problems-To:" "^X-Auth-User:" "^X-Post-Time:"
     "^X-Admin:" "^X-UID:" "^Resent-[-A-Za-z]+:" "^X-Mailing-List:"
     "^Precedence:" "^Original-[-A-Za-z]+:" "^X-filename:" "^X-Orcpt:"
-    "^Old-Received:" "^X-Pgp-Fingerprint:" "^X-Pgp-Key-Id:"
-    "^X-Pgp-Public-Key-Url:" "^X-Auth:" "^X-From-Line:"
+    "^Old-Received:" "^X-Pgp" "^X-Auth:" "^X-From-Line:"
     "^X-Gnus-Article-Number:" "^X-Majordomo:" "^X-Url:" "^X-Sender:"
-    "^X-Mailing-List:" "^MBOX-Line" "^Priority:" "^X-Pgp" "^X400-[-A-Za-z]+:"
-    "^Status:")
+    "^MBOX-Line" "^Priority:" "^X-Pgp" "^X400-[-A-Za-z]+:"
+    "^Status:" "^X-Gnus-Mail-Source:" "^Cancel-Lock:"
+    "^X-FTN" "^X-EXP32-SerialNo:" "^Encoding:" "^Importance:"
+    "^Autoforwarded:" "^Original-Encoded-Information-Types:" "^X-Ya-Pop3:"
+    "^X-Face-Version:" "^X-Vms-To:" "^X-ML-NAME:" "^X-ML-COUNT:"
+    "^Mailing-List:" "^X-finfo:" "^X-md5sum:" "^X-md5sum-Origin:"
+    "^X-Sun-Charset:" "^X-Accept-Language:" "^X-Envelope-Sender:"
+    "^List-[A-Za-z]+:" "^X-Listprocessor-Version:"
+    "^X-Received:" "^X-Distribute:" "^X-Sequence:" "^X-Juno-Line-Breaks:"
+    "^X-Notes-Item:" "^X-MS-TNEF-Correlator:" "^x-uunet-gateway:"
+    "^X-Received:" "^Content-length:" "X-precedence:")
   "*All headers that start with this regexp will be hidden.
 This variable can also be a list of regexps of headers to be ignored.
 If `gnus-visible-headers' is non-nil, this variable will be ignored."
@@ -121,7 +136,7 @@
   :group 'gnus-article-hiding)
 
 (defcustom gnus-visible-headers
-  "From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:\\|X-Sent:"
+  "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^[BGF]?Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:\\|^X-Sent:"
   "*All headers that do not match this regexp will be hidden.
 This variable can also be a list of regexp of headers to remain visible.
 If this variable is non-nil, `gnus-ignored-headers' will be ignored."
@@ -152,8 +167,8 @@
 	      (const :tag "Followup-to identical to newsgroups." followup-to)
 	      (const :tag "Reply-to identical to from." reply-to)
 	      (const :tag "Date less than four days old." date)
-	      (const :tag "Very long To header." long-to)
-	      (const :tag "Multiple To headers." many-to))
+	      (const :tag "Very long To and/or Cc header." long-to)
+	      (const :tag "Multiple To and/or Cc headers." many-to))
   :group 'gnus-article-hiding)
 
 (defcustom gnus-signature-separator '("^-- $" "^-- *$")
@@ -165,7 +180,7 @@
   :group 'gnus-article-signature)
 
 (defcustom gnus-signature-limit nil
-   "Provide a limit to what is considered a signature.
+  "Provide a limit to what is considered a signature.
 If it is a number, no signature may not be longer (in characters) than
 that number.  If it is a floating point number, no signature may be
 longer (in lines) than that number.  If it is a function, the function
@@ -183,12 +198,20 @@
   :type 'sexp
   :group 'gnus-article-hiding)
 
+;; Fixme: This isn't the right thing for mixed graphical and and
+;; non-graphical frames in a session.
+;; gnus-xmas.el overrides this for XEmacs.
 (defcustom gnus-article-x-face-command
-  "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | xv -quit -"
+  (if (and (fboundp 'image-type-available-p)
+	   (image-type-available-p 'xbm))
+      'gnus-article-display-xface
+    "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | display -")
   "*String or function to be executed to display an X-Face header.
 If it is a string, the command will be executed in a sub-shell
 asynchronously.	 The compressed face will be piped to this command."
-  :type 'string				;Leave function case to Lisp.
+  :type '(choice string
+		 (function-item gnus-article-display-xface)
+		 function)
   :group 'gnus-article-washing)
 
 (defcustom gnus-article-x-face-too-ugly nil
@@ -198,7 +221,7 @@
 
 (defcustom gnus-emphasis-alist
   (let ((format
-	 "\\(\\s-\\|^\\|[-\"]\\|\\s(\\|\\s)\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-?!.,;:\"]\\|\\s(\\|\\s)\\)")
+	 "\\(\\s-\\|^\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-,;:\"]\\s-\\|[?!.]+\\s-\\|\\s)\\)")
 	(types
 	 '(("_" "_" underline)
 	   ("/" "/" italic)
@@ -232,6 +255,14 @@
 		       face))
   :group 'gnus-article-emphasis)
 
+(defcustom gnus-emphasize-whitespace-regexp "^[ \t]+\\|[ \t]*\n"
+  "A regexp to describe whitespace which should not be emphasized.
+Typical values are \"^[ \\t]+\\\\|[ \\t]*\\n\" and \"[ \\t]+\\\\|[ \\t]*\\n\".
+The former avoids underlining of leading and trailing whitespace,
+and the latter avoids underlining any whitespace at all."
+  :group 'gnus-article-emphasis
+  :type 'regexp)
+
 (defface gnus-emphasis-bold '((t (:bold t)))
   "Face used for displaying strong emphasized text (*word*)."
   :group 'gnus-article-emphasis)
@@ -262,6 +293,11 @@
 Esample: (_/*word*/_)."
   :group 'gnus-article-emphasis)
 
+(defface gnus-emphasis-highlight-words
+  '((t (:background "black" :foreground "yellow")))
+  "Face used for displaying highlighted words."
+  :group 'gnus-article-emphasis)
+
 (defcustom gnus-article-time-format "%a, %b %d %Y %T %Z"
   "Format for display of Date headers in article bodies.
 See `format-time-string' for the possible values.
@@ -274,8 +310,6 @@
   :group 'gnus-article-washing)
 
 (eval-and-compile
-  (autoload 'hexl-hex-string-to-integer "hexl")
-  (autoload 'timezone-make-date-arpa-standard "timezone")
   (autoload 'mail-extract-address-components "mail-extr"))
 
 (defcustom gnus-save-all-headers t
@@ -377,34 +411,6 @@
 			 (cons :value ("" "") regexp (repeat string))
 			 (sexp :value nil))))
 
-(defcustom gnus-strict-mime t
-  "*If nil, MIME-decode even if there is no Mime-Version header."
-  :group 'gnus-article-mime
-  :type 'boolean)
-
-(defcustom gnus-show-mime-method 'metamail-buffer
-  "Function to process a MIME message.
-The function is called from the article buffer."
-  :group 'gnus-article-mime
-  :type 'function)
-
-(defcustom gnus-decode-encoded-word-method 'gnus-article-de-quoted-unreadable
-  "*Function to decode MIME encoded words.
-The function is called from the article buffer."
-  :group 'gnus-article-mime
-  :type 'function)
-
-(defcustom gnus-show-traditional-method
-  (if (and (featurep 'mule)
-	   (boundp 'enable-multibyte-characters))
-      (lambda ()
-	(if enable-multibyte-characters (gnus-mule-decode-article)))
-    (lambda ()))
-  "Function to decode ``localized RFC 822 messages''.
-The function is called from the article buffer."
-  :group 'gnus-article-mime
-  :type 'function)
-
 (defcustom gnus-page-delimiter "^\^L"
   "*Regexp describing what to use as article page delimiters.
 The default value is \"^\^L\", which is a form linefeed at the
@@ -412,9 +418,14 @@
   :type 'regexp
   :group 'gnus-article-various)
 
-(defcustom gnus-article-mode-line-format "Gnus: %%b %S"
+(defcustom gnus-article-mode-line-format "Gnus: %g [%w] %S%m"
   "*The format specification for the article mode line.
-See `gnus-summary-mode-line-format' for a closer description."
+See `gnus-summary-mode-line-format' for a closer description.
+
+The following additional specs are available:
+
+%w  The article washing status.
+%m  The number of MIME parts in the article."
   :type 'string
   :group 'gnus-article-various)
 
@@ -429,8 +440,7 @@
   :group 'gnus-article-various)
 
 (defcustom gnus-article-prepare-hook nil
-  "*A hook called after an article has been prepared in the article buffer.
-If you want to run a special decoding program like nkf, use this hook."
+  "*A hook called after an article has been prepared in the article buffer."
   :type 'hook
   :group 'gnus-article-various)
 
@@ -559,8 +569,410 @@
 			       (item :tag "skip" nil)
 			       (face :value default)))))
 
+(defcustom gnus-article-decode-hook
+  '(article-decode-charset article-decode-encoded-words)
+  "*Hook run to decode charsets in articles."
+  :group 'gnus-article-headers
+  :type 'hook)
+
+(defcustom gnus-display-mime-function 'gnus-display-mime
+  "Function to display MIME articles."
+  :group 'gnus-article-mime
+  :type 'function)
+
+(defvar gnus-decode-header-function 'mail-decode-encoded-word-region
+  "Function used to decode headers.")
+
+(defvar gnus-article-dumbquotes-map
+  '(("\202" ",")
+    ("\203" "f")
+    ("\204" ",,")
+    ("\205" "...")
+    ("\213" "<")
+    ("\214" "OE")
+    ("\221" "`")
+    ("\222" "'")
+    ("\223" "``")
+    ("\224" "\"")
+    ("\225" "*")
+    ("\226" "---")
+    ("\227" "-")
+    ("\231" "(TM)")
+    ("\233" ">")
+    ("\234" "oe")
+    ("\264" "'"))
+  "Table for MS-to-Latin1 translation.")
+
+(defcustom gnus-ignored-mime-types nil
+  "List of MIME types that should be ignored by Gnus."
+  :group 'gnus-article-mime
+  :type '(repeat regexp))
+
+(defcustom gnus-unbuttonized-mime-types '(".*/.*")
+  "List of MIME types that should not be given buttons when rendered inline."
+  :group 'gnus-article-mime
+  :type '(repeat regexp))
+
+(defcustom gnus-article-mime-part-function nil
+  "Function called with a MIME handle as the argument.
+This is meant for people who want to do something automatic based
+on parts -- for instance, adding Vcard info to a database."
+  :group 'gnus-article-mime
+  :type 'function)
+
+(defcustom gnus-mime-multipart-functions nil
+  "An alist of MIME types to functions to display them.")
+
+(defcustom gnus-article-date-lapsed-new-header nil
+  "Whether the X-Sent and Date headers can coexist.
+When using `gnus-treat-date-lapsed', the \"X-Sent:\" header will
+either replace the old \"Date:\" header (if this variable is nil), or
+be added below it (otherwise)."
+  :group 'gnus-article-headers
+  :type 'boolean)
+
+(defcustom gnus-article-mime-match-handle-function 'undisplayed-alternative
+  "Function called with a MIME handle as the argument.
+This is meant for people who want to view first matched part.
+For `undisplayed-alternative' (default), the first undisplayed 
+part or alternative part is used.  For `undisplayed', the first 
+undisplayed part is used.  For a function, the first part which 
+the function return `t' is used.  For `nil', the first part is
+used."
+  :group 'gnus-article-mime
+  :type '(choice 
+	  (item :tag "first" :value nil)
+	  (item :tag "undisplayed" :value undisplayed)
+	  (item :tag "undisplayed or alternative" 
+		:value undisplayed-alternative)
+	  (function)))
+
+;;;
+;;; The treatment variables
+;;;
+
+(defvar gnus-part-display-hook nil
+  "Hook called on parts that are to receive treatment.")
+
+(defvar gnus-article-treat-custom
+  '(choice (const :tag "Off" nil)
+	   (const :tag "On" t)
+	   (const :tag "Header" head)
+	   (const :tag "Last" last)
+	   (integer :tag "Less")
+	   (repeat :tag "Groups" regexp)
+	   (sexp :tag "Predicate")))
+
+(defvar gnus-article-treat-head-custom
+  '(choice (const :tag "Off" nil)
+	   (const :tag "Header" head)))
+
+(defvar gnus-article-treat-types '("text/plain")
+  "Parts to treat.")
+
+(defvar gnus-inhibit-treatment nil
+  "Whether to inhibit treatment.")
+
+(defcustom gnus-treat-highlight-signature '(or last (typep "text/x-vcard"))
+  "Highlight the signature.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-highlight-signature 'highlight t)
+
+(defcustom gnus-treat-buttonize 100000
+  "Add buttons.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-buttonize 'highlight t)
+
+(defcustom gnus-treat-buttonize-head 'head
+  "Add buttons to the head.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-buttonize-head 'highlight t)
+
+(defcustom gnus-treat-emphasize 50000
+  "Emphasize text.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-emphasize 'highlight t)
+
+(defcustom gnus-treat-strip-cr nil
+  "Remove carriage returns.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-hide-headers 'head
+  "Hide headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-hide-boring-headers nil
+  "Hide boring headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-hide-signature nil
+  "Hide the signature.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fill-article nil
+  "Fill the article.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-hide-citation nil
+  "Hide cited text.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-list-identifiers 'head
+  "Strip list identifiers from `gnus-list-identifiers`.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-pgp t
+  "Strip PGP signatures.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-pem nil
+  "Strip PEM signatures.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-banner t
+  "Strip banners from articles.
+The banner to be stripped is specified in the `banner' group parameter.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-highlight-headers 'head
+  "Highlight the headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-highlight-headers 'highlight t)
+
+(defcustom gnus-treat-highlight-citation t
+  "Highlight cited text.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-highlight-citation 'highlight t)
+
+(defcustom gnus-treat-date-ut nil
+  "Display the Date in UT (GMT).
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-date-local nil
+  "Display the Date in the local timezone.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-date-lapsed nil
+  "Display the Date header in a way that says how much time has elapsed.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-date-original nil
+  "Display the date in the original timezone.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-date-iso8601 nil
+  "Display the date in the ISO8601 format.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-date-user-defined nil
+  "Display the date in a user-defined format.
+The format is defined by the `gnus-article-time-format' variable.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+
+(defcustom gnus-treat-strip-headers-in-body t
+  "Strip the X-No-Archive header line from the beginning of the body.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-trailing-blank-lines nil
+  "Strip trailing blank lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-leading-blank-lines nil
+  "Strip leading blank lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-strip-multiple-blank-lines nil
+  "Strip multiple blank lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-overstrike t
+  "Treat overstrike highlighting.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-overstrike 'highlight t)
+
+(defcustom gnus-treat-display-xface (if (and gnus-xemacs (featurep 'xface))
+					'head nil)
+  "Display X-Face headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-display-xface 'highlight t)
+
+(defcustom gnus-treat-display-smileys (if (and gnus-xemacs
+					       (featurep 'xpm))
+					  t nil)
+  "Display smileys.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+(put 'gnus-treat-display-smileys 'highlight t)
+
+(defcustom gnus-treat-display-picons (if gnus-xemacs 'head nil)
+  "Display picons.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-display-picons 'highlight t)
+
+(defcustom gnus-treat-capitalize-sentences nil
+  "Capitalize sentence-starting words.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fill-long-lines nil
+  "Fill long lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-play-sounds nil
+  "Play sounds.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-translate nil
+  "Translate articles from one language to another.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
 ;;; Internal variables
 
+(defvar article-goto-body-goes-to-point-min-p nil)
+(defvar gnus-article-wash-types nil)
+(defvar gnus-article-emphasis-alist nil)
+
+(defvar gnus-article-mime-handle-alist-1 nil)
+(defvar gnus-treatment-function-alist
+  '((gnus-treat-strip-banner gnus-article-strip-banner)
+    (gnus-treat-strip-headers-in-body gnus-article-strip-headers-in-body)
+    (gnus-treat-highlight-signature gnus-article-highlight-signature)
+    (gnus-treat-buttonize gnus-article-add-buttons)
+    (gnus-treat-fill-article gnus-article-fill-cited-article)
+    (gnus-treat-fill-long-lines gnus-article-fill-long-lines)
+    (gnus-treat-strip-cr gnus-article-remove-cr)
+    (gnus-treat-emphasize gnus-article-emphasize)
+    (gnus-treat-display-xface gnus-article-display-x-face)
+    (gnus-treat-hide-headers gnus-article-maybe-hide-headers)
+    (gnus-treat-hide-boring-headers gnus-article-hide-boring-headers)
+    (gnus-treat-hide-signature gnus-article-hide-signature)
+    (gnus-treat-hide-citation gnus-article-hide-citation)
+    (gnus-treat-strip-list-identifiers gnus-article-hide-list-identifiers)
+    (gnus-treat-strip-pgp gnus-article-hide-pgp)
+    (gnus-treat-strip-pem gnus-article-hide-pem)
+    (gnus-treat-highlight-headers gnus-article-highlight-headers)
+    (gnus-treat-highlight-citation gnus-article-highlight-citation)
+    (gnus-treat-highlight-signature gnus-article-highlight-signature)
+    (gnus-treat-date-ut gnus-article-date-ut)
+    (gnus-treat-date-local gnus-article-date-local)
+    (gnus-treat-date-lapsed gnus-article-date-lapsed)
+    (gnus-treat-date-original gnus-article-date-original)
+    (gnus-treat-date-user-defined gnus-article-date-user)
+    (gnus-treat-date-iso8601 gnus-article-date-iso8601)
+    (gnus-treat-strip-trailing-blank-lines
+     gnus-article-remove-trailing-blank-lines)
+    (gnus-treat-strip-leading-blank-lines
+     gnus-article-strip-leading-blank-lines)
+    (gnus-treat-strip-multiple-blank-lines
+     gnus-article-strip-multiple-blank-lines)
+    (gnus-treat-overstrike gnus-article-treat-overstrike)
+    (gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
+    (gnus-treat-display-smileys gnus-smiley-display)
+    (gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
+    (gnus-treat-display-picons gnus-article-display-picons)
+    (gnus-treat-play-sounds gnus-earcon-display)))
+
+(defvar gnus-article-mime-handle-alist nil)
 (defvar article-lapsed-timer nil)
 (defvar gnus-article-current-summary nil)
 
@@ -576,7 +988,8 @@
 (defvar gnus-save-article-buffer nil)
 
 (defvar gnus-article-mode-line-format-alist
-  (nconc '((?w (gnus-article-wash-status) ?s))
+  (nconc '((?w (gnus-article-wash-status) ?s)
+	   (?m (gnus-article-mime-part-status) ?s))
 	 gnus-summary-mode-line-format-alist))
 
 (defvar gnus-number-of-articles-to-be-saved nil)
@@ -590,7 +1003,6 @@
     (put-text-property
      (max (1- b) (point-min))
      b 'intangible (cddr (memq 'intangible props)))))
-
 (defsubst gnus-article-unhide-text (b e)
   "Remove hidden text properties from region between B and E."
   (remove-text-properties b e gnus-hidden-properties)
@@ -600,11 +1012,14 @@
 
 (defun gnus-article-hide-text-type (b e type)
   "Hide text of TYPE between B and E."
+  (push type gnus-article-wash-types)
   (gnus-article-hide-text
    b e (cons 'article-type (cons type gnus-hidden-properties))))
 
 (defun gnus-article-unhide-text-type (b e type)
   "Unhide text of TYPE between B and E."
+  (setq gnus-article-wash-types
+	(delq type gnus-article-wash-types))
   (remove-text-properties
    b e (cons 'article-type (cons type gnus-hidden-properties)))
   (when (memq 'intangible gnus-hidden-properties)
@@ -653,79 +1068,60 @@
     i))
 
 (defun article-hide-headers (&optional arg delete)
-  "Toggle whether to hide unwanted headers and possibly sort them as well.
-If given a negative prefix, always show; if given a positive prefix,
-always hide."
-  (interactive (gnus-article-hidden-arg))
-  (current-buffer)
-  (if (gnus-article-check-hidden-text 'headers arg)
-      ;; Show boring headers as well.
-      (gnus-article-show-hidden-text 'boring-headers)
-    ;; This function might be inhibited.
-    (unless gnus-inhibit-hiding
-      (save-excursion
-	(save-restriction
-	  (let ((buffer-read-only nil)
-		(case-fold-search t)
-		(props (nconc (list 'article-type 'headers)
-			      gnus-hidden-properties))
-		(max (1+ (length gnus-sorted-header-list)))
-		(ignored (when (not gnus-visible-headers)
-			   (cond ((stringp gnus-ignored-headers)
-				  gnus-ignored-headers)
-				 ((listp gnus-ignored-headers)
-				  (mapconcat 'identity gnus-ignored-headers
-					     "\\|")))))
-		(visible
-		 (cond ((stringp gnus-visible-headers)
-			gnus-visible-headers)
-		       ((and gnus-visible-headers
-			     (listp gnus-visible-headers))
-			(mapconcat 'identity gnus-visible-headers "\\|"))))
-		(inhibit-point-motion-hooks t)
-		beg)
-	    ;; First we narrow to just the headers.
-	    (widen)
-	    (goto-char (point-min))
-	    ;; Hide any "From " lines at the beginning of (mail) articles.
-	    (while (looking-at "From ")
-	      (forward-line 1))
-	    (unless (bobp)
-	      (if delete
-		  (delete-region (point-min) (point))
-		(gnus-article-hide-text (point-min) (point) props)))
-	    ;; Then treat the rest of the header lines.
-	    (narrow-to-region
-	     (point)
-	     (if (search-forward "\n\n" nil t) ; if there's a body
-		 (progn (forward-line -1) (point))
-	       (point-max)))
-	    ;; Then we use the two regular expressions
-	    ;; `gnus-ignored-headers' and `gnus-visible-headers' to
-	    ;; select which header lines is to remain visible in the
-	    ;; article buffer.
-	    (goto-char (point-min))
-	    (while (re-search-forward "^[^ \t]*:" nil t)
-	      (beginning-of-line)
-	      ;; Mark the rank of the header.
-	      (put-text-property
-	       (point) (1+ (point)) 'message-rank
-	       (if (or (and visible (looking-at visible))
-		       (and ignored
-			    (not (looking-at ignored))))
-		   (gnus-article-header-rank)
-		 (+ 2 max)))
-	      (forward-line 1))
-	    (message-sort-headers-1)
-	    (when (setq beg (text-property-any
-			     (point-min) (point-max) 'message-rank (+ 2 max)))
-	      ;; We make the unwanted headers invisible.
-	      (if delete
-		  (delete-region beg (point-max))
-		;; Suggested by Sudish Joseph <joseph@cis.ohio-state.edu>.
-		(gnus-article-hide-text-type beg (point-max) 'headers))
-	      ;; Work around XEmacs lossage.
-	      (put-text-property (point-min) beg 'invisible nil))))))))
+  "Hide unwanted headers and possibly sort them as well."
+  (interactive)
+  ;; This function might be inhibited.
+  (unless gnus-inhibit-hiding
+    (save-excursion
+      (save-restriction
+	(let ((buffer-read-only nil)
+	      (case-fold-search t)
+	      (max (1+ (length gnus-sorted-header-list)))
+	      (ignored (when (not gnus-visible-headers)
+			 (cond ((stringp gnus-ignored-headers)
+				gnus-ignored-headers)
+			       ((listp gnus-ignored-headers)
+				(mapconcat 'identity gnus-ignored-headers
+					   "\\|")))))
+	      (visible
+	       (cond ((stringp gnus-visible-headers)
+		      gnus-visible-headers)
+		     ((and gnus-visible-headers
+			   (listp gnus-visible-headers))
+		      (mapconcat 'identity gnus-visible-headers "\\|"))))
+	      (inhibit-point-motion-hooks t)
+	      beg)
+	  ;; First we narrow to just the headers.
+	  (article-narrow-to-head)
+	  ;; Hide any "From " lines at the beginning of (mail) articles.
+	  (while (looking-at "From ")
+	    (forward-line 1))
+	  (unless (bobp)
+	    (delete-region (point-min) (point)))
+	  ;; Then treat the rest of the header lines.
+	  ;; Then we use the two regular expressions
+	  ;; `gnus-ignored-headers' and `gnus-visible-headers' to
+	  ;; select which header lines is to remain visible in the
+	  ;; article buffer.
+	  (while (re-search-forward "^[^ \t]*:" nil t)
+	    (beginning-of-line)
+	    ;; Mark the rank of the header.
+	    (put-text-property
+	     (point) (1+ (point)) 'message-rank
+	     (if (or (and visible (looking-at visible))
+		     (and ignored
+			  (not (looking-at ignored))))
+		 (gnus-article-header-rank)
+	       (+ 2 max)))
+	    (forward-line 1))
+	  (message-sort-headers-1)
+	  (when (setq beg (text-property-any
+			   (point-min) (point-max) 'message-rank (+ 2 max)))
+	    ;; We delete the unwanted headers.
+	    (push 'headers gnus-article-wash-types)
+	    (add-text-properties (point-min) (+ 5 (point-min))
+				 '(article-type headers dummy-invisible t))
+	    (delete-region beg (point-max))))))))
 
 (defun article-hide-boring-headers (&optional arg)
   "Toggle hiding of headers that aren't very interesting.
@@ -740,14 +1136,14 @@
 	      (list gnus-boring-article-headers)
 	      (inhibit-point-motion-hooks t)
 	      elem)
-	  (nnheader-narrow-to-headers)
+	  (article-narrow-to-head)
 	  (while list
 	    (setq elem (pop list))
 	    (goto-char (point-min))
 	    (cond
 	     ;; Hide empty headers.
 	     ((eq elem 'empty)
-	      (while (re-search-forward "^[^:]+:[ \t]*\n[^ \t]" nil t)
+	      (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
 		(forward-line -1)
 		(gnus-article-hide-text-type
 		 (progn (beginning-of-line) (point))
@@ -782,15 +1178,19 @@
 	     ((eq elem 'date)
 	      (let ((date (message-fetch-field "date")))
 		(when (and date
-			   (< (gnus-days-between (current-time-string) date)
+			   (< (days-between (current-time-string) date)
 			      4))
 		  (gnus-article-hide-header "date"))))
 	     ((eq elem 'long-to)
-	      (let ((to (message-fetch-field "to")))
+	      (let ((to (message-fetch-field "to"))
+		    (cc (message-fetch-field "cc")))
 		(when (> (length to) 1024)
-		  (gnus-article-hide-header "to"))))
+		  (gnus-article-hide-header "to"))
+		(when (> (length cc) 1024)
+		  (gnus-article-hide-header "cc"))))
 	     ((eq elem 'many-to)
-	      (let ((to-count 0))
+	      (let ((to-count 0)
+		    (cc-count 0))
 		(goto-char (point-min))
 		(while (re-search-forward "^to:" nil t)
 		  (setq to-count (1+ to-count)))
@@ -802,7 +1202,19 @@
 		      (forward-line -1)
 		      (narrow-to-region (point) (point-max))
 		      (gnus-article-hide-header "to"))
-		    (setq to-count (1- to-count)))))))))))))
+		    (setq to-count (1- to-count))))
+		(goto-char (point-min))
+		(while (re-search-forward "^cc:" nil t)
+		  (setq cc-count (1+ cc-count)))
+		(when (> cc-count 1)
+		  (while (> cc-count 0)
+		    (goto-char (point-min))
+		    (save-restriction
+		      (re-search-forward "^cc:" nil nil cc-count)
+		      (forward-line -1)
+		      (narrow-to-region (point) (point-max))
+		      (gnus-article-hide-header "cc"))
+		    (setq cc-count (1- cc-count)))))))))))))
 
 (defun gnus-article-hide-header (header)
   (save-excursion
@@ -817,18 +1229,50 @@
 	   (point-max)))
        'boring-headers))))
 
+(defvar gnus-article-normalized-header-length 40
+  "Length of normalized headers.")
+
+(defun article-normalize-headers ()
+  "Make all header lines 40 characters long."
+  (interactive)
+  (let ((buffer-read-only nil)
+	column)
+    (save-excursion
+      (save-restriction
+	(article-narrow-to-head)
+	(while (not (eobp))
+	  (cond
+	   ((< (setq column (- (gnus-point-at-eol) (point)))
+	       gnus-article-normalized-header-length)
+	    (end-of-line)
+	    (insert (make-string
+		     (- gnus-article-normalized-header-length column)
+		     ? )))
+	   ((> column gnus-article-normalized-header-length)
+	    (gnus-put-text-property
+	     (progn
+	       (forward-char gnus-article-normalized-header-length)
+	       (point))
+	     (gnus-point-at-eol)
+	     'invisible t))
+	   (t
+	    ;; Do nothing.
+	    ))
+	  (forward-line 1))))))
+
 (defun article-treat-dumbquotes ()
-  "Translate M******** sm*rtq**t*s into proper text."
+  "Translate M******** sm*rtq**t*s into proper text.
+Note that this function guesses whether a character is a sm*rtq**t* or
+not, so it should only be used interactively."
   (interactive)
-  (article-translate-characters "\221\222\223\223" "`'\"\""))
+  (article-translate-strings gnus-article-dumbquotes-map))
 
 (defun article-translate-characters (from to)
   "Translate all characters in the body of the article according to FROM and TO.
 FROM is a string of characters to translate from; to is a string of
 characters to translate to."
   (save-excursion
-    (goto-char (point-min))
-    (when (search-forward "\n\n" nil t)
+    (when (article-goto-body)
       (let ((buffer-read-only nil)
 	    (x (make-string 225 ?x))
 	    (i -1))
@@ -840,15 +1284,26 @@
 	  (incf i))
 	(translate-region (point) (point-max) x)))))
 
+(defun article-translate-strings (map)
+  "Translate all string in the body of the article according to MAP.
+MAP is an alist where the elements are on the form (\"from\" \"to\")."
+  (save-excursion
+    (when (article-goto-body)
+      (let ((buffer-read-only nil)
+	    elem)
+	(while (setq elem (pop map))
+	  (save-excursion
+	    (while (search-forward (car elem) nil t)
+	      (replace-match (cadr elem)))))))))
+
 (defun article-treat-overstrike ()
   "Translate overstrikes into bold text."
   (interactive)
   (save-excursion
-    (goto-char (point-min))
-    (when (search-forward "\n\n" nil t)
+    (when (article-goto-body)
       (let ((buffer-read-only nil))
 	(while (search-forward "\b" nil t)
-	  (let ((next (following-char))
+	  (let ((next (char-after))
 		(previous (char-after (- (point) 2))))
 	    ;; We do the boldification/underlining by hiding the
 	    ;; overstrikes and putting the proper text property
@@ -867,32 +1322,46 @@
 	      (put-text-property
 	       (point) (1+ (point)) 'face 'underline)))))))))
 
-(defun article-fill ()
-  "Format too long lines."
+(defun article-fill-long-lines ()
+  "Fill lines that are wider than the window width."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil))
-      (widen)
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
-      (end-of-line 1)
-      (let ((paragraph-start "^[>|#:<;* ]*[ \t]*$")
-	    (adaptive-fill-regexp "[ \t]*\\([|#:<;>*]+ *\\)?")
-	    (adaptive-fill-mode t))
-	(while (not (eobp))
-	  (and (>= (current-column) (min fill-column (window-width)))
-	       (/= (preceding-char) ?:)
-	       (fill-paragraph nil))
-	  (end-of-line 2))))))
+    (let ((buffer-read-only nil)
+	  (width (window-width (get-buffer-window (current-buffer)))))
+      (save-restriction
+	(article-goto-body)
+	(let ((adaptive-fill-mode nil))
+	  (while (not (eobp))
+	    (end-of-line)
+	    (when (>= (current-column) (min fill-column width))
+	      (narrow-to-region (point) (gnus-point-at-bol))
+	      (fill-paragraph nil)
+	      (goto-char (point-max))
+	      (widen))
+	    (forward-line 1)))))))
+
+(defun article-capitalize-sentences ()
+  "Capitalize the first word in each sentence."
+  (interactive)
+  (save-excursion
+    (let ((buffer-read-only nil)
+	  (paragraph-start "^[\n\^L]"))
+      (article-goto-body)
+      (while (not (eobp))
+	(capitalize-word 1)
+	(forward-sentence)))))
 
 (defun article-remove-cr ()
-  "Remove carriage returns from an article."
+  "Remove trailing CRs and then translate remaining CRs into LFs."
   (interactive)
   (save-excursion
     (let ((buffer-read-only nil))
       (goto-char (point-min))
+      (while (re-search-forward "\r+$" nil t)
+	(replace-match "" t t))
+      (goto-char (point-min))
       (while (search-forward "\r" nil t)
-	(replace-match "" t t)))))
+	(replace-match "\n" t t)))))
 
 (defun article-remove-trailing-blank-lines ()
   "Remove all trailing blank lines from the article."
@@ -904,7 +1373,9 @@
        (point)
        (progn
 	 (while (and (not (bobp))
-		     (looking-at "^[ \t]*$"))
+		     (looking-at "^[ \t]*$")
+		     (not (gnus-annotation-in-region-p
+			   (point) (gnus-point-at-eol))))
 	   (forward-line -1))
 	 (forward-line 1)
 	 (point))))))
@@ -920,7 +1391,8 @@
 	  (case-fold-search t)
 	  from last)
       (save-restriction
-	(nnheader-narrow-to-headers)
+	(article-narrow-to-head)
+	(goto-char (point-min))
 	(setq from (message-fetch-field "from"))
 	(goto-char (point-min))
 	(while (and gnus-article-x-face-command
@@ -959,99 +1431,176 @@
 		  (process-send-region "article-x-face" beg end)
 		  (process-send-eof "article-x-face"))))))))))
 
-(defun gnus-hack-decode-rfc1522 ()
-  "Emergency hack function for avoiding problems when decoding."
-  (let ((buffer-read-only nil))
-    (goto-char (point-min))
-    ;; Remove encoded TABs.
-    (while (search-forward "=09" nil t)
-      (replace-match " " t t))
-    ;; Remove encoded newlines.
-    (goto-char (point-min))
-    (while (search-forward "=10" nil t)
-      (replace-match " " t t))))
-
-(defalias 'gnus-decode-rfc1522 'article-decode-rfc1522)
-(defalias 'gnus-article-decode-rfc1522 'article-decode-rfc1522)
-(defun article-decode-rfc1522 ()
-  "Hack to remove QP encoding from headers."
-  (let ((case-fold-search t)
-	(inhibit-point-motion-hooks t)
-	(buffer-read-only nil)
-	string)
+(defun article-decode-mime-words ()
+  "Decode all MIME-encoded words in the article."
+  (interactive)
+  (save-excursion
+    (set-buffer gnus-article-buffer)
+    (let ((inhibit-point-motion-hooks t)
+	  buffer-read-only
+	  (mail-parse-charset gnus-newsgroup-charset)
+	  (mail-parse-ignored-charsets 
+	   (save-excursion (set-buffer gnus-summary-buffer)
+			   gnus-newsgroup-ignored-charsets)))
+      (mail-decode-encoded-word-region (point-min) (point-max)))))
+
+(defun article-decode-charset (&optional prompt)
+  "Decode charset-encoded text in the article.
+If PROMPT (the prefix), prompt for a coding system to use."
+  (interactive "P")
+  (let ((inhibit-point-motion-hooks t) (case-fold-search t)
+	buffer-read-only
+	(mail-parse-charset gnus-newsgroup-charset)
+	(mail-parse-ignored-charsets 
+	 (save-excursion (condition-case nil
+			     (set-buffer gnus-summary-buffer)
+			   (error))
+			 gnus-newsgroup-ignored-charsets))
+	ct cte ctl charset format)
+  (save-excursion
     (save-restriction
-      (narrow-to-region
-       (goto-char (point-min))
-       (or (search-forward "\n\n" nil t) (point-max)))
-      (goto-char (point-min))
-      (while (re-search-forward
-	      "=\\?iso-8859-1\\?q\\?\\([^?\t\n]*\\)\\?=" nil t)
-	(setq string (match-string 1))
-	(save-restriction
-	  (narrow-to-region (match-beginning 0) (match-end 0))
-	  (delete-region (point-min) (point-max))
-	  (insert string)
-	  (article-mime-decode-quoted-printable
-	   (goto-char (point-min)) (point-max))
-	  (subst-char-in-region (point-min) (point-max) ?_ ? )
-	  (goto-char (point-max)))
-	(goto-char (point-min))))))
+      (article-narrow-to-head)
+      (setq ct (message-fetch-field "Content-Type" t)
+	    cte (message-fetch-field "Content-Transfer-Encoding" t)
+	    ctl (and ct (ignore-errors
+			  (mail-header-parse-content-type ct)))
+	    charset (cond
+		     (prompt
+		      (mm-read-coding-system "Charset to decode: "))
+		     (ctl
+		      (mail-content-type-get ctl 'charset)))
+	    format (and ctl (mail-content-type-get ctl 'format)))
+      (when cte
+	(setq cte (mail-header-strip cte)))
+      (if (and ctl (not (string-match "/" (car ctl)))) 
+	  (setq ctl nil))
+      (goto-char (point-max)))
+    (forward-line 1)
+    (save-restriction
+      (narrow-to-region (point) (point-max))
+      (when (and (eq mail-parse-charset 'gnus-decoded)
+		 (eq (mm-body-7-or-8) '8bit))
+	;; The text code could have been decoded.
+	(setq charset mail-parse-charset))
+      (when (and (or (not ctl)
+		     (equal (car ctl) "text/plain"))
+		 (not format)) ;; article with format will decode later.
+	(mm-decode-body
+	 charset (and cte (intern (downcase
+				   (gnus-strip-whitespace cte))))
+	 (car ctl)))))))
+
+(defun article-decode-encoded-words ()
+  "Remove encoded-word encoding from headers."
+  (let ((inhibit-point-motion-hooks t)
+	(mail-parse-charset gnus-newsgroup-charset)
+	(mail-parse-ignored-charsets 
+	 (save-excursion (condition-case nil
+			     (set-buffer gnus-summary-buffer)
+			   (error))
+			 gnus-newsgroup-ignored-charsets))
+	buffer-read-only)
+    (save-restriction
+      (article-narrow-to-head)
+      (funcall gnus-decode-header-function (point-min) (point-max)))))
 
 (defun article-de-quoted-unreadable (&optional force)
-  "Do a naive translation of a quoted-printable-encoded article.
-This is in no way, shape or form meant as a replacement for real MIME
-processing, but is simply a stop-gap measure until MIME support is
-written.
+  "Translate a quoted-printable-encoded article.
 If FORCE, decode the article whether it is marked as quoted-printable
 or not."
   (interactive (list 'force))
   (save-excursion
-    (let ((case-fold-search t)
-	  (buffer-read-only nil)
-	  (type (gnus-fetch-field "content-transfer-encoding")))
-      (gnus-article-decode-rfc1522)
+    (let ((buffer-read-only nil)
+	  (type (gnus-fetch-field "content-transfer-encoding"))
+	  (charset gnus-newsgroup-charset))
       (when (or force
 		(and type (string-match "quoted-printable" (downcase type))))
-	(goto-char (point-min))
-	(search-forward "\n\n" nil 'move)
-	(article-mime-decode-quoted-printable (point) (point-max))))))
-
-(defun article-mime-decode-quoted-printable-buffer ()
-  "Decode Quoted-Printable in the current buffer."
-  (article-mime-decode-quoted-printable (point-min) (point-max)))
-
-(defun article-mime-decode-quoted-printable (from to)
-  "Decode Quoted-Printable in the region between FROM and TO."
-  (interactive "r")
-  (goto-char from)
-  (while (search-forward "=" to t)
-    (cond ((eq (following-char) ?\n)
-	   (delete-char -1)
-	   (delete-char 1))
-	  ((looking-at "[0-9A-F][0-9A-F]")
-	   (subst-char-in-region
-	    (1- (point)) (point) ?=
-	    (hexl-hex-string-to-integer
-	     (buffer-substring (point) (+ 2 (point)))))
-	   (delete-char 2))
-	  ((looking-at "=")
-	   (delete-char 1))
-	  ((gnus-message 3 "Malformed MIME quoted-printable message")))))
-
-(defun article-hide-pgp (&optional arg)
-  "Toggle hiding of any PGP headers and signatures in the current article.
-If given a negative prefix, always show; if given a positive prefix,
-always hide."
-  (interactive (gnus-article-hidden-arg))
-  (unless (gnus-article-check-hidden-text 'pgp arg)
-    (save-excursion
+	(article-goto-body)
+	(quoted-printable-decode-region (point) (point-max) charset)))))
+
+(defun article-de-base64-unreadable (&optional force)
+  "Translate a base64 article.
+If FORCE, decode the article whether it is marked as base64 not."
+  (interactive (list 'force))
+  (save-excursion
+    (let ((buffer-read-only nil)
+	  (type (gnus-fetch-field "content-transfer-encoding"))
+	  (charset gnus-newsgroup-charset))
+      (when (or force
+		(and type (string-match "base64" (downcase type))))
+	(article-goto-body)
+	(save-restriction
+	  (narrow-to-region (point) (point-max))
+	  (base64-decode-region (point-min) (point-max))
+	  (if (mm-coding-system-p charset)
+	      (mm-decode-coding-region (point-min) (point-max) charset)))))))
+
+(eval-when-compile
+  (require 'rfc1843))
+
+(defun article-decode-HZ ()
+  "Translate a HZ-encoded article."
+  (interactive)
+  (require 'rfc1843)
+  (save-excursion
+    (let ((buffer-read-only nil))
+      (rfc1843-decode-region (point-min) (point-max)))))
+
+(defun article-wash-html ()
+  "Format an html article."
+  (interactive)
+  (save-excursion
+    (let ((buffer-read-only nil)
+	  (charset gnus-newsgroup-charset))
+      (article-goto-body)
+      (save-window-excursion
+	(save-restriction
+	  (narrow-to-region (point) (point-max))
+	  (mm-setup-w3)
+	  (let ((w3-strict-width (window-width))
+		(url-standalone-mode t))
+	    (condition-case var
+		(w3-region (point-min) (point-max))
+	      (error))))))))
+
+(defun article-hide-list-identifiers ()
+  "Remove list identifies from the Subject header.
+The `gnus-list-identifiers' variable specifies what to do."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t)
+	    buffer-read-only)
+	(article-narrow-to-head)
+	(let ((regexp (if (stringp gnus-list-identifiers) gnus-list-identifiers
+			(mapconcat 'identity gnus-list-identifiers " *\\|"))))
+	  (when regexp
+	    (goto-char (point-min))
+	    (when (re-search-forward
+		   (concat "^Subject: +\\(\\(\\(Re: +\\)?\\(" regexp 
+			   " *\\)\\)+\\(Re: +\\)?\\)")
+		   nil t)
+	      (let ((s (or (match-string 3) (match-string 5))))
+		(delete-region (match-beginning 1) (match-end 1))
+		(when s
+		  (goto-char (match-beginning 1))
+		  (insert s))))))))))
+
+(defun article-hide-pgp ()
+  "Remove any PGP headers and signatures in the current article."
+  (interactive)
+  (save-excursion
+    (save-restriction
       (let ((inhibit-point-motion-hooks t)
 	    buffer-read-only beg end)
-	(widen)
-	(goto-char (point-min))
+	(article-goto-body)
 	;; Hide the "header".
-	(when (search-forward "\n-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
-	  (delete-region (1+ (match-beginning 0)) (match-end 0))
+	(when (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
+	  (push 'pgp gnus-article-wash-types)
+	  (delete-region (match-beginning 0) (match-end 0))
+	  ;; Remove armor headers (rfc2440 6.2)
+	  (delete-region (point) (or (re-search-forward "^[ \t]*\n" nil t)
+				     (point)))
 	  (setq beg (point))
 	  ;; Hide the actual signature.
 	  (and (search-forward "\n-----BEGIN PGP SIGNATURE-----\n" nil t)
@@ -1081,25 +1630,62 @@
   (unless (gnus-article-check-hidden-text 'pem arg)
     (save-excursion
       (let (buffer-read-only end)
-	(widen)
 	(goto-char (point-min))
-	;; hide the horrendously ugly "header".
-	(and (search-forward "\n-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n"
-			     nil
-			     t)
-	     (setq end (1+ (match-beginning 0)))
-	     (gnus-article-hide-text-type
-	      end
-	      (if (search-forward "\n\n" nil t)
-		  (match-end 0)
-		(point-max))
-	      'pem))
-	;; hide the trailer as well
-	(and (search-forward "\n-----END PRIVACY-ENHANCED MESSAGE-----\n"
-			     nil
-			     t)
-	     (gnus-article-hide-text-type
-	      (match-beginning 0) (match-end 0) 'pem))))))
+	;; Hide the horrendously ugly "header".
+	(when (and (search-forward
+		    "\n-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n"
+		    nil t)
+		   (setq end (1+ (match-beginning 0))))
+	  (push 'pem gnus-article-wash-types)
+	  (gnus-article-hide-text-type
+	   end
+	   (if (search-forward "\n\n" nil t)
+	       (match-end 0)
+	     (point-max))
+	   'pem)
+	  ;; Hide the trailer as well
+	  (when (search-forward "\n-----END PRIVACY-ENHANCED MESSAGE-----\n"
+				nil t)
+	    (gnus-article-hide-text-type
+	     (match-beginning 0) (match-end 0) 'pem)))))))
+
+(defun article-strip-banner ()
+  "Strip the banner specified by the `banner' group parameter."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t)
+	    (banner (gnus-group-get-parameter gnus-newsgroup-name 'banner))
+	    (gnus-signature-limit nil)
+	    buffer-read-only beg end)
+	(when banner
+	  (article-goto-body)
+	  (cond
+	   ((eq banner 'signature)
+	    (when (gnus-article-narrow-to-signature)
+	      (widen)
+	      (forward-line -1)
+	      (delete-region (point) (point-max))))
+	   ((stringp banner)
+	    (while (re-search-forward banner nil t)
+	      (delete-region (match-beginning 0) (match-end 0))))))))))
+
+(defun article-babel ()
+  "Translate article using an online translation service."
+  (interactive)
+  (require 'babel)
+  (save-excursion
+    (set-buffer gnus-article-buffer)
+    (when (article-goto-body)
+      (let* ((buffer-read-only nil)
+	     (start (point))
+	     (end (point-max))
+	     (orig (buffer-substring start end))
+             (trans (babel-as-string orig)))
+	(save-restriction
+	  (narrow-to-region start end)
+	  (delete-region start end)
+          (insert trans))))))
 
 (defun article-hide-signature (&optional arg)
   "Hide the signature in the current article.
@@ -1114,18 +1700,50 @@
 	    (gnus-article-hide-text-type
 	     (point-min) (point-max) 'signature)))))))
 
+(defun article-strip-headers-in-body ()
+  "Strip offensive headers from bodies."
+  (interactive)
+  (save-excursion
+    (article-goto-body)
+    (let ((case-fold-search t))
+      (when (looking-at "x-no-archive:")
+	(gnus-delete-line)))))
+
 (defun article-strip-leading-blank-lines ()
   "Remove all blank lines from the beginning of the article."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
 	  buffer-read-only)
-      (goto-char (point-min))
-      (when (search-forward "\n\n" nil t)
+      (when (article-goto-body)
 	(while (and (not (eobp))
 		    (looking-at "[ \t]*$"))
 	  (gnus-delete-line))))))
 
+(defun article-narrow-to-head ()
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
+  (narrow-to-region
+   (goto-char (point-min))
+   (if (search-forward "\n\n" nil 1)
+       (1- (point))
+     (point-max)))
+  (goto-char (point-min)))
+
+(defun article-goto-body ()
+  "Place point at the start of the body."
+  (goto-char (point-min))
+  (cond
+   ;; This variable is only bound when dealing with separate
+   ;; MIME body parts.
+   (article-goto-body-goes-to-point-min-p
+    t)
+   ((search-forward "\n\n" nil t)
+    t)
+   (t
+    (goto-char (point-max))
+    nil)))
+
 (defun article-strip-multiple-blank-lines ()
   "Replace consecutive blank lines with one empty line."
   (interactive)
@@ -1133,15 +1751,17 @@
     (let ((inhibit-point-motion-hooks t)
 	  buffer-read-only)
       ;; First make all blank lines empty.
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (while (re-search-forward "^[ \t]+$" nil t)
-	(replace-match "" nil t))
+	(unless (gnus-annotation-in-region-p
+		 (match-beginning 0) (match-end 0))
+	  (replace-match "" nil t)))
       ;; Then replace multiple empty lines with a single empty line.
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (while (re-search-forward "\n\n\n+" nil t)
-	(replace-match "\n\n" t t)))))
+	(unless (gnus-annotation-in-region-p
+		 (match-beginning 0) (match-end 0))
+	  (replace-match "\n\n" t t))))))
 
 (defun article-strip-leading-space ()
   "Remove all white space from the beginning of the lines in the article."
@@ -1149,11 +1769,20 @@
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
 	  buffer-read-only)
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (while (re-search-forward "^[ \t]+" nil t)
 	(replace-match "" t t)))))
 
+(defun article-strip-trailing-space ()
+  "Remove all white space from the end of the lines in the article."
+  (interactive)
+  (save-excursion
+    (let ((inhibit-point-motion-hooks t)
+	  buffer-read-only)
+      (article-goto-body)
+      (while (re-search-forward "[ \t]+$" nil t)
+	(replace-match "" t t)))))
+
 (defun article-strip-blank-lines ()
   "Strip leading, trailing and multiple blank lines."
   (interactive)
@@ -1167,26 +1796,13 @@
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
 	  buffer-read-only)
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (while (re-search-forward "^[ \t]*\n" nil t)
 	(replace-match "" t t)))))
 
-(defvar mime::preview/content-list)
-(defvar mime::preview-content-info/point-min)
 (defun gnus-article-narrow-to-signature ()
   "Narrow to the signature; return t if a signature is found, else nil."
-  (widen)
   (let ((inhibit-point-motion-hooks t))
-    (when (and (boundp 'mime::preview/content-list)
-	       mime::preview/content-list)
-      ;; We have a MIMEish article, so we use the MIME data to narrow.
-      (let ((pcinfo (car (last mime::preview/content-list))))
-	(ignore-errors
-	  (narrow-to-region
-	   (funcall (intern "mime::preview-content-info/point-min") pcinfo)
-	   (point-max)))))
-
     (when (gnus-article-search-signature)
       (forward-line 1)
       ;; Check whether we have some limits to what we consider
@@ -1226,38 +1842,6 @@
       (goto-char cur)
       nil)))
 
-(eval-and-compile
-  (autoload 'w3-display "w3-parse")
-  (autoload 'w3-do-setup "w3" "" t)
-  (autoload 'w3-region "w3-display" "" t))
-
-(defun gnus-article-treat-html ()
-  "Render HTML."
-  (interactive)
-  (let ((cbuf (current-buffer)))
-    (set-buffer gnus-article-buffer)
-    (let (buf buffer-read-only b e)
-      (w3-do-setup)
-      (goto-char (point-min))
-      (narrow-to-region
-       (if (search-forward "\n\n" nil t)
-	   (setq b (point))
-	 (point-max))
-       (setq e (point-max)))
-      (nnheader-temp-write nil
-	(insert-buffer-substring gnus-article-buffer b e)
-	(require 'url)
-	(save-window-excursion
-	  (w3-region (point-min) (point-max))
-	  (setq buf (buffer-substring-no-properties (point-min) (point-max)))))
-      (when buf
-	(delete-region (point-min) (point-max))
-	(insert buf))
-      (widen)
-      (goto-char (point-min))
-      (set-window-start (get-buffer-window (current-buffer)) (point-min))
-      (set-buffer cbuf))))
-
 (defun gnus-article-hidden-arg ()
   "Return the current prefix arg as a number, or 0 if no prefix."
   (list (if current-prefix-arg
@@ -1270,7 +1854,6 @@
 means show, 0 means toggle."
   (save-excursion
     (save-restriction
-      (widen)
       (let ((hide (gnus-article-hidden-text-p type)))
 	(cond
 	 ((or (null arg)
@@ -1287,12 +1870,13 @@
   "Say whether the current buffer contains hidden text of type TYPE."
   (let ((pos (text-property-any (point-min) (point-max) 'article-type type)))
     (while (and pos
-		(not (get-text-property pos 'invisible)))
+		(not (get-text-property pos 'invisible))
+		(not (get-text-property pos 'dummy-invisible)))
       (setq pos
 	    (text-property-any (1+ pos) (point-max) 'article-type type)))
     (if pos
 	'hidden
-      'shown)))
+      nil)))
 
 (defun gnus-article-show-hidden-text (type &optional hide)
   "Show all hidden text of type TYPE.
@@ -1325,144 +1909,158 @@
 (defun article-date-ut (&optional type highlight header)
   "Convert DATE date to universal time in the current article.
 If TYPE is `local', convert to local time; if it is `lapsed', output
-how much time has lapsed since DATE."
+how much time has lapsed since DATE.  For `lapsed', the value of
+`gnus-article-date-lapsed-new-header' says whether the \"X-Sent:\" header
+should replace the \"Date:\" one, or should be added below it."
   (interactive (list 'ut t))
   (let* ((header (or header
-		     (mail-header-date gnus-current-headers)
 		     (message-fetch-field "date")
 		     ""))
+	 (tdate-regexp "^Date:[ \t]\\|^X-Sent:[ \t]")
+ 	 (date-regexp
+	  (cond
+	   ((not gnus-article-date-lapsed-new-header)
+	    tdate-regexp)
+	   ((eq type 'lapsed)
+	    "^X-Sent:[ \t]")
+	   (t
+	    "^Date:[ \t]")))
 	 (date (if (vectorp header) (mail-header-date header)
 		 header))
-	 (date-regexp "^Date:[ \t]\\|^X-Sent:[ \t]")
 	 (inhibit-point-motion-hooks t)
-	 bface eface newline)
-    (when (and date (not (string= date "")))
-      (save-excursion
-	(save-restriction
-	  (nnheader-narrow-to-headers)
+	 pos
+	 bface eface)
+    (save-excursion
+      (save-restriction
+	(article-narrow-to-head)
+	(when (re-search-forward tdate-regexp nil t)
+	  (setq bface (get-text-property (gnus-point-at-bol) 'face)
+		date (or (get-text-property (gnus-point-at-bol)
+					    'original-date)
+			 date)
+		eface (get-text-property (1- (gnus-point-at-eol)) 'face))
+	  (forward-line 1))
+	(when (and date (not (string= date "")))
+	  (goto-char (point-min))
 	  (let ((buffer-read-only nil))
-	    ;; Delete any old Date headers.
-	    (if (re-search-forward date-regexp nil t)
-		(progn
-		  (setq bface (get-text-property (gnus-point-at-bol) 'face)
-			eface (get-text-property (1- (gnus-point-at-eol))
-						 'face))
+ 	    ;; Delete any old Date headers.
+ 	    (while (re-search-forward date-regexp nil t)
+	      (if pos
 		  (delete-region (progn (beginning-of-line) (point))
-				 (progn (end-of-line) (point)))
-		  (beginning-of-line))
-	      (goto-char (point-max))
-	      (setq newline t))
-	    (insert (article-make-date-line date type))
+				 (progn (forward-line 1) (point)))
+		(delete-region (progn (beginning-of-line) (point))
+			       (progn (end-of-line) (point)))
+		(setq pos (point))))
+	    (when (and (not pos) (re-search-forward tdate-regexp nil t))
+	      (forward-line 1))
+	    (if pos (goto-char pos))
+	    (insert (article-make-date-line date (or type 'ut)))
+	    (when (not pos)
+	      (insert "\n")
+	      (forward-line -1))
 	    ;; Do highlighting.
 	    (beginning-of-line)
 	    (when (looking-at "\\([^:]+\\): *\\(.*\\)$")
 	      (put-text-property (match-beginning 1) (1+ (match-end 1))
+				 'original-date date)
+	      (put-text-property (match-beginning 1) (1+ (match-end 1))
 				 'face bface)
 	      (put-text-property (match-beginning 2) (match-end 2)
-				 'face eface))
-	    (when newline
-	      (end-of-line)
-	      (insert "\n"))))))))
+				 'face eface))))))))
 
 (defun article-make-date-line (date type)
   "Return a DATE line of TYPE."
-  (cond
-   ;; Convert to the local timezone.  We have to slap a
-   ;; `condition-case' round the calls to the timezone
-   ;; functions since they aren't particularly resistant to
-   ;; buggy dates.
-   ((eq type 'local)
-    (concat "Date: " (condition-case ()
-			 (timezone-make-date-arpa-standard date)
-		       (error date))))
-   ;; Convert to Universal Time.
-   ((eq type 'ut)
-    (concat "Date: "
-	    (condition-case ()
-		(timezone-make-date-arpa-standard date nil "UT")
-	      (error date))))
-   ;; Get the original date from the article.
-   ((eq type 'original)
-    (concat "Date: " date))
-   ;; Let the user define the format.
-   ((eq type 'user)
-    (if (gnus-functionp gnus-article-time-format)
-	(funcall
-	 gnus-article-time-format
-	 (ignore-errors
-	   (gnus-encode-date
-	    (timezone-make-date-arpa-standard
-	     date nil "UT"))))
-      (concat
-       "Date: "
-       (format-time-string gnus-article-time-format
-			   (ignore-errors
-			     (gnus-encode-date
-			      (timezone-make-date-arpa-standard
-			       date nil "UT")))))))
-   ;; ISO 8601.
-   ((eq type 'iso8601)
-    (concat
-     "Date: "
-     (format-time-string "%Y%M%DT%h%m%s"
-			 (ignore-errors
-			   (gnus-encode-date
-			    (timezone-make-date-arpa-standard
-			     date nil "UT"))))))
-   ;; Do an X-Sent lapsed format.
-   ((eq type 'lapsed)
-    ;; If the date is seriously mangled, the timezone functions are
-    ;; liable to bug out, so we ignore all errors.
-    (let* ((now (current-time))
-	   (real-time
-	    (ignore-errors
-	      (gnus-time-minus
-	       (gnus-encode-date
-		(timezone-make-date-arpa-standard
-		 (current-time-string now)
-		 (current-time-zone now) "UT"))
-	       (gnus-encode-date
-		(timezone-make-date-arpa-standard
-		 date nil "UT")))))
-	   (real-sec (and real-time
-			  (+ (* (float (car real-time)) 65536)
-			     (cadr real-time))))
-	   (sec (and real-time (abs real-sec)))
-	   num prev)
-      (cond
-       ((null real-time)
-	"X-Sent: Unknown")
-       ((zerop sec)
-	"X-Sent: Now")
-       (t
+  (let ((time (condition-case ()
+		  (date-to-time date)
+		(error '(0 0)))))
+    (cond
+     ;; Convert to the local timezone.  We have to slap a
+     ;; `condition-case' round the calls to the timezone
+     ;; functions since they aren't particularly resistant to
+     ;; buggy dates.
+     ((eq type 'local)
+      (let ((tz (car (current-time-zone time))))
+	(format "Date: %s %s%02d%02d" (current-time-string time)
+		(if (> tz 0) "+" "-") (/ (abs tz) 3600) 
+		(/ (% (abs tz) 3600) 60))))
+     ;; Convert to Universal Time.
+     ((eq type 'ut)
+      (concat "Date: "
+	      (current-time-string
+	       (let* ((e (parse-time-string date))
+		      (tm (apply 'encode-time e))
+		      (ms (car tm))
+		      (ls (- (cadr tm) (car (current-time-zone time)))))
+		 (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
+		       ((> ls 65535) (list (1+ ms) (- ls 65536)))
+		       (t (list ms ls)))))
+	      " UT"))
+     ;; Get the original date from the article.
+     ((eq type 'original)
+      (concat "Date: " (if (string-match "\n+$" date)
+			   (substring date 0 (match-beginning 0))
+			 date)))
+     ;; Let the user define the format.
+     ((eq type 'user)
+      (if (gnus-functionp gnus-article-time-format)
+	  (funcall gnus-article-time-format time)
+	(concat
+	 "Date: "
+	 (format-time-string gnus-article-time-format time))))
+     ;; ISO 8601.
+     ((eq type 'iso8601)
+      (let ((tz (car (current-time-zone time))))
 	(concat
-	 "X-Sent: "
-	 ;; This is a bit convoluted, but basically we go
-	 ;; through the time units for years, weeks, etc,
-	 ;; and divide things to see whether that results
-	 ;; in positive answers.
-	 (mapconcat
-	  (lambda (unit)
-	    (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
-		;; The (remaining) seconds are too few to
-		;; be divided into this time unit.
-		""
-	      ;; It's big enough, so we output it.
-	      (setq sec (- sec (* num (cdr unit))))
-	      (prog1
-		  (concat (if prev ", " "") (int-to-string
-					     (floor num))
-			  " " (symbol-name (car unit))
-			  (if (> num 1) "s" ""))
-		(setq prev t))))
-	  article-time-units "")
-	 ;; If dates are odd, then it might appear like the
-	 ;; article was sent in the future.
-	 (if (> real-sec 0)
-	     " ago"
-	   " in the future"))))))
-   (t
-    (error "Unknown conversion type: %s" type))))
+	 "Date: "
+	 (format-time-string "%Y%m%dT%H%M%S" time)
+	 (format "%s%02d%02d"
+		 (if (> tz 0) "+" "-") (/ (abs tz) 3600) 
+		 (/ (% (abs tz) 3600) 60)))))
+     ;; Do an X-Sent lapsed format.
+     ((eq type 'lapsed)
+      ;; If the date is seriously mangled, the timezone functions are
+      ;; liable to bug out, so we ignore all errors.
+      (let* ((now (current-time))
+	     (real-time (subtract-time now time))
+	     (real-sec (and real-time
+			    (+ (* (float (car real-time)) 65536)
+			       (cadr real-time))))
+	     (sec (and real-time (abs real-sec)))
+	     num prev)
+	(cond
+	 ((null real-time)
+	  "X-Sent: Unknown")
+	 ((zerop sec)
+	  "X-Sent: Now")
+	 (t
+	  (concat
+	   "X-Sent: "
+	   ;; This is a bit convoluted, but basically we go
+	   ;; through the time units for years, weeks, etc,
+	   ;; and divide things to see whether that results
+	   ;; in positive answers.
+	   (mapconcat
+	    (lambda (unit)
+	      (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
+		  ;; The (remaining) seconds are too few to
+		  ;; be divided into this time unit.
+		  ""
+		;; It's big enough, so we output it.
+		(setq sec (- sec (* num (cdr unit))))
+		(prog1
+		    (concat (if prev ", " "") (int-to-string
+					       (floor num))
+			    " " (symbol-name (car unit))
+			    (if (> num 1) "s" ""))
+		  (setq prev t))))
+	    article-time-units "")
+	   ;; If dates are odd, then it might appear like the
+	   ;; article was sent in the future.
+	   (if (> real-sec 0)
+	       " ago"
+	     " in the future"))))))
+     (t
+      (error "Unknown conversion type: %s" type)))))
 
 (defun article-date-local (&optional highlight)
   "Convert the current article date to the local timezone."
@@ -1486,11 +2084,14 @@
   (let (deactivate-mark)
     (save-excursion
       (ignore-errors
-        (when (gnus-buffer-live-p gnus-article-buffer)
-          (set-buffer gnus-article-buffer)
-          (goto-char (point-min))
-          (when (re-search-forward "^X-Sent:" nil t)
-            (article-date-lapsed t)))))))
+	(walk-windows
+	 (lambda (w)
+	   (set-buffer (window-buffer w))
+	   (when (eq major-mode 'gnus-article-mode)
+	     (goto-char (point-min))
+	     (when (re-search-forward "^X-Sent:" nil t)
+	       (article-date-lapsed t))))
+	 nil 'visible)))))
 
 (defun gnus-start-date-timer (&optional n)
   "Start a timer to update the X-Sent header in the article buffers.
@@ -1533,13 +2134,17 @@
   (interactive (gnus-article-hidden-arg))
   (unless (gnus-article-check-hidden-text 'emphasis arg)
     (save-excursion
-      (let ((alist gnus-emphasis-alist)
+      (let ((alist (or 
+		    (condition-case nil
+			(with-current-buffer gnus-summary-buffer 
+			  gnus-article-emphasis-alist) 
+		      (error))
+		    gnus-emphasis-alist))
 	    (buffer-read-only nil)
 	    (props (append '(article-type emphasis)
 			   gnus-hidden-properties))
 	    regexp elem beg invisible visible face)
-	(goto-char (point-min))
-	(search-forward "\n\n" nil t)
+	(article-goto-body)
 	(setq beg (point))
 	(while (setq elem (pop alist))
 	  (goto-char beg)
@@ -1549,6 +2154,7 @@
 		face (nth 3 elem))
 	  (while (re-search-forward regexp nil t)
  	    (when (and (match-beginning visible) (match-beginning invisible))
+	      (push 'emphasis gnus-article-wash-types)
  	      (gnus-article-hide-text
  	       (match-beginning invisible) (match-end invisible) props)
  	      (gnus-article-unhide-text-type
@@ -1557,6 +2163,26 @@
  	       (match-beginning visible) (match-end visible) 'face face)
  	      (goto-char (match-end invisible)))))))))
 
+(defun gnus-article-setup-highlight-words (&optional highlight-words)
+  "Setup newsgroup emphasis alist."
+  (unless gnus-article-emphasis-alist
+    (let ((name (and gnus-newsgroup-name
+		     (gnus-group-real-name gnus-newsgroup-name))))
+      (make-local-variable 'gnus-article-emphasis-alist)
+      (setq gnus-article-emphasis-alist 
+	    (nconc 
+	     (let ((alist gnus-group-highlight-words-alist) elem highlight)
+	       (while (setq elem (pop alist))
+		 (when (and name (string-match (car elem) name))
+		   (setq alist nil
+			 highlight (copy-sequence (cdr elem)))))
+	       highlight)
+	     (copy-sequence highlight-words)
+	     (if gnus-newsgroup-name
+		 (copy-sequence (gnus-group-find-parameter 
+				 gnus-newsgroup-name 'highlight-words t)))
+	     gnus-emphasis-alist)))))
+
 (defvar gnus-summary-article-menu)
 (defvar gnus-summary-post-menu)
 
@@ -1576,7 +2202,7 @@
     (if (not gnus-default-article-saver)
 	(error "No default saver is defined")
       ;; !!! Magic!  The saving functions all save
-      ;; `gnus-original-article-buffer' (or so they think), but we
+      ;; `gnus-save-article-buffer' (or so they think), but we
       ;; bind that variable to our save-buffer.
       (set-buffer gnus-article-buffer)
       (let* ((gnus-save-article-buffer save-buffer)
@@ -1662,8 +2288,8 @@
 	 (gnus-make-directory (file-name-directory file))
 	 ;; If we have read a directory, we append the default file name.
 	 (when (file-directory-p file)
-	   (setq file (concat (file-name-as-directory file)
-			      (file-name-nondirectory default-name))))
+	   (setq file (expand-file-name (file-name-nondirectory default-name)
+					(file-name-as-directory file))))
 	 ;; Possibly translate some characters.
 	 (nnheader-translate-file-chars file)))))
     (gnus-make-directory (file-name-directory result))
@@ -1710,7 +2336,7 @@
 	(widen)
 	(if (and (file-readable-p filename)
 		 (mail-file-babyl-p filename))
-	    (gnus-output-to-rmail filename t)
+	    (rmail-output-to-rmail-file filename t)
 	  (gnus-output-to-mail filename)))))
   filename)
 
@@ -1750,8 +2376,7 @@
     (save-excursion
       (save-restriction
 	(widen)
-	(goto-char (point-min))
-	(when (search-forward "\n\n" nil t)
+	(when (article-goto-body)
 	  (narrow-to-region (point) (point-max)))
 	(gnus-output-to-file filename))))
   filename)
@@ -1759,7 +2384,8 @@
 (defun gnus-summary-save-in-pipe (&optional command)
   "Pipe this article to subprocess."
   (setq command
-	(cond ((eq command 'default)
+	(cond ((and (eq command 'default)
+		    gnus-last-shell-command)
 	       gnus-last-shell-command)
 	      (command command)
 	      (t (read-string
@@ -1823,17 +2449,6 @@
 	default
       (or last-file default))))
 
-(defun gnus-Plain-save-name (newsgroup headers &optional last-file)
-  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
-If variable `gnus-use-long-file-name' is non-nil, it is
-~/News/News.group.  Otherwise, it is like ~/News/news/group/news."
-  (or last-file
-      (expand-file-name
-       (if (gnus-use-long-file-name 'not-save)
-	   (gnus-capitalize-newsgroup newsgroup)
-	 (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
-       gnus-article-save-directory)))
-
 (defun gnus-plain-save-name (newsgroup headers &optional last-file)
   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
 If variable `gnus-use-long-file-name' is non-nil, it is
@@ -1842,7 +2457,7 @@
       (expand-file-name
        (if (gnus-use-long-file-name 'not-save)
 	   newsgroup
-	 (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
+	 (expand-file-name "news" (gnus-newsgroup-directory-form newsgroup)))
        gnus-article-save-directory)))
 
 (eval-and-compile
@@ -1854,42 +2469,53 @@
 		 gfunc (cdr func))
 	 (setq afunc func
 	       gfunc (intern (format "gnus-%s" func))))
-       (fset gfunc
-	     (if (not (fboundp afunc))
-		 nil
-	       `(lambda (&optional interactive &rest args)
-		  ,(documentation afunc t)
-		  (interactive (list t))
-		  (save-excursion
-		    (set-buffer gnus-article-buffer)
-		    (if interactive
-			(call-interactively ',afunc)
-		      (apply ',afunc args))))))))
+       (defalias gfunc
+	 (if (fboundp afunc)
+	   `(lambda (&optional interactive &rest args)
+	      ,(documentation afunc t)
+	      (interactive (list t))
+	      (save-excursion
+		(set-buffer gnus-article-buffer)
+		(if interactive
+		    (call-interactively ',afunc)
+		  (apply ',afunc args))))))))
    '(article-hide-headers
      article-hide-boring-headers
      article-treat-overstrike
-     (article-fill . gnus-article-word-wrap)
+     article-fill-long-lines
+     article-capitalize-sentences
      article-remove-cr
      article-display-x-face
      article-de-quoted-unreadable
-     article-mime-decode-quoted-printable
+     article-de-base64-unreadable
+     article-decode-HZ
+     article-wash-html
+     article-hide-list-identifiers
      article-hide-pgp
+     article-strip-banner
+     article-babel
      article-hide-pem
      article-hide-signature
+     article-strip-headers-in-body
      article-remove-trailing-blank-lines
      article-strip-leading-blank-lines
      article-strip-multiple-blank-lines
      article-strip-leading-space
+     article-strip-trailing-space
      article-strip-blank-lines
      article-strip-all-blank-lines
      article-date-local
      article-date-iso8601
      article-date-original
      article-date-ut
+     article-decode-mime-words
+     article-decode-charset
+     article-decode-encoded-words
      article-date-user
      article-date-lapsed
      article-emphasize
      article-treat-dumbquotes
+     article-normalize-headers
      (article-show-all . gnus-article-show-all-headers))))
 
 ;;;
@@ -1898,20 +2524,19 @@
 
 (put 'gnus-article-mode 'mode-class 'special)
 
+(set-keymap-parent gnus-article-mode-map widget-keymap)
+
 (gnus-define-keys gnus-article-mode-map
   " " gnus-article-goto-next-page
   "\177" gnus-article-goto-prev-page
   [delete] gnus-article-goto-prev-page
+  [backspace] gnus-article-goto-prev-page
   "\C-c^" gnus-article-refer-article
   "h" gnus-article-show-summary
   "s" gnus-article-show-summary
   "\C-c\C-m" gnus-article-mail
   "?" gnus-article-describe-briefly
-  gnus-mouse-2 gnus-article-push-button
-  "\r" gnus-article-press-button
-  "\t" gnus-article-next-button
-  "\M-\t" gnus-article-prev-button
-  "e" gnus-article-edit
+  "e" gnus-summary-edit-article
   "<" beginning-of-buffer
   ">" end-of-buffer
   "\C-c\C-i" gnus-info-find-node
@@ -1947,7 +2572,10 @@
        ["Hide citation" gnus-article-hide-citation t]
        ["Treat overstrike" gnus-article-treat-overstrike t]
        ["Remove carriage return" gnus-article-remove-cr t]
-       ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]))
+       ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
+       ["Remove base64" gnus-article-de-base64-unreadable t]
+       ["Treat html" gnus-article-wash-html t]
+       ["Decode HZ" gnus-article-decode-HZ t]))
 
     ;; Note "Commands" menu is defined in gnus-sum.el for consistency
 
@@ -1979,18 +2607,21 @@
   (setq mode-name "Article")
   (setq major-mode 'gnus-article-mode)
   (make-local-variable 'minor-mode-alist)
-  (unless (assq 'gnus-show-mime minor-mode-alist)
-    (push (list 'gnus-show-mime " MIME") minor-mode-alist))
   (use-local-map gnus-article-mode-map)
   (gnus-update-format-specifications nil 'article-mode)
   (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
   (make-local-variable 'gnus-page-broken)
   (make-local-variable 'gnus-button-marker-list)
   (make-local-variable 'gnus-article-current-summary)
+  (make-local-variable 'gnus-article-mime-handles)
+  (make-local-variable 'gnus-article-decoded-p)
+  (make-local-variable 'gnus-article-mime-handle-alist)
+  (make-local-variable 'gnus-article-wash-types)
   (gnus-set-default-directory)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq buffer-read-only t)
   (set-syntax-table gnus-article-mode-syntax-table)
+  (mm-enable-multibyte)
   (gnus-run-hooks 'gnus-article-mode-hook))
 
 (defun gnus-article-setup-buffer ()
@@ -2003,6 +2634,7 @@
 			 (substring name (match-end 0))))))
     (setq gnus-article-buffer name)
     (setq gnus-original-article-buffer original)
+    (setq gnus-article-mime-handle-alist nil)
     ;; This might be a variable local to the summary buffer.
     (unless gnus-single-article-buffer
       (save-excursion
@@ -2010,16 +2642,22 @@
 	(setq gnus-article-buffer name)
 	(setq gnus-original-article-buffer original)
 	(gnus-set-global-variables)))
+    (gnus-article-setup-highlight-words)
     ;; Init original article buffer.
     (save-excursion
       (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
-      (buffer-disable-undo (current-buffer))
+      (mm-enable-multibyte)
       (setq major-mode 'gnus-original-article-mode)
       (make-local-variable 'gnus-original-article))
     (if (get-buffer name)
 	(save-excursion
 	  (set-buffer name)
-	  (buffer-disable-undo (current-buffer))
+	  (when gnus-article-mime-handles
+	    (mm-destroy-parts gnus-article-mime-handles)
+	    (setq gnus-article-mime-handles nil))
+	  ;; Set it to nil in article-buffer!
+	  (setq gnus-article-mime-handle-alist nil) 
+	  (buffer-disable-undo)
 	  (setq buffer-read-only t)
 	  (unless (eq major-mode 'gnus-article-mode)
 	    (gnus-article-mode))
@@ -2028,6 +2666,7 @@
 	(set-buffer (gnus-get-buffer-create name))
 	(gnus-article-mode)
 	(make-local-variable 'gnus-summary-buffer)
+	(gnus-summary-set-local-parameters gnus-newsgroup-name)
 	(current-buffer)))))
 
 ;; Set article window start at LINE, where LINE is the number of lines
@@ -2084,8 +2723,7 @@
 		      (message "Message marked for downloading"))
 		  (gnus-summary-mark-article article gnus-canceled-mark)
 		  (unless (memq article gnus-newsgroup-sparse)
-		    (gnus-error 1
-		     "No such article (may have expired or been canceled)")))))
+		    (gnus-error 1 "No such article (may have expired or been canceled)")))))
 	  (if (or (eq result 'pseudo)
 		  (eq result 'nneething))
 	      (progn
@@ -2100,7 +2738,9 @@
 		      (gnus-configure-windows 'summary)
 		    (gnus-configure-windows 'article))
 		  (gnus-set-global-variables))
-		(gnus-set-mode-line 'article))
+		(let ((gnus-article-mime-handle-alist-1
+		       gnus-article-mime-handle-alist))
+		  (gnus-set-mode-line 'article)))
 	    ;; The result from the `request' was an actual article -
 	    ;; or at least some text that is now displayed in the
 	    ;; article buffer.
@@ -2131,85 +2771,723 @@
 		(when (gnus-visual-p 'article-highlight 'highlight)
 		  (gnus-run-hooks 'gnus-visual-mark-article-hook))
 		;; Set the global newsgroup variables here.
-		;; Suggested by Jim Sisolak
-		;; <sisolak@trans4.neep.wisc.edu>.
 		(gnus-set-global-variables)
 		(setq gnus-have-all-headers
 		      (or all-headers gnus-show-all-headers))))
 	    (when (or (numberp article)
 		      (stringp article))
-	      ;; Hooks for getting information from the article.
-	      ;; This hook must be called before being narrowed.
-	      (let (buffer-read-only)
-		(gnus-run-hooks 'gnus-tmp-internal-hook)
-		(gnus-run-hooks 'gnus-article-prepare-hook)
-		;; Decode MIME message.
- 		(if gnus-show-mime
- 		    (if (or (not gnus-strict-mime)
- 			    (gnus-fetch-field "Mime-Version"))
-		      (let ((coding-system-for-write 'binary)
-			    (coding-system-for-read 'binary))
- 			(funcall gnus-show-mime-method))
- 		      (funcall gnus-decode-encoded-word-method))
- 		  (funcall gnus-show-traditional-method))
-		;; Perform the article display hooks.
-		(gnus-run-hooks 'gnus-article-display-hook))
+	      (gnus-article-prepare-display)
 	      ;; Do page break.
 	      (goto-char (point-min))
 	      (setq gnus-page-broken
 		    (when gnus-break-pages
 		      (gnus-narrow-to-page)
 		      t)))
-	    (gnus-set-mode-line 'article)
+	    (let ((gnus-article-mime-handle-alist-1
+		   gnus-article-mime-handle-alist))
+	      (gnus-set-mode-line 'article))
+	    (article-goto-body)
+	    (set-window-point (get-buffer-window (current-buffer)) (point))
 	    (gnus-configure-windows 'article)
-	    (goto-char (point-min))
-	    (search-forward "\n\n" nil t)
-	    (set-window-point (get-buffer-window (current-buffer)) (point))
 	    t))))))
 
+;;;###autoload
+(defun gnus-article-prepare-display ()
+  "Make the current buffer look like a nice article."
+  ;; Hooks for getting information from the article.
+  ;; This hook must be called before being narrowed.
+  (let ((gnus-article-buffer (current-buffer))
+	buffer-read-only)
+    (unless (eq major-mode 'gnus-article-mode)
+      (gnus-article-mode))
+    (setq buffer-read-only nil
+	  gnus-article-wash-types nil)
+    (gnus-run-hooks 'gnus-tmp-internal-hook)
+    (when gnus-display-mime-function
+      (funcall gnus-display-mime-function))
+    (gnus-run-hooks 'gnus-article-prepare-hook)))
+
+;;;
+;;; Gnus MIME viewing functions
+;;;
+
+(defvar gnus-mime-button-line-format "%{%([%p. %d%T]%)%}%e\n"
+  "The following specs can be used:
+%t  The MIME type
+%T  MIME type, along with additional info
+%n  The `name' parameter
+%d  The description, if any
+%l  The length of the encoded part
+%p  The part identifier number
+%e  Dots if the part isn't displayed")
+
+(defvar gnus-mime-button-line-format-alist
+  '((?t gnus-tmp-type ?s)
+    (?T gnus-tmp-type-long ?s)
+    (?n gnus-tmp-name ?s)
+    (?d gnus-tmp-description ?s)
+    (?p gnus-tmp-id ?s)
+    (?l gnus-tmp-length ?d)
+    (?e gnus-tmp-dots ?s)))
+
+(defvar gnus-mime-button-commands
+  '((gnus-article-press-button "\r" "Toggle Display")
+    (gnus-mime-view-part "v" "View Interactively...")
+    (gnus-mime-view-part-as-type "t" "View As Type...")
+    (gnus-mime-save-part "o" "Save...")
+    (gnus-mime-copy-part "c" "View As Text, In Other Buffer")
+    (gnus-mime-inline-part "i" "View As Text, In This Buffer")
+    (gnus-mime-internalize-part "E" "View Internally")
+    (gnus-mime-externalize-part "e" "View Externally")
+    (gnus-mime-pipe-part "|" "Pipe To Command...")))
+
+(defun gnus-article-mime-part-status ()
+  (if gnus-article-mime-handle-alist-1
+      (format " (%d parts)" (length gnus-article-mime-handle-alist-1))
+    ""))
+
+(defvar gnus-mime-button-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map gnus-article-mode-map)
+    (define-key map gnus-mouse-2 'gnus-article-push-button)
+    (define-key map gnus-down-mouse-3 'gnus-mime-button-menu)
+    (dolist (c gnus-mime-button-commands)
+      (define-key map (cadr c) (car c)))
+    map))
+
+(defun gnus-mime-button-menu (event)
+  "Construct a context-sensitive menu of MIME commands."
+  (interactive "e")
+  (save-excursion
+    (let ((pos (event-start event)))
+      (set-buffer (window-buffer (posn-window pos)))
+      (goto-char (posn-point pos))
+      (gnus-article-check-buffer)
+      (let ((response (x-popup-menu
+		       t `("MIME Part"
+			   ("" ,@(mapcar (lambda (c)
+					   (cons (caddr c) (car c)))
+					 gnus-mime-button-commands))))))
+	(if response
+	    (call-interactively response))))))
+
+(defun gnus-mime-view-all-parts (&optional handles)
+  "View all the MIME parts."
+  (interactive)
+  (save-current-buffer
+    (set-buffer gnus-article-buffer)
+    (let ((handles (or handles gnus-article-mime-handles))
+	  (mail-parse-charset gnus-newsgroup-charset)
+	  (mail-parse-ignored-charsets 
+	   (save-excursion (set-buffer gnus-summary-buffer)
+			   gnus-newsgroup-ignored-charsets)))
+      (if (stringp (car handles))
+	  (gnus-mime-view-all-parts (cdr handles))
+	(mapcar 'mm-display-part handles)))))
+
+(defun gnus-mime-save-part ()
+  "Save the MIME part under point."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (mm-save-part data)))
+
+(defun gnus-mime-pipe-part ()
+  "Pipe the MIME part under point to a process."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (mm-pipe-part data)))
+
+(defun gnus-mime-view-part ()
+  "Interactively choose a viewing method for the MIME part under point."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let ((data (get-text-property (point) 'gnus-data)))
+    (mm-interactively-view-part data)))
+
+(defun gnus-mime-view-part-as-type-internal ()
+  (gnus-article-check-buffer)
+  (let* ((name (mail-content-type-get
+		(mm-handle-type (get-text-property (point) 'gnus-data))
+		'name))
+	 (def-type (and name (mm-default-file-encoding name))))
+    (and def-type (cons def-type 0))))
+
+(defun gnus-mime-view-part-as-type (mime-type)
+  "Choose a MIME media type, and view the part as such."
+  (interactive
+   (list (completing-read
+	  "View as MIME type: "
+	  (mapcar #'list (mailcap-mime-types))
+	  nil nil
+	  (gnus-mime-view-part-as-type-internal))))
+  (gnus-article-check-buffer)
+  (let ((handle (get-text-property (point) 'gnus-data)))
+    (gnus-mm-display-part
+     (mm-make-handle (mm-handle-buffer handle)
+		     (cons mime-type (cdr (mm-handle-type handle)))
+		     (mm-handle-encoding handle)
+		     (mm-handle-undisplayer handle)
+		     (mm-handle-disposition handle)
+		     (mm-handle-description handle)
+		     (mm-handle-cache handle)
+		     (mm-handle-id handle)))))
+
+(defun gnus-mime-copy-part (&optional handle)
+  "Put the the MIME part under point into a new buffer."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+	 (contents (mm-get-part handle))|
+	 (base (file-name-nondirectory
+		(or
+		 (mail-content-type-get (mm-handle-type handle) 'name)
+		 (mail-content-type-get (mm-handle-type handle)
+					'filename)
+		 "*decoded*")))
+	 (buffer (generate-new-buffer base)))
+    (switch-to-buffer buffer)
+    (insert contents)
+    ;; We do it this way to make `normal-mode' set the appropriate mode.
+    (unwind-protect
+	(progn
+	  (setq buffer-file-name (expand-file-name base))
+	  (normal-mode))
+      (setq buffer-file-name nil))
+    (goto-char (point-min))))
+
+(defun gnus-mime-inline-part (&optional handle)
+  "Insert the MIME part under point into the current buffer."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+	 contents
+	 (b (point))
+	 buffer-read-only)
+    (if (mm-handle-undisplayer handle)
+	(mm-remove-part handle)
+      (setq contents (mm-get-part handle))
+      (forward-line 2)
+      (mm-insert-inline handle contents)
+      (goto-char b))))
+
+(defun gnus-mime-externalize-part (&optional handle)
+  "View the MIME part under point with an external viewer."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+	 (mm-user-display-methods nil)
+	 (mm-inlined-types nil)
+	 (mail-parse-charset gnus-newsgroup-charset)
+	 (mail-parse-ignored-charsets 
+	  (save-excursion (set-buffer gnus-summary-buffer)
+			  gnus-newsgroup-ignored-charsets)))
+    (if (mm-handle-undisplayer handle)
+	(mm-remove-part handle)
+      (mm-display-part handle))))
+
+(defun gnus-mime-internalize-part (&optional handle)
+  "View the MIME part under point with an internal viewer.
+In no internal viewer is available, use an external viewer."
+  (interactive)
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+	 (mm-inlined-types '(".*"))
+	 (mm-inline-large-images t)
+	 (mail-parse-charset gnus-newsgroup-charset)
+	 (mail-parse-ignored-charsets 
+	  (save-excursion (set-buffer gnus-summary-buffer)
+			  gnus-newsgroup-ignored-charsets)))
+    (if (mm-handle-undisplayer handle)
+	(mm-remove-part handle)
+      (mm-display-part handle))))
+
+(defun gnus-article-part-wrapper (n function)
+  (save-current-buffer
+    (set-buffer gnus-article-buffer)
+    (when (> n (length gnus-article-mime-handle-alist))
+      (error "No such part"))
+    (gnus-article-goto-part n)
+    (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
+      (funcall function handle))))
+
+(defun gnus-article-pipe-part (n)
+  "Pipe MIME part N, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'mm-pipe-part))
+
+(defun gnus-article-save-part (n)
+  "Save MIME part N, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'mm-save-part))
+
+(defun gnus-article-interactively-view-part (n)
+  "View MIME part N interactively, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'mm-interactively-view-part))
+
+(defun gnus-article-copy-part (n)
+  "Copy MIME part N, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'gnus-mime-copy-part))
+
+(defun gnus-article-externalize-part (n)
+  "View MIME part N externally, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'gnus-mime-externalize-part))
+
+(defun gnus-article-inline-part (n)
+  "Inline MIME part N, which is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'gnus-mime-inline-part))
+
+(defun gnus-article-mime-match-handle-first (condition)
+  (if condition
+      (let ((alist gnus-article-mime-handle-alist) ihandle n)
+	(while (setq ihandle (pop alist))
+	  (if (and (cond 
+		    ((functionp condition)
+		     (funcall condition (cdr ihandle)))
+		    ((eq condition 'undisplayed) 
+		     (not (or (mm-handle-undisplayer (cdr ihandle))
+			      (equal (mm-handle-media-type (cdr ihandle))
+				     "multipart/alternative"))))
+		    ((eq condition 'undisplayed-alternative)
+		     (not (mm-handle-undisplayer (cdr ihandle))))
+		    (t t))
+		   (gnus-article-goto-part (car ihandle))
+		   (or (not n) (< (car ihandle) n)))
+	      (setq n (car ihandle))))
+	(or n 1))
+    1))
+
+(defun gnus-article-view-part (&optional n)
+  "View MIME part N, which is the numerical prefix."
+  (interactive "P")
+  (save-current-buffer
+    (set-buffer gnus-article-buffer)
+    (or (numberp n) (setq n (gnus-article-mime-match-handle-first 
+			     gnus-article-mime-match-handle-function)))
+    (when (> n (length gnus-article-mime-handle-alist))
+      (error "No such part"))
+    (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
+      (when (gnus-article-goto-part n)
+	(if (equal (car handle) "multipart/alternative")
+	    (gnus-article-press-button)
+	  (when (eq (gnus-mm-display-part handle) 'internal)
+	    (gnus-set-window-start)))))))
+
+(defun gnus-mm-display-part (handle)
+  "Display HANDLE and fix MIME button."
+  (let ((id (get-text-property (point) 'gnus-part))
+	(point (point))
+	buffer-read-only)
+    (forward-line 1)
+    (prog1
+	(let ((window (selected-window))
+	      (mail-parse-charset gnus-newsgroup-charset)
+	      (mail-parse-ignored-charsets 
+	       (save-excursion (set-buffer gnus-summary-buffer)
+			       gnus-newsgroup-ignored-charsets)))
+	  (save-excursion
+	    (unwind-protect
+		(let ((win (get-buffer-window (current-buffer) t))
+		      (beg (point)))
+		  (when win
+		    (select-window win))
+		  (goto-char point)
+		  (forward-line)
+		  (if (mm-handle-displayed-p handle)
+		      ;; This will remove the part.
+		      (mm-display-part handle)
+		    (save-restriction
+		      (narrow-to-region (point) (1+ (point)))
+		      (mm-display-part handle)
+		      ;; We narrow to the part itself and
+		      ;; then call the treatment functions.
+		      (goto-char (point-min))
+		      (forward-line 1)
+		      (narrow-to-region (point) (point-max))
+		      (gnus-treat-article
+		       nil id
+		       (1- (length gnus-article-mime-handles))
+		       (mm-handle-media-type handle)))))
+	      (select-window window))))
+      (goto-char point)
+      (delete-region (gnus-point-at-bol) (progn (forward-line 1) (point)))
+      (gnus-insert-mime-button
+       handle id (list (mm-handle-displayed-p handle)))
+      (goto-char point))))
+
+(defun gnus-article-goto-part (n)
+  "Go to MIME part N."
+  (let ((point (text-property-any (point-min) (point-max) 'gnus-part n)))
+    (when point
+      (goto-char point))))
+
+(defun gnus-insert-mime-button (handle gnus-tmp-id &optional displayed)
+  (let ((gnus-tmp-name
+	 (or (mail-content-type-get (mm-handle-type handle)
+				    'name)
+	     (mail-content-type-get (mm-handle-disposition handle)
+				    'filename)
+	     ""))
+	(gnus-tmp-type (mm-handle-media-type handle))
+	(gnus-tmp-description
+	 (mail-decode-encoded-word-string (or (mm-handle-description handle)
+					      "")))
+	(gnus-tmp-dots
+	 (if (if displayed (car displayed)
+	       (mm-handle-displayed-p handle))
+	     "" "..."))
+	(gnus-tmp-length (with-current-buffer (mm-handle-buffer handle)
+			   (buffer-size)))
+	gnus-tmp-type-long b e)
+    (when (string-match ".*/" gnus-tmp-name)
+      (setq gnus-tmp-name (replace-match "" t t gnus-tmp-name)))
+    (setq gnus-tmp-type-long (concat gnus-tmp-type
+				     (and (not (equal gnus-tmp-name ""))
+					  (concat "; " gnus-tmp-name))))
+    (or (equal gnus-tmp-description "")
+	(setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
+    (unless (bolp)
+      (insert "\n"))
+    (setq b (point))
+    (gnus-eval-format
+     gnus-mime-button-line-format gnus-mime-button-line-format-alist
+     `(local-map ,gnus-mime-button-map
+		 keymap ,gnus-mime-button-map
+		 gnus-callback gnus-mm-display-part
+		 gnus-part ,gnus-tmp-id
+		 article-type annotation
+		 gnus-data ,handle))
+    (setq e (point))
+    (widget-convert-button
+     'link b e
+     :mime-handle handle
+     :action 'gnus-widget-press-button
+     :button-keymap gnus-mime-button-map
+     :help-echo
+     (lambda (widget/window &optional overlay pos)
+       ;; Needed to properly clear the message due to a bug in
+       ;; wid-edit (XEmacs only).
+       (if (boundp 'help-echo-owns-message)
+	   (setq help-echo-owns-message t))
+       (format
+	"%S: %s the MIME part; %S: more options"
+	(aref gnus-mouse-2 0)
+	;; XEmacs will get a single widget arg; Emacs 21 will get
+	;; window, overlay, position.
+	(if (mm-handle-displayed-p
+	     (if overlay
+		 (with-current-buffer (overlay-buffer overlay)
+		   (widget-get (widget-at (overlay-start overlay))
+			       :mime-handle))
+	       (widget-get widget/window :mime-handle)))
+	    "hide" "show")
+	(aref gnus-down-mouse-3 0))))))
+
+(defun gnus-widget-press-button (elems el)
+  (goto-char (widget-get elems :from))
+  (gnus-article-press-button))
+
+(defvar gnus-displaying-mime nil)
+
+(defun gnus-display-mime (&optional ihandles)
+  "Display the MIME parts."
+  (save-excursion
+    (save-selected-window
+      (let ((window (get-buffer-window gnus-article-buffer))
+	    (point (point)))
+	(when window
+	  (select-window window)
+	  ;; We have to do this since selecting the window
+	  ;; may change the point.  So we set the window point.
+	  (set-window-point window point)))
+      (let* ((handles (or ihandles (mm-dissect-buffer) (mm-uu-dissect)))
+	     buffer-read-only handle name type b e display)
+	(when (and (not ihandles)
+		   (not gnus-displaying-mime))
+	  ;; Top-level call; we clean up.
+	  (when gnus-article-mime-handles
+	    (mm-destroy-parts gnus-article-mime-handles)
+	    (setq gnus-article-mime-handle-alist nil));; A trick.
+	  (setq gnus-article-mime-handles handles)
+	  ;; We allow users to glean info from the handles.
+	  (when gnus-article-mime-part-function
+	    (gnus-mime-part-function handles)))
+	(if (and handles
+		 (or (not (stringp (car handles)))
+		     (cdr handles)))
+	    (progn
+	      (when (and (not ihandles)
+			 (not gnus-displaying-mime))
+		;; Clean up for mime parts.
+		(article-goto-body)
+		(delete-region (point) (point-max)))
+	      (let ((gnus-displaying-mime t))
+		(gnus-mime-display-part handles)))
+	  (save-restriction
+	    (article-goto-body)
+	    (narrow-to-region (point) (point-max))
+	    (gnus-treat-article nil 1 1)
+	    (widen)))
+	(unless ihandles
+	  ;; Highlight the headers.
+	  (save-excursion
+	    (save-restriction
+	      (article-goto-body)
+	      (narrow-to-region (point-min) (point))
+	      (gnus-treat-article 'head))))))))
+
+(defvar gnus-mime-display-multipart-as-mixed nil)
+
+(defun gnus-mime-display-part (handle)
+  (cond
+   ;; Single part.
+   ((not (stringp (car handle)))
+    (gnus-mime-display-single handle))
+   ;; User-defined multipart
+   ((cdr (assoc (car handle) gnus-mime-multipart-functions))
+    (funcall (cdr (assoc (car handle) gnus-mime-multipart-functions))
+	     handle))
+   ;; multipart/alternative
+   ((and (equal (car handle) "multipart/alternative")
+	 (not gnus-mime-display-multipart-as-mixed))
+    (let ((id (1+ (length gnus-article-mime-handle-alist))))
+      (push (cons id handle) gnus-article-mime-handle-alist)
+      (gnus-mime-display-alternative (cdr handle) nil nil id)))
+   ;; multipart/related
+   ((and (equal (car handle) "multipart/related")
+	 (not gnus-mime-display-multipart-as-mixed))
+    ;;;!!!We should find the start part, but we just default
+    ;;;!!!to the first part.
+    (gnus-mime-display-part (cadr handle)))
+   ;; Other multiparts are handled like multipart/mixed.
+   (t
+    (gnus-mime-display-mixed (cdr handle)))))
+
+(defun gnus-mime-part-function (handles)
+  (if (stringp (car handles))
+      (mapcar 'gnus-mime-part-function (cdr handles))
+    (funcall gnus-article-mime-part-function handles)))
+
+(defun gnus-mime-display-mixed (handles)
+  (mapcar 'gnus-mime-display-part handles))
+
+(defun gnus-mime-display-single (handle)
+  (let ((type (mm-handle-media-type handle))
+	(ignored gnus-ignored-mime-types)
+	(not-attachment t)
+	(move nil)
+	display text)
+    (catch 'ignored
+      (progn
+	(while ignored
+	  (when (string-match (pop ignored) type)
+	    (throw 'ignored nil)))
+	(if (and (setq not-attachment
+		       (and (not (mm-inline-override-p handle))
+			    (or (not (mm-handle-disposition handle))
+				(equal (car (mm-handle-disposition handle))
+				       "inline")
+				(mm-attachment-override-p handle))))
+		 (mm-automatic-display-p handle)
+		 (or (mm-inlined-p handle)
+		     (mm-automatic-external-display-p type)))
+	    (setq display t)
+	  (when (equal (mm-handle-media-supertype handle) "text")
+	    (setq text t)))
+	(let ((id (1+ (length gnus-article-mime-handle-alist))))
+	  (push (cons id handle) gnus-article-mime-handle-alist)
+	  (when (or (not display)
+		    (not (gnus-unbuttonized-mime-type-p type)))
+	    ;(gnus-article-insert-newline)
+	    (gnus-insert-mime-button
+	     handle id (list (or display (and not-attachment text))))
+	    (gnus-article-insert-newline)
+	    ;(gnus-article-insert-newline)
+	    (setq move t)))
+	(let ((beg (point)))
+	  (cond
+	   (display
+	    (when move
+	      (forward-line -2)
+	      (setq beg (point)))
+	    (let ((mail-parse-charset gnus-newsgroup-charset)
+		  (mail-parse-ignored-charsets 
+		   (save-excursion (condition-case ()
+				       (set-buffer gnus-summary-buffer)
+				     (error))
+				   gnus-newsgroup-ignored-charsets)))
+	      (mm-display-part handle t))
+	    (goto-char (point-max)))
+	   ((and text not-attachment)
+	    (when move
+	      (forward-line -2)
+	      (setq beg (point)))
+	    (gnus-article-insert-newline)
+	    (mm-insert-inline handle (mm-get-part handle))
+	    (goto-char (point-max))))
+	  ;; Do highlighting.
+	  (save-excursion
+	    (save-restriction
+	      (narrow-to-region beg (point))
+	      (gnus-treat-article
+	       nil (length gnus-article-mime-handle-alist)
+	       (1- (length gnus-article-mime-handles))
+	       (mm-handle-media-type handle)))))))))
+
+(defun gnus-unbuttonized-mime-type-p (type)
+  "Say whether TYPE is to be unbuttonized."
+  (unless gnus-inhibit-mime-unbuttonizing
+    (catch 'found
+      (let ((types gnus-unbuttonized-mime-types))
+	(while types
+	  (when (string-match (pop types) type)
+	    (throw 'found t)))))))
+
+(defun gnus-article-insert-newline ()
+  "Insert a newline, but mark it as undeletable."
+  (gnus-put-text-property
+   (point) (progn (insert "\n") (point)) 'gnus-undeletable t))
+
+(defun gnus-mime-display-alternative (handles &optional preferred ibegend id)
+  (let* ((preferred (or preferred (mm-preferred-alternative handles)))
+	 (ihandles handles)
+	 (point (point))
+	 handle buffer-read-only from props begend not-pref)
+    (save-window-excursion
+      (save-restriction
+	(when ibegend
+	  (narrow-to-region (car ibegend)
+			    (or (cdr ibegend)
+				(progn
+				  (goto-char (car ibegend))
+				  (forward-line 2)
+				  (point))))
+	  (delete-region (point-min) (point-max))
+	  (mm-remove-parts handles))
+	(setq begend (list (point-marker)))
+	;; Do the toggle.
+	(unless (setq not-pref (cadr (member preferred ihandles)))
+	  (setq not-pref (car ihandles)))
+	(when (or ibegend
+		  (not (gnus-unbuttonized-mime-type-p
+			"multipart/alternative")))
+	  (gnus-add-text-properties
+	   (setq from (point))
+	   (progn
+	     (insert (format "%d.  " id))
+	     (point))
+	   `(gnus-callback
+	     (lambda (handles)
+	       (unless ,(not ibegend)
+		 (setq gnus-article-mime-handle-alist
+		       ',gnus-article-mime-handle-alist))
+	       (gnus-mime-display-alternative
+		',ihandles ',not-pref ',begend ,id))
+	     local-map ,gnus-mime-button-map
+	     ,gnus-mouse-face-prop ,gnus-article-mouse-face
+	     face ,gnus-article-button-face
+	     keymap ,gnus-mime-button-map
+	     gnus-part ,id
+	     gnus-data ,handle))
+	  (widget-convert-button 'link from (point)
+				 :action 'gnus-widget-press-button
+				 :button-keymap gnus-widget-button-keymap)
+	  ;; Do the handles
+	  (while (setq handle (pop handles))
+	    (gnus-add-text-properties
+	     (setq from (point))
+	     (progn
+	       (insert (format "(%c) %-18s"
+			       (if (equal handle preferred) ?* ? )
+			       (mm-handle-media-type handle)))
+	       (point))
+	     `(gnus-callback
+	       (lambda (handles)
+		 (unless ,(not ibegend)
+		   (setq gnus-article-mime-handle-alist
+			 ',gnus-article-mime-handle-alist))
+		 (gnus-mime-display-alternative
+		  ',ihandles ',handle ',begend ,id))
+	       local-map ,gnus-mime-button-map
+	       ,gnus-mouse-face-prop ,gnus-article-mouse-face
+	       face ,gnus-article-button-face
+	       keymap ,gnus-mime-button-map
+	       gnus-part ,id
+	       gnus-data ,handle))
+	    (widget-convert-button 'link from (point)
+				   :action 'gnus-widget-press-button
+				   :button-keymap gnus-widget-button-keymap)
+	    (insert "  "))
+	  (insert "\n\n"))
+	(when preferred
+	  (if (stringp (car preferred))
+	      (gnus-display-mime preferred)
+	    (let ((mail-parse-charset gnus-newsgroup-charset)
+		  (mail-parse-ignored-charsets 
+		   (save-excursion (set-buffer gnus-summary-buffer)
+				   gnus-newsgroup-ignored-charsets)))
+	      (mm-display-part preferred)
+	      ;; Do highlighting.
+	      (save-excursion
+		(save-restriction
+		  (narrow-to-region (car begend) (point-max))
+		  (gnus-treat-article
+		   nil (length gnus-article-mime-handle-alist)
+		   (1- (length gnus-article-mime-handles))
+		   (mm-handle-media-type handle))))))
+	  (goto-char (point-max))
+	  (setcdr begend (point-marker)))))
+    (when ibegend
+      (goto-char point))))
+
 (defun gnus-article-wash-status ()
   "Return a string which display status of article washing."
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (let ((cite (gnus-article-hidden-text-p 'cite))
-	  (headers (gnus-article-hidden-text-p 'headers))
-	  (boring (gnus-article-hidden-text-p 'boring-headers))
-	  (pgp (gnus-article-hidden-text-p 'pgp))
-	  (pem (gnus-article-hidden-text-p 'pem))
-	  (signature (gnus-article-hidden-text-p 'signature))
-	  (overstrike (gnus-article-hidden-text-p 'overstrike))
-	  (emphasis (gnus-article-hidden-text-p 'emphasis))
-	  (mime gnus-show-mime))
-      (format "%c%c%c%c%c%c%c"
+    (let ((cite (memq 'cite gnus-article-wash-types))
+	  (headers (memq 'headers gnus-article-wash-types))
+	  (boring (memq 'boring-headers gnus-article-wash-types))
+	  (pgp (memq 'pgp gnus-article-wash-types))
+	  (pem (memq 'pem gnus-article-wash-types))
+	  (signature (memq 'signature gnus-article-wash-types))
+	  (overstrike (memq 'overstrike gnus-article-wash-types))
+	  (emphasis (memq 'emphasis gnus-article-wash-types)))
+      (format "%c%c%c%c%c%c"
 	      (if cite ?c ? )
 	      (if (or headers boring) ?h ? )
 	      (if (or pgp pem) ?p ? )
 	      (if signature ?s ? )
 	      (if overstrike ?o ? )
-	      (if mime ?m ? )
 	      (if emphasis ?e ? )))))
 
-(fset 'gnus-article-hide-headers-if-wanted 'gnus-article-maybe-hide-headers)
+(defalias 'gnus-article-hide-headers-if-wanted 'gnus-article-maybe-hide-headers)
 
 (defun gnus-article-maybe-hide-headers ()
   "Hide unwanted headers if `gnus-have-all-headers' is nil.
 Provided for backwards compatibility."
-  (or (save-excursion (set-buffer gnus-summary-buffer) gnus-have-all-headers)
-      gnus-inhibit-hiding
-      (gnus-article-hide-headers)))
+  (when (and (or (not (gnus-buffer-live-p gnus-summary-buffer))
+		 (not (save-excursion (set-buffer gnus-summary-buffer)
+				      gnus-have-all-headers)))
+	     (not gnus-inhibit-hiding))
+    (gnus-article-hide-headers)))
 
 ;;; Article savers.
 
 (defun gnus-output-to-file (file-name)
   "Append the current article to a file named FILE-NAME."
   (let ((artbuf (current-buffer)))
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (insert-buffer-substring artbuf)
       ;; Append newline at end of the buffer as separator, and then
       ;; save it to file.
       (goto-char (point-max))
       (insert "\n")
-      (append-to-file (point-min) (point-max) file-name)
+      (mm-append-to-file (point-min) (point-max) file-name)
       t)))
 
 (defun gnus-narrow-to-page (&optional arg)
@@ -2337,8 +3615,7 @@
 (defun gnus-article-describe-briefly ()
   "Describe article mode commands briefly."
   (interactive)
-  (gnus-message 6
-		(substitute-command-keys "\\<gnus-article-mode-map>\\[gnus-article-goto-next-page]:Next page	 \\[gnus-article-goto-prev-page]:Prev page  \\[gnus-article-show-summary]:Show summary  \\[gnus-info-find-node]:Run Info  \\[gnus-article-describe-briefly]:This help")))
+  (gnus-message 6 (substitute-command-keys "\\<gnus-article-mode-map>\\[gnus-article-goto-next-page]:Next page	 \\[gnus-article-goto-prev-page]:Prev page  \\[gnus-article-show-summary]:Show summary  \\[gnus-info-find-node]:Run Info  \\[gnus-article-describe-briefly]:This help")))
 
 (defun gnus-article-summary-command ()
   "Execute the last keystroke in the summary buffer."
@@ -2361,9 +3638,15 @@
     (setq func (lookup-key (current-local-map) (this-command-keys)))
     (call-interactively func)))
 
+(defun gnus-article-check-buffer ()
+  "Beep if not in an article buffer."
+  (unless (equal major-mode 'gnus-article-mode)
+    (error "Command invoked outside of a Gnus article buffer")))
+
 (defun gnus-article-read-summary-keys (&optional arg key not-restore-window)
   "Read a summary buffer key sequence and execute it from the article buffer."
   (interactive "P")
+  (gnus-article-check-buffer)
   (let ((nosaves
          '("q" "Q"  "c" "r" "R" "\C-c\C-f" "m"  "a" "f" "F"
            "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
@@ -2379,7 +3662,10 @@
       (set-buffer gnus-article-current-summary)
       (let (gnus-pick-mode)
         (push (or key last-command-event) unread-command-events)
-        (setq keys (read-key-sequence nil))))
+        (setq keys (if gnus-xemacs
+		       (events-to-keys (read-key-sequence nil))
+		     (read-key-sequence nil)))))
+		     
     (message "")
 
     (if (or (member keys nosaves)
@@ -2391,7 +3677,8 @@
             ;; We disable the pick minor mode commands.
             (let (gnus-pick-mode)
               (setq func (lookup-key (current-local-map) keys))))
-          (if (not func)
+          (if (or (not func)
+		  (numberp func))
               (ding)
             (unless (member keys nosave-in-article)
               (set-buffer gnus-article-current-summary))
@@ -2421,9 +3708,12 @@
           (set-buffer obuf)
           (unless not-restore-window
             (set-window-configuration owin))
-          (unless (or (not (eq selected 'old)) (member keys up-to-top))
+          (when (eq selected 'old)
+	    (article-goto-body)
+            (set-window-start (get-buffer-window (current-buffer))
+                              1)
             (set-window-point (get-buffer-window (current-buffer))
-                              opoint))
+                              (point)))
           (let ((win (get-buffer-window gnus-article-current-summary)))
             (when win
               (set-window-point win new-sum-point))))))))
@@ -2435,6 +3725,7 @@
 If given a prefix, show the hidden text instead."
   (interactive (append (gnus-article-hidden-arg) (list 'force)))
   (gnus-article-hide-headers arg)
+  (gnus-article-hide-list-identifiers arg)
   (gnus-article-hide-pgp arg)
   (gnus-article-hide-citation-maybe arg force)
   (gnus-article-hide-signature arg))
@@ -2467,8 +3758,7 @@
 	  ;; We only request an article by message-id when we do not have the
 	  ;; headers for it, so we'll have to get those.
 	  (when (stringp article)
-	    (let ((gnus-override-method gnus-refer-article-method))
-	      (gnus-read-header article)))
+	    (gnus-read-header article))
 
 	  ;; If the article number is negative, that means that this article
 	  ;; doesn't belong in this newsgroup (possibly), so we find its
@@ -2486,8 +3776,7 @@
 		    ;; This is a sparse gap article.
 		    (setq do-update-line article)
 		    (setq article (mail-header-id header))
-		    (let ((gnus-override-method gnus-refer-article-method))
-		      (setq sparse-header (gnus-read-header article)))
+		    (setq sparse-header (gnus-read-header article))
 		    (setq gnus-newsgroup-sparse
 			  (delq article gnus-newsgroup-sparse)))
 		   ((vectorp header)
@@ -2502,11 +3791,11 @@
 			       gnus-newsgroup-name)))
 		  (when (and (eq (car method) 'nneething)
 			     (vectorp header))
-		    (let ((dir (concat
+		    (let ((dir (expand-file-name
+				(mail-header-subject header)
 				(file-name-as-directory
 				 (or (cadr (assq 'nneething-address method))
-				     (nth 1 method)))
-				(mail-header-subject header))))
+				     (nth 1 method))))))
 		      (when (file-directory-p dir)
 			(setq article 'nneething)
 			(gnus-group-enter-directory dir))))))))
@@ -2547,20 +3836,40 @@
 		 (gnus-cache-request-article article group))
 	    'article)
 	   ;; Get the article and put into the article buffer.
-	   ((or (stringp article) (numberp article))
-	    (let ((gnus-override-method
-		   (and (stringp article) gnus-refer-article-method))
+	   ((or (stringp article)
+		(numberp article))
+	    (let ((gnus-override-method gnus-override-method)
+		  (methods (and (stringp article) 
+				gnus-refer-article-method))
+		  result
 		  (buffer-read-only nil))
-	      (erase-buffer)
-	      (gnus-kill-all-overlays)
-	      (gnus-check-group-server)
-	      (when (gnus-request-article article group (current-buffer))
-		(when (numberp article)
-		  (gnus-async-prefetch-next group article gnus-summary-buffer)
-		  (when gnus-keep-backlog
-		    (gnus-backlog-enter-article
-		     group article (current-buffer))))
-		'article)))
+	      (setq methods
+		    (if (listp methods)
+			methods
+		      (list methods)))
+	      (when (and (null gnus-override-method)
+			 methods)
+		(setq gnus-override-method (pop methods)))
+	      (while (not result)
+		(when (eq gnus-override-method 'current)
+		  (setq gnus-override-method gnus-current-select-method))
+		(erase-buffer)
+		(gnus-kill-all-overlays)
+		(let ((gnus-newsgroup-name group))
+		  (gnus-check-group-server))
+		(when (gnus-request-article article group (current-buffer))
+		  (when (numberp article)
+		    (gnus-async-prefetch-next group article 
+					      gnus-summary-buffer)
+		    (when gnus-keep-backlog
+		      (gnus-backlog-enter-article
+		       group article (current-buffer))))
+		  (setq result 'article))
+		(if (not result)
+		    (if methods
+			(setq gnus-override-method (pop methods))
+		      (setq result 'done))))
+	      (and (eq result 'article) 'article)))
 	   ;; It was a pseudo.
 	   (t article)))
 
@@ -2576,13 +3885,18 @@
 	  (if (get-buffer gnus-original-article-buffer)
 	      (set-buffer gnus-original-article-buffer)
 	    (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
-	    (buffer-disable-undo (current-buffer))
+	    (buffer-disable-undo)
 	    (setq major-mode 'gnus-original-article-mode)
 	    (setq buffer-read-only t))
 	  (let (buffer-read-only)
 	    (erase-buffer)
 	    (insert-buffer-substring gnus-article-buffer))
-	  (setq gnus-original-article (cons group article))))
+	  (setq gnus-original-article (cons group article)))
+
+	;; Decode charsets.
+	(run-hooks 'gnus-article-decode-hook)
+	;; Mark article as decoded or not.
+	(setq gnus-article-decoded-p gnus-article-decode-hook))
 
       ;; Update sparse articles.
       (when (and do-update-line
@@ -2609,8 +3923,10 @@
 
 (defvar gnus-article-edit-mode-map nil)
 
+;; Should we be using derived.el for this?
 (unless gnus-article-edit-mode-map
-  (setq gnus-article-edit-mode-map (copy-keymap text-mode-map))
+  (setq gnus-article-edit-mode-map (make-sparse-keymap))
+  (set-keymap-parent gnus-article-edit-mode-map text-mode-map)
 
   (gnus-define-keys gnus-article-edit-mode-map
     "\C-c\C-c" gnus-article-edit-done
@@ -2647,18 +3963,19 @@
     (error "The current newsgroup does not support article editing"))
   (gnus-article-date-original)
   (gnus-article-edit-article
+   'ignore
    `(lambda (no-highlight)
+      'ignore
       (gnus-summary-edit-article-done
        ,(or (mail-header-references gnus-current-headers) "")
        ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))
 
-(defun gnus-article-edit-article (exit-func)
+(defun gnus-article-edit-article (start-func exit-func)
   "Start editing the contents of the current article buffer."
   (let ((winconf (current-window-configuration)))
     (set-buffer gnus-article-buffer)
     (gnus-article-edit-mode)
-    (gnus-article-delete-text-of-type 'annotation)
-    (gnus-set-text-properties (point-min) (point-max) nil)
+    (funcall start-func)
     (gnus-configure-windows 'edit-article)
     (setq gnus-article-edit-done-function exit-func)
     (setq gnus-prev-winconf winconf)
@@ -2670,8 +3987,7 @@
   (save-excursion
     (save-restriction
       (widen)
-      (goto-char (point-min))
-      (when (search-forward "\n\n" nil 1)
+      (when (article-goto-body)
 	(let ((lines (count-lines (point) (point-max)))
 	      (length (- (point-max) (point)))
 	      (case-fold-search t)
@@ -2696,7 +4012,19 @@
     (save-excursion
       (set-buffer buf)
       (let ((buffer-read-only nil))
-	(funcall func arg)))
+	(funcall func arg))
+      ;; The cache and backlog have to be flushed somewhat.
+      (when gnus-keep-backlog
+	(gnus-backlog-remove-article
+	 (car gnus-article-current) (cdr gnus-article-current)))
+      ;; Flush original article as well.
+      (save-excursion
+	(when (get-buffer gnus-original-article-buffer)
+	  (set-buffer gnus-original-article-buffer)
+	  (setq gnus-original-article nil)))
+      (when gnus-use-cache
+	(gnus-cache-update-article
+	 (car gnus-article-current) (cdr gnus-article-current))))
     (set-buffer buf)
     (set-window-start (get-buffer-window buf) start)
     (set-window-point (get-buffer-window buf) (point))))
@@ -2705,7 +4033,7 @@
   "Exit the article editing without updating."
   (interactive)
   ;; We remove all text props from the article buffer.
-  (let ((buf (format "%s" (buffer-string)))
+  (let ((buf (buffer-substring-no-properties (point-min) (point-max)))
 	(curbuf (current-buffer))
 	(p (point))
 	(window-start (window-start)))
@@ -2713,25 +4041,12 @@
     (insert buf)
     (let ((winconf gnus-prev-winconf))
       (gnus-article-mode)
-      ;; The cache and backlog have to be flushed somewhat.
-      (when gnus-use-cache
-	(gnus-cache-update-article
-	 (car gnus-article-current) (cdr gnus-article-current)))
-      (when gnus-keep-backlog
-	(gnus-backlog-remove-article
-	 (car gnus-article-current) (cdr gnus-article-current)))
-      ;; Flush original article as well.
-      (save-excursion
-	(when (get-buffer gnus-original-article-buffer)
-	  (set-buffer gnus-original-article-buffer)
-	  (setq gnus-original-article nil)))
       (set-window-configuration winconf)
       ;; Tippy-toe some to make sure that point remains where it was.
-      (let ((buf (current-buffer)))
+      (save-current-buffer
 	(set-buffer curbuf)
 	(set-window-start (get-buffer-window (current-buffer)) window-start)
-	(goto-char p)
-	(set-buffer buf)))))
+	(goto-char p)))))
 
 (defun gnus-article-edit-full-stops ()
   "Interactively repair spacing at end of sentences."
@@ -2750,15 +4065,15 @@
 
 ;;; Internal Variables:
 
-(defcustom gnus-button-url-regexp "\\b\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)"
+(defcustom gnus-button-url-regexp "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)"
   "Regular expression that matches URLs."
   :group 'gnus-article-buttons
   :type 'regexp)
 
 (defcustom gnus-button-alist
-  `(("<\\(url:[>\n\t ]*?\\)?news:[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>" 0 t
-     gnus-button-message-id 2)
-    ("\\bnews:\\([^>\n\t ]*@[^>\n\t ]*\\)" 0 t gnus-button-message-id 1)
+  `(("<\\(url:[>\n\t ]*?\\)?news:[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
+     0 t gnus-button-message-id 2)
+    ("\\bnews:\\([^>\n\t ]*@[^>)!;:,\n\t ]*\\)" 0 t gnus-button-message-id 1)
     ("\\(\\b<\\(url:[>\n\t ]*\\)?news:[>\n\t ]*\\(//\\)?\\([^>\n\t ]*\\)>\\)"
      1 t
      gnus-button-fetch-group 4)
@@ -2766,12 +4081,12 @@
     ("\\bin\\( +article\\| +message\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)" 2
      t gnus-button-message-id 3)
     ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>" 0 t gnus-url-mailto 2)
-    ("mailto:\\([a-zA-Z.-@_+0-9%]+\\)" 0 t gnus-url-mailto 1)
+    ("mailto:\\([-a-zA-Z.@_+0-9%]+\\)" 0 t gnus-url-mailto 1)
     ("\\bmailto:\\([^ \n\t]+\\)" 0 t gnus-url-mailto 1)
     ;; This is how URLs _should_ be embedded in text...
-    ("<URL: *\\([^>]*\\)>" 0 t gnus-button-embedded-url 1)
+    ("<URL: *\\([^<>]*\\)>" 0 t gnus-button-embedded-url 1)
     ;; Raw URLs.
-    (,gnus-button-url-regexp 0 t gnus-button-url 0))
+    (,gnus-button-url-regexp 0 t browse-url 0))
   "*Alist of regexps matching buttons in article bodies.
 
 Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
@@ -2799,9 +4114,9 @@
     ("^\\(From\\|Reply-To\\):" ": *\\(.+\\)$" 1 t gnus-button-reply 1)
     ("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
      0 t gnus-button-mailto 0)
-    ("^X-[Uu][Rr][Ll]:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
-    ("^Subject:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
-    ("^[^:]+:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
+    ("^X-[Uu][Rr][Ll]:" ,gnus-button-url-regexp 0 t browse-url 0)
+    ("^Subject:" ,gnus-button-url-regexp 0 t browse-url 0)
+    ("^[^:]+:" ,gnus-button-url-regexp 0 t browse-url 0)
     ("^[^:]+:" "\\(<\\(url: \\)?news:\\([^>\n ]*\\)>\\)" 1 t
      gnus-button-message-id 3))
   "*Alist of headers and regexps to match buttons in article heads.
@@ -2856,40 +4171,6 @@
     (when fun
       (funcall fun data))))
 
-(defun gnus-article-prev-button (n)
-  "Move point to N buttons backward.
-If N is negative, move forward instead."
-  (interactive "p")
-  (gnus-article-next-button (- n)))
-
-(defun gnus-article-next-button (n)
-  "Move point to N buttons forward.
-If N is negative, move backward instead."
-  (interactive "p")
-  (let ((function (if (< n 0) 'previous-single-property-change
-		    'next-single-property-change))
-	(inhibit-point-motion-hooks t)
-	(backward (< n 0))
-	(limit (if (< n 0) (point-min) (point-max))))
-    (setq n (abs n))
-    (while (and (not (= limit (point)))
-		(> n 0))
-      ;; Skip past the current button.
-      (when (get-text-property (point) 'gnus-callback)
-	(goto-char (funcall function (point) 'gnus-callback nil limit)))
-      ;; Go to the next (or previous) button.
-      (gnus-goto-char (funcall function (point) 'gnus-callback nil limit))
-      ;; Put point at the start of the button.
-      (when (and backward (not (get-text-property (point) 'gnus-callback)))
-	(goto-char (funcall function (point) 'gnus-callback nil limit)))
-      ;; Skip past intangible buttons.
-      (when (get-text-property (point) 'intangible)
-	(incf n))
-      (decf n))
-    (unless (zerop n)
-      (gnus-message 5 "No more buttons"))
-    n))
-
 (defun gnus-article-highlight (&optional force)
   "Highlight current article.
 This function calls `gnus-article-highlight-headers',
@@ -2924,7 +4205,7 @@
 	    (case-fold-search t)
 	    (inhibit-point-motion-hooks t)
 	    entry regexp header-face field-face from hpoints fpoints)
-	(message-narrow-to-head)
+	(article-narrow-to-head)
 	(while (setq entry (pop alist))
 	  (goto-char (point-min))
 	  (setq regexp (concat "^\\("
@@ -2990,18 +4271,19 @@
 	  (alist gnus-button-alist)
 	  beg entry regexp)
       ;; Remove all old markers.
-      (let (marker entry)
+      (let (marker entry new-list)
 	(while (setq marker (pop gnus-button-marker-list))
-	  (goto-char marker)
-	  (when (setq entry (gnus-button-entry))
-	    (put-text-property (match-beginning (nth 1 entry))
-			       (match-end (nth 1 entry))
-			       'gnus-callback nil))
-	  (set-marker marker nil)))
+	  (if (or (< marker (point-min)) (>= marker (point-max)))
+	      (push marker new-list)
+	    (goto-char marker)
+	    (when (setq entry (gnus-button-entry))
+	      (put-text-property (match-beginning (nth 1 entry))
+				 (match-end (nth 1 entry))
+				 'gnus-callback nil))
+	    (set-marker marker nil)))
+	(setq gnus-button-marker-list new-list))
       ;; We skip the headers.
-      (goto-char (point-min))
-      (unless (search-forward "\n\n" nil t)
-	(goto-char (point-max)))
+      (article-goto-body)
       (setq beg (point))
       (while (setq entry (pop alist))
 	(setq regexp (car entry))
@@ -3027,38 +4309,38 @@
   (interactive)
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil)
-	  (inhibit-point-motion-hooks t)
-	  (case-fold-search t)
-	  (alist gnus-header-button-alist)
-	  entry beg end)
-      (nnheader-narrow-to-headers)
-      (while alist
-	;; Each alist entry.
-	(setq entry (car alist)
-	      alist (cdr alist))
-	(goto-char (point-min))
-	(while (re-search-forward (car entry) nil t)
-	  ;; Each header matching the entry.
-	  (setq beg (match-beginning 0))
-	  (setq end (or (and (re-search-forward "^[^ \t]" nil t)
-			     (match-beginning 0))
-			(point-max)))
-	  (goto-char beg)
-	  (while (re-search-forward (nth 1 entry) end t)
-	    ;; Each match within a header.
-	    (let* ((entry (cdr entry))
-		   (start (match-beginning (nth 1 entry)))
-		   (end (match-end (nth 1 entry)))
-		   (form (nth 2 entry)))
-	      (goto-char (match-end 0))
-	      (when (eval form)
-		(gnus-article-add-button
-		 start end (nth 3 entry)
-		 (buffer-substring (match-beginning (nth 4 entry))
-				   (match-end (nth 4 entry)))))))
-	  (goto-char end))))
-    (widen)))
+    (save-restriction
+      (let ((buffer-read-only nil)
+	    (inhibit-point-motion-hooks t)
+	    (case-fold-search t)
+	    (alist gnus-header-button-alist)
+	    entry beg end)
+	(article-narrow-to-head)
+	(while alist
+	  ;; Each alist entry.
+	  (setq entry (car alist)
+		alist (cdr alist))
+	  (goto-char (point-min))
+	  (while (re-search-forward (car entry) nil t)
+	    ;; Each header matching the entry.
+	    (setq beg (match-beginning 0))
+	    (setq end (or (and (re-search-forward "^[^ \t]" nil t)
+			       (match-beginning 0))
+			  (point-max)))
+	    (goto-char beg)
+	    (while (re-search-forward (nth 1 entry) end t)
+	      ;; Each match within a header.
+	      (let* ((entry (cdr entry))
+		     (start (match-beginning (nth 1 entry)))
+		     (end (match-end (nth 1 entry)))
+		     (form (nth 2 entry)))
+		(goto-char (match-end 0))
+		(when (eval form)
+		  (gnus-article-add-button
+		   start end (nth 3 entry)
+		   (buffer-substring (match-beginning (nth 4 entry))
+				     (match-end (nth 4 entry)))))))
+	    (goto-char end)))))))
 
 ;;; External functions:
 
@@ -3072,7 +4354,9 @@
    (nconc (and gnus-article-mouse-face
 	       (list gnus-mouse-face-prop gnus-article-mouse-face))
 	  (list 'gnus-callback fun)
-	  (and data (list 'gnus-data data)))))
+	  (and data (list 'gnus-data data))))
+  (widget-convert-button 'link from to :action 'gnus-widget-press-button
+			 :button-keymap gnus-widget-button-keymap))
 
 ;;; Internal functions:
 
@@ -3104,7 +4388,6 @@
 (defun gnus-button-push (marker)
   ;; Push button starting at MARKER.
   (save-excursion
-    (set-buffer gnus-article-buffer)
     (goto-char marker)
     (let* ((entry (gnus-button-entry))
 	   (inhibit-point-motion-hooks t)
@@ -3149,7 +4432,7 @@
 
 (defun gnus-url-parse-query-string (query &optional downcase)
   (let (retval pairs cur key val)
-    (setq pairs (gnus-split-string query "&"))
+    (setq pairs (split-string query "&"))
     (while pairs
       (setq cur (car pairs)
             pairs (cdr pairs))
@@ -3230,13 +4513,8 @@
   ;; Reply to ADDRESS.
   (message-reply address))
 
-(defun gnus-button-url (address)
-  "Browse ADDRESS."
-  (browse-url address))
-
 (defun gnus-button-embedded-url (address)
   "Browse ADDRESS."
-  ;; In Emacs 20, `browse-url-browser-function' may be an alist.
   (browse-url (gnus-strip-whitespace address)))
 
 ;;; Next/prev buttons in the article buffer.
@@ -3256,7 +4534,7 @@
      gnus-prev-page-line-format nil
      `(gnus-prev t local-map ,gnus-prev-page-map
 		 gnus-callback gnus-article-button-prev-page
-		 gnus-type annotation))))
+		 article-type annotation))))
 
 (defvar gnus-next-page-map nil)
 (unless gnus-next-page-map
@@ -3287,7 +4565,7 @@
 		      `(gnus-next
 			t local-map ,gnus-next-page-map
 			gnus-callback gnus-article-button-next-page
-			gnus-type annotation))))
+			article-type annotation))))
 
 (defun gnus-article-button-next-page (arg)
   "Go to the next page."
@@ -3305,6 +4583,117 @@
     (gnus-article-prev-page)
     (select-window win)))
 
+(defvar gnus-decode-header-methods
+  '(mail-decode-encoded-word-region)
+  "List of methods used to decode headers.
+
+This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
+is FUNCTION, FUNCTION will be apply to all newsgroups.  If item is a
+(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
+whose names match REGEXP.
+
+For example:
+((\"chinese\" . gnus-decode-encoded-word-region-by-guess)
+ mail-decode-encoded-word-region
+ (\"chinese\" . rfc1843-decode-region))
+")
+
+(defvar gnus-decode-header-methods-cache nil)
+
+(defun gnus-multi-decode-header (start end)
+  "Apply the functions from `gnus-encoded-word-methods' that match."
+  (unless (and gnus-decode-header-methods-cache
+	       (eq gnus-newsgroup-name
+		   (car gnus-decode-header-methods-cache)))
+    (setq gnus-decode-header-methods-cache (list gnus-newsgroup-name))
+    (mapcar (lambda (x)
+	      (if (symbolp x)
+		  (nconc gnus-decode-header-methods-cache (list x))
+		(if (and gnus-newsgroup-name
+			 (string-match (car x) gnus-newsgroup-name))
+		    (nconc gnus-decode-header-methods-cache
+			   (list (cdr x))))))
+	  gnus-decode-header-methods))
+  (let ((xlist gnus-decode-header-methods-cache))
+    (pop xlist)
+    (save-restriction
+      (narrow-to-region start end)
+      (while xlist
+	(funcall (pop xlist) (point-min) (point-max))))))
+
+;;;
+;;; Treatment top-level handling.
+;;;
+
+(defun gnus-treat-article (condition &optional part-number total-parts type)
+  (let ((length (- (point-max) (point-min)))
+	(alist gnus-treatment-function-alist)
+	(article-goto-body-goes-to-point-min-p t)
+	(treated-type
+	 (or (not type)
+	     (catch 'found
+	       (let ((list gnus-article-treat-types))
+		 (while list
+		   (when (string-match (pop list) type)
+		     (throw 'found t)))))))
+	(highlightp (gnus-visual-p 'article-highlight 'highlight))
+	val elem)
+    (gnus-run-hooks 'gnus-part-display-hook)
+    (while (setq elem (pop alist))
+      (setq val
+	    (save-excursion
+	      (if (gnus-buffer-live-p gnus-summary-buffer)
+		  (set-buffer gnus-summary-buffer))
+	      (symbol-value (car elem))))
+      (when (and (or (consp val)
+		     treated-type)
+		 (gnus-treat-predicate val)
+		 (or (not (get (car elem) 'highlight))
+		     highlightp))
+	(save-restriction
+	  (funcall (cadr elem)))))))
+
+;; Dynamic variables.
+(defvar part-number)
+(defvar total-parts)
+(defvar type)
+(defvar condition)
+(defvar length)
+(defun gnus-treat-predicate (val)
+  (cond
+   ((null val)
+    nil)
+   ((and (listp val)
+	 (stringp (car val)))
+    (apply 'gnus-or (mapcar `(lambda (s)
+			       (string-match s ,(or gnus-newsgroup-name "")))
+			    val)))
+   ((listp val)
+    (let ((pred (pop val)))
+      (cond
+       ((eq pred 'or)
+	(apply 'gnus-or (mapcar 'gnus-treat-predicate val)))
+       ((eq pred 'and)
+	(apply 'gnus-and (mapcar 'gnus-treat-predicate val)))
+       ((eq pred 'not)
+	(not (gnus-treat-predicate (car val))))
+       ((eq pred 'typep)
+	(equal (car val) type))
+       (t
+	(error "%S is not a valid predicate" pred)))))
+   (condition
+    (eq condition val))
+   ((eq val t)
+    t)
+   ((eq val 'head)
+    nil)
+   ((eq val 'last)
+    (eq part-number total-parts))
+   ((numberp val)
+    (< length val))
+   (t
+    (error "%S is not a valid value" val))))
+
 (gnus-ems-redefine)
 
 (provide 'gnus-art)
--- a/lisp/gnus/gnus-async.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-async.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; gnus-async.el --- asynchronous support for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +27,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-sum)
 (require 'nntp)
@@ -37,7 +35,7 @@
   "Support for asynchronous operations."
   :group 'gnus)
 
-(defcustom gnus-asynchronous t
+(defcustom gnus-asynchronous nil
   "*If nil, inhibit all Gnus asynchronicity.
 If non-nil, let the other asynch variables be heeded."
   :group 'gnus-asynchronous
@@ -49,8 +47,8 @@
 if t, prefetch as many articles as possible."
   :group 'gnus-asynchronous
   :type '(choice (const :tag "off" nil)
-		 (integer :tag "some" 0)
-		 (other :tag "all" t)))
+		 (const :tag "all" t)
+		 (integer :tag "some" 0)))
 
 (defcustom gnus-prefetched-article-deletion-strategy '(read exit)
   "List of symbols that say when to remove articles from the prefetch buffer.
@@ -79,7 +77,10 @@
 (defvar gnus-async-article-alist nil)
 (defvar gnus-async-article-semaphore '(nil))
 (defvar gnus-async-fetch-list nil)
-(defvar gnus-asynch-obarray nil)
+(defvar gnus-async-hashtb nil)
+(defvar gnus-async-current-prefetch-group nil)
+(defvar gnus-async-current-prefetch-article nil)
+(defvar gnus-async-timer nil)
 
 (defvar gnus-async-prefetch-headers-buffer " *Async Prefetch Headers*")
 (defvar gnus-async-header-prefetched nil)
@@ -108,8 +109,8 @@
 	 ,@forms)
      (gnus-async-release-semaphore 'gnus-async-article-semaphore)))
 
-(put 'gnus-asynch-with-semaphore 'lisp-indent-function 0)
-(put 'gnus-asynch-with-semaphore 'edebug-form-spec '(body))
+(put 'gnus-async-with-semaphore 'lisp-indent-function 0)
+(put 'gnus-async-with-semaphore 'edebug-form-spec '(body))
 
 ;;;
 ;;; Article prefetch
@@ -119,14 +120,14 @@
 (defun gnus-async-close ()
   (gnus-kill-buffer gnus-async-prefetch-article-buffer)
   (gnus-kill-buffer gnus-async-prefetch-headers-buffer)
-  (setq gnus-async-article-alist nil
+  (setq gnus-async-hashtb nil
+	gnus-async-article-alist nil
 	gnus-async-header-prefetched nil))
 
 (defun gnus-async-set-buffer ()
   (nnheader-set-temp-buffer gnus-async-prefetch-article-buffer t)
-  (unless gnus-asynch-obarray
-    (set (make-local-variable 'gnus-asynch-obarray)
-	 (gnus-make-hashtable 1023))))
+  (unless gnus-async-hashtb
+    (setq gnus-async-hashtb (gnus-make-hashtable 1023))))
 
 (defun gnus-async-halt-prefetch ()
   "Stop prefetching."
@@ -146,49 +147,54 @@
 	      ;; do this, which leads to slightly slower article
 	      ;; buffer display.
 	      (gnus-async-prefetch-article group next summary)
-	    (run-with-idle-timer
-	     0.1 nil 'gnus-async-prefetch-article group next summary)))))))
+	    (when gnus-async-timer
+	      (ignore-errors
+		(nnheader-cancel-timer 'gnus-async-timer)))
+	    (setq gnus-async-timer
+		  (run-with-idle-timer
+		   0.1 nil 'gnus-async-prefetch-article
+		   group next summary))))))))
 
 (defun gnus-async-prefetch-article (group article summary &optional next)
   "Possibly prefetch several articles starting with ARTICLE."
   (if (not (gnus-buffer-live-p summary))
       (gnus-async-with-semaphore
-       (setq gnus-async-fetch-list nil))
+	(setq gnus-async-fetch-list nil))
     (when (and gnus-asynchronous
 	       (gnus-alive-p))
       (when next
 	(gnus-async-with-semaphore
-	 (pop gnus-async-fetch-list)))
+	  (pop gnus-async-fetch-list)))
       (let ((do-fetch next)
-	    (do-message t)) ;(eq major-mode 'gnus-summary-mode)))
+	    (do-message t))		;(eq major-mode 'gnus-summary-mode)))
 	(when (and (gnus-group-asynchronous-p group)
 		   (gnus-buffer-live-p summary)
 		   (or (not next)
 		       gnus-async-fetch-list))
 	  (gnus-async-with-semaphore
-	   (unless next
-	     (setq do-fetch (not gnus-async-fetch-list))
-	     ;; Nix out any outstanding requests.
-	     (setq gnus-async-fetch-list nil)
-	     ;; Fill in the new list.
-	     (let ((n gnus-use-article-prefetch)
-		   (data (gnus-data-find-list article))
-		   d)
-	       (while (and (setq d (pop data))
-			   (if (numberp n)
-			       (natnump (decf n))
-			     n))
-		 (unless (or (gnus-async-prefetched-article-entry
-			      group (setq article (gnus-data-number d)))
-			     (not (natnump article))
-			     (not (funcall gnus-async-prefetch-article-p d)))
-		   ;; Not already fetched -- so we add it to the list.
-		   (push article gnus-async-fetch-list)))
-	       (setq gnus-async-fetch-list
-		     (nreverse gnus-async-fetch-list))))
+	    (unless next
+	      (setq do-fetch (not gnus-async-fetch-list))
+	      ;; Nix out any outstanding requests.
+	      (setq gnus-async-fetch-list nil)
+	      ;; Fill in the new list.
+	      (let ((n gnus-use-article-prefetch)
+		    (data (gnus-data-find-list article))
+		    d)
+		(while (and (setq d (pop data))
+			    (if (numberp n)
+				(natnump (decf n))
+			      n))
+		  (unless (or (gnus-async-prefetched-article-entry
+			       group (setq article (gnus-data-number d)))
+			      (not (natnump article))
+			      (not (funcall gnus-async-prefetch-article-p d)))
+		    ;; Not already fetched -- so we add it to the list.
+		    (push article gnus-async-fetch-list)))
+		(setq gnus-async-fetch-list
+		      (nreverse gnus-async-fetch-list))))
 
-	   (when do-fetch
-	     (setq article (car gnus-async-fetch-list))))
+	    (when do-fetch
+	      (setq article (car gnus-async-fetch-list))))
 
 	  (when (and do-fetch article)
 	    ;; We want to fetch some more articles.
@@ -206,26 +212,33 @@
 		  (when do-message
 		    (gnus-message 9 "Prefetching article %d in group %s"
 				  article group))
+		  (setq gnus-async-current-prefetch-group group)
+		  (setq gnus-async-current-prefetch-article article)
 		  (gnus-request-article article group))))))))))
 
 (defun gnus-make-async-article-function (group article mark summary next)
   "Return a callback function."
   `(lambda (arg)
-     (save-excursion
-       (when arg
-	 (gnus-async-set-buffer)
-	 (gnus-async-with-semaphore
-	  (setq
-	   gnus-async-article-alist
-	   (cons (list ',(intern (format "%s-%d" group article)
-				 gnus-asynch-obarray)
-		       ,mark (set-marker (make-marker) (point-max))
-		       ,group ,article)
-		 gnus-async-article-alist))))
-       (if (not (gnus-buffer-live-p ,summary))
-	   (gnus-async-with-semaphore
-	    (setq gnus-async-fetch-list nil))
-	 (gnus-async-prefetch-article ,group ,next ,summary t)))))
+     (gnus-async-article-callback arg ,group ,article ,mark ,summary ,next)))
+
+(defun gnus-async-article-callback (arg group article mark summary next)
+  "Function called when an async article is done being fetched."
+  (save-excursion
+    (setq gnus-async-current-prefetch-article nil)
+    (when arg
+      (gnus-async-set-buffer)
+      (gnus-async-with-semaphore
+	(setq
+	 gnus-async-article-alist
+	 (cons (list (intern (format "%s-%d" group article)
+			     gnus-async-hashtb)
+		     mark (set-marker (make-marker) (point-max))
+		     group article)
+	       gnus-async-article-alist))))
+    (if (not (gnus-buffer-live-p summary))
+	(gnus-async-with-semaphore
+	  (setq gnus-async-fetch-list nil))
+      (gnus-async-prefetch-article group next summary t))))
 
 (defun gnus-async-unread-p (data)
   "Return non-nil if DATA represents an unread article."
@@ -234,6 +247,9 @@
 (defun gnus-async-request-fetched-article (group article buffer)
   "See whether we have ARTICLE from GROUP and put it in BUFFER."
   (when (numberp article)
+    (when (and (equal group gnus-async-current-prefetch-group)
+	       (eq article gnus-async-current-prefetch-article))
+      (gnus-async-wait-for-article article))
     (let ((entry (gnus-async-prefetched-article-entry group article)))
       (when entry
 	(save-excursion
@@ -241,18 +257,48 @@
 	  (copy-to-buffer buffer (cadr entry) (caddr entry))
 	  ;; Remove the read article from the prefetch buffer.
 	  (when (memq 'read gnus-prefetched-article-deletion-strategy)
-	    (gnus-async-delete-prefected-entry entry))
+	    (gnus-async-delete-prefetched-entry entry))
 	  t)))))
 
-(defun gnus-async-delete-prefected-entry (entry)
+(defun gnus-async-wait-for-article (article)
+  "Wait until ARTICLE is no longer the currently-being-fetched article."
+  (save-excursion
+    (gnus-async-set-buffer)
+    (let ((proc (nntp-find-connection (current-buffer)))
+	  (nntp-server-buffer (current-buffer))
+	  (nntp-have-messaged nil)
+	  (tries 0))
+      (condition-case nil
+	  ;; FIXME: we could stop waiting after some
+	  ;; timeout, but this is the wrong place to do it.
+	  ;; rather than checking time-spent-waiting, we
+	  ;; should check time-since-last-output, which
+	  ;; needs to be done in nntp.el.
+	  (while (eq article gnus-async-current-prefetch-article)
+	    (incf tries)
+	    (when (nntp-accept-process-output proc 1)
+	      (setq tries 0))
+	    (when (and (not nntp-have-messaged) (eq 3 tries))
+	      (gnus-message 5 "Waiting for async article...")
+	      (setq nntp-have-messaged t)))
+	(quit
+	 ;; if the user interrupted on a slow/hung connection,
+	 ;; do something friendly.
+	 (when (< 3 tries)
+	   (setq gnus-async-current-prefetch-article nil))
+	 (signal 'quit nil)))
+      (when nntp-have-messaged
+	(gnus-message 5 "")))))
+
+(defun gnus-async-delete-prefetched-entry (entry)
   "Delete ENTRY from buffer and alist."
   (ignore-errors
     (delete-region (cadr entry) (caddr entry))
     (set-marker (cadr entry) nil)
     (set-marker (caddr entry) nil))
   (gnus-async-with-semaphore
-   (setq gnus-async-article-alist
-	 (delq entry gnus-async-article-alist))))
+    (setq gnus-async-article-alist
+	  (delq entry gnus-async-article-alist))))
 
 (defun gnus-async-prefetch-remove-group (group)
   "Remove all articles belonging to GROUP from the prefetch buffer."
@@ -263,7 +309,7 @@
 	(gnus-async-set-buffer)
 	(while alist
 	  (when (equal group (nth 3 (car alist)))
-	    (gnus-async-delete-prefected-entry (car alist)))
+	    (gnus-async-delete-prefetched-entry (car alist)))
 	  (pop alist))))))
 
 (defun gnus-async-prefetched-article-entry (group article)
@@ -271,7 +317,7 @@
   (let ((entry (save-excursion
 		 (gnus-async-set-buffer)
 		 (assq (intern (format "%s-%d" group article)
-			       gnus-asynch-obarray)
+			       gnus-async-hashtb)
 		       gnus-async-article-alist))))
     ;; Perhaps something has emptied the buffer?
     (if (and entry
--- a/lisp/gnus/gnus-audio.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-audio.el	Tue Sep 19 13:37:09 2000 +0000
@@ -47,37 +47,37 @@
   "Executable program for playing WAV files.")
 
 ;;; The following isn't implemented yet.  Wait for Millennium Gnus.
-;(defvar gnus-audio-effects-enabled t
-;  "When t, Gnus will use sound effects.")
-;(defvar gnus-audio-enable-hooks nil
-;  "Functions run when enabling sound effects.")
-;(defvar gnus-audio-disable-hooks nil
-;  "Functions run when disabling sound effects.")
-;(defvar gnus-audio-theme-song nil
-;  "Theme song for Gnus.")
-;(defvar gnus-audio-enter-group nil
-;  "Sound effect played when selecting a group.")
-;(defvar gnus-audio-exit-group nil
-;  "Sound effect played when exiting a group.")
-;(defvar gnus-audio-score-group nil
-;  "Sound effect played when scoring a group.")
-;(defvar gnus-audio-busy-sound nil
-;  "Sound effect played when going into a ... sequence.")
+;;(defvar gnus-audio-effects-enabled t
+;;  "When t, Gnus will use sound effects.")
+;;(defvar gnus-audio-enable-hooks nil
+;;  "Functions run when enabling sound effects.")
+;;(defvar gnus-audio-disable-hooks nil
+;;  "Functions run when disabling sound effects.")
+;;(defvar gnus-audio-theme-song nil
+;;  "Theme song for Gnus.")
+;;(defvar gnus-audio-enter-group nil
+;;  "Sound effect played when selecting a group.")
+;;(defvar gnus-audio-exit-group nil
+;;  "Sound effect played when exiting a group.")
+;;(defvar gnus-audio-score-group nil
+;;  "Sound effect played when scoring a group.")
+;;(defvar gnus-audio-busy-sound nil
+;;  "Sound effect played when going into a ... sequence.")
 
 
 ;;;###autoload
-					;(defun gnus-audio-enable-sound ()
-;  "Enable Sound Effects for Gnus."
-;  (interactive)
-;  (setq gnus-audio-effects-enabled t)
-;  (gnus-run-hooks gnus-audio-enable-hooks))
+;;(defun gnus-audio-enable-sound ()
+;;  "Enable Sound Effects for Gnus."
+;;  (interactive)
+;;  (setq gnus-audio-effects-enabled t)
+;;  (gnus-run-hooks gnus-audio-enable-hooks))
 
 ;;;###autoload
 					;(defun gnus-audio-disable-sound ()
-;  "Disable Sound Effects for Gnus."
-;  (interactive)
-;  (setq gnus-audio-effects-enabled nil)
-;  (gnus-run-hooks gnus-audio-disable-hooks))
+;;  "Disable Sound Effects for Gnus."
+;;  (interactive)
+;;  (setq gnus-audio-effects-enabled nil)
+;;  (gnus-run-hooks gnus-audio-disable-hooks))
 
 ;;;###autoload
 (defun gnus-audio-play (file)
@@ -104,16 +104,16 @@
 
 
 ;;; The following isn't implemented yet, wait for Red Gnus
-					;(defun gnus-audio-startrek-sounds ()
-;  "Enable sounds from Star Trek the original series."
-;  (interactive)
-;  (setq gnus-audio-busy-sound "working.au")
-;  (setq gnus-audio-enter-group "bulkhead_door.au")
-;  (setq gnus-audio-exit-group "bulkhead_door.au")
-;  (setq gnus-audio-score-group "ST_laser.au")
-;  (setq gnus-audio-theme-song "startrek.au")
-;  (add-hook 'gnus-select-group-hook 'gnus-audio-startrek-select-group)
-;  (add-hook 'gnus-exit-group-hook 'gnus-audio-startrek-exit-group))
+;;(defun gnus-audio-startrek-sounds ()
+;;  "Enable sounds from Star Trek the original series."
+;;  (interactive)
+;;  (setq gnus-audio-busy-sound "working.au")
+;;  (setq gnus-audio-enter-group "bulkhead_door.au")
+;;  (setq gnus-audio-exit-group "bulkhead_door.au")
+;;  (setq gnus-audio-score-group "ST_laser.au")
+;;  (setq gnus-audio-theme-song "startrek.au")
+;;  (add-hook 'gnus-select-group-hook 'gnus-audio-startrek-select-group)
+;;  (add-hook 'gnus-exit-group-hook 'gnus-audio-startrek-exit-group))
 ;;;***
 
 (defvar gnus-startup-jingle "Tuxedomoon.Jingle4.au"
--- a/lisp/gnus/gnus-bcklg.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-bcklg.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; gnus-bcklg.el --- backlog functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +27,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 
 ;;;
@@ -44,7 +42,7 @@
   (or (get-buffer gnus-backlog-buffer)
       (save-excursion
 	(set-buffer (gnus-get-buffer-create gnus-backlog-buffer))
-	(buffer-disable-undo (current-buffer))
+	(buffer-disable-undo)
 	(setq buffer-read-only t)
 	(get-buffer gnus-backlog-buffer))))
 
@@ -84,7 +82,9 @@
 	  (setq b (point))
 	  (insert-buffer-substring buffer)
 	  ;; Tag the beginning of the article with the ident.
-	  (gnus-put-text-property b (1+ b) 'gnus-backlog ident))))))
+	  (if (> (point-max) b)
+	      (gnus-put-text-property b (1+ b) 'gnus-backlog ident)
+	    (gnus-error 3 "Article %d is blank" number)))))))
 
 (defun gnus-backlog-remove-oldest-article ()
   (save-excursion
@@ -126,7 +126,7 @@
 	      t))
 	  (setq gnus-backlog-articles (delq ident gnus-backlog-articles)))))))
 
-(defun gnus-backlog-request-article (group number buffer)
+(defun gnus-backlog-request-article (group number &optional buffer)
   (when (numberp number)
     (gnus-backlog-setup)
     (let ((ident (intern (concat group ":" (int-to-string number))
@@ -146,10 +146,12 @@
 	    (setq end
 		  (next-single-property-change
 		   (1+ beg) 'gnus-backlog (current-buffer) (point-max)))))
-	(let ((buffer-read-only nil))
-	  (erase-buffer)
-	  (insert-buffer-substring gnus-backlog-buffer beg end)
-	  t)))))
+	(save-excursion
+	  (and buffer (set-buffer buffer))
+	  (let ((buffer-read-only nil))
+	    (erase-buffer)
+	    (insert-buffer-substring gnus-backlog-buffer beg end)))
+	t))))
 
 (provide 'gnus-bcklg)
 
--- a/lisp/gnus/gnus-cache.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-cache.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-cache.el --- cache interface for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-int)
 (require 'gnus-range)
@@ -62,7 +61,7 @@
 it's not cached."
   :group 'gnus-cache
   :type '(choice (const :tag "off" nil)
-                regexp))
+		 regexp))
 
 (defcustom gnus-uncacheable-groups nil
   "*Groups that match this regexp will not be cached.
@@ -79,6 +78,9 @@
 (defvar gnus-cache-overview-coding-system 'raw-text
   "Coding system used on Gnus cache files.")
 
+(defvar gnus-cache-coding-system 'raw-text
+  "Coding system used on Gnus cache files.")
+
 
 
 ;;; Internal variables.
@@ -144,20 +146,17 @@
       (setq gnus-cache-buffer nil))))
 
 (defun gnus-cache-possibly-enter-article
-  (group article headers ticked dormant unread &optional force)
+  (group article ticked dormant unread &optional force)
   (when (and (or force (not (eq gnus-use-cache 'passive)))
 	     (numberp article)
-	     (> article 0)
-	     (vectorp headers))		; This might be a dummy article.
-    ;; If this is a virtual group, we find the real group.
-    (when (gnus-virtual-group-p group)
-      (let ((result (nnvirtual-find-group-art
-		     (gnus-group-real-name group) article)))
-	(setq group (car result)
-	      headers (copy-sequence headers))
-	(mail-header-set-number headers (cdr result))))
-    (let ((number (mail-header-number headers))
-	  file)
+	     (> article 0))		; This might be a dummy article.
+    (let ((number article) file headers)
+      ;; If this is a virtual group, we find the real group.
+      (when (gnus-virtual-group-p group)
+	(let ((result (nnvirtual-find-group-art
+		       (gnus-group-real-name group) article)))
+	  (setq group (car result)
+		number (cdr result))))
       (when (and number
 		 (> number 0)		; Reffed article.
 		 (or force
@@ -177,10 +176,15 @@
 	    t				; The article already is saved.
 	  (save-excursion
 	    (set-buffer nntp-server-buffer)
-	    (let ((gnus-use-cache nil))
+	    (require 'gnus-art)
+	    (let ((gnus-use-cache nil)
+		  (gnus-article-decode-hook nil))
 	      (gnus-request-article-this-buffer number group))
 	    (when (> (buffer-size) 0)
-	      (gnus-write-buffer file)
+	      (let ((coding-system-for-write gnus-cache-coding-system))
+		(gnus-write-buffer file))
+	      (setq headers (nnheader-parse-head t))
+	      (mail-header-set-number headers number)
 	      (gnus-cache-change-buffer group)
 	      (set-buffer (cdr gnus-cache-buffer))
 	      (goto-char (point-max))
@@ -202,17 +206,7 @@
 		    (beginning-of-line))
 		(forward-line 1))
 	      (beginning-of-line)
-	      ;; [number subject from date id references chars lines xref]
-	      (insert (format "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n"
-			      (mail-header-number headers)
-			      (mail-header-subject headers)
-			      (mail-header-from headers)
-			      (mail-header-date headers)
-			      (mail-header-id headers)
-			      (or (mail-header-references headers) "")
-			      (or (mail-header-chars headers) "")
-			      (or (mail-header-lines headers) "")
-			      (or (mail-header-xref headers) "")))
+	      (nnheader-insert-nov headers)
 	      ;; Update the active info.
 	      (set-buffer gnus-summary-buffer)
 	      (gnus-cache-update-active group number)
@@ -266,7 +260,8 @@
     (when (file-exists-p file)
       (erase-buffer)
       (gnus-kill-all-overlays)
-      (insert-file-contents file)
+      (let ((coding-system-for-read gnus-cache-coding-system))
+	(insert-file-contents file))
       t)))
 
 (defun gnus-cache-possibly-alter-active (group active)
@@ -312,7 +307,9 @@
 	    ;; unsuccessful), so we use the cached headers exclusively.
 	    (set-buffer nntp-server-buffer)
 	    (erase-buffer)
-	    (insert-file-contents cache-file)
+	    (let ((coding-system-for-read 
+		   gnus-cache-overview-coding-system))
+	      (insert-file-contents cache-file))
 	    'nov)
 	   ((eq type 'nov)
 	    ;; We have both cached and uncached NOV headers, so we
@@ -337,7 +334,6 @@
       (if (natnump article)
 	  (when (gnus-cache-possibly-enter-article
 		 gnus-newsgroup-name article
-		 (gnus-summary-article-header article)
 		 nil nil nil t)
 	    (push article out))
 	(gnus-message 2 "Can't cache article %d" article))
@@ -371,7 +367,7 @@
 (defun gnus-summary-insert-cached-articles ()
   "Insert all the articles cached for this group into the current buffer."
   (interactive)
-  (let ((cached (sort (copy-sequence gnus-newsgroup-cached) '<))
+  (let ((cached (sort (copy-sequence gnus-newsgroup-cached) '>))
 	(gnus-verbose (max 6 gnus-verbose)))
     (unless cached
       (gnus-message 3 "No cached articles for this group"))
@@ -397,7 +393,6 @@
 	    (cons group
 		  (set-buffer (gnus-get-buffer-create
 			       " *gnus-cache-overview*"))))
-      (buffer-disable-undo (current-buffer))
       ;; Insert the contents of this group's cache overview.
       (erase-buffer)
       (let ((file (gnus-cache-file-name group ".overview")))
@@ -420,7 +415,9 @@
 	   (nnheader-translate-file-chars
 	    (if (gnus-use-long-file-name 'not-cache)
 		group
-	      (let ((group (nnheader-replace-chars-in-string group ?/ ?_)))
+	      (let ((group (nnheader-replace-duplicate-chars-in-string
+			    (nnheader-replace-chars-in-string group ?/ ?_)
+			    ?. ?_)))
 		;; Translate the first colon into a slash.
 		(when (string-match ":" group)
 		  (aset group (match-beginning 0) ?/))
@@ -431,10 +428,10 @@
 (defun gnus-cache-update-article (group article)
   "If ARTICLE is in the cache, remove it and re-enter it."
   (gnus-cache-change-buffer group)
-  (when (gnus-cache-possibly-remove-article article nil nil nil t)    
+  (when (gnus-cache-possibly-remove-article article nil nil nil t)
     (let ((gnus-use-cache nil))
       (gnus-cache-possibly-enter-article
-       gnus-newsgroup-name article (gnus-summary-article-header article)
+       gnus-newsgroup-name article
        nil nil nil t))))
 
 (defun gnus-cache-possibly-remove-article (article ticked dormant unread
@@ -489,9 +486,11 @@
     (gnus-cache-save-buffers)
     (save-excursion
       (set-buffer cache-buf)
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (insert-file-contents (or file (gnus-cache-file-name group ".overview")))
+      (let ((coding-system-for-read 
+	     gnus-cache-overview-coding-system))
+	(insert-file-contents 
+	 (or file (gnus-cache-file-name group ".overview"))))
       (goto-char (point-min))
       (insert "\n")
       (goto-char (point-min)))
@@ -519,7 +518,6 @@
   (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*")))
     (save-excursion
       (set-buffer cache-buf)
-      (buffer-disable-undo (current-buffer))
       (erase-buffer))
     (set-buffer nntp-server-buffer)
     (goto-char (point-min))
@@ -534,7 +532,9 @@
       (save-excursion
 	(set-buffer cache-buf)
 	(erase-buffer)
-	(insert-file-contents (gnus-cache-file-name group (car cached)))
+	(let ((coding-system-for-read 
+	       gnus-cache-coding-system))
+	  (insert-file-contents (gnus-cache-file-name group (car cached))))
 	(goto-char (point-min))
 	(insert "220 ")
 	(princ (car cached) (current-buffer))
@@ -557,6 +557,7 @@
   (let ((gnus-mark-article-hook nil)
 	(gnus-expert-user t)
 	(nnmail-spool-file nil)
+	(mail-sources nil)
 	(gnus-use-dribble-file nil)
 	(gnus-novice-user nil)
 	(gnus-large-newsgroup nil))
@@ -585,7 +586,7 @@
     ;; We simply read the active file.
     (save-excursion
       (gnus-set-work-buffer)
-      (insert-file-contents gnus-cache-active-file)
+      (nnheader-insert-file-contents gnus-cache-active-file)
       (gnus-active-to-gnus-format
        nil (setq gnus-cache-active-hashtb
 		 (gnus-make-hashtable
@@ -597,14 +598,7 @@
   (when (or force
 	    (and gnus-cache-active-hashtb
 		 gnus-cache-active-altered))
-    (nnheader-temp-write gnus-cache-active-file
-      (mapatoms
-       (lambda (sym)
-	 (when (and sym (boundp sym))
-	   (insert (format "%s %d %d y\n"
-			   (symbol-name sym) (cdr (symbol-value sym))
-			   (car (symbol-value sym))))))
-       gnus-cache-active-hashtb))
+    (gnus-write-active-file gnus-cache-active-file gnus-cache-active-hashtb t)
     ;; Mark the active hashtb as unaltered.
     (setq gnus-cache-active-altered nil)))
 
--- a/lisp/gnus/gnus-cite.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-cite.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,7 +1,13 @@
 ;;; gnus-cite.el --- parse citations in articles for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
-;; Author: Per Abhiddenware; you can redistribute it and/or modify
+;; Author: Per Abhiddenware
+
+;; This file is part of GNU Emacs.
+
+;; 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.
@@ -22,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-art)
 (require 'gnus-range)
@@ -44,10 +48,10 @@
   :type 'string)
 
 (defcustom gnus-cite-always-check nil
-  "Check article always for citations. Set it t to check all articles."
+  "Check article always for citations.  Set it t to check all articles."
   :group 'gnus-cite
   :type '(choice (const :tag "no" nil)
-		  (const :tag "yes" t)))
+		 (const :tag "yes" t)))
 
 (defcustom gnus-cited-opened-text-button-line-format "%(%{[-]%}%)\n"
   "Format of opened cited text buttons."
@@ -60,10 +64,13 @@
   :type 'string)
 
 (defcustom gnus-cited-lines-visible nil
-  "The number of lines of hidden cited text to remain visible."
+  "The number of lines of hidden cited text to remain visible.
+Or a pair (cons) of numbers which are the number of lines at the top
+and bottom of the text, respectively, to remain visible."
   :group 'gnus-cite
   :type '(choice (const :tag "none" nil)
-		 integer))
+		 integer
+		 (cons :tag "Top and Bottom" integer integer)))
 
 (defcustom gnus-cite-parse-max-size 25000
   "Maximum article size (in bytes) where parsing citations is allowed.
@@ -73,7 +80,7 @@
 		 integer))
 
 (defcustom gnus-cite-prefix-regexp
-  "^[]>|:}+ ]*[]>|:}+]\\(.*>\\)?\\|^.*>"
+  "^[]>»|:}+ ]*[]>»|:}+]\\(.*>»\\)?\\|^.*>"
   "*Regexp matching the longest possible citation prefix on a line."
   :group 'gnus-cite
   :type 'regexp)
@@ -103,13 +110,13 @@
   :type 'integer)
 
 (defcustom gnus-cite-attribution-prefix
-  "In article\\|in <\\|On \\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\),"
+  "In article\\|in <\\|On \\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\),\\|-----Original Message-----"
   "*Regexp matching the beginning of an attribution line."
   :group 'gnus-cite
   :type 'regexp)
 
 (defcustom gnus-cite-attribution-suffix
-  "\\(\\(wrote\\|writes\\|said\\|says\\|>\\)\\(:\\|\\.\\.\\.\\)\\)[ \t]*$"
+  "\\(\\(wrote\\|writes\\|said\\|says\\|>\\)\\(:\\|\\.\\.\\.\\)\\|-----Original Message-----\\)[ \t]*$"
   "*Regexp matching the end of an attribution line.
 The text matching the first grouping will be used as a button."
   :group 'gnus-cite
@@ -237,8 +244,8 @@
 
 (defcustom gnus-cite-face-list
   '(gnus-cite-face-1 gnus-cite-face-2 gnus-cite-face-3 gnus-cite-face-4
-    gnus-cite-face-5 gnus-cite-face-6 gnus-cite-face-7 gnus-cite-face-8
-    gnus-cite-face-9 gnus-cite-face-10 gnus-cite-face-11)
+		     gnus-cite-face-5 gnus-cite-face-6 gnus-cite-face-7 gnus-cite-face-8
+		     gnus-cite-face-9 gnus-cite-face-10 gnus-cite-face-11)
   "*List of faces used for highlighting citations.
 
 When there are citations from multiple articles in the same message,
@@ -342,7 +349,8 @@
 	      skip (gnus-cite-find-prefix number)
 	      face (cdr (assoc prefix face-alist)))
 	;; Add attribution button.
-	(goto-line number)
+	(goto-char (point-min))
+	(forward-line (1- number))
 	(when (re-search-forward gnus-cite-attribution-suffix
 				 (save-excursion (end-of-line 1) (point))
 				 t)
@@ -364,7 +372,7 @@
   "Dissect the article buffer looking for cited text."
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe nil t)
     (let ((alist gnus-cite-prefix-alist)
 	  prefix numbers number marks m)
       ;; Loop through citation prefixes.
@@ -383,8 +391,7 @@
 	  (forward-line (1- number))
 	  (push (cons (point-marker) prefix) marks)))
       ;; Skip to the beginning of the body.
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (push (cons (point-marker) "") marks)
       ;; Find the end of the body.
       (goto-char (point-max))
@@ -434,7 +441,6 @@
 	  (fill-column (if width (prefix-numeric-value width) fill-column)))
       (save-restriction
 	(while (cdr marks)
-	  (widen)
 	  (narrow-to-region (caar marks) (caadr marks))
 	  (let ((adaptive-fill-regexp
 		 (concat "^" (regexp-quote (cdar marks)) " *"))
@@ -488,10 +494,18 @@
 	  ;; Skip past lines we want to leave visible.
 	  (when (and beg end gnus-cited-lines-visible)
 	    (goto-char beg)
-	    (forward-line gnus-cited-lines-visible)
+	    (forward-line (if (consp gnus-cited-lines-visible)
+			      (car gnus-cited-lines-visible)
+			    gnus-cited-lines-visible))
 	    (if (>= (point) end)
 		(setq beg nil)
-	      (setq beg (point-marker))))
+	      (setq beg (point-marker))
+	      (when (consp gnus-cited-lines-visible)
+		(goto-char end)
+		(forward-line (- (cdr gnus-cited-lines-visible)))
+		(if (<= (point) beg)
+		    (setq beg nil)
+		  (setq end (point-marker))))))
 	  (when (and beg end)
 	    ;; We use markers for the end-points to facilitate later
 	    ;; wrapping and mangling of text.
@@ -517,17 +531,19 @@
 (defun gnus-article-toggle-cited-text (args)
   "Toggle hiding the text in REGION."
   (let* ((region (car args))
+	 (beg (car region))
+	 (end (cdr region))
 	 (start (cadr args))
 	 (hidden
 	  (text-property-any
-	   (car region) (1- (cdr region))
+	   beg (1- end)
 	   (car gnus-hidden-properties) (cadr gnus-hidden-properties)))
 	 (inhibit-point-motion-hooks t)
 	 buffer-read-only)
     (funcall
      (if hidden
 	 'remove-text-properties 'gnus-add-text-properties)
-     (car region) (cdr region) gnus-hidden-properties)
+     beg end gnus-hidden-properties)
     (save-excursion
       (goto-char start)
       (gnus-delete-line)
@@ -560,8 +576,7 @@
     (save-excursion
       (set-buffer gnus-article-buffer)
       (gnus-cite-parse-maybe force)
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (let ((start (point))
 	    (atts gnus-cite-attribution-alist)
 	    (buffer-read-only nil)
@@ -585,7 +600,8 @@
 	    (while total
 	      (setq hidden (car total)
 		    total (cdr total))
-	      (goto-line hidden)
+	      (goto-char (point-min))
+	      (forward-line (1- hidden))
 	      (unless (assq hidden gnus-cite-attribution-alist)
 		(gnus-add-text-properties
 		 (point) (progn (forward-line 1) (point))
@@ -605,45 +621,42 @@
 
 ;;; Internal functions:
 
-(defun gnus-cite-parse-maybe (&optional force)
-  ;; Parse if the buffer has changes since last time.
-  (if (and (not force)
-	   (equal gnus-cite-article gnus-article-current))
+(defun gnus-cite-parse-maybe (&optional force no-overlay)
+  "Always parse the buffer."
+  (gnus-cite-localize)
+  ;;Reset parser information.
+  (setq gnus-cite-prefix-alist nil
+	gnus-cite-attribution-alist nil
+	gnus-cite-loose-prefix-alist nil
+	gnus-cite-loose-attribution-alist nil)
+  (unless no-overlay
+    (gnus-cite-delete-overlays))
+  ;; Parse if not too large.
+  (if (and gnus-cite-parse-max-size
+	   (> (buffer-size) gnus-cite-parse-max-size))
       ()
-    (gnus-cite-localize)
-    ;;Reset parser information.
-    (setq gnus-cite-prefix-alist nil
-	  gnus-cite-attribution-alist nil
-	  gnus-cite-loose-prefix-alist nil
-	  gnus-cite-loose-attribution-alist nil)
-    (while gnus-cite-overlay-list
-      (gnus-delete-overlay (pop gnus-cite-overlay-list)))
-    ;; Parse if not too large.
-    (if (and (not force)
-	     gnus-cite-parse-max-size
-	     (> (buffer-size) gnus-cite-parse-max-size))
-	()
-      (setq gnus-cite-article (cons (car gnus-article-current)
-				    (cdr gnus-article-current)))
-      (gnus-cite-parse-wrapper))))
+    (setq gnus-cite-article (cons (car gnus-article-current)
+				  (cdr gnus-article-current)))
+    (gnus-cite-parse-wrapper)))
+
+(defun gnus-cite-delete-overlays ()
+  (dolist (overlay gnus-cite-overlay-list)
+    (when (or (not (gnus-overlay-end overlay))
+	      (and (>= (gnus-overlay-end overlay) (point-min))
+		   (<= (gnus-overlay-end overlay) (point-max))))
+      (setq gnus-cite-overlay-list (delete overlay gnus-cite-overlay-list))
+      (gnus-delete-overlay overlay))))
 
 (defun gnus-cite-parse-wrapper ()
-  ;; Wrap chopped gnus-cite-parse
-  (goto-char (point-min))
-  (unless (search-forward "\n\n" nil t)
-    (goto-char (point-max)))
-  (save-excursion
-    (gnus-cite-parse-attributions))
-  ;; Try to avoid check citation if there is no reason to believe
-  ;; that article has citations
-  (if (or gnus-cite-always-check
-	  (save-excursion
-	    (re-search-backward gnus-cite-reply-regexp nil t))
-	  gnus-cite-loose-attribution-alist)
-      (progn (save-excursion
-	       (gnus-cite-parse))
-	     (save-excursion
-	       (gnus-cite-connect-attributions)))))
+  ;; Wrap chopped gnus-cite-parse.
+  (article-goto-body)
+  (let ((inhibit-point-motion-hooks t))
+    (save-excursion
+      (gnus-cite-parse-attributions))
+    (save-excursion
+      (gnus-cite-parse))
+    (save-excursion
+      (gnus-cite-connect-attributions))))
 
 (defun gnus-cite-parse ()
   ;; Parse and connect citation prefixes and attribution lines.
@@ -898,8 +911,8 @@
   (when face
     (let ((inhibit-point-motion-hooks t)
 	  from to overlay)
-      (goto-line number)
-      (unless (eobp)			; Sometimes things become confused.
+      (goto-char (point-min))
+      (when (zerop (forward-line (1- number)))
 	(forward-char (length prefix))
 	(skip-chars-forward " \t")
 	(setq from (point))
@@ -914,7 +927,7 @@
 (defun gnus-cite-toggle (prefix)
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe nil t)
     (let ((buffer-read-only nil)
 	  (numbers (cdr (assoc prefix gnus-cite-prefix-alist)))
 	  (inhibit-point-motion-hooks t)
@@ -922,7 +935,8 @@
       (while numbers
 	(setq number (car numbers)
 	      numbers (cdr numbers))
-	(goto-line number)
+	(goto-char (point-min))
+	(forward-line (1- number))
 	(cond ((get-text-property (point) 'invisible)
 	       (remove-text-properties (point) (progn (forward-line 1) (point))
 				       gnus-hidden-properties))
@@ -958,4 +972,8 @@
 
 (provide 'gnus-cite)
 
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
+
 ;;; gnus-cite.el ends here
--- a/lisp/gnus/gnus-cus.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-cus.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,6 +1,6 @@
 ;;; gnus-cus.el --- customization commands for Gnus
 ;;
-;; Copyright (C) 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1996,1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: news
@@ -28,6 +28,7 @@
 
 (require 'wid-edit)
 (require 'gnus-score)
+(require 'gnus-topic)
 
 ;;; Widgets:
 
@@ -51,6 +52,21 @@
   (setq major-mode 'gnus-custom-mode
 	mode-name "Gnus Customize")
   (use-local-map widget-keymap)
+  ;; Emacs 21 stuff:
+  (when (and (facep 'custom-button-face)
+	     (facep 'custom-button-pressed-face))
+    (set (make-local-variable 'widget-button-face)
+	 'custom-button-face)
+    (set (make-local-variable 'widget-button-pressed-face)
+	 'custom-button-pressed-face)
+    (set (make-local-variable 'widget-mouse-face)
+	 'custom-button-pressed-face))
+  (when (and (boundp 'custom-raised-buttons)
+	     (symbol-value 'custom-raised-buttons))
+    (set (make-local-variable 'widget-push-button-prefix) "")
+    (set (make-local-variable 'widget-push-button-suffix) "")
+    (set (make-local-variable 'widget-link-prefix) "")
+    (set (make-local-variable 'widget-link-suffix) ""))
   (gnus-run-hooks 'gnus-custom-mode-hook))
 
 ;;; Group Customization:
@@ -70,14 +86,63 @@
 `fa.4ad-l'.  This is a real newsgroup, but the server has gotten the
 articles from a mail-to-news gateway.  Posting directly to this group
 is therefore impossible--you have to send mail to the mailing list
-address instead.")
+address instead.
+
+The gnus-group-split mail splitting mechanism will behave as if this
+address was listed in gnus-group-split Addresses (see below).")
 
     (to-list (gnus-email-address :tag "To List") "\
 This address will be used when doing a `a' in the group.
 
 It is totally ignored when doing a followup--except that if it is
 present in a news group, you'll get mail group semantics when doing
-`f'.")
+`f'.
+
+The gnus-group-split mail splitting mechanism will behave as if this
+address was listed in gnus-group-split Addresses (see below).")
+
+    (extra-aliases (choice
+		    :tag "Extra Aliases"
+		    (list
+		     :tag "List"
+		     (editable-list
+		      :inline t
+		      (gnus-email-address :tag "Address")))
+		    (gnus-email-address :tag "Address")) "\
+Store messages posted from or to this address in this group.
+
+You must be using gnus-group-split for this to work.  The VALUE of the
+nnmail-split-fancy SPLIT generated for this group will match these
+addresses.")
+
+    (split-regexp (regexp :tag "gnus-group-split Regular Expression") "\
+Like gnus-group-split Address, but expects a regular expression.")
+
+    (split-exclude (list :tag "gnus-group-split Restricts"
+			 (editable-list
+			  :inline t (regexp :tag "Restrict"))) "\
+Regular expression that cancels gnus-group-split matches.
+
+Each entry is added to the nnmail-split-fancy SPLIT as a separate
+RESTRICT clause.")
+
+    (split-spec (choice :tag "gnus-group-split Overrider"
+			(sexp :tag "Fancy Split")
+			(const :tag "Catch All" catch-all)
+			(const :tag "Ignore" nil)) "\
+Override all other gnus-group-split fields.
+
+In `Fancy Split', you can enter any nnmail-split-fancy SPLIT.  Note
+that the name of this group won't be automatically assumed, you have
+to add it to the SPLITs yourself.  This means you can use such splits
+to split messages to other groups too.
+
+If you select `Catch All', this group will get postings for any
+messages not matched in any other group.  It overrides the variable
+gnus-group-split-default-catch-all-group.
+
+Selecting `Ignore' forces no SPLIT to be generated for this group,
+disabling all other gnus-group-split fields.")
 
     (broken-reply-to (const :tag "Broken Reply To" t) "\
 Ignore `Reply-To' headers in this group.
@@ -87,7 +152,7 @@
 listserv itself.  This is broken behavior.  So there!")
 
     (to-group (string :tag "To Group") "\
-All posts will be send to the specified group.")
+All posts will be sent to the specified group.")
 
     (gcc-self (choice :tag  "GCC"
 		      :value t
@@ -97,12 +162,18 @@
 Specify default value for GCC header.
 
 If this symbol is present in the group parameter list and set to `t',
-new composed messages will be `Gcc''d to the current group. If it is
+new composed messages will be `Gcc''d to the current group.  If it is
 present and set to `none', no `Gcc:' header will be generated, if it
 is present and a string, this string will be inserted literally as a
 `gcc' header (this symbol takes precedence over any default `Gcc'
 rules as described later).")
 
+    (banner (choice :tag "Banner"
+		    (const signature)
+		    regexp
+		    (const :tag "None" nil)) "\
+Regular expression matching banners to be removed from articles.")
+
     (auto-expire (const :tag "Automatic Expire" t) "\
 All articles that are read will be marked as expirable.")
 
@@ -121,10 +192,19 @@
 When to expire.
 
 Overrides any `nnmail-expiry-wait' and `nnmail-expiry-wait-function'
-when expiring expirable messages. The value can either be a number of
+when expiring expirable messages.  The value can either be a number of
 days (not necessarily an integer) or the symbols `never' or
 `immediate'.")
 
+    (expiry-target (choice :tag "Expiry Target"
+                           :value delete
+                           (const delete)
+                           (function :format "%v" nnmail-)
+                           string) "\
+Where expired messages end up.
+
+Overrides `nnmail-expiry-target', which see.")
+
     (score-file (file :tag "Score File") "\
 Make the specified file into the current score file.
 This means that all score commands you issue will end up in this file.")
@@ -159,30 +239,78 @@
 
     (visible (const :tag "Permanently visible" t) "\
 Always display this group, even when there are no unread articles
-in it.."))
-  "Alist of valid group parameters.
+in it..")
+
+    (charset (symbol :tag "Charset") "\
+The default charset to use in the group.")
+	     
+    (ignored-charsets 
+     (choice :tag "Ignored charsets" 
+	     :value nil
+	     (repeat (symbol))) "\
+List of charsets that should be ignored.
+
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead.")
+	     
+    (highlight-words 
+     (choice :tag "Highlight words"
+	     :value nil
+	     (repeat (list (regexp :tag "Highlight regexp")
+			   (number :tag "Group for entire word" 0)
+			   (number :tag "Group for displayed part" 0)
+			   (symbol :tag "Face" 
+				   gnus-emphasis-highlight-words))))
+     "highlight regexps.
+See gnus-emphasis-alist."))
+  "Alist of valid group or topic parameters.
 
 Each entry has the form (NAME TYPE DOC), where NAME is the parameter
 itself (a symbol), TYPE is the parameters type (a sexp widget), and
 DOC is a documentation string for the parameter.")
 
+(defconst gnus-extra-topic-parameters
+  '((subscribe (regexp :tag "Subscribe") "\
+If `gnus-subscribe-newsgroup-method' is set to
+`gnus-subscribe-topics', new groups that matches this regexp will
+automatically be subscribed to this topic")) 
+  "Alist of topic parameters that are not also group parameters.
+
+Each entry has the form (NAME TYPE DOC), where NAME is the parameter
+itself (a symbol), TYPE is the parameters type (a sexp widget), and
+DOC is a documentation string for the parameter.")
+
+(defconst gnus-extra-group-parameters
+  '((uidvalidity (string :tag "IMAP uidvalidity") "\
+Server-assigned value attached to IMAP groups, used to maintain consistency."))
+  "Alist of group parameters that are not also topic parameters.
+
+Each entry has the form (NAME TYPE DOC), where NAME is the parameter
+itself (a symbol), TYPE is the parameters type (a sexp widget), and
+DOC is a documentation string for the parameter.")
 (defvar gnus-custom-params)
 (defvar gnus-custom-method)
 (defvar gnus-custom-group)
+(defvar gnus-custom-topic)
 
-(defun gnus-group-customize (group)
-  "Edit the group on the current line."
-  (interactive (list (gnus-group-group-name)))
+(defun gnus-group-customize (group &optional topic)
+  "Edit the group or topic on the current line."
+  (interactive (list (gnus-group-group-name) (gnus-group-topic-name)))
   (let (info
 	(types (mapcar (lambda (entry)
 			 `(cons :format "%v%h\n"
 				:doc ,(nth 2 entry)
 				(const :format "" ,(nth 0 entry))
 				,(nth 1 entry)))
-		       gnus-group-parameters)))
-    (unless group
+		       (append gnus-group-parameters 
+			       (if group
+				   gnus-extra-group-parameters
+				 gnus-extra-topic-parameters)))))
+    (unless (or group topic)
       (error "No group on current line"))
-    (unless (setq info (gnus-get-info group))
+    (when (and group topic)
+      (error "Both a group an topic on current line"))
+    (unless (or topic (setq info (gnus-get-info group)))
       (error "Killed group; can't be edited"))
     ;; Ready.
     (kill-buffer (gnus-get-buffer-create "*Gnus Customize*"))
@@ -190,13 +318,21 @@
     (gnus-custom-mode)
     (make-local-variable 'gnus-custom-group)
     (setq gnus-custom-group group)
+    (make-local-variable 'gnus-custom-topic)
+    (setq gnus-custom-topic topic)
+    (buffer-disable-undo)
     (widget-insert "Customize the ")
-    (widget-create 'info-link
-		   :help-echo "Push me to learn more."
-		   :tag "group parameters"
-		   "(gnus)Group Parameters")
+    (if group
+	(widget-create 'info-link
+		       :help-echo "Push me to learn more."
+		       :tag "group parameters"
+		       "(gnus)Group Parameters")
+      (widget-create 'info-link
+		     :help-echo "Push me to learn more."
+		     :tag  "topic parameters"
+		     "(gnus)Topic Parameters"))
     (widget-insert " for <")
-    (widget-insert group)
+    (widget-insert (gnus-group-decoded-name (or group topic)))
     (widget-insert "> and press ")
     (widget-create 'push-button
 		   :tag "done"
@@ -206,15 +342,17 @@
     (make-local-variable 'gnus-custom-params)
     (setq gnus-custom-params
 	  (widget-create 'group
-			 :value (gnus-info-params info)
+			 :value (if group
+				    (gnus-info-params info)
+				  (gnus-topic-parameters topic))
 			 `(set :inline t
 			       :greedy t
 			       :tag "Parameters"
 			       :format "%t:\n%h%v"
 			       :doc "\
-These special paramerters are recognized by Gnus.
-Check the [ ] for the parameters you want to apply to this group, then
-edit the value to suit your taste."
+These special parameters are recognized by Gnus.
+Check the [ ] for the parameters you want to apply to this group or
+to the groups in this topic, then edit the value to suit your taste."
 			       ,@types)
 			 '(repeat :inline t
 				  :tag "Variables"
@@ -232,34 +370,40 @@
 put something like `(dummy-variable (ding))' in the parameters of that
 group.  `dummy-variable' will be set to the result of the `(ding)'
 form, but who cares?"
-				  (group :value (nil nil)
-					 (symbol :tag "Variable")
-					 (sexp :tag
-					       "Value")))
+				  (list :format "%v" :value (nil nil)
+					(symbol :tag "Variable")
+					(sexp :tag
+					      "Value")))
 
 			 '(repeat :inline t
 				  :tag "Unknown entries"
 				  sexp)))
-    (widget-insert "\n\nYou can also edit the ")
-    (widget-create 'info-link
-		   :tag "select method"
-		   :help-echo "Push me to learn more about select methods."
-		   "(gnus)Select Methods")
-    (widget-insert " for the group.\n")
-    (setq gnus-custom-method
-	  (widget-create 'sexp
-			 :tag "Method"
-			 :value (gnus-info-method info)))
+    (when group
+      (widget-insert "\n\nYou can also edit the ")
+      (widget-create 'info-link
+		     :tag "select method"
+		     :help-echo "Push me to learn more about select methods."
+		     "(gnus)Select Methods")
+      (widget-insert " for the group.\n")
+      (setq gnus-custom-method
+	    (widget-create 'sexp
+			   :tag "Method"
+			   :value (gnus-info-method info))))
     (use-local-map widget-keymap)
-    (widget-setup)))
+    (widget-setup)
+    (buffer-enable-undo)
+    (goto-char (point-min))))
 
 (defun gnus-group-customize-done (&rest ignore)
   "Apply changes and bury the buffer."
   (interactive)
-  (gnus-group-edit-group-done 'params gnus-custom-group
-			      (widget-value gnus-custom-params))
-  (gnus-group-edit-group-done 'method gnus-custom-group
-			      (widget-value gnus-custom-method))
+  (if gnus-custom-topic
+      (gnus-topic-set-parameters gnus-custom-topic
+				 (widget-value gnus-custom-params))
+    (gnus-group-edit-group-done 'params gnus-custom-group
+				(widget-value gnus-custom-params))
+    (gnus-group-edit-group-done 'method gnus-custom-group
+				(widget-value gnus-custom-method)))
   (bury-buffer))
 
 ;;; Score Customization:
@@ -375,9 +519,9 @@
 	 (item `(const :format "" :value ,(downcase tag)))
 	 (match '(string :tag "Match"))
 	 (score '(choice :tag "Score"
-			(const :tag "default" nil)
-			(integer :format "%v"
-				 :hide-front-space t)))
+			 (const :tag "default" nil)
+			 (integer :format "%v"
+				  :hide-front-space t)))
 	 (expire '(choice :tag "Expire"
 			  (const :tag "off" nil)
 			  (integer :format "%v"
@@ -448,9 +592,9 @@
 	 (item `(const :format "" :value ,(downcase tag)))
 	 (match '(integer :tag "Match"))
 	 (score '(choice :tag "Score"
-			(const :tag "default" nil)
-			(integer :format "%v"
-				 :hide-front-space t)))
+			 (const :tag "default" nil)
+			 (integer :format "%v"
+				  :hide-front-space t)))
 	 (expire '(choice :tag "Expire"
 			  (const :tag "off" nil)
 			  (integer :format "%v"
@@ -485,9 +629,9 @@
 	 (item `(const :format "" :value ,(downcase tag)))
 	 (match '(string :tag "Match"))
 	 (score '(choice :tag "Score"
-			(const :tag "default" nil)
-			(integer :format "%v"
-				 :hide-front-space t)))
+			 (const :tag "default" nil)
+			 (integer :format "%v"
+				  :hide-front-space t)))
 	 (expire '(choice :tag "Expire"
 			  (const :tag "off" nil)
 			  (integer :format "%v"
@@ -537,11 +681,11 @@
   (interactive (list gnus-current-score-file))
   (let ((scores (gnus-score-load file))
 	(types (mapcar (lambda (entry)
-		 `(group :format "%v%h\n"
-			 :doc ,(nth 2 entry)
-			 (const :format "" ,(nth 0 entry))
-			 ,(nth 1 entry)))
-	       gnus-score-parameters)))
+			 `(group :format "%v%h\n"
+				 :doc ,(nth 2 entry)
+				 (const :format "" ,(nth 0 entry))
+				 ,(nth 1 entry)))
+		       gnus-score-parameters)))
     ;; Ready.
     (kill-buffer (gnus-get-buffer-create "*Gnus Customize*"))
     (switch-to-buffer (gnus-get-buffer-create "*Gnus Customize*"))
@@ -580,6 +724,7 @@
 				     (gnus-score-string :tag "Subject")
 				     (gnus-score-string :tag "References")
 				     (gnus-score-string :tag "Xref")
+				     (gnus-score-string :tag "Extra")
 				     (gnus-score-string :tag "Message-ID")
 				     (gnus-score-integer :tag "Lines")
 				     (gnus-score-integer :tag "Chars")
--- a/lisp/gnus/gnus-demon.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-demon.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; gnus-demon.el --- daemonic Gnus behaviour
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995,96,97,98,99 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +27,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-int)
 (require 'nnheader)
@@ -84,10 +82,6 @@
 (defvar gnus-inhibit-demon nil
   "*If non-nil, no daemonic function will be run.")
 
-(eval-and-compile
-  (autoload 'timezone-parse-date "timezone")
-  (autoload 'timezone-make-arpa-date "timezone"))
-
 ;;; Functions.
 
 (defun gnus-demon-add-handler (function time idle)
@@ -121,8 +115,7 @@
 		   (nth 2 handler)))
 	   gnus-demon-handlers))
     (setq gnus-demon-idle-time 0)
-    (setq gnus-demon-idle-has-been-called nil)
-    (setq gnus-use-demon t)))
+    (setq gnus-demon-idle-has-been-called nil)))
 
 (gnus-add-shutdown 'gnus-demon-cancel 'gnus)
 
@@ -132,7 +125,6 @@
   (when gnus-demon-timer
     (nnheader-cancel-timer gnus-demon-timer))
   (setq gnus-demon-timer nil
-	gnus-use-demon nil
 	gnus-demon-idle-has-been-called nil)
   (condition-case ()
       (nnheader-cancel-function-timers 'gnus-demon)
@@ -157,17 +149,17 @@
       time
     (let* ((now (current-time))
            ;; obtain NOW as discrete components -- make a vector for speed
-           (nowParts (apply 'vector (decode-time now)))
+           (nowParts (decode-time now))
            ;; obtain THEN as discrete components
-           (thenParts (timezone-parse-time time))
-           (thenHour (string-to-int (elt thenParts 0)))
-           (thenMin (string-to-int (elt thenParts 1)))
+           (thenParts (parse-time-string time))
+           (thenHour (elt thenParts 0))
+           (thenMin (elt thenParts 1))
            ;; convert time as elements into number of seconds since EPOCH.
            (then (encode-time 0
                               thenMin
                               thenHour
                               ;; If THEN is earlier than NOW, make it
-                              ;; same time tomorrow. Doc for encode-time
+                              ;; same time tomorrow.  Doc for encode-time
                               ;; says that this is OK.
                               (+ (elt nowParts 3)
                                  (if (or (< thenHour (elt nowParts 2))
@@ -199,6 +191,10 @@
     ;; sufficiently ripe.
     (let ((handlers gnus-demon-handler-state)
 	  (gnus-inhibit-demon t)
+	  ;; Try to avoid dialog boxes, e.g. by Mailcrypt.
+	  ;; Unfortunately, Emacs 20's `message-or-box...' doesn't
+	  ;; obey `use-dialog-box'.
+	  use-dialog-box (last-nonmenu-event 10)
 	  handler time idle)
       (while handlers
 	(setq handler (pop handlers))
@@ -266,12 +262,11 @@
   "Add daemonic nntp server disconnection to Gnus.
 If no commands have gone out via nntp during the last five
 minutes, the connection is closed."
-  (gnus-demon-add-handler 'gnus-demon-close-connections 5 nil))
+  (gnus-demon-add-handler 'gnus-demon-nntp-close-connections 5 nil))
 
 (defun gnus-demon-nntp-close-connection ()
   (save-window-excursion
-    (when (nnmail-time-less '(0 300)
-			    (nnmail-time-since nntp-last-command-time))
+    (when (time-less-p '(0 300) (time-since nntp-last-command-time))
       (nntp-close-server))))
 
 (defun gnus-demon-add-scanmail ()
@@ -281,8 +276,8 @@
 (defun gnus-demon-scan-mail ()
   (save-window-excursion
     (let ((servers gnus-opened-servers)
-	  server)
-      (gnus-clear-inboxes-moved)
+	  server
+	  (nnmail-fetched-sources (list t)))
       (while (setq server (car (pop servers)))
 	(and (gnus-check-backend-function 'request-scan (car server))
 	     (or (gnus-server-opened server)
--- a/lisp/gnus/gnus-draft.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-draft.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-draft.el --- draft message support for Gnus
-;; Copyright (C) 1997,98 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -67,12 +68,13 @@
   (interactive "P")
   (when (eq major-mode 'gnus-summary-mode)
     (when (set (make-local-variable 'gnus-draft-mode)
-		  (if (null arg) (not gnus-draft-mode)
-		    (> (prefix-numeric-value arg) 0)))
+	       (if (null arg) (not gnus-draft-mode)
+		 (> (prefix-numeric-value arg) 0)))
       ;; Set up the menu.
       (when (gnus-visual-p 'draft-menu 'menu)
 	(gnus-draft-make-menu-bar))
       (gnus-add-minor-mode 'gnus-draft-mode " Draft" gnus-draft-mode-map)
+      (mml-mode)
       (gnus-run-hooks 'gnus-draft-mode-hook))))
 
 ;;; Commands
@@ -94,9 +96,11 @@
   (interactive)
   (let ((article (gnus-summary-article-number)))
     (gnus-summary-mark-as-read article gnus-canceled-mark)
-    (gnus-draft-setup article gnus-newsgroup-name)
+    (gnus-draft-setup article gnus-newsgroup-name t)
     (set-buffer-modified-p t)
     (save-buffer)
+    (let ((gnus-verbose-backends nil))
+      (gnus-request-expire-articles (list article) gnus-newsgroup-name t))
     (push
      `((lambda ()
 	 (when (gnus-buffer-exists-p ,gnus-summary-buffer)
@@ -113,14 +117,22 @@
     (while (setq article (pop articles))
       (gnus-summary-remove-process-mark article)
       (unless (memq article gnus-newsgroup-unsendable)
-	(gnus-draft-send article gnus-newsgroup-name)
+	(gnus-draft-send article gnus-newsgroup-name t)
 	(gnus-summary-mark-article article gnus-canceled-mark)))))
 
-(defun gnus-draft-send (article &optional group)
+(defun gnus-draft-send (article &optional group interactive)
   "Send message ARTICLE."
-  (gnus-draft-setup article (or group "nndraft:queue"))
-  (let ((message-syntax-checks 'dont-check-for-anything-just-trust-me)
-	message-send-hook type method)
+  (let ((message-syntax-checks (if interactive nil
+				 'dont-check-for-anything-just-trust-me))
+	(message-inhibit-body-encoding (or (not group) 
+					   (equal group "nndraft:queue")
+					   message-inhibit-body-encoding))
+	(message-send-hook (and group (not (equal group "nndraft:queue"))
+				message-send-hook))
+	(message-setup-hook (and group (not (equal group "nndraft:queue"))
+				 message-setup-hook))
+	type method)
+    (gnus-draft-setup article (or group "nndraft:queue"))
     ;; We read the meta-information that says how and where
     ;; this message is to be sent.
     (save-restriction
@@ -176,20 +188,22 @@
 ;;;!!!but for the time being, we'll just run this tiny function uncompiled.
 
 (progn
-(defun gnus-draft-setup (narticle group)
-  (gnus-setup-message 'forward
-    (let ((article narticle))
-      (message-mail)
-      (erase-buffer)
-      (if (not (gnus-request-restore-buffer article group))
-	  (error "Couldn't restore the article")
-	;; Insert the separator.
-	(goto-char (point-min))
-	(search-forward "\n\n")
-	(forward-char -1)
-	(insert mail-header-separator)
-	(forward-line 1)
-	(message-set-auto-save-file-name))))))
+  (defun gnus-draft-setup (narticle group &optional restore)
+    (gnus-setup-message 'forward
+      (let ((article narticle))
+	(message-mail)
+	(erase-buffer)
+	(if (not (gnus-request-restore-buffer article group))
+	    (error "Couldn't restore the article")
+	  (if (and restore (equal group "nndraft:queue"))
+	      (mime-to-mml))
+	  ;; Insert the separator.
+	  (goto-char (point-min))
+	  (search-forward "\n\n")
+	  (forward-char -1)
+	  (insert mail-header-separator)
+	  (forward-line 1)
+	  (message-set-auto-save-file-name))))))
 
 (defun gnus-draft-article-sendable-p (article)
   "Say whether ARTICLE is sendable."
--- a/lisp/gnus/gnus-dup.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-dup.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-dup.el --- suppression of duplicate articles in Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -32,8 +33,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-art)
 
@@ -100,7 +99,7 @@
   "Save the duplicate suppression list."
   (when (and gnus-save-duplicate-list
 	     gnus-dup-list-dirty)
-    (nnheader-temp-write gnus-duplicate-file
+    (with-temp-file gnus-duplicate-file
       (gnus-prin1 `(setq gnus-dup-list ',gnus-dup-list))))
   (setq gnus-dup-list-dirty nil))
 
@@ -138,6 +137,8 @@
     (gnus-dup-open))
   (gnus-message 6 "Suppressing duplicates...")
   (let ((headers gnus-newsgroup-headers)
+	(auto (and gnus-newsgroup-auto-expire
+		   (memq gnus-duplicate-mark gnus-auto-expirable-marks)))
 	number header)
     (while (setq header (pop headers))
       (when (and (intern-soft (mail-header-id header) gnus-dup-hashtb)
@@ -145,8 +146,10 @@
 	(setq gnus-newsgroup-unreads
 	      (delq (setq number (mail-header-number header))
 		    gnus-newsgroup-unreads))
-	(push (cons number gnus-duplicate-mark)
-	      gnus-newsgroup-reads))))
+	(if (not auto)
+	    (push (cons number gnus-duplicate-mark) gnus-newsgroup-reads)
+	  (push number gnus-newsgroup-expirable)
+	  (push (cons number gnus-expirable-mark) gnus-newsgroup-reads)))))
   (gnus-message 6 "Suppressing duplicates...done"))
 
 (defun gnus-dup-unsuppress-article (article)
--- a/lisp/gnus/gnus-eform.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-eform.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-eform.el --- a mode for editing forms for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -53,7 +54,8 @@
 
 (defvar gnus-edit-form-mode-map nil)
 (unless gnus-edit-form-mode-map
-  (setq gnus-edit-form-mode-map (copy-keymap emacs-lisp-mode-map))
+  (setq gnus-edit-form-mode-map (make-sparse-keymap))
+  (set-keymap-parent gnus-edit-form-mode-map emacs-lisp-mode-map)
   (gnus-define-keys gnus-edit-form-mode-map
     "\C-c\C-c" gnus-edit-form-done
     "\C-c\C-k" gnus-edit-form-exit))
--- a/lisp/gnus/gnus-ems.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-ems.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-ems.el --- functions for making Gnus work under different Emacsen
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -29,11 +30,14 @@
 
 ;;; Function aliases later to be redefined for XEmacs usage.
 
-(defvar gnus-xemacs (string-match "XEmacs\\|Lucid" emacs-version)
-  "Non-nil if running under XEmacs.")
+(eval-and-compile
+  (defvar gnus-xemacs (featurep 'xemacs)
+    "Non-nil if running under XEmacs."))
 
 (defvar gnus-mouse-2 [mouse-2])
+(defvar gnus-down-mouse-3 [down-mouse-3])
 (defvar gnus-down-mouse-2 [down-mouse-2])
+(defvar gnus-widget-button-keymap nil)
 (defvar gnus-mode-line-modified
   (if (or gnus-xemacs
 	  (< emacs-major-version 20))
@@ -45,103 +49,42 @@
   (autoload 'gnus-xmas-redefine "gnus-xmas")
   (autoload 'appt-select-lowest-window "appt"))
 
-(or (fboundp 'mail-file-babyl-p)
-    (fset 'mail-file-babyl-p 'rmail-file-p))
-
 ;;; Mule functions.
 
-(defun gnus-mule-cite-add-face (number prefix face)
-  ;; At line NUMBER, ignore PREFIX and add FACE to the rest of the line.
-  (when face
-    (let ((inhibit-point-motion-hooks t)
-	  from to)
-      (goto-line number)
-      (unless (eobp)            ; Sometimes things become confused (broken).
-        (if (boundp 'MULE)
-            (forward-char (chars-in-string prefix))
-          (forward-char (length prefix)))
-        (skip-chars-forward " \t")
-        (setq from (point))
-        (end-of-line 1)
-        (skip-chars-backward " \t")
-        (setq to (point))
-        (when (< from to)
-          (push (setq overlay (gnus-make-overlay from to))
-                gnus-cite-overlay-list)
-          (gnus-overlay-put (gnus-make-overlay from to) 'face face))))))
-
 (defun gnus-mule-max-width-function (el max-width)
-  (` (let* ((val (eval (, el)))
-	    (valstr (if (numberp val)
-			(int-to-string val) val)))
-       (if (> (length valstr) (, max-width))
-	   (truncate-string valstr (, max-width))
-	 valstr))))
-
-(defun gnus-encode-coding-string (string system)
-  string)
-
-(defun gnus-decode-coding-string (string system)
-  string)
-
-(defun gnus-encode-coding-string (string system)
-  string)
+  `(let* ((val (eval (, el)))
+	  (valstr (if (numberp val)
+		      (int-to-string val) val)))
+     (if (> (length valstr) ,max-width)
+	 (truncate-string-to-width valstr ,max-width)
+       valstr)))
 
 (eval-and-compile
-  (if (string-match "XEmacs\\|Lucid" emacs-version)
-      nil
-
+  (if gnus-xemacs
+      (gnus-xmas-define)
     (defvar gnus-mouse-face-prop 'mouse-face
-      "Property used for highlighting mouse regions."))
-
-  (cond
-   ((string-match "XEmacs\\|Lucid" emacs-version)
-    (gnus-xmas-define))
-
-   ((or (not (boundp 'emacs-minor-version))
-	(and (< emacs-major-version 20)
-	     (< emacs-minor-version 30)))
-    ;; Remove the `intangible' prop.
-    (let ((props (and (boundp 'gnus-hidden-properties)
-		      gnus-hidden-properties)))
-      (while (and props (not (eq (car (cdr props)) 'intangible)))
-	(setq props (cdr props)))
-      (when props
-	(setcdr props (cdr (cdr (cdr props))))))
-    (unless (fboundp 'buffer-substring-no-properties)
-      (defun buffer-substring-no-properties (beg end)
-	(format "%s" (buffer-substring beg end)))))
-
-   ((boundp 'MULE)
-    (provide 'gnusutil))))
+      "Property used for highlighting mouse regions.")))
 
 (eval-and-compile
   (cond
    ((not window-system)
-    (defun gnus-dummy-func (&rest args))
     (let ((funcs '(mouse-set-point set-face-foreground
 				   set-face-background x-popup-menu)))
       (while funcs
 	(unless (fboundp (car funcs))
-	  (fset (car funcs) 'gnus-dummy-func))
-	(setq funcs (cdr funcs))))))
-  (unless (fboundp 'file-regular-p)
-    (defun file-regular-p (file)
-      (and (not (file-directory-p file))
-	   (not (file-symlink-p file))
-	   (file-exists-p file))))
-  (unless (fboundp 'face-list)
-    (defun face-list (&rest args))))
+	  (defalias (car funcs) 'ignore))
+	(setq funcs (cdr funcs)))))))
 
 (eval-and-compile
   (let ((case-fold-search t))
     (cond
-     ((string-match "windows-nt\\|os/2\\|emx\\|cygwin"
+     ((string-match "windows-nt\\|os/2\\|emx\\|cygwin32"
 		    (symbol-name system-type))
       (setq nnheader-file-name-translation-alist
 	    (append nnheader-file-name-translation-alist
-		    '((?: . ?_)
-		      (?+ . ?-))))))))
+		    (mapcar (lambda (c) (cons c ?_))
+			    '(?: ?* ?\" ?< ?> ??))
+		    '((?+ . ?-))))))))
 
 (defvar gnus-tmp-unread)
 (defvar gnus-tmp-replied)
@@ -155,37 +98,31 @@
 
 (defun gnus-ems-redefine ()
   (cond
-   ((string-match "XEmacs\\|Lucid" emacs-version)
+   (gnus-xemacs
     (gnus-xmas-redefine))
 
    ((featurep 'mule)
     ;; Mule and new Emacs definitions
 
     ;; [Note] Now there are three kinds of mule implementations,
-    ;; original MULE, XEmacs/mule and beta version of Emacs including
-    ;; some mule features. Unfortunately these API are different. In
+    ;; original MULE, XEmacs/mule and Emacs 20+ including
+    ;; MULE features.  Unfortunately these API are different.  In
     ;; particular, Emacs (including original MULE) and XEmacs are
-    ;; quite different.
+    ;; quite different.  Howvere, this version of Gnus doesn't support
+    ;; anything other than XEmacs 20+ and Emacs 20.3+.
+
     ;; Predicates to check are following:
     ;; (boundp 'MULE) is t only if MULE (original; anything older than
     ;;                     Mule 2.3) is running.
     ;; (featurep 'mule) is t when every mule variants are running.
 
-    ;; These implementations may be able to share between original
-    ;; MULE and beta version of new Emacs. In addition, it is able to
-    ;; detect XEmacs/mule by (featurep 'mule) and to check variable
-    ;; `emacs-version'. In this case, implementation for XEmacs/mule
-    ;; may be able to share between XEmacs and XEmacs/mule.
-
-    (defalias 'gnus-truncate-string 'truncate-string)
+    ;; It is possible to detect XEmacs/mule by (featurep 'mule) and
+    ;; checking `emacs-version'.  In this case, the implementation for
+    ;; XEmacs/mule may be shareable between XEmacs and XEmacs/mule.
 
     (defvar gnus-summary-display-table nil
       "Display table used in summary mode buffers.")
-    (fset 'gnus-cite-add-face 'gnus-mule-cite-add-face)
-    (fset 'gnus-max-width-function 'gnus-mule-max-width-function)
-    (fset 'gnus-summary-set-display-table (lambda ()))
-    (fset 'gnus-encode-coding-string 'encode-coding-string)
-    (fset 'gnus-decode-coding-string 'decode-coding-string)
+    (defalias 'gnus-max-width-function 'gnus-mule-max-width-function)
 
     (when (boundp 'gnus-check-before-posting)
       (setq gnus-check-before-posting
@@ -203,18 +140,12 @@
 	  (format "%4d: %-20s"
 		  gnus-tmp-lines
 		  (if (> (length gnus-tmp-name) 20)
-		      (truncate-string gnus-tmp-name 20)
+		      (truncate-string-to-width gnus-tmp-name 20)
 		    gnus-tmp-name))
 	  gnus-tmp-closing-bracket)
 	 (point))
        gnus-mouse-face-prop gnus-mouse-face)
-      (insert " " gnus-tmp-subject-or-nil "\n"))
-
-    (when (and (boundp 'enable-multibyte-characters)
-	       enable-multibyte-characters)
-      (require 'gnus-mule)
-      (gnus-mule-initialize))
-    )))
+      (insert " " gnus-tmp-subject-or-nil "\n")))))
 
 (defun gnus-region-active-p ()
   "Say whether the region is active."
@@ -223,9 +154,9 @@
        (boundp 'mark-active)
        mark-active))
 
-(defun gnus-add-minor-mode (mode name map)
-  (if (fboundp 'add-minor-mode)
-      (add-minor-mode mode name map)
+(if (fboundp 'add-minor-mode)
+    (defalias 'gnus-add-minor-mode 'add-minor-mode)
+  (defun gnus-add-minor-mode (mode name map &rest rest)
     (set (make-local-variable mode) t)
     (unless (assq mode minor-mode-alist)
       (push `(,mode ,name) minor-mode-alist))
@@ -242,41 +173,90 @@
       (let ((buffer-read-only nil))
 	(erase-buffer)
 	(when (and dir
-		   (file-exists-p (setq file (concat dir "x-splash"))))
-	  (nnheader-temp-write nil
+		   (file-exists-p (setq file
+					(expand-file-name "x-splash" dir))))
+	  (with-temp-buffer
 	    (insert-file-contents file)
 	    (goto-char (point-min))
 	    (ignore-errors
 	      (setq pixmap (read (current-buffer))))))
 	(when pixmap
-	  (erase-buffer)
-	  (unless (facep 'gnus-splash)
-	    (make-face 'gnus-splash))
+	  (make-face 'gnus-splash)
 	  (setq height (/ (car pixmap) (frame-char-height))
 		width (/ (cadr pixmap) (frame-char-width)))
-	  (set-face-foreground 'gnus-splash "ForestGreen")
+	  (set-face-foreground 'gnus-splash "Brown")
 	  (set-face-stipple 'gnus-splash pixmap)
 	  (insert-char ?\n (* (/ (window-height) 2 height) height))
 	  (setq i height)
 	  (while (> i 0)
-	    (insert-char ?  (* (+ (/ (window-width) 2 width) 1) width))
+	    (insert-char ?\  (* (/ (window-width) 2 width) width))
 	    (setq beg (point))
-	    (insert-char ?  width)
+	    (insert-char ?\  width)
 	    (set-text-properties beg (point) '(face gnus-splash))
-	    (insert "\n")
+	    (insert ?\n)
 	    (decf i))
 	  (goto-char (point-min))
 	  (sit-for 0))))))
 
-(if (fboundp 'split-string)
-    (fset 'gnus-split-string 'split-string)
-  (defun gnus-split-string (string pattern)
-    "Return a list of substrings of STRING which are separated by PATTERN."
-    (let (parts (start 0))
-      (while (string-match pattern string start)
-	(setq parts (cons (substring string start (match-beginning 0)) parts)
-	      start (match-end 0)))
-      (nreverse (cons (substring string start) parts)))))
+(defvar gnus-article-xface-ring-internal nil
+  "Cache for face data.")
+
+;; Worth customizing?
+(defvar gnus-article-xface-ring-size 6
+  "Length of the ring used for `gnus-article-xface-ring-internal'.")
+
+(defun gnus-article-display-xface (beg end)
+  "Display an XFace header from between BEG and END in the current article.
+Requires support for images in your Emacs and the external programs
+`uncompface', `icontopbm' and `ppmtoxbm'.  On a GNU/Linux system these
+might be in packages with names like `compface' or `faces-xface' and
+`netpbm' or `libgr-progs', for instance.
+
+This function is for Emacs 21+.  See `gnus-xmas-article-display-xface'
+for XEmacs."
+  ;; It might be worth converting uncompface's output in Lisp.
+
+  (unless gnus-article-xface-ring-internal ; Only load ring when needed.
+    (setq gnus-article-xface-ring-internal
+	  (make-ring gnus-article-xface-ring-size)))
+  (save-excursion
+    (let* ((cur (current-buffer))
+	   (data (buffer-substring beg end))
+	   (image (cdr-safe (assoc data (ring-elements
+					 gnus-article-xface-ring-internal)))))
+      (when (if (fboundp 'display-graphic-p)
+		(display-graphic-p))
+	(unless image
+	  (let ((coding-system-for-read 'binary)
+		(coding-system-for-write 'binary))
+	    (with-temp-buffer
+	      (insert data)
+	      (and (eq 0 (call-process-region (point-min) (point-max)
+					      "uncompface"
+					      'delete '(t nil)))
+		   (goto-char (point-min))
+		   (progn (insert "/* Width=48, Height=48 */\n") t)
+		   (eq 0 (call-process-region (point-min) (point-max)
+					      "icontopbm"
+					      'delete '(t nil)))
+		   (eq 0 (call-process-region (point-min) (point-max)
+					      "pbmtoxbm"
+					      'delete '(t nil)))
+		   ;; Miles Bader says that faces don't look right as
+		   ;; light on dark.
+		   (if (eq 'dark (cdr-safe (assq 'background-mode
+						 (frame-parameters))))
+		       (setq image (create-image (buffer-string) 'xbm t
+						 :ascent 'center
+						 :foreground "black"
+						 :background "white"))
+		     (setq image (create-image (buffer-string) 'xbm t
+					       :ascent 'center))))))
+	  (ring-insert gnus-article-xface-ring-internal (cons data image))))
+      (when image
+	(goto-char (point-min))
+	(re-search-forward "^From:" nil 'move)
+	(insert-image image)))))
 
 (provide 'gnus-ems)
 
--- a/lisp/gnus/gnus-gl.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-gl.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; gnus-gl.el --- an interface to GroupLens for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Brad Miller <bmiller@cs.umn.edu>
 ;; Keywords: news, score
@@ -137,10 +139,10 @@
 This pseudonym is obtained during the registration process")
 
 (defvar grouplens-bbb-host "grouplens.cs.umn.edu"
-  "Host where the bbbd is running" )
+  "Host where the bbbd is running.")
 
 (defvar grouplens-bbb-port 9000
-  "Port where the bbbd is listening" )
+  "Port where the bbbd is listening.")
 
 (defvar grouplens-newsgroups
   '("comp.groupware" "comp.human-factors" "comp.lang.c++"
@@ -194,19 +196,19 @@
 ;;;; Program global variables
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (defvar grouplens-bbb-token nil
-  "Current session token number")
+  "Current session token number.")
 
 (defvar grouplens-bbb-process nil
-  "Process Id of current bbbd network stream process")
+  "Process Id of current bbbd network stream process.")
 
 (defvar grouplens-bbb-buffer nil
-  "Buffer associated with the BBBD process")
+  "Buffer associated with the BBBD process.")
 
 (defvar grouplens-rating-alist nil
-  "Current set of  message-id rating pairs")
+  "Current set of  message-id rating pairs.")
 
 (defvar grouplens-current-hashtable nil
-  "A hashtable to hold predictions from the BBB")
+  "A hashtable to hold predictions from the BBB.")
 
 (defvar grouplens-current-group nil)
 
@@ -312,7 +314,7 @@
 				(concat "login " grouplens-pseudonym))
 	      (if (bbb-read-response bbb-process)
 		  (setq grouplens-bbb-token (bbb-extract-token-number))
-	      (gnus-message 3 "Error: GroupLens login failed")))))
+		(gnus-message 3 "Error: GroupLens login failed")))))
     (gnus-message 3 "Error: you must set a pseudonym"))
   grouplens-bbb-token)
 
@@ -406,7 +408,7 @@
 		pred (bbb-get-pred))
 	  (push `(,mid ,pred nil s) resp)
 	  (gnus-sethash mid (list pred (bbb-get-confl) (bbb-get-confh))
-		      grouplens-current-hashtable)
+			grouplens-current-hashtable)
 	  (forward-line 1)
 	  t)
 	 ((looking-at "\\(<.*>\\) :pred=\\([0-9]\.[0-9][0-9]\\)")
@@ -765,7 +767,7 @@
 (defun gnus-gl-get-trace ()
   "Insert the contents of the BBBD trace buffer."
   (when grouplens-bbb-buffer
-    (insert-buffer grouplens-bbb-buffer)))
+    (insert-buffer-substring grouplens-bbb-buffer)))
 
 ;;
 ;; GroupLens minor mode
@@ -779,12 +781,12 @@
 (unless gnus-grouplens-mode-map
   (setq gnus-grouplens-mode-map (make-keymap))
   (gnus-define-keys
-   gnus-grouplens-mode-map
-   "n" grouplens-next-unread-article
-   "r" bbb-summary-rate-article
-   "k" grouplens-score-thread
-   "c" grouplens-summary-catchup-and-exit
-   "," grouplens-best-unread-article))
+      gnus-grouplens-mode-map
+    "n" grouplens-next-unread-article
+    "r" bbb-summary-rate-article
+    "k" grouplens-score-thread
+    "c" grouplens-summary-catchup-and-exit
+    "," grouplens-best-unread-article))
 
 (defun gnus-grouplens-make-menu-bar ()
   (unless (boundp 'gnus-grouplens-menu)
--- a/lisp/gnus/gnus-group.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-group.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-group.el --- group mode commands for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-start)
 (require 'nnmail)
@@ -37,6 +36,7 @@
 (require 'gnus-range)
 (require 'gnus-win)
 (require 'gnus-undo)
+(require 'time-date)
 
 (defcustom gnus-group-archive-directory
   "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
@@ -50,7 +50,7 @@
   :group 'gnus-group-foreign
   :type 'directory)
 
-(defcustom gnus-no-groups-message "No news is no news"
+(defcustom gnus-no-groups-message "No gnus is bad news"
   "*Message displayed by Gnus when no groups are available."
   :group 'gnus-start
   :type 'string)
@@ -162,6 +162,7 @@
 %n    Select from where (string)
 %z    A string that look like `<%s:%n>' if a foreign select method is used
 %d    The date the group was last entered.
+%E    Icon as defined by `gnus-group-icon-list'.
 %u    User defined specifier.  The next character in the format string should
       be a letter.  Gnus will call the function gnus-user-format-function-X,
       where X is the letter following %u.  The function will be passed the
@@ -300,6 +301,18 @@
      gnus-group-news-3-empty-face)
     ((and (not mailp) (eq level 3)) .
      gnus-group-news-3-face)
+    ((and (= unread 0) (not mailp) (eq level 4)) .
+     gnus-group-news-4-empty-face)
+    ((and (not mailp) (eq level 4)) .
+     gnus-group-news-4-face)
+    ((and (= unread 0) (not mailp) (eq level 5)) .
+     gnus-group-news-5-empty-face)
+    ((and (not mailp) (eq level 5)) .
+     gnus-group-news-5-face)
+    ((and (= unread 0) (not mailp) (eq level 6)) .
+     gnus-group-news-6-empty-face)
+    ((and (not mailp) (eq level 6)) .
+     gnus-group-news-6-face)
     ((and (= unread 0) (not mailp)) .
      gnus-group-news-low-empty-face)
     ((and (not mailp)) .
@@ -320,7 +333,7 @@
     ((= unread 0) .
      gnus-group-mail-low-empty-face)
     (t .
-     gnus-group-mail-low-face))
+       gnus-group-mail-low-face))
   "*Controls the highlighting of group buffer lines.
 
 Below is a list of `Form'/`Face' pairs.  When deciding how a a
@@ -349,6 +362,56 @@
   :group 'gnus-group-visual
   :type 'character)
 
+(defgroup gnus-group-icons nil
+  "Add Icons to your group buffer.  "
+  :group 'gnus-group-visual)
+
+(defcustom gnus-group-icon-list
+  nil
+  "*Controls the insertion of icons into group buffer lines.
+
+Below is a list of `Form'/`File' pairs.  When deciding how a
+particular group line should be displayed, each form is evaluated.
+The icon from the file field after the first true form is used.  You
+can change how those group lines are displayed by editing the file
+field.  The File will either be found in the
+`gnus-group-glyph-directory' or by designating absolute path to the
+file.
+
+It is also possible to change and add form fields, but currently that
+requires an understanding of Lisp expressions.  Hopefully this will
+change in a future release.  For now, you can use the following
+variables in the Lisp expression:
+
+group: The name of the group.
+unread: The number of unread articles in the group.
+method: The select method used.
+mailp: Whether it's a mail group or not.
+newsp: Whether it's a news group or not
+level: The level of the group.
+score: The score of the group.
+ticked: The number of ticked articles."
+  :group 'gnus-group-icons
+  :type '(repeat (cons (sexp :tag "Form") file)))
+
+(defcustom gnus-group-name-charset-method-alist nil
+  "*Alist of method and the charset for group names.
+
+For example:
+    (((nntp \"news.com.cn\") . cn-gb-2312))
+"
+  :group 'gnus-charset
+  :type '(repeat (cons (sexp :tag "Method") (symbol :tag "Charset"))))
+
+(defcustom gnus-group-name-charset-group-alist nil
+  "*Alist of group regexp and the charset for group names.
+
+For example:
+    ((\"\\.com\\.cn:\" . cn-gb-2312))
+"
+  :group 'gnus-charset
+  :type '(repeat (cons (regexp :tag "Group") (symbol :tag "Charset"))))
+
 ;;; Internal variables
 
 (defvar gnus-group-sort-alist-function 'gnus-group-sort-flat
@@ -393,6 +456,7 @@
     (?s gnus-tmp-news-server ?s)
     (?n gnus-tmp-news-method ?s)
     (?P gnus-group-indentation ?s)
+    (?E gnus-tmp-group-icon ?s)
     (?l gnus-tmp-grouplens ?s)
     (?z gnus-tmp-news-method-string ?s)
     (?m (gnus-group-new-mail gnus-tmp-group) ?c)
@@ -415,6 +479,9 @@
 
 (defvar gnus-group-list-mode nil)
 
+
+(defvar gnus-group-icon-cache nil)
+
 ;;;
 ;;; Gnus group mode
 ;;;
@@ -427,6 +494,7 @@
     "=" gnus-group-select-group
     "\r" gnus-group-select-group
     "\M-\r" gnus-group-quick-select-group
+    "\M- " gnus-group-visible-select-group
     [(meta control return)] gnus-group-select-group-ephemerally
     "j" gnus-group-jump-to-group
     "n" gnus-group-next-unread-group
@@ -503,6 +571,7 @@
     "u" gnus-group-make-useful-group
     "a" gnus-group-make-archive-group
     "k" gnus-group-make-kiboze-group
+    "l" gnus-group-nnimap-edit-acl
     "m" gnus-group-make-group
     "E" gnus-group-edit-group
     "e" gnus-group-edit-group-method
@@ -514,6 +583,7 @@
     "w" gnus-group-make-web-group
     "r" gnus-group-rename-group
     "c" gnus-group-customize
+    "x" gnus-group-nnimap-expunge
     "\177" gnus-group-delete-group
     [delete] gnus-group-delete-group)
 
@@ -552,7 +622,9 @@
     "d" gnus-group-description-apropos
     "m" gnus-group-list-matching
     "M" gnus-group-list-all-matching
-    "l" gnus-group-list-level)
+    "l" gnus-group-list-level
+    "c" gnus-group-list-cached
+    "?" gnus-group-list-dormant)
 
   (gnus-define-keys (gnus-group-score-map "W" gnus-group-mode-map)
     "f" gnus-score-flush-cache)
@@ -628,7 +700,9 @@
 	["Group and description apropos..." gnus-group-description-apropos t]
 	["List groups matching..." gnus-group-list-matching t]
 	["List all groups matching..." gnus-group-list-all-matching t]
-	["List active file" gnus-group-list-active t])
+	["List active file" gnus-group-list-active t]
+	["List groups with cached" gnus-group-list-cached t]
+	["List groups with dormant" gnus-group-list-dormant t])
        ("Sort"
 	["Default sort" gnus-group-sort-groups t]
 	["Sort by method" gnus-group-sort-groups-by-method t]
@@ -714,7 +788,6 @@
 	["Pack packet" gnus-soup-pack-packet (fboundp 'gnus-soup-pack-packet)]
 	["Save areas" gnus-soup-save-areas (fboundp 'gnus-soup-pack-packet)]
 	["Brew SOUP" gnus-group-brew-soup (fboundp 'gnus-soup-pack-packet)])
-       ["Send a bug report" gnus-bug t]
        ["Send a mail" gnus-group-mail t]
        ["Post an article..." gnus-group-post-news t]
        ["Check for new news" gnus-group-get-new-news t]
@@ -765,14 +838,12 @@
   (gnus-group-set-mode-line)
   (setq mode-line-process nil)
   (use-local-map gnus-group-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq truncate-lines t)
   (setq buffer-read-only t)
   (gnus-set-default-directory)
   (gnus-update-format-specifications nil 'group 'group-mode)
   (gnus-update-group-mark-positions)
-  (make-local-hook 'post-command-hook)
-  (add-hook 'post-command-hook 'gnus-clear-inboxes-moved nil t)
   (when gnus-use-undo
     (gnus-undo-mode 1))
   (when gnus-slave
@@ -793,9 +864,6 @@
 	    (list (cons 'process (and (search-forward "\200" nil t)
 				      (- (point) 2))))))))
 
-(defun gnus-clear-inboxes-moved ()
-  (setq nnmail-moved-inboxes nil))
-
 (defun gnus-mouse-pick-group (e)
   "Enter the group under the mouse pointer."
   (interactive "e")
@@ -826,6 +894,29 @@
     (when gnus-carpal
       (gnus-carpal-setup-buffer 'group))))
 
+(defsubst gnus-group-name-charset (method group)
+  (if (null method)
+      (setq method (gnus-find-method-for-group group)))
+  (let ((item (assoc method gnus-group-name-charset-method-alist))
+	(alist gnus-group-name-charset-group-alist)
+	result)
+    (if item 
+	(cdr item)
+      (while (setq item (pop alist))
+	(if (string-match (car item) group)
+	    (setq alist nil
+		  result (cdr item))))
+      result)))
+
+(defsubst gnus-group-name-decode (string charset)
+  (if (and string charset (featurep 'mule))
+      (mm-decode-coding-string string charset)
+    string))
+
+(defun gnus-group-decoded-name (string)
+  (let ((charset (gnus-group-name-charset nil string)))
+    (gnus-group-name-decode string charset)))
+
 (defun gnus-group-list-groups (&optional level unread lowest)
   "List newsgroups with level LEVEL or lower that have unread articles.
 Default is all subscribed groups.
@@ -840,8 +931,6 @@
 	    (gnus-group-default-level nil t)
 	    gnus-group-default-list-level
 	    gnus-level-subscribed))))
-  ;; Just do this here, for no particular good reason.
-  (gnus-clear-inboxes-moved)
   (unless level
     (setq level (car gnus-group-list-mode)
 	  unread (cdr gnus-group-list-mode)))
@@ -920,7 +1009,7 @@
 	      params (gnus-info-params info)
 	      newsrc (cdr newsrc)
 	      unread (car (gnus-gethash group gnus-newsrc-hashtb)))
-	(and unread			; This group might be bogus
+	(and unread			; This group might be unchecked
 	     (or (not regexp)
 		 (string-match regexp group))
 	     (<= (setq clevel (gnus-info-level info)) level)
@@ -971,16 +1060,24 @@
 	  (when (string-match regexp group)
 	    (gnus-add-text-properties
 	     (point) (prog1 (1+ (point))
-		       (insert " " mark "     *: " group "\n"))
+		       (insert " " mark "     *: "
+			       (gnus-group-name-decode group 
+						       (gnus-group-name-charset
+							nil group)) 
+			       "\n"))
 	     (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
 		   'gnus-unread t
 		   'gnus-level level))))
       ;; This loop is used when listing all groups.
       (while groups
+	(setq group (pop groups))
 	(gnus-add-text-properties
 	 (point) (prog1 (1+ (point))
 		   (insert " " mark "     *: "
-			   (setq group (pop groups)) "\n"))
+			   (gnus-group-name-decode group 
+						   (gnus-group-name-charset
+						    nil group)) 
+			   "\n"))
 	 (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
 	       'gnus-unread t
 	       'gnus-level level))))))
@@ -1032,7 +1129,11 @@
 						    gnus-tmp-marked number
 						    gnus-tmp-method)
   "Insert a group line in the group buffer."
-  (let* ((gnus-tmp-active (gnus-active gnus-tmp-group))
+  (let* ((gnus-tmp-method
+	  (gnus-server-get-method gnus-tmp-group gnus-tmp-method)) 
+	 (group-name-charset (gnus-group-name-charset gnus-tmp-method
+						      gnus-tmp-group))
+	 (gnus-tmp-active (gnus-active gnus-tmp-group))
 	 (gnus-tmp-number-total
 	  (if gnus-tmp-active
 	      (1+ (- (cdr gnus-tmp-active) (car gnus-tmp-active)))
@@ -1049,10 +1150,14 @@
 		((<= gnus-tmp-level gnus-level-unsubscribed) ?U)
 		((= gnus-tmp-level gnus-level-zombie) ?Z)
 		(t ?K)))
-	 (gnus-tmp-qualified-group (gnus-group-real-name gnus-tmp-group))
+	 (gnus-tmp-qualified-group 
+	  (gnus-group-name-decode (gnus-group-real-name gnus-tmp-group)
+				  group-name-charset))
 	 (gnus-tmp-newsgroup-description
 	  (if gnus-description-hashtb
-	      (or (gnus-gethash gnus-tmp-group gnus-description-hashtb) "")
+	      (or (gnus-group-name-decode
+		   (gnus-gethash gnus-tmp-group gnus-description-hashtb) 
+		   group-name-charset) "")
 	    ""))
 	 (gnus-tmp-moderated
 	  (if (and gnus-moderated-hashtb
@@ -1060,8 +1165,7 @@
 	      ?m ? ))
 	 (gnus-tmp-moderated-string
 	  (if (eq gnus-tmp-moderated ?m) "(m)" ""))
-	 (gnus-tmp-method
-	  (gnus-server-get-method gnus-tmp-group gnus-tmp-method)) ;
+	 (gnus-tmp-group-icon "==&&==")
 	 (gnus-tmp-news-server (or (cadr gnus-tmp-method) ""))
 	 (gnus-tmp-news-method (or (car gnus-tmp-method) ""))
 	 (gnus-tmp-news-method-string
@@ -1095,10 +1199,10 @@
 		  gnus-marked ,gnus-tmp-marked-mark
 		  gnus-indentation ,gnus-group-indentation
 		  gnus-level ,gnus-tmp-level))
+    (forward-line -1)
     (when (inline (gnus-visual-p 'group-highlight 'highlight))
-      (forward-line -1)
-      (gnus-run-hooks 'gnus-group-update-hook)
-      (forward-line))
+      (gnus-run-hooks 'gnus-group-update-hook))
+    (forward-line)
     ;; Allow XEmacs to remove front-sticky text properties.
     (gnus-group-remove-excess-properties)))
 
@@ -1317,6 +1421,12 @@
 
 ;; Group marking.
 
+(defun gnus-group-mark-line-p ()
+  (save-excursion
+    (beginning-of-line)
+    (forward-char (or (cdr (assq 'process gnus-group-mark-positions)) 2))
+    (eq (char-after) gnus-process-mark)))
+
 (defun gnus-group-mark-group (n &optional unmark no-advance)
   "Mark the current group."
   (interactive "p")
@@ -1329,7 +1439,7 @@
 	(beginning-of-line)
 	(forward-char (or (cdr (assq 'process gnus-group-mark-positions)) 2))
 	(subst-char-in-region
-	 (point) (1+ (point)) (following-char)
+	 (point) (1+ (point)) (char-after)
 	 (if unmark
 	     (progn
 	       (setq gnus-group-marked (delete group gnus-group-marked))
@@ -1383,10 +1493,10 @@
 	(gnus-group-set-mark group))))
   (gnus-group-position-point))
 
-(defun gnus-group-remove-mark (group)
+(defun gnus-group-remove-mark (group &optional test-marked)
   "Remove the process mark from GROUP and move point there.
 Return nil if the group isn't displayed."
-  (if (gnus-group-goto-group group)
+  (if (gnus-group-goto-group group nil test-marked)
       (save-excursion
 	(gnus-group-mark-group 1 'unmark t)
 	t)
@@ -1465,12 +1575,14 @@
     (eval
      `(defun gnus-group-iterate (arg ,function)
 	"Iterate FUNCTION over all process/prefixed groups.
-FUNCTION will be called with the group name as the paremeter
+FUNCTION will be called with the group name as the parameter
 and with point over the group in question."
 	(let ((,groups (gnus-group-process-prefix arg))
 	      (,window (selected-window))
 	      ,group)
-	  (while (setq ,group (pop ,groups))
+	  (while ,groups
+	    (setq ,group (car ,groups)
+		  ,groups (cdr ,groups))
 	    (select-window ,window)
 	    (gnus-group-remove-mark ,group)
 	    (save-selected-window
@@ -1565,7 +1677,7 @@
 (defun gnus-fetch-group (group)
   "Start Gnus if necessary and enter GROUP.
 Returns whether the fetching was successful or not."
-  (interactive "sGroup name: ")
+  (interactive (list (completing-read "Group name: " gnus-active-hashtb)))
   (unless (get-buffer gnus-group-buffer)
     (gnus-no-server))
   (gnus-group-read-group nil nil group))
@@ -1597,7 +1709,7 @@
 If REQUEST-ONLY, don't actually read the group; just request it.
 If SELECT-ARTICLES, only select those articles.
 
-Return the name of the group is selection was successful."
+Return the name of the group if selection was successful."
   ;; Transform the select method into a unique server.
   (when (stringp method)
     (setq method (gnus-server-to-method method)))
@@ -1654,41 +1766,56 @@
   ;; Adjust cursor point.
   (gnus-group-position-point))
 
-(defun gnus-group-goto-group (group &optional far)
+(defun gnus-group-goto-group (group &optional far test-marked)
   "Goto to newsgroup GROUP.
-If FAR, it is likely that the group is not on the current line."
+If FAR, it is likely that the group is not on the current line.
+If TEST-MARKED, the line must be marked."
   (when group
-    (if far
-	(gnus-goto-char
-	 (text-property-any
-	  (point-min) (point-max)
-	  'gnus-group (gnus-intern-safe group gnus-active-hashtb)))
-      (beginning-of-line)
-      (cond
-       ;; It's quite likely that we are on the right line, so
-       ;; we check the current line first.
-       ((eq (get-text-property (point) 'gnus-group)
-	    (gnus-intern-safe group gnus-active-hashtb))
-	(point))
-       ;; Previous and next line are also likely, so we check them as well.
-       ((save-excursion
-	  (forward-line -1)
-	  (eq (get-text-property (point) 'gnus-group)
-	      (gnus-intern-safe group gnus-active-hashtb)))
-	(forward-line -1)
-	(point))
-       ((save-excursion
-	  (forward-line 1)
-	  (eq (get-text-property (point) 'gnus-group)
-	      (gnus-intern-safe group gnus-active-hashtb)))
-	(forward-line 1)
-	(point))
-       (t
-	;; Search through the entire buffer.
-	(gnus-goto-char
-	 (text-property-any
-	  (point-min) (point-max)
-	  'gnus-group (gnus-intern-safe group gnus-active-hashtb))))))))
+    (beginning-of-line)
+    (cond
+     ;; It's quite likely that we are on the right line, so
+     ;; we check the current line first.
+     ((and (not far)
+	   (eq (get-text-property (point) 'gnus-group)
+	       (gnus-intern-safe group gnus-active-hashtb))
+	   (or (not test-marked) (gnus-group-mark-line-p)))
+      (point))
+     ;; Previous and next line are also likely, so we check them as well.
+     ((and (not far)
+	   (save-excursion
+	     (forward-line -1)
+	     (and (eq (get-text-property (point) 'gnus-group)
+		      (gnus-intern-safe group gnus-active-hashtb))
+		  (or (not test-marked) (gnus-group-mark-line-p)))))
+      (forward-line -1)
+      (point))
+     ((and (not far)
+	   (save-excursion
+	     (forward-line 1)
+	     (and (eq (get-text-property (point) 'gnus-group)
+		      (gnus-intern-safe group gnus-active-hashtb))
+		  (or (not test-marked) (gnus-group-mark-line-p)))))
+      (forward-line 1)
+      (point))
+     (test-marked
+      (goto-char (point-min))
+      (let (found)
+	(while (and (not found) 
+		    (gnus-goto-char
+		     (text-property-any
+		      (point) (point-max)
+		      'gnus-group 
+		      (gnus-intern-safe group gnus-active-hashtb))))
+	  (if (gnus-group-mark-line-p)
+	      (setq found t)
+	    (forward-line 1)))
+	found))
+     (t
+      ;; Search through the entire buffer.
+      (gnus-goto-char
+       (text-property-any
+	(point-min) (point-max)
+	'gnus-group (gnus-intern-safe group gnus-active-hashtb)))))))
 
 (defun gnus-group-next-group (n &optional silent)
   "Go to next N'th newsgroup.
@@ -1804,11 +1931,12 @@
     (gnus-read-method "From method: ")))
 
   (when (stringp method)
-    (setq method (gnus-server-to-method method)))
-  (let* ((meth (when (and method
-			  (not (gnus-server-equal method gnus-select-method)))
-		 (if address (list (intern method) address)
-		   method)))
+    (setq method (or (gnus-server-to-method method) method)))
+  (let* ((meth (gnus-method-simplify
+		(when (and method
+			   (not (gnus-server-equal method gnus-select-method)))
+		  (if address (list (intern method) address)
+		    method))))
 	 (nname (if method (gnus-group-prefixed-name name meth) name))
 	 backend info)
     (when (gnus-gethash nname gnus-newsrc-hashtb)
@@ -1843,8 +1971,20 @@
       (gnus-request-create-group nname nil args))
     t))
 
-(defun gnus-group-delete-group (group &optional force)
-  "Delete the current group.  Only meaningful with mail groups.
+(defun gnus-group-delete-groups (&optional arg)
+  "Delete the current group.  Only meaningful with editable groups."
+  (interactive "P")
+  (let ((n (length (gnus-group-process-prefix arg))))
+    (when (gnus-yes-or-no-p
+	   (if (= n 1)
+	       "Delete this 1 group? "
+	     (format "Delete these %d groups? " n)))
+      (gnus-group-iterate arg
+	(lambda (group)
+	  (gnus-group-delete-group group nil t))))))
+
+(defun gnus-group-delete-group (group &optional force no-prompt)
+  "Delete the current group.  Only meaningful with editable groups.
 If FORCE (the prefix) is non-nil, all the articles in the group will
 be deleted.  This is \"deleted\" as in \"removed forever from the face
 of the Earth\".	 There is no undo.  The user will be prompted before
@@ -1857,10 +1997,11 @@
   (unless (gnus-check-backend-function 'request-delete-group group)
     (error "This backend does not support group deletion"))
   (prog1
-      (if (not (gnus-yes-or-no-p
-		(format
-		 "Do you really want to delete %s%s? "
-		 group (if force " and all its contents" ""))))
+      (if (and (not no-prompt)
+	       (not (gnus-yes-or-no-p
+		     (format
+		      "Do you really want to delete %s%s? "
+		      group (if force " and all its contents" "")))))
 	  ()				; Whew!
 	(gnus-message 6 "Deleting group %s..." group)
 	(if (not (gnus-request-delete-group group force))
@@ -1947,7 +2088,7 @@
        ((eq part 'method) "select method")
        ((eq part 'params) "group parameters")
        (t "group info"))
-      group)
+      (gnus-group-decoded-name group))
      `(lambda (form)
 	(gnus-group-edit-group-done ',part ,group form)))))
 
@@ -2043,6 +2184,7 @@
 			  ((= char ?d) 'digest)
 			  ((= char ?f) 'forward)
 			  ((= char ?a) 'mmfd)
+			  ((= char ?g) 'guess)
 			  (t (setq err (format "%c unknown. " char))
 			     nil))))
       (setq type found)))
@@ -2093,6 +2235,42 @@
        (cons (current-buffer)
 	     (if (eq major-mode 'gnus-summary-mode) 'summary 'group))))))
 
+(defvar nnwarchive-type-definition)
+(defvar gnus-group-warchive-type-history nil)
+(defvar gnus-group-warchive-login-history nil)
+(defvar gnus-group-warchive-address-history nil)
+
+(defun gnus-group-make-warchive-group ()
+  "Create a nnwarchive group."
+  (interactive)
+  (require 'nnwarchive)
+  (let* ((group (gnus-read-group "Group name: "))
+	 (default-type (or (car gnus-group-warchive-type-history)
+			   (symbol-name (caar nnwarchive-type-definition))))
+	 (type
+	  (gnus-string-or
+	   (completing-read
+	    (format "Warchive type (default %s): " default-type)
+	    (mapcar (lambda (elem) (list (symbol-name (car elem))))
+		    nnwarchive-type-definition)
+	    nil t nil 'gnus-group-warchive-type-history)
+	   default-type))
+	 (address (read-string "Warchive address: "
+			       nil 'gnus-group-warchive-address-history))
+	 (default-login (or (car gnus-group-warchive-login-history)
+			    user-mail-address))
+	 (login
+	  (gnus-string-or
+	   (read-string
+	    (format "Warchive login (default %s): " user-mail-address)
+	    default-login 'gnus-group-warchive-login-history)
+	   user-mail-address))
+	 (method
+	  `(nnwarchive ,address 
+		       (nnwarchive-type ,(intern type))
+		       (nnwarchive-login ,login))))
+    (gnus-group-make-group group method)))
+
 (defun gnus-group-make-archive-group (&optional all)
   "Create the (ding) Gnus archive group of the most recent articles.
 Given a prefix, create a full group."
@@ -2157,7 +2335,7 @@
 	(push (cons header regexps) scores))
       scores)))
   (gnus-group-make-group group "nnkiboze" address)
-  (nnheader-temp-write (gnus-score-file-name (concat "nnkiboze:" group))
+  (with-temp-file (gnus-score-file-name (concat "nnkiboze:" group))
     (let (emacs-lisp-mode-hook)
       (pp scores (current-buffer)))))
 
@@ -2211,6 +2389,62 @@
 		       'summary 'group)))
       (error "Couldn't enter %s" dir))))
 
+(eval-and-compile
+  (autoload 'nnimap-expunge "nnimap")
+  (autoload 'nnimap-acl-get "nnimap")
+  (autoload 'nnimap-acl-edit "nnimap"))
+
+(defun gnus-group-nnimap-expunge (group)
+  "Expunge deleted articles in current nnimap GROUP."
+  (interactive (list (gnus-group-group-name)))
+  (let ((mailbox (gnus-group-real-name group)) method)
+    (unless group
+      (error "No group on current line"))
+    (unless (gnus-get-info group)
+      (error "Killed group; can't be edited"))
+    (unless (eq 'nnimap (car (setq method (gnus-find-method-for-group group))))
+      (error "%s is not an nnimap group" group))
+    (nnimap-expunge mailbox (cadr method))))
+
+(defun gnus-group-nnimap-edit-acl (group)
+  "Edit the Access Control List of current nnimap GROUP."
+  (interactive (list (gnus-group-group-name)))
+  (let ((mailbox (gnus-group-real-name group)) method acl)
+    (unless group
+      (error "No group on current line"))
+    (unless (gnus-get-info group)
+      (error "Killed group; can't be edited"))
+    (unless (eq (car (setq method (gnus-find-method-for-group group))) 'nnimap)
+      (error "%s is not an nnimap group" group))
+    (gnus-edit-form (setq acl (nnimap-acl-get mailbox (cadr method)))
+		    (format "Editing the access control list for `%s'.
+
+   An access control list is a list of (identifier . rights) elements.
+
+   The identifier string specifies the corresponding user.  The
+   identifier \"anyone\" is reserved to refer to the universal identity.
+
+   Rights is a string listing a (possibly empty) set of alphanumeric
+   characters, each character listing a set of operations which is being
+   controlled.  Letters are reserved for ``standard'' rights, listed
+   below.  Digits are reserved for implementation or site defined rights.
+
+   l - lookup (mailbox is visible to LIST/LSUB commands)
+   r - read (SELECT the mailbox, perform CHECK, FETCH, PARTIAL,
+       SEARCH, COPY from mailbox)
+   s - keep seen/unseen information across sessions (STORE \\SEEN flag)
+   w - write (STORE flags other than \\SEEN and \\DELETED)
+   i - insert (perform APPEND, COPY into mailbox)
+   p - post (send mail to submission address for mailbox,
+       not enforced by IMAP4 itself)
+   c - create and delete mailbox (CREATE new sub-mailboxes in any
+       implementation-defined hierarchy, RENAME or DELETE mailbox)
+   d - delete messages (STORE \\DELETED flag, perform EXPUNGE)
+   a - administer (perform SETACL)" group)
+		    `(lambda (form)
+		       (nnimap-acl-edit
+			,mailbox ',method ',acl form)))))
+
 ;; Group sorting commands
 ;; Suggested by Joe Hildebrand <hildjj@idaho.fuentez.com>.
 
@@ -2302,46 +2536,52 @@
     ;; Go through all the infos and replace the old entries
     ;; with the new infos.
     (while infos
-      (setcar entries (pop infos))
+      (setcar (car entries) (pop infos))
       (pop entries))
     ;; Update the hashtable.
     (gnus-make-hashtable-from-newsrc-alist)))
 
-(defun gnus-group-sort-selected-groups-by-alphabet (&optional reverse)
+(defun gnus-group-sort-selected-groups-by-alphabet (&optional n reverse)
   "Sort the group buffer alphabetically by group name.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-alphabet reverse))
-
-(defun gnus-group-sort-selected-groups-by-unread (&optional reverse)
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-group-sort-selected-groups-by-unread (&optional n reverse)
   "Sort the group buffer by number of unread articles.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-unread reverse))
-
-(defun gnus-group-sort-selected-groups-by-level (&optional reverse)
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-group-sort-selected-groups-by-level (&optional n reverse)
   "Sort the group buffer by group level.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-level reverse))
-
-(defun gnus-group-sort-selected-groups-by-score (&optional reverse)
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-level reverse))
+
+(defun gnus-group-sort-selected-groups-by-score (&optional n reverse)
   "Sort the group buffer by group score.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-score reverse))
-
-(defun gnus-group-sort-selected-groups-by-rank (&optional reverse)
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-score reverse))
+
+(defun gnus-group-sort-selected-groups-by-rank (&optional n reverse)
   "Sort the group buffer by group rank.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-rank reverse))
-
-(defun gnus-group-sort-selected-groups-by-method (&optional reverse)
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-group-sort-selected-groups-by-method (&optional n reverse)
   "Sort the group buffer alphabetically by backend name.
-If REVERSE, sort in reverse order."
-  (interactive "P")
-  (gnus-group-sort-selected-groups 'gnus-group-sort-by-method reverse))
+Obeys the process/prefix convention.  If REVERSE (the symbolic prefix),
+sort in reverse order."
+  (interactive (gnus-interactive "P\ny"))
+  (gnus-group-sort-selected-groups n 'gnus-group-sort-by-method reverse))
 
 ;;; Sorting predicates.
 
@@ -2428,7 +2668,7 @@
 ;; Group catching up.
 
 (defun gnus-group-catchup-current (&optional n all)
-  "Mark all articles not marked as unread in current newsgroup as read.
+  "Mark all unread articles in the current newsgroup as read.
 If prefix argument N is numeric, the next N newsgroups will be
 caught up.  If ALL is non-nil, marked articles will also be marked as
 read.  Cross references (Xref: header) of articles are ignored.
@@ -2436,7 +2676,8 @@
 up is returned."
   (interactive "P")
   (let ((groups (gnus-group-process-prefix n))
-	(ret 0))
+	(ret 0)
+	group)
     (unless groups (error "No groups selected"))
     (if (not
 	 (or (not gnus-interactive-catchup) ;Without confirmation?
@@ -2450,21 +2691,20 @@
 		   (car groups)
 		 (format "these %d groups" (length groups)))))))
 	n
-      (while groups
+      (while (setq group (pop groups))
+	(gnus-group-remove-mark group)
 	;; Virtual groups have to be given special treatment.
-	(let ((method (gnus-find-method-for-group (car groups))))
+	(let ((method (gnus-find-method-for-group group)))
 	  (when (eq 'nnvirtual (car method))
 	    (nnvirtual-catchup-group
-	     (gnus-group-real-name (car groups)) (nth 1 method) all)))
-	(gnus-group-remove-mark (car groups))
-	(if (>= (gnus-group-group-level) gnus-level-zombie)
+	     (gnus-group-real-name group) (nth 1 method) all)))
+	(if (>= (gnus-group-level group) gnus-level-zombie)
 	    (gnus-message 2 "Dead groups can't be caught up")
 	  (if (prog1
-		  (gnus-group-goto-group (car groups))
-		(gnus-group-catchup (car groups) all))
+		  (gnus-group-goto-group group)
+		(gnus-group-catchup group all))
 	      (gnus-group-update-group-line)
-	    (setq ret (1+ ret))))
-	(setq groups (cdr groups)))
+	    (setq ret (1+ ret)))))
       (gnus-group-next-unread-group 1)
       ret)))
 
@@ -2481,6 +2721,8 @@
 or nil if no action could be taken."
   (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
 	 (num (car entry)))
+    ;; Remove entries for this group.
+    (nnmail-purge-split-history (gnus-group-real-name group))
     ;; Do the updating only if the newsgroup isn't killed.
     (if (not (numberp (car entry)))
 	(gnus-message 1 "Can't catch up %s; non-active group" group)
@@ -2513,32 +2755,41 @@
       (error "No groups to expire"))
     (while (setq group (pop groups))
       (gnus-group-remove-mark group)
-      (when (gnus-check-backend-function 'request-expire-articles group)
-	(gnus-message 6 "Expiring articles in %s..." group)
-	(let* ((info (gnus-get-info group))
-	       (expirable (if (gnus-group-total-expirable-p group)
-			      (cons nil (gnus-list-of-read-articles group))
-			    (assq 'expire (gnus-info-marks info))))
-	       (expiry-wait (gnus-group-find-parameter group 'expiry-wait)))
-	  (when expirable
-	    (setcdr
-	     expirable
-	     (gnus-compress-sequence
-	      (if expiry-wait
-		  ;; We set the expiry variables to the group
-		  ;; parameter.
-		  (let ((nnmail-expiry-wait-function nil)
-			(nnmail-expiry-wait expiry-wait))
-		    (gnus-request-expire-articles
-		     (gnus-uncompress-sequence (cdr expirable)) group))
-		;; Just expire using the normal expiry values.
-		(gnus-request-expire-articles
-		 (gnus-uncompress-sequence (cdr expirable)) group))))
-	    (gnus-close-group group))
-	  (gnus-message 6 "Expiring articles in %s...done" group)))
+      (gnus-group-expire-articles-1 group)
       (gnus-dribble-touch)
       (gnus-group-position-point))))
 
+(defun gnus-group-expire-articles-1 (group)
+  (when (gnus-check-backend-function 'request-expire-articles group)
+    (gnus-message 6 "Expiring articles in %s..." group)
+    (let* ((info (gnus-get-info group))
+	   (expirable (if (gnus-group-total-expirable-p group)
+			  (cons nil (gnus-list-of-read-articles group))
+			(assq 'expire (gnus-info-marks info))))
+	   (expiry-wait (gnus-group-find-parameter group 'expiry-wait))
+	   (nnmail-expiry-target
+	    (or (gnus-group-find-parameter group 'expiry-target)
+		nnmail-expiry-target)))
+      (when expirable
+	(gnus-check-group group)
+	(setcdr
+	 expirable
+	 (gnus-compress-sequence
+	  (if expiry-wait
+	      ;; We set the expiry variables to the group
+	      ;; parameter.
+	      (let ((nnmail-expiry-wait-function nil)
+		    (nnmail-expiry-wait expiry-wait))
+		(gnus-request-expire-articles
+		 (gnus-uncompress-sequence (cdr expirable)) group))
+	    ;; Just expire using the normal expiry values.
+	    (gnus-request-expire-articles
+	     (gnus-uncompress-sequence (cdr expirable)) group))))
+	(gnus-close-group group))
+      (gnus-message 6 "Expiring articles in %s...done" group)
+      ;; Return the list of un-expired articles.
+      (cdr expirable))))
+
 (defun gnus-group-expire-all-groups ()
   "Expire all expirable articles in all newsgroups."
   (interactive)
@@ -2565,7 +2816,7 @@
 			      gnus-level-default-subscribed))
 	 s)))))
   (unless (and (>= level 1) (<= level gnus-level-killed))
-    (error "Illegal level: %d" level))
+    (error "Invalid level: %d" level))
   (let ((groups (gnus-group-process-prefix n))
 	group)
     (while (setq group (pop groups))
@@ -2666,13 +2917,15 @@
     (gnus-group-yank-group)
     (gnus-group-position-point)))
 
-(defun gnus-group-kill-all-zombies ()
-  "Kill all zombie newsgroups."
-  (interactive)
-  (setq gnus-killed-list (nconc gnus-zombie-list gnus-killed-list))
-  (setq gnus-zombie-list nil)
-  (gnus-dribble-touch)
-  (gnus-group-list-groups))
+(defun gnus-group-kill-all-zombies (&optional dummy)
+  "Kill all zombie newsgroups.
+The optional DUMMY should always be nil."
+  (interactive (list (not (gnus-yes-or-no-p "Really kill all zombies? "))))
+  (unless dummy
+    (setq gnus-killed-list (nconc gnus-zombie-list gnus-killed-list))
+    (setq gnus-zombie-list nil)
+    (gnus-dribble-touch)
+    (gnus-group-list-groups)))
 
 (defun gnus-group-kill-region (begin end)
   "Kill newsgroups in current region (excluding current point).
@@ -2721,7 +2974,8 @@
 	    (push (cons (car entry) (nth 2 entry))
 		  gnus-list-of-killed-groups))
 	  (gnus-group-change-level
-	   (if entry entry group) gnus-level-killed (if entry nil level)))
+	   (if entry entry group) gnus-level-killed (if entry nil level))
+	  (message "Killed group %s" group))
       ;; If there are lots and lots of groups to be killed, we use
       ;; this thing instead.
       (let (entry)
@@ -2807,7 +3061,7 @@
       (gnus-make-hashtable-from-newsrc-alist)
       (gnus-group-list-groups)))
    (t
-    (error "Can't kill; illegal level: %d" level))))
+    (error "Can't kill; invalid level: %d" level))))
 
 (defun gnus-group-list-all-groups (&optional arg)
   "List all newsgroups with level ARG or lower.
@@ -2850,7 +3104,8 @@
   (interactive)
   ;; First we make sure that we have really read the active file.
   (unless (gnus-read-active-file-p)
-    (let ((gnus-read-active-file t))
+    (let ((gnus-read-active-file t)
+	  (gnus-agent nil))		; Trick the agent into ignoring the active file.
       (gnus-read-active-file)))
   ;; Find all groups and sort them.
   (let ((groups
@@ -2868,10 +3123,14 @@
 	group)
     (erase-buffer)
     (while groups
+      (setq group (pop groups))
       (gnus-add-text-properties
        (point) (prog1 (1+ (point))
 		 (insert "       *: "
-			 (setq group (pop groups)) "\n"))
+			 (gnus-group-name-decode group 
+						 (gnus-group-name-charset
+						  nil group))
+			 "\n"))
        (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
 	     'gnus-unread t
 	     'gnus-level (inline (gnus-group-level group)))))
@@ -2890,7 +3149,11 @@
 re-scanning.  If ARG is non-nil and not a number, this will force
 \"hard\" re-reading of the active files from all servers."
   (interactive "P")
-  (let ((gnus-inhibit-demon t))
+  (require 'nnmail)
+  (let ((gnus-inhibit-demon t)
+	;; Binding this variable will inhibit multiple fetchings
+	;; of the same mail source.
+	(nnmail-fetched-sources (list t)))
     (gnus-run-hooks 'gnus-get-new-news-hook)
 
     ;; Read any slave files.
@@ -2931,7 +3194,12 @@
 	 (ret (if (numberp n) (- n (length groups)) 0))
 	 (beg (unless n
 		(point)))
-	 group method)
+	 group method
+	 (gnus-inhibit-demon t)
+	 ;; Binding this variable will inhibit multiple fetchings
+	 ;; of the same mail source.
+	 (nnmail-fetched-sources (list t)))
+    (gnus-run-hooks 'gnus-get-new-news-hook)
     (while (setq group (pop groups))
       (gnus-group-remove-mark group)
       ;; Bypass any previous denials from the server.
@@ -2942,8 +3210,9 @@
 	     (gnus-get-info group) (gnus-active group) t)
 	    (unless (gnus-virtual-group-p group)
 	      (gnus-close-group group))
-	    (gnus-agent-save-group-info
-	     method (gnus-group-real-name group) (gnus-active group))
+	    (when gnus-agent
+	      (gnus-agent-save-group-info
+	       method (gnus-group-real-name group) (gnus-active group)))
 	    (gnus-group-update-group group))
 	(if (eq (gnus-server-status (gnus-find-method-for-group group))
 		'denied)
@@ -3020,8 +3289,12 @@
     (mapatoms
      (lambda (group)
        (setq b (point))
-       (insert (format "      *: %-20s %s\n" (symbol-name group)
-		       (symbol-value group)))
+       (let ((charset (gnus-group-name-charset nil (symbol-name group))))
+	 (insert (format "      *: %-20s %s\n" 
+			 (gnus-group-name-decode
+			  (symbol-name group) charset)
+			 (gnus-group-name-decode
+			  (symbol-value group) charset))))
        (gnus-add-text-properties
 	b (1+ b) (list 'gnus-group group
 		       'gnus-unread t 'gnus-marked nil
@@ -3057,17 +3330,19 @@
       ;; Print out all the groups.
       (save-excursion
 	(pop-to-buffer "*Gnus Help*")
-	(buffer-disable-undo (current-buffer))
+	(buffer-disable-undo)
 	(erase-buffer)
 	(setq groups (sort groups 'string<))
 	(while groups
 	  ;; Groups may be entered twice into the list of groups.
 	  (when (not (string= (car groups) prev))
-	    (insert (setq prev (car groups)) "\n")
-	    (when (and gnus-description-hashtb
-		       (setq des (gnus-gethash (car groups)
-					       gnus-description-hashtb)))
-	      (insert "  " des "\n")))
+	    (setq prev (car groups))
+	    (let ((charset (gnus-group-name-charset nil prev)))
+	      (insert (gnus-group-name-decode prev charset) "\n")
+	      (when (and gnus-description-hashtb
+			 (setq des (gnus-gethash (car groups)
+						 gnus-description-hashtb)))
+		(insert "  " (gnus-group-name-decode des charset) "\n"))))
 	  (setq groups (cdr groups)))
 	(goto-char (point-min))))
     (pop-to-buffer obuf)))
@@ -3267,59 +3542,60 @@
   (gnus-browse-foreign-server method))
 
 (defun gnus-group-set-info (info &optional method-only-group part)
-  (let* ((entry (gnus-gethash
-		 (or method-only-group (gnus-info-group info))
-		 gnus-newsrc-hashtb))
-	 (part-info info)
-	 (info (if method-only-group (nth 2 entry) info))
-	 method)
-    (when method-only-group
+  (when (or info part)
+    (let* ((entry (gnus-gethash
+		   (or method-only-group (gnus-info-group info))
+		   gnus-newsrc-hashtb))
+	   (part-info info)
+	   (info (if method-only-group (nth 2 entry) info))
+	   method)
+      (when method-only-group
+	(unless entry
+	  (error "Trying to change non-existent group %s" method-only-group))
+	;; We have received parts of the actual group info - either the
+	;; select method or the group parameters.	 We first check
+	;; whether we have to extend the info, and if so, do that.
+	(let ((len (length info))
+	      (total (if (eq part 'method) 5 6)))
+	  (when (< len total)
+	    (setcdr (nthcdr (1- len) info)
+		    (make-list (- total len) nil)))
+	  ;; Then we enter the new info.
+	  (setcar (nthcdr (1- total) info) part-info)))
       (unless entry
-	(error "Trying to change non-existent group %s" method-only-group))
-      ;; We have received parts of the actual group info - either the
-      ;; select method or the group parameters.	 We first check
-      ;; whether we have to extend the info, and if so, do that.
-      (let ((len (length info))
-	    (total (if (eq part 'method) 5 6)))
-	(when (< len total)
-	  (setcdr (nthcdr (1- len) info)
-		  (make-list (- total len) nil)))
-	;; Then we enter the new info.
-	(setcar (nthcdr (1- total) info) part-info)))
-    (unless entry
-      ;; This is a new group, so we just create it.
-      (save-excursion
-	(set-buffer gnus-group-buffer)
-	(setq method (gnus-info-method info))
-	(when (gnus-server-equal method "native")
-	  (setq method nil))
+	;; This is a new group, so we just create it.
 	(save-excursion
 	  (set-buffer gnus-group-buffer)
-	  (if method
-	      ;; It's a foreign group...
-	      (gnus-group-make-group
-	       (gnus-group-real-name (gnus-info-group info))
-	       (if (stringp method) method
-		 (prin1-to-string (car method)))
-	       (and (consp method)
-		    (nth 1 (gnus-info-method info))))
-	    ;; It's a native group.
-	    (gnus-group-make-group (gnus-info-group info))))
-	(gnus-message 6 "Note: New group created")
-	(setq entry
-	      (gnus-gethash (gnus-group-prefixed-name
-			     (gnus-group-real-name (gnus-info-group info))
-			     (or (gnus-info-method info) gnus-select-method))
-			    gnus-newsrc-hashtb))))
-    ;; Whether it was a new group or not, we now have the entry, so we
-    ;; can do the update.
-    (if entry
-	(progn
-	  (setcar (nthcdr 2 entry) info)
-	  (when (and (not (eq (car entry) t))
-		     (gnus-active (gnus-info-group info)))
-	    (setcar entry (length (gnus-list-of-unread-articles (car info))))))
-      (error "No such group: %s" (gnus-info-group info)))))
+	  (setq method (gnus-info-method info))
+	  (when (gnus-server-equal method "native")
+	    (setq method nil))
+	  (save-excursion
+	    (set-buffer gnus-group-buffer)
+	    (if method
+		;; It's a foreign group...
+		(gnus-group-make-group
+		 (gnus-group-real-name (gnus-info-group info))
+		 (if (stringp method) method
+		   (prin1-to-string (car method)))
+		 (and (consp method)
+		      (nth 1 (gnus-info-method info))))
+	      ;; It's a native group.
+	      (gnus-group-make-group (gnus-info-group info))))
+	  (gnus-message 6 "Note: New group created")
+	  (setq entry
+		(gnus-gethash (gnus-group-prefixed-name
+			       (gnus-group-real-name (gnus-info-group info))
+			       (or (gnus-info-method info) gnus-select-method))
+			      gnus-newsrc-hashtb))))
+      ;; Whether it was a new group or not, we now have the entry, so we
+      ;; can do the update.
+      (if entry
+	  (progn
+	    (setcar (nthcdr 2 entry) info)
+	    (when (and (not (eq (car entry) t))
+		       (gnus-active (gnus-info-group info)))
+	      (setcar entry (length (gnus-list-of-unread-articles (car info))))))
+	(error "No such group: %s" (gnus-info-group info))))))
 
 (defun gnus-group-set-method-info (group select-method)
   (gnus-group-set-info select-method group 'method))
@@ -3329,7 +3605,7 @@
 
 (defun gnus-add-marked-articles (group type articles &optional info force)
   ;; Add ARTICLES of TYPE to the info of GROUP.
-  ;; If INFO is non-nil, use that info.	 If FORCE is non-nil, don't
+  ;; If INFO is non-nil, use that info.  If FORCE is non-nil, don't
   ;; add, but replace marked articles of TYPE with ARTICLES.
   (let ((info (or info (gnus-get-info group)))
 	marked m)
@@ -3373,8 +3649,8 @@
 (defun gnus-group-timestamp-delta (group)
   "Return the offset in seconds from the timestamp for GROUP to the current time, as a floating point number."
   (let* ((time (or (gnus-group-timestamp group)
-		  (list 0 0)))
-         (delta (gnus-time-minus (current-time) time)))
+		   (list 0 0)))
+         (delta (subtract-time (current-time) time)))
     (+ (* (nth 0 delta) 65536.0)
        (nth 1 delta))))
 
@@ -3385,6 +3661,118 @@
 	""
       (gnus-time-iso8601 time))))
 
+(defun gnus-group-prepare-flat-list-dead-predicate 
+  (groups level mark predicate)
+  (let (group)
+    (if predicate
+	;; This loop is used when listing groups that match some
+	;; regexp.
+	(while (setq group (pop groups))
+	  (when (funcall predicate group)
+	    (gnus-add-text-properties
+	     (point) (prog1 (1+ (point))
+		       (insert " " mark "     *: " 
+			       (gnus-group-name-decode group 
+						       (gnus-group-name-charset
+							nil group))
+			       "\n"))
+	     (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
+		   'gnus-unread t
+		   'gnus-level level)))))))
+
+(defun gnus-group-prepare-flat-predicate (level predicate &optional lowest
+						dead-predicate)
+  "List all newsgroups with unread articles of level LEVEL or lower.
+If LOWEST is non-nil, list all newsgroups of level LOWEST or higher.
+If PREDICATE, only list groups which PREDICATE returns non-nil.
+If DEAD-PREDICATE, list dead groups which DEAD-PREDICATE returns non-nil."
+  (set-buffer gnus-group-buffer)
+  (let ((buffer-read-only nil)
+	(newsrc (cdr gnus-newsrc-alist))
+	(lowest (or lowest 1))
+	info clevel unread group params)
+    (erase-buffer)
+    ;; List living groups.
+    (while newsrc
+      (setq info (car newsrc)
+	    group (gnus-info-group info)
+	    params (gnus-info-params info)
+	    newsrc (cdr newsrc)
+	    unread (car (gnus-gethash group gnus-newsrc-hashtb)))
+      (and unread			; This group might be unchecked
+	   (funcall predicate info)
+	   (<= (setq clevel (gnus-info-level info)) level)
+	   (>= clevel lowest)
+	   (gnus-group-insert-group-line
+	    group (gnus-info-level info)
+	    (gnus-info-marks info) unread (gnus-info-method info))))
+
+    ;; List dead groups.
+    (and (>= level gnus-level-zombie) (<= lowest gnus-level-zombie)
+	 (gnus-group-prepare-flat-list-dead-predicate
+	  (setq gnus-zombie-list (sort gnus-zombie-list 'string<))
+	  gnus-level-zombie ?Z
+	  dead-predicate))
+    (and (>= level gnus-level-killed) (<= lowest gnus-level-killed)
+	 (gnus-group-prepare-flat-list-dead-predicate
+	  (setq gnus-killed-list (sort gnus-killed-list 'string<))
+	  gnus-level-killed ?K dead-predicate))
+
+    (gnus-group-set-mode-line)
+    (setq gnus-group-list-mode (cons level t))
+    (gnus-run-hooks 'gnus-group-prepare-hook)
+    t))
+
+(defun gnus-group-list-cached (level &optional lowest)
+  "List all groups with cached articles.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (when (or (not level) (>= level gnus-level-zombie))
+    (gnus-cache-open))
+  (gnus-group-prepare-flat-predicate (or level gnus-level-subscribed)
+				#'(lambda (info)
+				    (let ((marks (gnus-info-marks info)))
+				      (assq 'cache marks)))
+				lowest
+				#'(lambda (group)
+				    (or (gnus-gethash group 
+						      gnus-cache-active-hashtb)
+					;; Cache active file might use "." 
+					;; instead of ":".
+					(gnus-gethash 
+					 (mapconcat 'identity
+						    (split-string group ":")
+						    ".")
+					 gnus-cache-active-hashtb))))
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-dormant (level &optional lowest)
+  "List all groups with dormant articles.
+If the prefix LEVEL is non-nil, it should be a number that says which
+level to cut off listing groups.
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
+  (interactive "P")
+  (when level
+    (setq level (prefix-numeric-value level)))
+  (when (or (not level) (>= level gnus-level-zombie))
+    (gnus-cache-open))
+  (gnus-group-prepare-flat-predicate (or level gnus-level-subscribed)
+				#'(lambda (info)
+				    (let ((marks (gnus-info-marks info)))
+				      (assq 'dormant marks)))
+				lowest)
+  (goto-char (point-min))
+  (gnus-group-position-point))
+
 (provide 'gnus-group)
 
 ;;; gnus-group.el ends here
--- a/lisp/gnus/gnus-int.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-int.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-int.el --- backend interface functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 
 (defcustom gnus-open-server-hook nil
@@ -93,6 +92,7 @@
        ;; gnus-open-server-hook might have opened it
        (gnus-server-opened gnus-select-method)
        (gnus-open-server gnus-select-method)
+       gnus-batch-mode
        (gnus-y-or-n-p
 	(format
 	 "%s (%s) open error: '%s'.  Continue? "
@@ -220,10 +220,12 @@
 
 (defun gnus-server-opened (gnus-command-method)
   "Check whether a connection to GNUS-COMMAND-METHOD has been opened."
-  (when (stringp gnus-command-method)
-    (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
-  (funcall (inline (gnus-get-function gnus-command-method 'server-opened))
-	   (nth 1 gnus-command-method)))
+  (unless (eq (gnus-server-status gnus-command-method)
+	      'denied)
+    (when (stringp gnus-command-method)
+      (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
+    (funcall (inline (gnus-get-function gnus-command-method 'server-opened))
+	     (nth 1 gnus-command-method))))
 
 (defun gnus-status-message (gnus-command-method)
   "Return the status message from GNUS-COMMAND-METHOD.
@@ -270,6 +272,14 @@
       (funcall (gnus-get-function gnus-command-method func)
 	       (gnus-group-real-name group) (nth 1 gnus-command-method)))))
 
+(defun gnus-request-group-articles (group)
+  "Request a list of existing articles in GROUP."
+  (let ((gnus-command-method (gnus-find-method-for-group group))
+	(func 'request-group-articles))
+    (when (gnus-check-backend-function func group)
+      (funcall (gnus-get-function gnus-command-method func)
+	       (gnus-group-real-name group) (nth 1 gnus-command-method)))))
+
 (defun gnus-close-group (group)
   "Request the GROUP be closed."
   (let ((gnus-command-method (inline (gnus-find-method-for-group group))))
@@ -309,6 +319,16 @@
       (funcall (gnus-get-function gnus-command-method 'request-type)
 	       (gnus-group-real-name group) article))))
 
+(defun gnus-request-set-mark (group action)
+  "Set marks on articles in the backend."
+  (let ((gnus-command-method (gnus-find-method-for-group group)))
+    (if (not (gnus-check-backend-function
+	      'request-set-mark (car gnus-command-method)))
+	action
+      (funcall (gnus-get-function gnus-command-method 'request-set-mark)
+	       (gnus-group-real-name group) action
+	       (nth 1 gnus-command-method)))))
+
 (defun gnus-request-update-mark (group article mark)
   "Allow the backend to change the mark the user tries to put on an article."
   (let ((gnus-command-method (gnus-find-method-for-group group)))
@@ -394,13 +414,14 @@
 (defun gnus-request-scan (group gnus-command-method)
   "Request a SCAN being performed in GROUP from GNUS-COMMAND-METHOD.
 If GROUP is nil, all groups on GNUS-COMMAND-METHOD are scanned."
-  (when gnus-plugged
-    (let ((gnus-command-method
-	   (if group (gnus-find-method-for-group group) gnus-command-method))
-	  (gnus-inhibit-demon t))
-      (funcall (gnus-get-function gnus-command-method 'request-scan)
-	       (and group (gnus-group-real-name group))
-	       (nth 1 gnus-command-method)))))
+  (let ((gnus-command-method
+	 (if group (gnus-find-method-for-group group) gnus-command-method))
+	(gnus-inhibit-demon t)
+	(mail-source-plugged gnus-plugged))
+    (if (or gnus-plugged (not (gnus-agent-method-p gnus-command-method)))
+	(funcall (gnus-get-function gnus-command-method 'request-scan)
+		 (and group (gnus-group-real-name group))
+		 (nth 1 gnus-command-method)))))
 
 (defsubst gnus-request-update-info (info gnus-command-method)
   "Request that GNUS-COMMAND-METHOD update INFO."
@@ -425,7 +446,8 @@
 	     article (gnus-group-real-name group)
 	     (nth 1 gnus-command-method) accept-function last)))
 
-(defun gnus-request-accept-article (group &optional gnus-command-method last)
+(defun gnus-request-accept-article (group &optional gnus-command-method last
+					  no-encode)
   ;; Make sure there's a newline at the end of the article.
   (when (stringp gnus-command-method)
     (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
@@ -435,6 +457,12 @@
   (goto-char (point-max))
   (unless (bolp)
     (insert "\n"))
+  (unless no-encode
+    (save-restriction
+      (message-narrow-to-head)
+      (let ((mail-parse-charset message-default-charset))
+	(mail-encode-encoded-word-buffer)))
+    (message-encode-message-body))
   (let ((func (car (or gnus-command-method
 		       (gnus-find-method-for-group group)))))
     (funcall (intern (format "%s-request-accept-article" func))
@@ -442,7 +470,13 @@
 	     (cadr gnus-command-method)
 	     last)))
 
-(defun gnus-request-replace-article (article group buffer)
+(defun gnus-request-replace-article (article group buffer &optional no-encode)
+  (unless no-encode
+    (save-restriction
+      (message-narrow-to-head)
+      (let ((mail-parse-charset message-default-charset))
+	(mail-encode-encoded-word-buffer)))
+    (message-encode-message-body))
   (let ((func (car (gnus-group-name-to-method group))))
     (funcall (intern (format "%s-request-replace-article" func))
 	     article (gnus-group-real-name group) buffer)))
--- a/lisp/gnus/gnus-kill.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-kill.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-kill.el --- kill commands for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,8 +29,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-art)
 (require 'gnus-range)
@@ -51,7 +50,8 @@
   :type 'boolean)
 
 (defcustom gnus-winconf-kill-file nil
-  "What does this do, Lars?"
+  "What does this do, Lars?
+I don't know, Per."
   :group 'gnus-score-kill
   :type 'sexp)
 
@@ -431,7 +431,7 @@
 (defun gnus-score-insert-help (string alist idx)
   (save-excursion
     (pop-to-buffer "*Score Help*")
-    (buffer-disable-undo (current-buffer))
+    (buffer-disable-undo)
     (erase-buffer)
     (insert string ":\n\n")
     (while alist
@@ -446,7 +446,7 @@
 	     (setq beg (point))
 	     (setq form (ignore-errors (read (current-buffer)))))
       (unless (listp form)
-	(error "Illegal kill entry (possibly rn kill file?): %s" form))
+	(error "Invalid kill entry (possibly rn kill file?): %s" form))
       (if (or (eq (car form) 'gnus-kill)
 	      (eq (car form) 'gnus-raise)
 	      (eq (car form) 'gnus-lower))
@@ -526,7 +526,7 @@
 		  ;; It's on the form (regexp . date).
 		  (if (zerop (gnus-execute field (car kill-list)
 					   command nil (not all)))
-		      (when (> (gnus-days-between date (cdr kill-list))
+		      (when (> (days-between date (cdr kill-list))
 			       gnus-kill-expiry-days)
 			(setq regexp nil))
 		    (setcdr kill-list date))
@@ -537,7 +537,7 @@
 			(setq kdate (cdr kill))
 			(if (zerop (gnus-execute
 				    field (car kill) command nil (not all)))
-			    (when (> (gnus-days-between date kdate)
+			    (when (> (days-between date kdate)
 				     gnus-kill-expiry-days)
 			      ;; Time limit has been exceeded, so we
 			      ;; remove the match.
@@ -568,7 +568,7 @@
       (concat "\n" (gnus-prin1-to-string object))
     (save-excursion
       (set-buffer (gnus-get-buffer-create "*Gnus PP*"))
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (erase-buffer)
       (insert (format "\n(%S %S\n  '(" (nth 0 object) (nth 1 object)))
       (let ((klist (cadr (nth 2 object)))
@@ -685,6 +685,7 @@
 		   (mapconcat 'identity command-line-args-left " "))))
 	 (gnus-expert-user t)
 	 (nnmail-spool-file nil)
+	 (mail-sources nil)
 	 (gnus-use-dribble-file nil)
 	 (gnus-batch-mode t)
 	 info group newsrc entry
@@ -704,7 +705,8 @@
 		 (and (car entry)
 		      (or (eq (car entry) t)
 			  (not (zerop (car entry))))))
-	(gnus-summary-read-group group nil t nil t)
+	(ignore-errors
+	  (gnus-summary-read-group group nil t nil t))
 	(when (eq (current-buffer) (get-buffer gnus-summary-buffer))
 	  (gnus-summary-exit))))
     ;; Exit Emacs.
--- a/lisp/gnus/gnus-logic.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-logic.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-logic.el --- advanced scoring code for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-score)
 (require 'gnus-util)
@@ -173,9 +172,9 @@
      ((eq type 'at)
       (equal date match))
      ((eq type 'before)
-      (gnus-time-less match date))
+      (time-less-p match date))
      ((eq type 'after)
-      (gnus-time-less date match))
+      (time-less-p date match))
      (t
       (error "No such date score type: %s" type)))))
 
@@ -220,7 +219,7 @@
 		      ((memq type '(s S string String))
 		       'search-forward)
 		      (t
-		       (error "Illegal match type: %s" type)))))
+		       (error "Invalid match type: %s" type)))))
 	  (goto-char (point-min))
 	  (prog1
 	      (funcall search-func match nil t)
--- a/lisp/gnus/gnus-mh.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-mh.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-mh.el --- mh-e interface for Gnus
-;; Copyright (C) 1994,95,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -66,8 +67,8 @@
 		   t))))
 	(errbuf (gnus-get-buffer-create " *Gnus rcvstore*"))
 	;; Find the rcvstore program.
-	(exec-path (if mh-lib-progs (cons mh-lib-progs exec-path) exec-path)))
-    (gnus-eval-in-buffer-window gnus-original-article-buffer
+	(exec-path (if mh-lib (cons mh-lib exec-path) exec-path)))
+    (with-current-buffer gnus-original-article-buffer
       (save-restriction
 	(widen)
 	(unwind-protect
--- a/lisp/gnus/gnus-move.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-move.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-move.el --- commands for moving Gnus from one server to another
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-start)
 (require 'gnus-int)
@@ -47,6 +46,7 @@
 
   ;; First start Gnus.
   (let ((gnus-activate-level 0)
+	(mail-sources nil)
 	(nnmail-spool-file nil))
     (gnus))
 
@@ -92,6 +92,8 @@
 	;; Then we read the headers from the `from-server'.
 	(when (and (gnus-request-group group nil from-server)
 		   (gnus-active group)
+		   (gnus-uncompress-range
+		    (gnus-active group))
 		   (setq type (gnus-retrieve-headers
 			       (gnus-uncompress-range
 				(gnus-active group))
--- a/lisp/gnus/gnus-msg.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-msg.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-msg.el --- mail and post interface for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,26 +29,24 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-ems)
 (require 'message)
 (require 'gnus-art)
 
-(defcustom gnus-post-method nil
+(defcustom gnus-post-method 'current
   "*Preferred method for posting USENET news.
 
 If this variable is `current', Gnus will use the \"current\" select
 method when posting.  If it is nil (which is the default), Gnus will
-use the native posting method of the server.
+use the native select method when posting.
 
 This method will not be used in mail groups and the like, only in
 \"real\" newsgroups.
 
 If not nil nor `native', the value must be a valid method as discussed
-in the documentation of `gnus-select-method'. It can also be a list of
-methods. If that is the case, the user will be queried for what select
+in the documentation of `gnus-select-method'.  It can also be a list of
+methods.  If that is the case, the user will be queried for what select
 method to use when posting."
   :group 'gnus-group-foreign
   :type `(choice (const nil)
@@ -102,13 +101,37 @@
 (defvar gnus-posting-styles nil
   "*Alist of styles to use when posting.")
 
-(defvar gnus-posting-style-alist
-  '((organization . message-user-organization)
-    (signature . message-signature)
-    (signature-file . message-signature-file)
-    (address . user-mail-address)
-    (name . user-full-name))
-  "*Mapping from style parameters to variables.")
+(defcustom gnus-group-posting-charset-alist
+  '(("^\\(no\\|fr\\|dk\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\|dk\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
+    ("^\\(fido7\\|relcom\\)\\.[^,]*\\(,[ \t\n]*\\(fido7\\|relcom\\)\\.[^,]*\\)*$" koi8-r (koi8-r))
+    (message-this-is-mail nil nil)
+    (message-this-is-news nil t))
+  "Alist of regexps and permitted unencoded charsets for posting.
+Each element of the alist has the form (TEST HEADER BODY-LIST), where
+TEST is either a regular expression matching the newsgroup header or a
+variable to query,
+HEADER is the charset which may be left unencoded in the header (nil
+means encode all charsets),
+BODY-LIST is a list of charsets which may be encoded using 8bit
+content-transfer encoding in the body, or one of the special values
+nil (always encode using quoted-printable) or t (always use 8bit).
+
+Note that any value other than nil for HEADER infringes some RFCs, so
+use this option with care."
+  :type '(repeat (list :tag "Permitted unencoded charsets"
+		  (choice :tag "Where"
+		   (regexp :tag "Group")
+		   (const :tag "Mail message" :value message-this-is-mail)
+		   (const :tag "News article" :value message-this-is-news))
+		  (choice :tag "Header"
+		   (const :tag "None" nil)
+		   (symbol :tag "Charset"))
+		  (choice :tag "Body"
+			  (const :tag "Any" :value t)
+			  (const :tag "None" :value nil)
+			  (repeat :tag "Charsets"
+				  (symbol :tag "Charset")))))
+  :group 'gnus-charset)
 
 ;;; Internal variables.
 
@@ -127,9 +150,10 @@
 The buffer below is a mail buffer.  When you press `C-c C-c', it will
 be sent to the Gnus Bug Exterminators.
 
-At the bottom of the buffer you'll see lots of variable settings.
-Please do not delete those.  They will tell the Bug People what your
-environment is, so that it will be easier to locate the bugs.
+The thing near the bottom of the buffer is how the environment
+settings will be included in the mail.  Please do not delete that.
+They will tell the Bug People what your environment is, so that it
+will be easier to locate the bugs.
 
 If you have found a bug that makes Emacs go \"beep\", set
 debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET')
@@ -159,6 +183,7 @@
   "c" gnus-summary-cancel-article
   "s" gnus-summary-supersede-article
   "r" gnus-summary-reply
+  "y" gnus-summary-yank-message
   "R" gnus-summary-reply-with-original
   "w" gnus-summary-wide-reply
   "W" gnus-summary-wide-reply-with-original
@@ -177,6 +202,20 @@
   ;; "c" gnus-summary-send-draft
   "r" gnus-summary-resend-message)
 
+;;;###autoload
+(defun gnus-msg-mail (&rest args)
+  "Start editing a mail message to be sent.
+Like `message-mail', but with Gnus paraphernalia, particularly the
+the Gcc: header for archiving purposes."
+  (interactive)
+  (gnus-setup-message 'message
+    (apply 'message-mail args)))
+
+;;;###autoload
+(define-mail-user-agent 'gnus-user-agent
+      'gnus-msg-mail 'message-send-and-exit
+      'message-kill-buffer 'message-send-hook)
+
 ;;; Internal functions.
 
 (defvar gnus-article-reply nil)
@@ -191,7 +230,9 @@
 	   (,group gnus-newsgroup-name)
 	   (message-header-setup-hook
 	    (copy-sequence message-header-setup-hook))
+	   (mbl mml-buffer-list)
 	   (message-mode-hook (copy-sequence message-mode-hook)))
+       (setq mml-buffer-list nil)
        (add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc)
        (add-hook 'message-header-setup-hook 'gnus-inews-insert-archive-gcc)
        (add-hook 'message-mode-hook 'gnus-configure-posting-styles)
@@ -202,12 +243,37 @@
 	 (setq gnus-message-buffer (current-buffer))
 	 (set (make-local-variable 'gnus-message-group-art)
 	      (cons ,group ,article))
-	 (make-local-variable 'gnus-newsgroup-name)
-	 (gnus-run-hooks 'gnus-message-setup-hook))
+	 (set (make-local-variable 'gnus-newsgroup-name) ,group)
+	 (gnus-run-hooks 'gnus-message-setup-hook)
+	 (if (eq major-mode 'message-mode)
+	     ;; Make mml-buffer-list local.
+	     ;; Restore global mml-buffer-list value as mbl.
+	     ;; What a hack! -- Shenghuo
+	     (let ((mml-buffer-list mml-buffer-list))
+	       (setq mml-buffer-list mbl)
+	       (make-local-variable 'mml-buffer-list)
+	       (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
+	   (mml-destroy-buffers)
+	   (setq mml-buffer-list mbl)))
        (gnus-add-buffer)
        (gnus-configure-windows ,config t)
        (set-buffer-modified-p nil))))
 
+(defun gnus-setup-posting-charset (group)
+  (let ((alist gnus-group-posting-charset-alist)
+	(group (or group ""))
+	elem)
+    (when group
+      (catch 'found
+	(while (setq elem (pop alist))
+	  (when (or (and (stringp (car elem))
+			 (string-match (car elem) group))
+		    (and (gnus-functionp (car elem))
+			 (funcall (car elem) group))
+		    (and (symbolp (car elem))
+			 (symbol-value (car elem))))
+	    (throw 'found (cons (cadr elem) (caddr elem)))))))))
+
 (defun gnus-inews-add-send-actions (winconf buffer article)
   (make-local-hook 'message-sent-hook)
   (add-hook 'message-sent-hook 'gnus-inews-do-gcc nil t)
@@ -230,11 +296,29 @@
 
 ;;; Post news commands of Gnus group mode and summary mode
 
-(defun gnus-group-mail ()
-  "Start composing a mail."
-  (interactive)
-  (gnus-setup-message 'message
-    (message-mail)))
+(defun gnus-group-mail (&optional arg)
+  "Start composing a mail.
+If ARG, use the group under the point to find a posting style.
+If ARG is 1, prompt for a group name to find the posting style."
+  (interactive "P")
+  ;; We can't `let' gnus-newsgroup-name here, since that leads
+  ;; to local variables leaking.
+  (let ((group gnus-newsgroup-name)
+	(buffer (current-buffer)))
+    (unwind-protect
+	(progn
+	  (setq gnus-newsgroup-name
+		(if arg
+		    (if (= 1 (prefix-numeric-value arg))
+			(completing-read "Use posting style of group: "
+					 gnus-active-hashtb nil
+					 (gnus-read-active-file-p))
+		      (gnus-group-group-name))
+		  ""))
+	  (gnus-setup-message 'message (message-mail)))
+      (save-excursion
+	(set-buffer buffer)
+	(setq gnus-newsgroup-name group)))))
 
 (defun gnus-group-post-news (&optional arg)
   "Start composing a news message.
@@ -355,7 +439,9 @@
   ;; if ARTICLE-BUFFER is nil, gnus-article-buffer is used
   ;; this buffer should be passed to all mail/news reply/post routines.
   (setq gnus-article-copy (gnus-get-buffer-create " *gnus article copy*"))
-  (buffer-disable-undo gnus-article-copy)
+  (save-excursion
+    (set-buffer gnus-article-copy)
+    (mm-enable-multibyte))
   (let ((article-buffer (or article-buffer gnus-article-buffer))
 	end beg)
     (if (not (and (get-buffer article-buffer)
@@ -374,7 +460,7 @@
 	  (gnus-remove-text-with-property 'gnus-next)
 	  (insert
 	   (prog1
-	       (format "%s" (buffer-string))
+	       (buffer-substring-no-properties (point-min) (point-max))
 	     (erase-buffer)))
 	  ;; Find the original headers.
 	  (set-buffer gnus-original-article-buffer)
@@ -386,10 +472,10 @@
 	  ;; Delete the headers from the displayed articles.
 	  (set-buffer gnus-article-copy)
 	  (delete-region (goto-char (point-min))
-			 (or (search-forward "\n\n" nil t) (point)))
+			 (or (search-forward "\n\n" nil t) (point-max)))
 	  ;; Insert the original article headers.
 	  (insert-buffer-substring gnus-original-article-buffer beg end)
-	  (gnus-article-decode-rfc1522)))
+	  (article-decode-encoded-words)))
       gnus-article-copy)))
 
 (defun gnus-post-news (post &optional group header article-buffer yank subject
@@ -402,6 +488,7 @@
 			      (article-buffer 'reply)
 			      (t 'message))
       (let* ((group (or group gnus-newsgroup-name))
+	     (charset (gnus-group-name-charset nil group))
 	     (pgroup group)
 	     to-address to-group mailing-list to-list
 	     newsgroup-p)
@@ -412,7 +499,8 @@
 		newsgroup-p (gnus-group-find-parameter group 'newsgroup)
 		mailing-list (when gnus-mailing-list-groups
 			       (string-match gnus-mailing-list-groups group))
-		group (gnus-group-real-name group)))
+		group (gnus-group-name-decode (gnus-group-real-name group)
+					      charset)))
 	(if (or (and to-group
 		     (gnus-news-group-p to-group))
 		newsgroup-p
@@ -464,7 +552,7 @@
      ;; the default method.
      ((null group-method)
       (or (and (null (eq gnus-post-method 'active)) gnus-post-method)
-	       gnus-select-method message-post-method))
+	  gnus-select-method message-post-method))
      ;; We want the inverse of the default
      ((and arg (not (eq arg 0)))
       (if (eq gnus-post-method 'active)
@@ -485,14 +573,16 @@
 		   (list gnus-post-method)))
 	       gnus-secondary-select-methods
 	       (mapcar 'cdr gnus-server-alist)
+	       (mapcar 'car gnus-opened-servers)
 	       (list gnus-select-method)
 	       (list group-method)))
 	     method-alist post-methods method)
 	;; Weed out all mail methods.
 	(while methods
 	  (setq method (gnus-server-get-method "" (pop methods)))
-	  (when (or (gnus-method-option-p method 'post)
-		    (gnus-method-option-p method 'post-mail))
+	  (when (and (or (gnus-method-option-p method 'post)
+			 (gnus-method-option-p method 'post-mail))
+		     (not (member method post-methods)))
 	    (push method post-methods)))
 	;; Create a name-method alist.
 	(setq method-alist
@@ -515,8 +605,9 @@
      ;; Override normal method.
      ((and (eq gnus-post-method 'current)
 	   (not (eq (car group-method) 'nndraft))
+	   (gnus-get-function group-method 'request-post t)
 	   (not arg))
-      group-method) 
+      group-method)
      ((and gnus-post-method
 	   (not (eq gnus-post-method 'current)))
       gnus-post-method)
@@ -525,69 +616,32 @@
 
 
 
-;; Dummy to avoid byte-compile warning.
+;; Dummies to avoid byte-compile warning.
 (defvar nnspool-rejected-article-hook)
 (defvar xemacs-codename)
 
-;;; Since the X-Newsreader/X-Mailer are ``vanity'' headers, they might
-;;; as well include the Emacs version as well.
-;;; The following function works with later GNU Emacs, and XEmacs.
 (defun gnus-extended-version ()
   "Stringified Gnus version and Emacs version."
   (interactive)
   (concat
-   gnus-version
-   "/"
+   "Gnus/" (prin1-to-string (gnus-continuum-version gnus-version) t)
+   " (" gnus-version ")"
+   " "
    (cond
-    ((string-match "^\\([0-9]+\\.[0-9]+\\)\\.[.0-9]+$" emacs-version)
-     (concat "Emacs " (substring emacs-version
-				 (match-beginning 1)
-				 (match-end 1))))
+    ((string-match "^\\(\\([.0-9]+\\)*\\)\\.[0-9]+$" emacs-version)
+     (concat "Emacs/" (match-string 1 emacs-version)))
     ((string-match "\\([A-Z]*[Mm][Aa][Cc][Ss]\\)[^(]*\\(\\((beta.*)\\|'\\)\\)?"
 		   emacs-version)
-     (concat (substring emacs-version
-			(match-beginning 1)
-			(match-end 1))
-	     (format " %d.%d" emacs-major-version emacs-minor-version)
+     (concat (match-string 1 emacs-version)
+	     (format "/%d.%d" emacs-major-version emacs-minor-version)
 	     (if (match-beginning 3)
-		 (substring emacs-version
-			    (match-beginning 3)
-			    (match-end 3))
+		 (match-string 3 emacs-version)
 	       "")
 	     (if (boundp 'xemacs-codename)
-		 (concat " - \"" xemacs-codename "\""))))
+		 (concat " (" xemacs-codename ")")
+	       "")))
     (t emacs-version))))
 
-;; Written by "Mr. Per Persson" <pp@gnu.org>.
-(defun gnus-inews-insert-mime-headers ()
-  "Insert MIME headers.
-Assumes ISO-Latin-1 is used iff 8-bit characters are present."
-  (goto-char (point-min))
-  (let ((mail-header-separator
-	 (progn
-	   (goto-char (point-min))
-	   (if (and (search-forward (concat "\n" mail-header-separator "\n")
-				    nil t)
-		    (not (search-backward "\n\n" nil t)))
-	       mail-header-separator
-	     ""))))
-    (or (mail-position-on-field "Mime-Version")
-	(insert "1.0")
-	(cond ((save-restriction
-		 (widen)
-		 (goto-char (point-min))
-		 (re-search-forward "[^\000-\177]" nil t))
-	       (or (mail-position-on-field "Content-Type")
-		   (insert "text/plain; charset=ISO-8859-1"))
-	       (or (mail-position-on-field "Content-Transfer-Encoding")
-		   (insert "8bit")))
-	      (t (or (mail-position-on-field "Content-Type")
-		     (insert "text/plain; charset=US-ASCII"))
-		 (or (mail-position-on-field "Content-Transfer-Encoding")
-		     (insert "7bit")))))))
-
-(custom-add-option 'message-header-hook 'gnus-inews-insert-mime-headers)
-
 
 ;;;
 ;;; Gnus Mail Functions
@@ -610,6 +664,10 @@
       (gnus-summary-select-article)
       (set-buffer (gnus-copy-article-buffer))
       (gnus-msg-treat-broken-reply-to)
+      (save-restriction
+	(message-narrow-to-head)
+	(goto-char (point-max)))
+      (mml-quote-region (point) (point-max))
       (message-reply nil wide)
       (when yank
 	(gnus-inews-yank-articles yank)))))
@@ -635,16 +693,51 @@
   (interactive "P")
   (gnus-summary-reply-with-original n t))
 
-(defun gnus-summary-mail-forward (&optional full-headers post)
-  "Forward the current message to another user.
-If FULL-HEADERS (the prefix), include full headers when forwarding."
+(defun gnus-summary-mail-forward (&optional arg post)
+  "Forward the current message to another user.  
+If ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
+if ARG is 1, decode the message and forward directly inline;
+if ARG is 2, foward message as an rfc822 MIME section;
+if ARG is 3, decode message and forward as an rfc822 MIME section;
+if ARG is 4, foward message directly inline;
+otherwise, use flipped `message-forward-as-mime'.
+If POST, post instead of mail."
   (interactive "P")
-  (gnus-setup-message 'forward
-    (gnus-summary-select-article)
-    (set-buffer gnus-original-article-buffer)
-    (let ((message-included-forward-headers
-	   (if full-headers "" message-included-forward-headers)))
-      (message-forward post))))
+  (let ((message-forward-as-mime message-forward-as-mime)
+	(message-forward-show-mml message-forward-show-mml))
+    (cond 
+     ((null arg))
+     ((eq arg 1) (setq message-forward-as-mime nil
+		       message-forward-show-mml t))
+     ((eq arg 2) (setq message-forward-as-mime t
+		       message-forward-show-mml nil))
+     ((eq arg 3) (setq message-forward-as-mime t
+		       message-forward-show-mml t))
+     ((eq arg 4) (setq message-forward-as-mime nil
+		       message-forward-show-mml nil))
+     (t (setq message-forward-as-mime (not message-forward-as-mime))))
+    (gnus-setup-message 'forward
+      (gnus-summary-select-article)
+      (let ((mail-parse-charset gnus-newsgroup-charset)
+	    (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+	    text)
+	(save-excursion
+	  (set-buffer gnus-original-article-buffer)
+	  (mm-with-unibyte-current-buffer
+	    (setq text (buffer-string))))
+	(set-buffer 
+	 (gnus-get-buffer-create
+	  (generate-new-buffer-name " *Gnus forward*")))
+	(erase-buffer)
+	(mm-disable-multibyte)
+	(insert text)
+	(goto-char (point-min))
+	(when (looking-at "From ")
+	  (replace-match "X-From-Line: ") )
+	(when message-forward-show-mml
+	  (mm-enable-multibyte)
+	  (mime-to-mml))
+	(message-forward post)))))
 
 (defun gnus-summary-resend-message (address n)
   "Resend the current article to ADDRESS."
@@ -657,11 +750,11 @@
 	(set-buffer gnus-original-article-buffer)
 	(message-resend address)))))
 
-(defun gnus-summary-post-forward (&optional full-headers)
+(defun gnus-summary-post-forward (&optional arg)
   "Forward the current article to a newsgroup.
-If FULL-HEADERS (the prefix), include full headers when forwarding."
+See `gnus-summary-mail-forward' for ARG."
   (interactive "P")
-  (gnus-summary-mail-forward full-headers t))
+  (gnus-summary-mail-forward arg t))
 
 (defvar gnus-nastygram-message
   "The following article was inappropriately posted to %s.\n\n"
@@ -694,7 +787,8 @@
 	(gnus-summary-select-article)
 	(set-buffer gnus-original-article-buffer)
 	(if (and (<= (length (message-tokenize-header
-			      (setq newsgroups (mail-fetch-field "newsgroups"))
+			      (setq newsgroups
+				    (mail-fetch-field "newsgroups"))
 			      ", "))
 		     1)
 		 (or (not (setq followup-to (mail-fetch-field "followup-to")))
@@ -833,7 +927,12 @@
 	       (stringp nntp-server-type))
       (insert nntp-server-type))
     (insert "\n\n\n\n\n")
-    (gnus-debug)
+    (let (text)
+      (save-excursion
+	(set-buffer (gnus-get-buffer-create " *gnus environment info*"))
+	(gnus-debug)
+	(setq text (buffer-string)))
+      (insert "<#part type=application/x-emacs-lisp disposition=inline description=\"User settings\">\n" text "\n<#/part>"))
     (goto-char (point-min))
     (search-forward "Subject: " nil t)
     (message "")))
@@ -842,6 +941,19 @@
   (when (get-buffer "*Gnus Help Bug*")
     (kill-buffer "*Gnus Help Bug*")))
 
+(defun gnus-summary-yank-message (buffer n)
+  "Yank the current article into a composed message."
+  (interactive
+   (list (completing-read "Buffer: " (mapcar 'list (message-buffers)) nil t)
+	 current-prefix-arg))
+  (gnus-summary-iterate n
+    (let ((gnus-display-mime-function nil)
+	  (gnus-inhibit-treatment t))
+      (gnus-summary-select-article))
+    (save-excursion
+      (set-buffer buffer)
+      (message-yank-buffer gnus-article-buffer))))
+
 (defun gnus-debug ()
   "Attempts to go through the Gnus source file and report what variables have been changed.
 The source file has to be in the Emacs load path."
@@ -857,7 +969,6 @@
     ;; Go through all the files looking for non-default values for variables.
     (save-excursion
       (set-buffer (gnus-get-buffer-create " *gnus bug info*"))
-      (buffer-disable-undo (current-buffer))
       (while files
 	(erase-buffer)
 	(when (and (setq file (locate-library (pop files)))
@@ -940,7 +1051,8 @@
 	  (when gcc
 	    (message-remove-header "gcc")
 	    (widen)
-	    (setq groups (message-tokenize-header gcc " ,"))
+	    (setq groups (message-unquote-tokens
+                          (message-tokenize-header gcc " ,")))
 	    ;; Copy the article over to some group(s).
 	    (while (setq group (pop groups))
 	      (gnus-check-server
@@ -964,12 +1076,20 @@
 	      (save-excursion
 		(nnheader-set-temp-buffer " *acc*")
 		(insert-buffer-substring cur)
+		(message-encode-message-body)
+		(save-restriction
+		  (message-narrow-to-headers)
+		  (let ((mail-parse-charset message-default-charset)
+			(rfc2047-header-encoding-alist
+			 (cons '("Newsgroups" . default)
+			       rfc2047-header-encoding-alist)))
+		    (mail-encode-encoded-word-buffer)))
 		(goto-char (point-min))
 		(when (re-search-forward
 		       (concat "^" (regexp-quote mail-header-separator) "$")
 		       nil t)
 		  (replace-match "" t t ))
-		(unless (gnus-request-accept-article group method t)
+		(unless (gnus-request-accept-article group method t t)
 		  (gnus-message 1 "Couldn't store article in group %s: %s"
 				group (gnus-status-message method))
 		  (sit-for 2))
@@ -998,9 +1118,10 @@
 	 (group (or group gnus-newsgroup-name ""))
 	 (gcc-self-val
 	  (and gnus-newsgroup-name
+	       (not (equal gnus-newsgroup-name ""))
 	       (gnus-group-find-parameter
 		gnus-newsgroup-name 'gcc-self)))
-	 result 
+	 result
 	 (groups
 	  (cond
 	   ((null gnus-message-archive-method)
@@ -1068,86 +1189,131 @@
 
 ;;; Posting styles.
 
-(defvar gnus-message-style-insertions nil)
-
 (defun gnus-configure-posting-styles ()
   "Configure posting styles according to `gnus-posting-styles'."
   (unless gnus-inhibit-posting-styles
-    (let ((styles gnus-posting-styles)
-	  (gnus-newsgroup-name (or gnus-newsgroup-name ""))
-	  style match variable attribute value value-value)
-      (make-local-variable 'gnus-message-style-insertions)
+    (let ((group (or gnus-newsgroup-name ""))
+	  (styles gnus-posting-styles)
+	  style match variable attribute value v results
+	  filep name address element)
+      ;; If the group has a posting-style parameter, add it at the end with a
+      ;; regexp matching everything, to be sure it takes precedence over all
+      ;; the others.
+      (when gnus-newsgroup-name
+	(let ((tmp-style (gnus-group-find-parameter group 'posting-style t)))
+	  (when tmp-style
+	    (setq styles (append styles (list (cons ".*" tmp-style)))))))
       ;; Go through all styles and look for matches.
-      (while styles
-	(setq style (pop styles)
-	      match (pop style))
-	(when (cond ((stringp match)
-		     ;; Regexp string match on the group name.
-		     (string-match match gnus-newsgroup-name))
-		    ((or (symbolp match)
-			 (gnus-functionp match))
-		     (cond ((gnus-functionp match)
-			    ;; Function to be called.
-			    (funcall match))
-			   ((boundp match)
-			    ;; Variable to be checked.
-			    (symbol-value match))))
-		    ((listp match)
-		     ;; This is a form to be evaled.
-		     (eval match)))
+      (dolist (style styles)
+	(setq match (pop style))
+	(goto-char (point-min))
+	(when (cond
+	       ((stringp match)
+		;; Regexp string match on the group name.
+		(string-match match group))
+	       ((eq match 'header)
+		(let ((header (message-fetch-field (pop style))))
+		  (and header
+		       (string-match (pop style) header))))
+	       ((or (symbolp match)
+		    (gnus-functionp match))
+		(cond
+		 ((gnus-functionp match)
+		  ;; Function to be called.
+		  (funcall match))
+		 ((boundp match)
+		  ;; Variable to be checked.
+		  (symbol-value match))))
+	       ((listp match)
+		;; This is a form to be evaled.
+		(eval match)))
 	  ;; We have a match, so we set the variables.
-	  (while style
-	    (setq attribute (pop style)
-		  value (cadr attribute)
-		  variable nil)
-	    ;; We find the variable that is to be modified.
-	    (if (and (not (stringp (car attribute)))
-		     (not (eq 'body (car attribute)))
-		     (not (setq variable
-				(cdr (assq (car attribute) 
-					   gnus-posting-style-alist)))))
-		(message "Couldn't find attribute %s" (car attribute))
-	      ;; We get the value.
-	      (setq value-value
-		    (cond ((stringp value)
-			   value)
-			  ((or (symbolp value)
-			       (gnus-functionp value))
-			   (cond ((gnus-functionp value)
-				  (funcall value))
-				 ((boundp value)
-				  (symbol-value value))))
-			  ((listp value)
-			   (eval value))))
-	      (if variable
-		  ;; This is an ordinary variable.
-		  (set (make-local-variable variable) value-value)
-		;; This is either a body or a header to be inserted in the
-		;; message.
-		(when value-value
-		  (let ((attr (car attribute)))
-		    (make-local-variable 'message-setup-hook)
-		    (if (eq 'body attr)
-			(add-hook 'message-setup-hook
-				  `(lambda ()
-				     (save-excursion
-				       (message-goto-body)
-				       (insert ,value-value))))
-		      (add-hook 'message-setup-hook
-				'gnus-message-insert-stylings)
-		      (push (cons (if (stringp attr) attr
-				    (symbol-name attr))
-				  value-value)
-			    gnus-message-style-insertions))))))))))))
-
-(defun gnus-message-insert-stylings ()
-  (let (val)
-    (save-excursion
-      (message-goto-eoh)
-      (while (setq val (pop gnus-message-style-insertions))
-	(when (cdr val)
-	  (insert (car val) ": " (cdr val) "\n"))
-	(gnus-pull (car val) gnus-message-style-insertions)))))
+	  (dolist (attribute style)
+	    (setq element (pop attribute)
+		  variable nil
+		  filep nil)
+	    (setq value
+		  (cond
+		   ((eq (car attribute) :file)
+		    (setq filep t)
+		    (cadr attribute))
+		   ((eq (car attribute) :value)
+		    (cadr attribute))
+		   (t
+		    (car attribute))))
+	    ;; We get the value.
+	    (setq v
+		  (cond
+		   ((stringp value)
+		    value)
+		   ((or (symbolp value)
+			(gnus-functionp value))
+		    (cond ((gnus-functionp value)
+			   (funcall value))
+			  ((boundp value)
+			   (symbol-value value))))
+		   ((listp value)
+		    (eval value))))
+	    ;; Translate obsolescent value.
+	    (when (eq element 'signature-file)
+	      (setq element 'signature
+		    filep t))
+	    ;; Get the contents of file elems.
+	    (when (and filep v)
+	      (setq v (with-temp-buffer
+			(insert-file-contents v)
+			(buffer-string))))
+	    (setq results (delq (assoc element results) results))
+	    (push (cons element v) results))))
+      ;; Now we have all the styles, so we insert them.
+      (setq name (assq 'name results)
+	    address (assq 'address results))
+      (setq results (delq name (delq address results)))
+      (make-local-variable 'message-setup-hook)
+      (dolist (result results)
+	(add-hook 'message-setup-hook
+		  (cond
+		   ((eq 'eval (car result))
+		    'ignore)
+		   ((eq 'body (car result))
+		    `(lambda ()
+		       (save-excursion
+			 (message-goto-body)
+			 (insert ,(cdr result)))))
+		   ((eq 'signature (car result))
+		    (set (make-local-variable 'message-signature) nil)
+		    (set (make-local-variable 'message-signature-file) nil)
+		    (if (not (cdr result))
+			'ignore
+		      `(lambda ()
+			 (save-excursion
+			   (let ((message-signature ,(cdr result)))
+			     (when message-signature
+			       (message-insert-signature)))))))
+		   (t
+		    (let ((header
+			   (if (symbolp (car result))
+			       (capitalize (symbol-name (car result)))
+			     (car result))))
+		      `(lambda ()
+			 (save-excursion
+			   (message-remove-header ,header)
+			   (let ((value ,(cdr result)))
+			     (when value
+			       (message-goto-eoh)
+			       (insert ,header ": " value "\n"))))))))))
+      (when (or name address)
+	(add-hook 'message-setup-hook
+		  `(lambda ()
+ 		     (set (make-local-variable 'user-mail-address)
+ 			  ,(or (cdr address) user-mail-address))
+		     (let ((user-full-name ,(or (cdr name) (user-full-name)))
+			   (user-mail-address
+			    ,(or (cdr address) user-mail-address)))
+		       (save-excursion
+			 (message-remove-header "From")
+			 (message-goto-eoh)
+			 (insert "From: " (message-make-from) "\n")))))))))
 
 ;;; Allow redefinition of functions.
 
--- a/lisp/gnus/gnus-nocem.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-nocem.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-nocem.el --- NoCeM pseudo-cancellation treatment
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'nnmail)
 (require 'gnus-art)
@@ -52,8 +51,7 @@
     "clewis@ferret.ocunix.on.ca"	; Chris Lewis
     "jem@xpat.com"			; Despammer from Korea
     "snowhare@xmission.com"		; Benjamin "Snowhare" Franz
-    "red@redpoll.mrfs.oh.us (Richard E. Depew)" ; ARMM! ARMM!
-    )
+    "red@redpoll.mrfs.oh.us (Richard E. Depew)") ; ARMM! ARMM!
   "*List of NoCeM issuers to pay attention to.
 
 This can also be a list of `(ISSUER CONDITIONS)' elements."
@@ -123,7 +121,7 @@
   (interactive)
   (let ((groups gnus-nocem-groups)
 	(gnus-inhibit-demon t)
-	group active gactive articles)
+	group active gactive articles check-headers)
     (gnus-make-directory gnus-nocem-directory)
     ;; Load any previous NoCeM headers.
     (gnus-nocem-load-cache)
@@ -148,7 +146,7 @@
 	  (save-excursion
 	    (let ((dependencies (make-vector 10 nil))
 		  headers header)
-	      (nnheader-temp-write nil
+	      (with-temp-buffer
 		(setq headers
 		      (if (eq 'nov
 			      (gnus-retrieve-headers
@@ -175,7 +173,14 @@
 				    (null (mail-header-references header)))
 				(not (member (mail-header-message-id header)
 					     gnus-nocem-seen-message-ids))))
-		       (gnus-nocem-check-article group header)))))))
+		       (push header check-headers)))
+		(let ((i 0)
+		      (len (length check-headers)))
+		  (dolist (h check-headers)
+		    (gnus-message
+		     7 "Checking article %d in %s for NoCeM (%d of %d)..."
+		     (mail-header-number h) group (incf i) len)
+		    (gnus-nocem-check-article group h)))))))
 	(setq gnus-nocem-active
 	      (cons (list group gactive)
 		    (delq (assoc group gnus-nocem-active)
@@ -187,14 +192,12 @@
 (defun gnus-nocem-check-article (group header)
   "Check whether the current article is an NCM article and that we want it."
   ;; Get the article.
-  (gnus-message 7 "Checking article %d in %s for NoCeM..."
-		(mail-header-number header) group)
   (let ((date (mail-header-date header))
 	issuer b e type)
     (when (or (not date)
-	      (nnmail-time-less
-	       (nnmail-time-since (nnmail-date-to-time date))
-	       (nnmail-days-to-time gnus-nocem-expiry-wait)))
+	      (time-less-p
+	       (time-since (date-to-time date))
+	       (days-to-time gnus-nocem-expiry-wait)))
       (gnus-request-article-this-buffer (mail-header-number header) group)
       (goto-char (point-min))
       (when (re-search-forward "-----BEGIN PGP MESSAGE-----" nil t)
@@ -273,7 +276,7 @@
 			      gnus-nocem-real-group-hashtb)
 	    ;; Valid group.
 	    (beginning-of-line)
-	    (while (= (following-char) ?\t)
+	    (while (eq (char-after) ?\t)
 	      (forward-line -1))
 	    (setq id (buffer-substring (point) (1- (search-forward "\t"))))
 	    (unless (gnus-gethash id gnus-nocem-hashtb)
@@ -281,7 +284,7 @@
 	      (gnus-sethash id t gnus-nocem-hashtb)
 	      (push id ncm))
 	    (forward-line 1)
-	    (while (= (following-char) ?\t)
+	    (while (eq (char-after) ?\t)
 	      (forward-line 1))))))
       (when ncm
 	(setq gnus-nocem-touched-alist t)
@@ -304,13 +307,13 @@
   "Save the NoCeM cache."
   (when (and gnus-nocem-alist
 	     gnus-nocem-touched-alist)
-    (nnheader-temp-write (gnus-nocem-cache-file)
+    (with-temp-file (gnus-nocem-cache-file)
       (gnus-prin1 `(setq gnus-nocem-alist ',gnus-nocem-alist)))
     (setq gnus-nocem-touched-alist nil)))
 
 (defun gnus-nocem-save-active ()
   "Save the NoCeM active file."
-  (nnheader-temp-write (gnus-nocem-active-file)
+  (with-temp-file (gnus-nocem-active-file)
     (gnus-prin1 `(setq gnus-nocem-active ',gnus-nocem-active))))
 
 (defun gnus-nocem-alist-to-hashtb ()
@@ -318,11 +321,11 @@
   (let* ((alist gnus-nocem-alist)
 	 (pprev (cons nil alist))
 	 (prev pprev)
-	 (expiry (nnmail-days-to-time gnus-nocem-expiry-wait))
+	 (expiry (days-to-time gnus-nocem-expiry-wait))
 	 entry)
     (setq gnus-nocem-hashtb (gnus-make-hashtable (* (length alist) 51)))
     (while (setq entry (car alist))
-      (if (not (nnmail-time-less (nnmail-time-since (car entry)) expiry))
+      (if (not (time-less-p (time-since (car entry)) expiry))
 	  ;; This entry has expired, so we remove it.
 	  (setcdr prev (cdr alist))
 	(setq prev alist)
--- a/lisp/gnus/gnus-range.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-range.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-range.el --- range and sequence functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 ;;; List and range functions
 
 (defun gnus-last-element (list)
@@ -226,13 +225,81 @@
 	(setq ranges (cdr ranges)))
       out)))
 
-(defun gnus-remove-from-range (ranges list)
-  "Return a list of ranges that has all articles from LIST removed from RANGES.
-Note: LIST has to be sorted over `<'."
-  ;; !!! This function shouldn't look like this, but I've got a headache.
-  (gnus-compress-sequence
-   (gnus-sorted-complement
-    (gnus-uncompress-range ranges) list)))
+(defun gnus-remove-from-range (range1 range2)
+  "Return a range that has all articles from RANGE2 removed from RANGE1.
+The returned range is always a list.  RANGE2 can also be a unsorted
+list of articles.  RANGE1 is modified by side effects, RANGE2 is not
+modified."
+  (if (or (null range1) (null range2))
+      range1
+    (let (out r1 r2 r1_min r1_max r2_min r2_max
+	      (range2 (gnus-copy-sequence range2)))
+      (setq range1 (if (listp (cdr range1)) range1 (list range1))
+	    range2 (sort (if (listp (cdr range2)) range2 (list range2))
+			 (lambda (e1 e2)
+			   (< (if (consp e1) (car e1) e1)
+			      (if (consp e2) (car e2) e2))))
+	    r1 (car range1)
+	    r2 (car range2)
+	    r1_min (if (consp r1) (car r1) r1)
+	    r1_max (if (consp r1) (cdr r1) r1)
+	    r2_min (if (consp r2) (car r2) r2)
+	    r2_max (if (consp r2) (cdr r2) r2))
+      (while (and range1 range2)
+	(cond ((< r2_max r1_min)	; r2 < r1
+	       (pop range2)
+	       (setq r2 (car range2)
+		     r2_min (if (consp r2) (car r2) r2)
+		     r2_max (if (consp r2) (cdr r2) r2)))
+	      ((and (<= r2_min r1_min) (<= r1_max r2_max)) ; r2 overlap r1
+	       (pop range1)
+	       (setq r1 (car range1)
+		     r1_min (if (consp r1) (car r1) r1)
+		     r1_max (if (consp r1) (cdr r1) r1)))
+	      ((and (<= r2_min r1_min) (<= r2_max r1_max)) ; r2 overlap min r1
+	       (pop range2)
+	       (setq r1_min (1+ r2_max)
+		     r2 (car range2)
+		     r2_min (if (consp r2) (car r2) r2)
+		     r2_max (if (consp r2) (cdr r2) r2)))
+	      ((and (<= r1_min r2_min) (<= r2_max r1_max)) ; r2 contained in r1
+	       (if (eq r1_min (1- r2_min))
+		   (push r1_min out)
+		 (push (cons r1_min (1- r2_min)) out))
+	       (pop range2)
+	       (if (< r2_max r1_max)	; finished with r1?
+		   (setq r1_min (1+ r2_max))
+		 (pop range1)
+		 (setq r1 (car range1)
+		       r1_min (if (consp r1) (car r1) r1)
+		       r1_max (if (consp r1) (cdr r1) r1)))
+	       (setq r2 (car range2)
+		     r2_min (if (consp r2) (car r2) r2)
+		     r2_max (if (consp r2) (cdr r2) r2)))
+	      ((and (<= r2_min r1_max) (<= r1_max r2_max)) ; r2 overlap max r1
+	       (if (eq r1_min (1- r2_min))
+		   (push r1_min out)
+		 (push (cons r1_min (1- r2_min)) out))
+	       (pop range1)
+	       (setq r1 (car range1)
+		     r1_min (if (consp r1) (car r1) r1)
+		     r1_max (if (consp r1) (cdr r1) r1)))
+	      ((< r1_max r2_min)	; r2 > r1
+	       (pop range1)
+	       (if (eq r1_min r1_max)
+		   (push r1_min out)
+		 (push (cons r1_min r1_max) out))
+	       (setq r1 (car range1)
+		     r1_min (if (consp r1) (car r1) r1)
+		     r1_max (if (consp r1) (cdr r1) r1)))))
+      (when r1
+	(if (eq r1_min r1_max)
+	    (push r1_min out)
+	  (push (cons r1_min r1_max) out))
+	(pop range1))
+      (while range1
+	(push (pop range1) out))
+      (nreverse out))))
 
 (defun gnus-member-of-range (number ranges)
   (if (not (listp (cdr ranges)))
@@ -266,19 +333,59 @@
     sublistp))
 
 (defun gnus-range-add (range1 range2)
-  "Add RANGE2 to RANGE1 destructively."
-  (cond
-   ;; If either are nil, then the job is quite easy.
-   ((or (null range1) (null range2))
-    (or range1 range2))
-   (t
-    ;; I don't like thinking.
-    (gnus-compress-sequence
-     (sort
-      (nconc
-       (gnus-uncompress-range range1)
-       (gnus-uncompress-range range2))
-      '<)))))
+  "Add RANGE2 to RANGE1 (nondestructively)."
+  (unless (listp (cdr range1))
+    (setq range1 (list range1)))
+  (unless (listp (cdr range2))
+    (setq range2 (list range2)))
+  (let ((item1 (pop range1))
+	(item2 (pop range2))
+	range item selector)
+    (while (or item1 item2)
+      (setq selector
+	    (cond 
+	     ((null item1) nil)
+	     ((null item2) t)
+	     ((and (numberp item1) (numberp item2)) (< item1 item2))
+	     ((numberp item1) (< item1 (car item2)))
+	     ((numberp item2) (< (car item1) item2))
+	     (t (< (car item1) (car item2)))))
+      (setq item
+	    (or
+	     (let ((tmp1 item) (tmp2 (if selector item1 item2)))
+	       (cond 
+		((null tmp1) tmp2)
+		((null tmp2) tmp1)
+		((and (numberp tmp1) (numberp tmp2))
+		 (cond 
+		  ((eq tmp1 tmp2) tmp1)
+		  ((eq (1+ tmp1) tmp2) (cons tmp1 tmp2))
+		  ((eq (1+ tmp2) tmp1) (cons tmp2 tmp1))
+		  (t nil)))
+		((numberp tmp1)
+		 (cond 
+		  ((and (>= tmp1 (car tmp2)) (<= tmp1 (cdr tmp2))) tmp2)
+		  ((eq (1+ tmp1) (car tmp2)) (cons tmp1 (cdr tmp2)))
+		  ((eq (1- tmp1) (cdr tmp2)) (cons (car tmp2) tmp1))
+		  (t nil)))
+		((numberp tmp2)
+		 (cond 
+		  ((and (>= tmp2 (car tmp1)) (<= tmp2 (cdr tmp1))) tmp1)
+		  ((eq (1+ tmp2) (car tmp1)) (cons tmp2 (cdr tmp1)))
+		  ((eq (1- tmp2) (cdr tmp1)) (cons (car tmp1) tmp2))
+		  (t nil)))
+		((< (1+ (cdr tmp1)) (car tmp2)) nil)
+		((< (1+ (cdr tmp2)) (car tmp1)) nil)
+		(t (cons (min (car tmp1) (car tmp2)) 
+			 (max (cdr tmp1) (cdr tmp2))))))
+	     (progn
+	       (if item (push item range))
+	       (if selector item1 item2))))
+      (if selector
+	  (setq item1 (pop range1))
+	(setq item2 (pop range2))))
+    (if item (push item range))
+    (reverse range)))
 
 (provide 'gnus-range)
 
--- a/lisp/gnus/gnus-salt.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-salt.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-sum)
 
@@ -55,7 +54,7 @@
   :group 'gnus-summary-pick)
 
 (defcustom gnus-pick-elegant-flow t
-  "If non-nil, gnus-pick-start-reading will run gnus-summary-next-group when no articles have been picked."
+  "If non-nil, `gnus-pick-start-reading' runs `gnus-summary-next-group' when no articles have been picked."
   :type 'boolean
   :group 'gnus-summary-pick)
 
@@ -78,8 +77,7 @@
     "u" gnus-pick-unmark-article-or-thread
     "." gnus-pick-article-or-thread
     gnus-down-mouse-2 gnus-pick-mouse-pick-region
-    "\r" gnus-pick-start-reading
-    ))
+    "\r" gnus-pick-start-reading))
 
 (defun gnus-pick-make-menu-bar ()
   (unless (boundp 'gnus-pick-menu)
@@ -123,7 +121,8 @@
       ;; Set up the menu.
       (when (gnus-visual-p 'pick-menu 'menu)
 	(gnus-pick-make-menu-bar))
-      (gnus-add-minor-mode 'gnus-pick-mode " Pick" gnus-pick-mode-map)
+      (gnus-add-minor-mode 'gnus-pick-mode " Pick" gnus-pick-mode-map
+			   nil 'gnus-pick-mode)
       (gnus-run-hooks 'gnus-pick-mode-hook))))
 
 (defun gnus-pick-setup-message ()
@@ -133,7 +132,8 @@
 	       (set-buffer gnus-summary-buffer)
 	       gnus-pick-mode))
     (message-add-action
-     '(gnus-configure-windows 'pick t) 'send 'exit 'postpone 'kill)))
+     '(gnus-configure-windows ,gnus-current-window-configuration t)
+     'send 'exit 'postpone 'kill)))
 
 (defvar gnus-pick-line-number 1)
 (defun gnus-pick-line-number ()
@@ -164,8 +164,8 @@
       (error "No articles have been picked"))))
 
 (defun gnus-pick-goto-article (arg)
-  "Go to the article number indicated by ARG.  If ARG is an invalid
-article number, then stay on current line."
+  "Go to the article number indicated by ARG.
+If ARG is an invalid article number, then stay on current line."
   (let (pos)
     (save-excursion
       (goto-char (point-min))
@@ -174,9 +174,9 @@
     (if (not pos)
 	(gnus-error 2 "No such line: %s" arg)
       (goto-char pos))))
-    
+
 (defun gnus-pick-article (&optional arg)
-    "Pick the article on the current line.
+  "Pick the article on the current line.
 If ARG, pick the article on that line instead."
   (interactive "P")
   (when arg
@@ -184,27 +184,31 @@
   (gnus-summary-mark-as-processable 1))
 
 (defun gnus-pick-article-or-thread (&optional arg)
-  "If gnus-thread-hide-subtree is t, then pick the thread on the current line.
+  "If `gnus-thread-hide-subtree' is t, then pick the thread on the current line.
 Otherwise pick the article on the current line.
 If ARG, pick the article/thread on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
-      (gnus-uu-mark-thread)
+      (progn
+	(save-excursion
+	  (gnus-uu-mark-thread))
+	(forward-line 1))
     (gnus-summary-mark-as-processable 1)))
-		  
+
 (defun gnus-pick-unmark-article-or-thread (&optional arg)
-  "If gnus-thread-hide-subtree is t, then unmark the thread on current line.
+  "If `gnus-thread-hide-subtree' is t, then unmark the thread on current line.
 Otherwise unmark the article on current line.
 If ARG, unmark thread/article on that line instead."
   (interactive "P")
   (when arg
     (gnus-pick-goto-article arg))
   (if gnus-thread-hide-subtree
-      (gnus-uu-unmark-thread)
+      (save-excursion
+	(gnus-uu-unmark-thread))
     (gnus-summary-unmark-as-processable 1)))
-  
+
 (defun gnus-pick-mouse-pick (e)
   (interactive "e")
   (mouse-set-point e)
@@ -242,46 +246,46 @@
     ;; (but not outside the window where the drag started).
     (let (event end end-point (end-of-range (point)))
       (track-mouse
-	(while (progn
-		 (setq event (cdr (gnus-read-event-char)))
-		 (or (mouse-movement-p event)
-		     (eq (car-safe event) 'switch-frame)))
-	  (if (eq (car-safe event) 'switch-frame)
-	      nil
-	    (setq end (event-end event)
-		  end-point (posn-point end))
+       (while (progn
+		(setq event (cdr (gnus-read-event-char)))
+		(or (mouse-movement-p event)
+		    (eq (car-safe event) 'switch-frame)))
+	 (if (eq (car-safe event) 'switch-frame)
+	     nil
+	   (setq end (event-end event)
+		 end-point (posn-point end))
 
-	    (cond
-	     ;; Are we moving within the original window?
-	     ((and (eq (posn-window end) start-window)
-		   (integer-or-marker-p end-point))
-	      ;; Go to START-POINT first, so that when we move to END-POINT,
-	      ;; if it's in the middle of intangible text,
-	      ;; point jumps in the direction away from START-POINT.
-	      (goto-char start-point)
-	      (goto-char end-point)
-	      (gnus-pick-article)
-	      ;; In case the user moved his mouse really fast, pick
-	      ;; articles on the line between this one and the last one.
-	      (let* ((this-line (1+ (count-lines 1 end-point)))
-		     (min-line (min this-line start-line))
-		     (max-line (max this-line start-line)))
-		(while (< min-line max-line)
-		  (goto-line min-line)
-		  (gnus-pick-article)
-		  (setq min-line (1+ min-line)))
-		(setq start-line this-line))
-	      (when (zerop (% click-count 3))
-		(setq end-of-range (point))))
-	     (t
-	      (let ((mouse-row (cdr (cdr (mouse-position)))))
-		(cond
-		 ((null mouse-row))
-		 ((< mouse-row top)
-		  (mouse-scroll-subr start-window (- mouse-row top)))
-		 ((>= mouse-row bottom)
-		  (mouse-scroll-subr start-window
-				     (1+ (- mouse-row bottom)))))))))))
+	   (cond
+	    ;; Are we moving within the original window?
+	    ((and (eq (posn-window end) start-window)
+		  (integer-or-marker-p end-point))
+	     ;; Go to START-POINT first, so that when we move to END-POINT,
+	     ;; if it's in the middle of intangible text,
+	     ;; point jumps in the direction away from START-POINT.
+	     (goto-char start-point)
+	     (goto-char end-point)
+	     (gnus-pick-article)
+	     ;; In case the user moved his mouse really fast, pick
+	     ;; articles on the line between this one and the last one.
+	     (let* ((this-line (1+ (count-lines 1 end-point)))
+		    (min-line (min this-line start-line))
+		    (max-line (max this-line start-line)))
+	       (while (< min-line max-line)
+		 (goto-line min-line)
+		 (gnus-pick-article)
+		 (setq min-line (1+ min-line)))
+	       (setq start-line this-line))
+	     (when (zerop (% click-count 3))
+	       (setq end-of-range (point))))
+	    (t
+	     (let ((mouse-row (cdr (cdr (mouse-position)))))
+	       (cond
+		((null mouse-row))
+		((< mouse-row top)
+		 (mouse-scroll-subr start-window (- mouse-row top)))
+		((>= mouse-row bottom)
+		 (mouse-scroll-subr start-window
+				    (1+ (- mouse-row bottom)))))))))))
       (when (consp event)
 	(let ((fun (key-binding (vector (car event)))))
 	  ;; Run the binding of the terminating up-event, if possible.
@@ -323,8 +327,8 @@
   (setq gnus-binary-mode-map (make-sparse-keymap))
 
   (gnus-define-keys
-   gnus-binary-mode-map
-   "g" gnus-binary-show-article))
+      gnus-binary-mode-map
+    "g" gnus-binary-show-article))
 
 (defun gnus-binary-make-menu-bar ()
   (unless (boundp 'gnus-binary-menu)
@@ -350,7 +354,8 @@
       ;; Set up the menu.
       (when (gnus-visual-p 'binary-menu 'menu)
 	(gnus-binary-make-menu-bar))
-      (gnus-add-minor-mode 'gnus-binary-mode " Binary" gnus-binary-mode-map)
+      (gnus-add-minor-mode 'gnus-binary-mode " Binary"
+			   gnus-binary-mode-map nil 'gnus-binary-mode-map)
       (gnus-run-hooks 'gnus-binary-mode-hook))))
 
 (defun gnus-binary-display-article (article &optional all-header)
@@ -432,6 +437,7 @@
 (defvar gnus-selected-tree-overlay nil)
 
 (defvar gnus-tree-displayed-thread nil)
+(defvar gnus-tree-inhibit nil)
 
 (defvar gnus-tree-mode-map nil)
 (put 'gnus-tree-mode 'mode-class 'special)
@@ -440,13 +446,13 @@
   (setq gnus-tree-mode-map (make-keymap))
   (suppress-keymap gnus-tree-mode-map)
   (gnus-define-keys
-   gnus-tree-mode-map
-   "\r" gnus-tree-select-article
-   gnus-mouse-2 gnus-tree-pick-article
-   "\C-?" gnus-tree-read-summary-keys
-   "h" gnus-tree-show-summary
+      gnus-tree-mode-map
+    "\r" gnus-tree-select-article
+    gnus-mouse-2 gnus-tree-pick-article
+    "\C-?" gnus-tree-read-summary-keys
+    "h" gnus-tree-show-summary
 
-   "\C-c\C-i" gnus-info-find-node)
+    "\C-c\C-i" gnus-info-find-node)
 
   (substitute-key-definition
    'undefined 'gnus-tree-read-summary-keys gnus-tree-mode-map))
@@ -470,7 +476,7 @@
   (setq mode-name "Tree")
   (setq major-mode 'gnus-tree-mode)
   (use-local-map gnus-tree-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq buffer-read-only t)
   (setq truncate-lines t)
   (save-excursion
@@ -482,15 +488,17 @@
 (defun gnus-tree-read-summary-keys (&optional arg)
   "Read a summary buffer key sequence and execute it."
   (interactive "P")
-  (let ((buf (current-buffer))
-	win)
-    (set-buffer gnus-article-buffer)      
-    (gnus-article-read-summary-keys arg nil t)
-    (when (setq win (get-buffer-window buf))
-      (select-window win)
-      (when gnus-selected-tree-overlay
-	(goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
-      (gnus-tree-minimize))))
+  (unless gnus-tree-inhibit
+    (let ((buf (current-buffer))
+	  (gnus-tree-inhibit t)
+	  win)
+      (set-buffer gnus-article-buffer)
+      (gnus-article-read-summary-keys arg nil t)
+      (when (setq win (get-buffer-window buf))
+	(select-window win)
+	(when gnus-selected-tree-overlay
+	  (goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
+	(gnus-tree-minimize)))))
 
 (defun gnus-tree-show-summary ()
   "Reconfigure windows to show summary buffer."
@@ -521,12 +529,14 @@
 
 (defun gnus-tree-article-region (article)
   "Return a cons with BEG and END of the article region."
-  (let ((pos (text-property-any (point-min) (point-max) 'gnus-number article)))
+  (let ((pos (text-property-any
+	      (point-min) (point-max) 'gnus-number article)))
     (when pos
       (cons pos (next-single-property-change pos 'gnus-number)))))
 
 (defun gnus-tree-goto-article (article)
-  (let ((pos (text-property-any (point-min) (point-max) 'gnus-number article)))
+  (let ((pos (text-property-any
+	      (point-min) (point-max) 'gnus-number article)))
     (when pos
       (goto-char pos))))
 
@@ -704,7 +714,7 @@
 	  (while (progn
 		   (forward-line -1)
 		   (forward-char col)
-		   (= (following-char) ? ))
+		   (eq (char-after) ? ))
 	    (delete-char 1)
 	    (insert (caddr gnus-tree-parent-child-edges)))
 	  (goto-char beg)))
@@ -762,7 +772,7 @@
 	  (forward-char -1)
 	  ;; Draw "-" lines leftwards.
 	  (while (and (> (point) 1)
-		      (= (char-after (1- (point))) ? ))
+		      (eq (char-after (1- (point))) ? ))
 	    (delete-char -1)
 	    (insert (car gnus-tree-parent-child-edges))
 	    (forward-char -1))
@@ -969,7 +979,7 @@
   (setq mode-name "Gnus Carpal")
   (setq mode-line-process nil)
   (use-local-map gnus-carpal-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq buffer-read-only t)
   (make-local-variable 'gnus-carpal-attached-buffer)
   (gnus-run-hooks 'gnus-carpal-mode-hook))
--- a/lisp/gnus/gnus-score.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-score.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-score.el --- scoring code for Gnus
-;; Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,8 +29,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-sum)
 (require 'gnus-range)
@@ -109,8 +108,8 @@
 See the documentation to these functions for more information.
 
 This variable can also be a list of functions to be called.  Each
-function should either return a list of score files, or a list of
-score alists.
+function is given the group name as argument and should either return
+a list of score files, or a list of score alists.
 
 If functions other than these pre-defined functions are used,
 the `a' symbolic prefix to the score commands will always use
@@ -119,13 +118,17 @@
   :type '(radio (function-item gnus-score-find-single)
 		(function-item gnus-score-find-hierarchical)
 		(function-item gnus-score-find-bnews)
-		(function :tag "Other")))
+		(repeat :tag "List of functions"
+			(choice (function :tag "Other" :value 'ignore)
+				(function-item gnus-score-find-single)
+				(function-item gnus-score-find-hierarchical)
+				(function-item gnus-score-find-bnews)))
+		(function :tag "Other" :value 'ignore)))
 
 (defcustom gnus-score-interactive-default-score 1000
   "*Scoring commands will raise/lower the score with this number as the default."
   :group 'gnus-score-default
-  :type '(choice (const nil)
-		 integer))
+  :type 'integer)
 
 (defcustom gnus-score-expiry-days 7
   "*Number of days before unused score file entries are expired.
@@ -141,12 +144,6 @@
   :group 'gnus-score-expire
   :type 'boolean)
 
-(defcustom gnus-orphan-score nil
-  "*All orphans get this score added.  Set in the score file."
-  :group 'gnus-score-default
-  :type '(choice (const nil)
-		 integer))
-
 (defcustom gnus-decay-scores nil
   "*If non-nil, decay non-permanent scores."
   :group 'gnus-score-decay
@@ -204,6 +201,8 @@
 		 (repeat (choice string
 				 (cons regexp (repeat file))
 				 (function :value fun)))
+		 (function-item gnus-hierarchial-home-score-file)
+		 (function-item gnus-current-home-score-file)
 		 (function :value fun)))
 
 (defcustom gnus-home-adapt-file nil
@@ -224,14 +223,14 @@
     (gnus-catchup-mark (subject -10))
     (gnus-killed-mark (from -1) (subject -20))
     (gnus-del-mark (from -2) (subject -15)))
-"*Alist of marks and scores."
-:group 'gnus-score-adapt
-:type '(repeat (cons (symbol :tag "Mark")
-		     (repeat (list (choice :tag "Header"
-					   (const from)
-					   (const subject)
-					   (symbol :tag "other"))
-				   (integer :tag "Score"))))))
+  "*Alist of marks and scores."
+  :group 'gnus-score-adapt
+  :type '(repeat (cons (symbol :tag "Mark")
+		       (repeat (list (choice :tag "Header"
+					     (const from)
+					     (const subject)
+					     (symbol :tag "other"))
+				     (integer :tag "Score"))))))
 
 (defcustom gnus-ignored-adaptive-words nil
   "List of words to be ignored when doing adaptive word scoring."
@@ -262,10 +261,10 @@
     (,gnus-catchup-mark . -10)
     (,gnus-killed-mark . -20)
     (,gnus-del-mark . -15))
-"*Alist of marks and scores."
-:group 'gnus-score-adapt
-:type '(repeat (cons (character :tag "Mark")
-		     (integer :tag "Score"))))
+  "*Alist of marks and scores."
+  :group 'gnus-score-adapt
+  :type '(repeat (cons (character :tag "Mark")
+		       (integer :tag "Score"))))
 
 (defcustom gnus-adaptive-word-minimum nil
   "If a number, this is the minimum score value that can be assigned to a word."
@@ -311,6 +310,7 @@
  i: message-id
  t: references
  x: xref
+ e: `extra' (non-standard overview)
  l: lines
  d: date
  f: followup
@@ -324,6 +324,7 @@
 		 (const :tag "message-id" i)
 		 (const :tag "references" t)
 		 (const :tag "xref" x)
+		 (const :tag "extra" e)
 		 (const :tag "lines" l)
 		 (const :tag "date" d)
 		 (const :tag "followup" f)
@@ -388,7 +389,7 @@
 (defcustom gnus-score-thread-simplify nil
   "If non-nil, subjects will simplified as in threading."
   :group 'gnus-score-various
-  :type 'boolean) 
+  :type 'boolean)
 
 
 
@@ -447,6 +448,7 @@
     ("chars" 6 gnus-score-integer)
     ("lines" 7 gnus-score-integer)
     ("xref" 8 gnus-score-string)
+    ("extra" 9 gnus-score-string)
     ("head" -1 gnus-score-body)
     ("body" -1 gnus-score-body)
     ("all" -1 gnus-score-body)
@@ -480,7 +482,7 @@
 permanence, and the string to be used.  The numerical prefix will be
 used as score."
   (interactive (gnus-interactive "P\ny"))
-  (gnus-summary-increase-score (- (gnus-score-default score)) symp))
+  (gnus-summary-increase-score (- (gnus-score-delta-default score)) symp))
 
 (defun gnus-score-kill-help-buffer ()
   (when (get-buffer "*Score Help*")
@@ -494,7 +496,7 @@
 permanence, and the string to be used.  The numerical prefix will be
 used as score."
   (interactive (gnus-interactive "P\ny"))
-  (let* ((nscore (gnus-score-default score))
+  (let* ((nscore (gnus-score-delta-default score))
 	 (prefix (if (< nscore 0) ?L ?I))
 	 (increase (> nscore 0))
 	 (char-to-header
@@ -502,9 +504,10 @@
 	    (?s "subject" nil nil string)
 	    (?b "body" "" nil body-string)
 	    (?h "head" "" nil body-string)
-	    (?i "message-id" nil t string)
+	    (?i "message-id" nil nil string)
 	    (?r "references" "message-id" nil string)
 	    (?x "xref" nil nil string)
+	    (?e "extra" nil nil string)
 	    (?l "lines" nil nil number)
 	    (?d "date" nil nil date)
 	    (?f "followup" nil nil string)
@@ -533,7 +536,7 @@
 		     (aref (symbol-name gnus-score-default-type) 0)))
 	 (pchar (and gnus-score-default-duration
 		     (aref (symbol-name gnus-score-default-duration) 0)))
-	 entry temporary type match)
+	 entry temporary type match extra)
 
     (unwind-protect
 	(progn
@@ -555,7 +558,7 @@
 	  (gnus-score-kill-help-buffer)
 	  (unless (setq entry (assq (downcase hchar) char-to-header))
 	    (if mimic (error "%c %c" prefix hchar)
-	      (error "Illegal header type")))
+	      (error "Invalid header type")))
 
 	  (when (/= (downcase hchar) hchar)
 	    ;; This was a majuscule, so we end reading and set the defaults.
@@ -588,7 +591,7 @@
 	    (gnus-score-kill-help-buffer)
 	    (unless (setq type (nth 1 (assq (downcase tchar) legal-types)))
 	      (if mimic (error "%c %c" prefix hchar)
-		(error "Illegal match type"))))
+		(error "Invalid match type"))))
 
 	  (when (/= (downcase tchar) tchar)
 	    ;; It was a majuscule, so we end reading and use the default.
@@ -616,18 +619,35 @@
 	    ;; Deal with der(r)ided superannuated paradigms.
 	    (when (and (eq (1+ prefix) 77)
 		       (eq (+ hchar 12) 109)
-		       (eq tchar 114)
+		       (eq (1- tchar) 113)
 		       (eq (- pchar 4) 111))
 	      (error "You rang?"))
 	    (if mimic
 		(error "%c %c %c %c" prefix hchar tchar pchar)
-	      (error "Illegal match duration"))))
+	      (error "Invalid match duration"))))
       ;; Always kill the score help buffer.
       (gnus-score-kill-help-buffer))
 
+    ;; If scoring an extra (non-standard overview) header,
+    ;; we must find out which header is in question.
+    (setq extra
+	  (and gnus-extra-headers
+	       (equal (nth 1 entry) "extra")
+	       (intern			; need symbol
+		(gnus-completing-read
+		 (symbol-name (car gnus-extra-headers))	; default response
+		 "Score extra header:"	; prompt
+		 (mapcar (lambda (x)	; completion list
+			   (cons (symbol-name x) x))
+			 gnus-extra-headers)
+		 nil			; no completion limit
+		 t))))			; require match
+    ;; extra is now nil or a symbol.
+
     ;; We have all the data, so we enter this score.
     (setq match (if (string= (nth 2 entry) "") ""
-		  (gnus-summary-header (or (nth 2 entry) (nth 1 entry)))))
+		  (gnus-summary-header (or (nth 2 entry) (nth 1 entry))
+				       nil extra)))
 
     ;; Modify the match, perhaps.
     (cond
@@ -654,7 +674,7 @@
 	   current-score-file)
 	  (t
 	   (gnus-score-file-name "all"))))))
-    
+
     (gnus-summary-score-entry
      (nth 1 entry)			; Header
      match				; Match
@@ -663,7 +683,9 @@
      (if (eq temporary 'perm)		; Temp
 	 nil
        temporary)
-     (not (nth 3 entry)))		; Prompt
+     (not (nth 3 entry))		; Prompt
+     nil				; not silent
+     extra)				; non-standard overview.
 
     (when (eq symp 'a)
       ;; We change the score file back to the previous one.
@@ -675,7 +697,7 @@
   (setq gnus-score-help-winconf (current-window-configuration))
   (save-excursion
     (set-buffer (gnus-get-buffer-create "*Score Help*"))
-    (buffer-disable-undo (current-buffer))
+    (buffer-disable-undo)
     (delete-windows-on (current-buffer))
     (erase-buffer)
     (insert string ":\n\n")
@@ -710,16 +732,18 @@
     (pop-to-buffer "*Score Help*")
     (let ((window-min-height 1))
       (shrink-window-if-larger-than-buffer))
-    (select-window (get-buffer-window gnus-summary-buffer))))
+    (select-window (get-buffer-window gnus-summary-buffer t))))
 
-(defun gnus-summary-header (header &optional no-err)
+(defun gnus-summary-header (header &optional no-err extra)
   ;; Return HEADER for current articles, or error.
   (let ((article (gnus-summary-article-number))
 	headers)
     (if article
 	(if (and (setq headers (gnus-summary-article-header article))
 		 (vectorp headers))
-	    (aref headers (nth 1 (assoc header gnus-header-index)))
+	    (if extra			; `header' must be "extra"
+		(or (cdr (assq extra (mail-header-extra headers))) "")
+	      (aref headers (nth 1 (assoc header gnus-header-index))))
 	  (if no-err
 	      nil
 	    (error "Pseudo-articles can't be scored")))
@@ -745,7 +769,7 @@
 		  (gnus-newsgroup-score-alist)))))
 
 (defun gnus-summary-score-entry (header match type score date
-					&optional prompt silent)
+					&optional prompt silent extra)
   "Enter score file entry.
 HEADER is the header being scored.
 MATCH is the string we are looking for.
@@ -753,7 +777,8 @@
 SCORE is the score to add.
 DATE is the expire date, or nil for no expire, or 'now for immediate expire.
 If optional argument `PROMPT' is non-nil, allow user to edit match.
-If optional argument `SILENT' is nil, show effect of score entry."
+If optional argument `SILENT' is nil, show effect of score entry.
+If optional argument `EXTRA' is non-nil, it's a non-standard overview header."
   ;; Regexp is the default type.
   (when (eq type t)
     (setq type 'r))
@@ -762,9 +787,10 @@
 	 (setq match (if match (gnus-simplify-subject-re match) "")))
 	((eq type 'f)
 	 (setq match (gnus-simplify-subject-fuzzy match))))
-  (let ((score (gnus-score-default score))
-	(header (format "%s" (downcase header)))
+  (let ((score (gnus-score-delta-default score))
+	(header (downcase header))
 	new)
+    (set-text-properties 0 (length header) nil header)
     (when prompt
       (setq match (read-string
 		   (format "Match %s on %s, %s: "
@@ -779,8 +805,7 @@
 		       (int-to-string match)
 		     match))))
 
-    ;; Get rid of string props.
-    (setq match (format "%s" match))
+    (set-text-properties 0 (length match) nil match)
 
     ;; If this is an integer comparison, we transform from string to int.
     (when (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer)
@@ -794,12 +819,17 @@
 	    elem)
 	(setq new
 	      (cond
+	       (extra
+		(list match score
+		      (and date (if (numberp date) date
+				  (date-to-day date)))
+		      type (symbol-name extra)))
 	       (type
 		(list match score
 		      (and date (if (numberp date) date
-				  (gnus-day-number date)))
+				  (date-to-day date)))
 		      type))
-	       (date (list match score (gnus-day-number date)))
+	       (date (list match score (date-to-day date)))
 	       (score (list match score))
 	       (t (list match))))
 	;; We see whether we can collapse some score entries.
@@ -824,18 +854,19 @@
       (if (and (>= (nth 1 (assoc header gnus-header-index)) 0)
 	       (eq (nth 2 (assoc header gnus-header-index))
 		   'gnus-score-string))
-	  (gnus-summary-score-effect header match type score)
+	  (gnus-summary-score-effect header match type score extra)
 	(gnus-summary-rescore)))
 
     ;; Return the new scoring rule.
     new))
 
-(defun gnus-summary-score-effect (header match type score)
+(defun gnus-summary-score-effect (header match type score extra)
   "Simulate the effect of a score file entry.
 HEADER is the header being scored.
 MATCH is the string we are looking for.
 TYPE is the score type.
-SCORE is the score to add."
+SCORE is the score to add.
+EXTRA is the possible non-standard header."
   (interactive (list (completing-read "Header: "
 				      gnus-header-index
 				      (lambda (x) (fboundp (nth 2 x)))
@@ -856,7 +887,7 @@
 			(t
 			 (regexp-quote match)))))
       (while (not (eobp))
-	(let ((content (gnus-summary-header header 'noerr))
+	(let ((content (gnus-summary-header header 'noerr extra))
 	      (case-fold-search t))
 	  (and content
 	       (when (if (eq type 'f)
@@ -939,7 +970,7 @@
 (defun gnus-score-followup-article (&optional score)
   "Add SCORE to all followups to the article in the current buffer."
   (interactive "P")
-  (setq score (gnus-score-default score))
+  (setq score (gnus-score-delta-default score))
   (when (gnus-buffer-live-p gnus-summary-buffer)
     (save-excursion
       (save-restriction
@@ -954,7 +985,7 @@
 (defun gnus-score-followup-thread (&optional score)
   "Add SCORE to all later articles in the thread the current buffer is part of."
   (interactive "P")
-  (setq score (gnus-score-default score))
+  (setq score (gnus-score-delta-default score))
   (when (gnus-buffer-live-p gnus-summary-buffer)
     (save-excursion
       (save-restriction
@@ -999,7 +1030,7 @@
     (let ((buffer-read-only nil))
       ;; Set score.
       (gnus-summary-update-mark
-       (if (= n (or gnus-summary-default-score 0)) ? 
+       (if (= n (or gnus-summary-default-score 0)) ?  ;Whitespace
 	 (if (< n (or gnus-summary-default-score 0))
 	     gnus-score-below-mark gnus-score-over-mark))
        'score))
@@ -1124,7 +1155,7 @@
 		 (or (not decay)
 		     (gnus-decay-scores alist decay)))
 	(gnus-score-set 'touched '(t) alist)
-	(gnus-score-set 'decay (list (gnus-time-to-day (current-time))) alist))
+	(gnus-score-set 'decay (list (time-to-days (current-time))) alist))
       ;; We do not respect eval and files atoms from global score
       ;; files.
       (when (and files (not global))
@@ -1205,9 +1236,9 @@
 	;; Couldn't read file.
 	(setq gnus-score-alist nil)
       ;; Read file.
-      (save-excursion
-	(gnus-set-work-buffer)
-	(insert-file-contents file)
+      (with-temp-buffer
+	(let ((coding-system-for-read score-mode-coding-system))
+	  (insert-file-contents file))
 	(goto-char (point-min))
 	;; Only do the loading if the score file isn't empty.
 	(when (save-excursion (re-search-forward "[()0-9a-zA-Z]" nil t))
@@ -1247,11 +1278,11 @@
 	 err
 	 (cond
 	  ((not (listp (car a)))
-	   (format "Illegal score element %s in %s" (car a) file))
+	   (format "Invalid score element %s in %s" (car a) file))
 	  ((stringp (caar a))
 	   (cond
 	    ((not (listp (setq sr (cdar a))))
-	     (format "Illegal header match %s in %s" (nth 1 (car a)) file))
+	     (format "Invalid header match %s in %s" (nth 1 (car a)) file))
 	    (t
 	     (setq type (caar a))
 	     (while (and sr (not err))
@@ -1262,7 +1293,7 @@
 		 ((if (member (downcase type) '("lines" "chars"))
 		      (not (numberp (car s)))
 		    (not (stringp (car s))))
-		  (format "Illegal match %s in %s" (car s) file))
+		  (format "Invalid match %s in %s" (car s) file))
 		 ((and (cadr s) (not (integerp (cadr s))))
 		  (format "Non-integer score %s in %s" (cadr s) file))
 		 ((and (caddr s) (not (integerp (caddr s))))
@@ -1293,7 +1324,7 @@
 	      (setcar scor
 		      (list (caar scor) (nth 2 (car scor))
 			    (and (nth 3 (car scor))
-				 (gnus-day-number (nth 3 (car scor))))
+				 (date-to-day (nth 3 (car scor))))
 			    (if (nth 1 (car scor)) 'r 's)))
 	      (setq scor (cdr scor))))
 	(push (if (not (listp (cdr entry)))
@@ -1313,7 +1344,7 @@
       (while cache
 	(current-buffer)
 	(setq entry (pop cache)
-	      file (car entry)
+	      file (nnheader-translate-file-chars (car entry) t)
 	      score (cdr entry))
 	(if (or (not (equal (gnus-score-get 'touched score) '(t)))
 		(gnus-score-get 'read-only score)
@@ -1340,7 +1371,8 @@
 	      (delete-file file)
 	    ;; There are scores, so we write the file.
 	    (when (file-writable-p file)
-	      (gnus-write-buffer file)
+	      (let ((coding-system-for-write score-mode-coding-system))
+		(gnus-write-buffer file))
 	      (when gnus-score-after-write-file-function
 		(funcall gnus-score-after-write-file-function file)))))
 	(and gnus-score-uncacheable-files
@@ -1388,7 +1420,7 @@
       (when (and gnus-summary-default-score
 		 scores)
 	(let* ((entries gnus-header-index)
-	       (now (gnus-day-number (current-time-string)))
+	       (now (date-to-day (current-time-string)))
 	       (expire (and gnus-score-expiry-days
 			    (- now gnus-score-expiry-days)))
 	       (headers gnus-newsgroup-headers)
@@ -1407,7 +1439,7 @@
 
 	  (save-excursion
 	    (set-buffer (gnus-get-buffer-create "*Headers*"))
-	    (buffer-disable-undo (current-buffer))
+	    (buffer-disable-undo)
 	    (when (gnus-buffer-live-p gnus-summary-buffer)
 	      (message-clone-locals gnus-summary-buffer))
 
@@ -1431,6 +1463,10 @@
 		(when (setq new (funcall (nth 2 entry) scores header
 					 now expire trace))
 		  (push new news))))
+	    (when (gnus-buffer-live-p gnus-summary-buffer)
+	      (let ((scored gnus-newsgroup-scored))
+		(with-current-buffer gnus-summary-buffer
+		  (setq gnus-newsgroup-scored scored))))
 	    ;; Remove the buffer.
 	    (kill-buffer (current-buffer)))
 
@@ -1447,85 +1483,56 @@
 	  (let (score)
 	    (while (setq score (pop scores))
 	      (while score
-		(when (listp (caar score))
+		(when (consp (caar score))
 		  (gnus-score-advanced (car score) trace))
 		(pop score))))
 
 	  (gnus-message 5 "Scoring...done"))))))
 
-
-(defun gnus-get-new-thread-ids (articles)
-  (let ((index (nth 1 (assoc "message-id" gnus-header-index)))
-        (refind gnus-score-index)
-        id-list art this tref)
-    (while articles
-      (setq art (car articles)
-            this (aref (car art) index)
-            tref (aref (car art) refind)
-            articles (cdr articles))
-      (when (string-equal tref "")	;no references line
-	(push this id-list)))
-    id-list))
-
-;; Orphan functions written by plm@atcmp.nl (Peter Mutsaers).
-(defun gnus-score-orphans (score)
-  (let ((new-thread-ids (gnus-get-new-thread-ids gnus-scores-articles))
-        alike articles art arts this last this-id)
-
-    (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<)
-	  articles gnus-scores-articles)
+(defun gnus-score-lower-thread (thread score-adjust)
+  "Lower the socre on THREAD with SCORE-ADJUST.
+THREAD is expected to contain a list of the form `(PARENT [CHILD1
+CHILD2 ...])' where PARENT is a header array and each CHILD is a list
+of the same form as THREAD.  The empty list `nil' is valid.  For each
+article in the tree, the score of the corresponding entry in
+GNUS-NEWSGROUP-SCORED is adjusted by SCORE-ADJUST."
+  (while thread
+    (let ((head (car thread)))
+      (if (listp head)
+	  ;; handle a child and its descendants
+	  (gnus-score-lower-thread head score-adjust)
+	;; handle the parent
+	(let* ((article (mail-header-number head))
+	       (score (assq article gnus-newsgroup-scored)))
+	  (if score (setcdr score (+ (cdr score) score-adjust))
+	    (push (cons article score-adjust) gnus-newsgroup-scored)))))
+    (setq thread (cdr thread))))
 
-    ;;more or less the same as in gnus-score-string
-    (erase-buffer)
-    (while articles
-      (setq art (car articles)
-            this (aref (car art) gnus-score-index)
-            articles (cdr articles))
-      ;;completely skip if this is empty (not a child, so not an orphan)
-      (when (not (string= this ""))
-	(if (equal last this)
-	    ;; O(N*H) cons-cells used here, where H is the number of
-	    ;; headers.
-	    (push art alike)
-	  (when last
-	    ;; Insert the line, with a text property on the
-	    ;; terminating newline referring to the articles with
-	    ;; this line.
-	    (insert last ?\n)
-	    (put-text-property (1- (point)) (point) 'articles alike))
-	  (setq alike (list art)
-		last this))))
-    (when last				; Bwadr, duplicate code.
-      (insert last ?\n)
-      (put-text-property (1- (point)) (point) 'articles alike))
-
-    ;; PLM: now delete those lines that contain an entry from new-thread-ids
-    (while new-thread-ids
-      (setq this-id (car new-thread-ids)
-            new-thread-ids (cdr new-thread-ids))
-      (goto-char (point-min))
-      (while (search-forward this-id nil t)
-        ;; found a match.  remove this line
-	(beginning-of-line)
-	(kill-line 1)))
-
-    ;; now for each line: update its articles with score by moving to
-    ;; every end-of-line in the buffer and read the articles property
-    (goto-char (point-min))
-    (while (eq 0 (progn
-                   (end-of-line)
-                   (setq arts (get-text-property (point) 'articles))
-                   (while arts
-                     (setq art (car arts)
-                           arts (cdr arts))
-                     (setcdr art (+ score (cdr art))))
-                   (forward-line))))))
-
+(defun gnus-score-orphans (score)
+  "Score orphans.
+A root is an article with no references.  An orphan is an article
+which has references, but is not connected via its references to a
+root article.  This function finds all the orphans, and adjusts their
+score in GNUS-NEWSGROUP-SCORED by SCORE."
+  (let ((threads (gnus-make-threads)))
+    ;; gnus-make-threads produces a list, where each entry is a "thread"
+    ;; as described in the gnus-score-lower-thread docs.  This function
+    ;; will be called again (after limiting has been done) if the display
+    ;; is threaded.  It would be nice to somehow save this info and use
+    ;; it later.
+    (while threads
+      (let* ((thread (car threads))
+	     (id (aref (car thread) gnus-score-index)))
+	;; If the parent of the thread is not a root, lower the score of
+	;; it and its descendants.  Note that some roots seem to satisfy
+	;; (eq id nil) and some (eq id "");  not sure why.
+	(if (and id (not (string= id "")))
+	    (gnus-score-lower-thread thread score)))
+      (setq threads (cdr threads)))))
 
 (defun gnus-score-integer (scores header now expire &optional trace)
   (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
 	entries alist)
-
     ;; Find matches.
     (while scores
       (setq alist (car scores)
@@ -1542,7 +1549,7 @@
 	       (match-func (if (or (eq type '>) (eq type '<) (eq type '<=)
 				   (eq type '>=) (eq type '=))
 			       type
-			     (error "Illegal match type: %s" type)))
+			     (error "Invalid match type: %s" type)))
 	       (articles gnus-scores-articles))
 	  ;; Instead of doing all the clever stuff that
 	  ;; `gnus-score-string' does to minimize searches and stuff,
@@ -1574,7 +1581,6 @@
 (defun gnus-score-date (scores header now expire &optional trace)
   (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
 	entries alist match match-func article)
-
     ;; Find matches.
     (while scores
       (setq alist (car scores)
@@ -1602,7 +1608,7 @@
 	   ((eq type 'regexp)
 	    (setq match-func 'string-match
 		  match (nth 0 kill)))
-	   (t (error "Illegal match type: %s" type)))
+	   (t (error "Invalid match type: %s" type)))
 	  ;; Instead of doing all the clever stuff that
 	  ;; `gnus-score-string' does to minimize searches and stuff,
 	  ;; I will assume that people generally will put so few
@@ -1661,8 +1667,8 @@
 	  (while articles
 	    (setq article (mail-header-number (caar articles)))
 	    (gnus-message 7 "Scoring article %s of %s..." article last)
+	    (widen)
 	    (when (funcall request-func article gnus-newsgroup-name)
-	      (widen)
 	      (goto-char (point-min))
 	      ;; If just parts of the article is to be searched, but the
 	      ;; backend didn't support partial fetching, we just narrow
@@ -1700,7 +1706,7 @@
 				     (eq type 'string) (eq type 'String))
 				 'search-forward)
 				(t
-				 (error "Illegal match type: %s" type)))))
+				 (error "Invalid match type: %s" type)))))
 		    (goto-char (point-min))
 		    (when (funcall search-func match nil t)
 		      ;; Found a match, update scores.
@@ -1786,7 +1792,7 @@
 	       (search-func
 		(cond ((= dmt ?r) 're-search-forward)
 		      ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
-		      (t (error "Illegal match type: %s" type))))
+		      (t (error "Invalid match type: %s" type))))
 	       arts art)
 	  (goto-char (point-min))
 	  (if (= dmt ?e)
@@ -1867,12 +1873,23 @@
     ;; and U is the number of unique headers.  It is assumed (but
     ;; untested) this will be a net win because of the large constant
     ;; factor involved with string matching.
-    (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<)
+    (setq gnus-scores-articles
+	  ;; We cannot string-sort the extra headers list.  *sigh*
+	  (if (= gnus-score-index 9)
+	      gnus-scores-articles
+	    (sort gnus-scores-articles 'gnus-score-string<))
 	  articles gnus-scores-articles)
 
     (erase-buffer)
     (while (setq art (pop articles))
       (setq this (aref (car art) gnus-score-index))
+
+      ;; If we're working with non-standard headers, we are stuck
+      ;; with working on them as a group.  What a hassle.
+      ;; Just wait 'til you see what horrors we commit against `match'...
+      (if (= gnus-score-index 9)
+	  (setq this (prin1-to-string this))) ; ick.
+
       (if simplify
 	  (setq this (gnus-map-function gnus-simplify-subject-functions this)))
       (if (equal last this)
@@ -1903,11 +1920,12 @@
 	       (type (or (nth 3 kill) 's))
 	       (score (or (nth 1 kill) gnus-score-interactive-default-score))
 	       (date (nth 2 kill))
+	       (extra (nth 4 kill))	; non-standard header; string.
 	       (found nil)
 	       (mt (aref (symbol-name type) 0))
 	       (case-fold-search (not (memq mt '(?R ?S ?E ?F))))
 	       (dmt (downcase mt))
-					; Assume user already simplified regexp and fuzzies
+	       ;; Assume user already simplified regexp and fuzzies
 	       (match (if (and simplify (not (memq dmt '(?f ?r))))
                           (gnus-map-function
                            gnus-simplify-subject-functions
@@ -1917,7 +1935,14 @@
 		(cond ((= dmt ?r) 're-search-forward)
 		      ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
 		      ((= dmt ?w) nil)
-		      (t (error "Illegal match type: %s" type)))))
+		      (t (error "Invalid match type: %s" type)))))
+
+	  ;; Evil hackery to make match usable in non-standard headers.
+	  (when extra
+	    (setq match (concat "[ (](" extra " \\. \"[^)]*"
+				match "[^(]*\")[ )]")
+		  search-func 're-search-forward)) ; XXX danger?!?
+
 	  (cond
 	   ;; Fuzzy matches.  We save these for later.
 	   ((= dmt ?f)
@@ -2044,6 +2069,7 @@
 	      (cond
 	       ;; Permanent.
 	       ((null date)
+		;; Do nothing.
 		)
 	       ;; Match, update date.
 	       ((and found gnus-update-score-entry-dates)
@@ -2082,6 +2108,7 @@
 		(cond
 		 ;; Permanent.
 		 ((null date)
+		  ;; Do nothing.
 		  )
 		 ;; Match, update date.
 		 ((and found gnus-update-score-entry-dates)
@@ -2212,9 +2239,9 @@
     ;; Perform adaptive word scoring.
     (when (and (listp gnus-newsgroup-adaptive)
 	       (memq 'word gnus-newsgroup-adaptive))
-      (nnheader-temp-write nil
+      (with-temp-buffer
 	(let* ((hashtb (gnus-make-hashtable 1000))
-	       (date (gnus-day-number (current-time-string)))
+	       (date (date-to-day (current-time-string)))
 	       (data gnus-newsgroup-data)
 	       (syntab (syntax-table))
 	       word d score val)
@@ -2250,7 +2277,7 @@
 	  (let ((ignored (append gnus-ignored-adaptive-words
 				 (if gnus-adaptive-word-no-group-words
 				     (message-tokenize-header
-				      (gnus-group-real-name 
+				      (gnus-group-real-name
 				       gnus-newsgroup-name)
 				      "."))
 				 gnus-default-ignored-adaptive-words)))
@@ -2292,11 +2319,10 @@
 	   1 "No score rules apply to the current article (default score %d)."
 	   gnus-summary-default-score)
 	(set-buffer "*Score Trace*")
+	(setq truncate-lines t)
 	(while trace
 	  (insert (format "%S  ->  %s\n" (cdar trace)
-			  (if (caar trace)
-			      (file-name-nondirectory (caar trace))
-			    "(non-file rule)")))
+			  (or (caar trace) "(non-file rule)")))
 	  (setq trace (cdr trace)))
 	(goto-char (point-min))
 	(gnus-configure-windows 'score-trace)))
@@ -2389,14 +2415,14 @@
       (gnus-summary-raise-score score))
     (gnus-summary-next-subject 1 t)))
 
-(defun gnus-score-default (level)
+(defun gnus-score-delta-default (level)
   (if level (prefix-numeric-value level)
     gnus-score-interactive-default-score))
 
 (defun gnus-summary-raise-thread (&optional score)
   "Raise the score of the articles in the current thread with SCORE."
   (interactive "P")
-  (setq score (gnus-score-default score))
+  (setq score (gnus-score-delta-default score))
   (let (e)
     (save-excursion
       (let ((articles (gnus-summary-articles-in-thread)))
@@ -2425,7 +2451,7 @@
 (defun gnus-summary-lower-thread (&optional score)
   "Lower score of articles in the current thread with SCORE."
   (interactive "P")
-  (gnus-summary-raise-thread (- (1- (gnus-score-default score)))))
+  (gnus-summary-raise-thread (- (1- (gnus-score-delta-default score)))))
 
 ;;; Finding score files.
 
@@ -2474,8 +2500,8 @@
 	seen out file)
     (while (setq file (pop files))
       (cond
-       ;; Ignore "." and "..".
-       ((member (file-name-nondirectory file) '("." ".."))
+       ;; Ignore files that start with a dot.
+       ((string-match "^\\." (file-name-nondirectory file))
 	nil)
        ;; Add subtrees of directory to also be searched.
        ((and (file-directory-p file)
@@ -2505,10 +2531,11 @@
 	 (klen (length kill-dir))
 	 (score-regexp (gnus-score-file-regexp))
 	 (trans (cdr (assq ?: nnheader-file-name-translation-alist)))
+	 (group-trans (nnheader-translate-file-chars group t))
 	 ofiles not-match regexp)
     (save-excursion
       (set-buffer (gnus-get-buffer-create "*gnus score files*"))
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       ;; Go through all score file names and create regexp with them
       ;; as the source.
       (while sfiles
@@ -2551,16 +2578,18 @@
 	  (if (looking-at "not.")
 	      (progn
 		(setq not-match t)
-		(setq regexp (concat "^" (buffer-substring 5 (point-max)) "$")))
+		(setq regexp
+		      (concat "^" (buffer-substring 5 (point-max)) "$")))
 	    (setq regexp (concat "^" (buffer-substring 1 (point-max)) "$"))
 	    (setq not-match nil))
 	  ;; Finally - if this resulting regexp matches the group name,
 	  ;; we add this score file to the list of score files
 	  ;; applicable to this group.
 	  (when (or (and not-match
-			 (not (string-match regexp group)))
-		    (and (not not-match)
-			 (string-match regexp group)))
+ 			 (ignore-errors
+			   (not (string-match regexp group-trans))))
+  		    (and (not not-match)
+ 			 (ignore-errors (string-match regexp group-trans))))
 	    (push (car sfiles) ofiles)))
 	(setq sfiles (cdr sfiles)))
       (kill-buffer (current-buffer))
@@ -2628,7 +2657,7 @@
 
 (defun gnus-sort-score-files (files)
   "Sort FILES so that the most general files come first."
-  (nnheader-temp-write nil
+  (with-temp-buffer
     (let ((alist
 	   (mapcar
 	    (lambda (file)
@@ -2797,12 +2826,14 @@
 	     ;; Function.
 	     ((gnus-functionp elem)
 	      (funcall elem group))
-	     ;; Regexp-file cons
+	     ;; Regexp-file cons.
 	     ((consp elem)
 	      (when (string-match (gnus-globalify-regexp (car elem)) group)
-		(replace-match (cadr elem) t nil group ))))))
+		(replace-match (cadr elem) t nil group))))))
     (when found
-      (nnheader-concat gnus-kill-files-directory found))))
+      (if (file-name-absolute-p found)
+          found
+        (nnheader-concat gnus-kill-files-directory found)))))
 
 (defun gnus-hierarchial-home-score-file (group)
   "Return the score file of the top-level hierarchy of GROUP."
@@ -2840,7 +2871,7 @@
 
 (defun gnus-decay-scores (alist day)
   "Decay non-permanent scores in ALIST."
-  (let ((times (- (gnus-time-to-day (current-time)) day))
+  (let ((times (- (time-to-days (current-time)) day))
 	kill entry updated score n)
     (unless (zerop times)		;Done decays today already?
       (while (setq entry (pop alist))
@@ -2854,7 +2885,7 @@
 		    n times)
 	      (while (natnump (decf n))
 		(setq score (funcall gnus-decay-score-function score)))
-	      (setcdr kill (cons score 
+	      (setcdr kill (cons score
 				 (cdr (cdr kill)))))))))
     ;; Return whether this score file needs to be saved.  By Je-haysuss!
     updated))
@@ -2913,8 +2944,7 @@
        (cond
 	(bad (cons 'bad bad))
 	(new (cons 'new new))
-	;; or nil
-	)))))
+	(t nil))))))
 
 (provide 'gnus-score)
 
--- a/lisp/gnus/gnus-setup.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-setup.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-setup.el --- Initialization & Setup for Gnus 5
-;; Copyright (C) 1995, 96 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
 
 ;; Author: Steven L. Baur <steve@miranova.com>
 ;; Keywords: news
@@ -65,22 +66,20 @@
 					 "site-lisp/bbdb-1.51/")
   "Directory where Big Brother Database is found.")
 
-(defvar gnus-use-tm running-xemacs
-  "Set this if you want MIME support for Gnus")
 (defvar gnus-use-mhe nil
-  "Set this if you want to use MH-E for mail reading")
+  "Set this if you want to use MH-E for mail reading.")
 (defvar gnus-use-rmail nil
-  "Set this if you want to use RMAIL for mail reading")
+  "Set this if you want to use RMAIL for mail reading.")
 (defvar gnus-use-sendmail t
-  "Set this if you want to use SENDMAIL for mail reading")
+  "Set this if you want to use SENDMAIL for mail reading.")
 (defvar gnus-use-vm nil
-  "Set this if you want to use the VM package for mail reading")
+  "Set this if you want to use the VM package for mail reading.")
 (defvar gnus-use-sc nil
-  "Set this if you want to use Supercite")
+  "Set this if you want to use Supercite.")
 (defvar gnus-use-mailcrypt t
-  "Set this if you want to use Mailcrypt for dealing with PGP messages")
+  "Set this if you want to use Mailcrypt for dealing with PGP messages.")
 (defvar gnus-use-bbdb nil
-  "Set this if you want to use the Big Brother DataBase")
+  "Set this if you want to use the Big Brother DataBase.")
 
 (when (and (not gnus-use-installed-gnus)
 	   (null (member gnus-gnus-lisp-directory load-path)))
@@ -89,19 +88,6 @@
 ;;; We can't do this until we know where Gnus is.
 (require 'message)
 
-;;; Tools for MIME by
-;;; UMEDA Masanobu <umerin@mse.kyutech.ac.jp>
-;;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
-
-(when gnus-use-tm
-  (when (and (not gnus-use-installed-tm)
-	     (null (member gnus-tm-lisp-directory load-path)))
-    (setq load-path (cons gnus-tm-lisp-directory load-path)))
-  ;; tm may or may not be dumped with XEmacs.  In Sunpro it is, otherwise
-  ;; it isn't.
-  (unless (featurep 'mime-setup)
-    (load "mime-setup")))
-
 ;;; Mailcrypt by
 ;;; Jin Choi <jin@atype.com>
 ;;; Patrick LoPresti <patl@lcs.mit.edu>
--- a/lisp/gnus/gnus-soup.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-soup.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; gnus-soup.el --- SOUP packet writing support for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <abraham@iesd.auc.dk>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,8 +30,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-art)
 (require 'message)
@@ -69,9 +69,9 @@
 
 ;;; Internal Variables:
 
-(defvar gnus-soup-encoding-type ?n
+(defvar gnus-soup-encoding-type ?u
   "*Soup encoding type.
-`n' is news format, `m' is Unix mbox format, and `M' is MMDF mailbox
+`u' is USENET news format, `m' is Unix mbox format, and `M' is MMDF mailbox
 format.")
 
 (defvar gnus-soup-index-type ?c
@@ -142,21 +142,19 @@
     (buffer-disable-undo tmp-buf)
     (save-excursion
       (while articles
-	;; Find the header of the article.
-	(set-buffer gnus-summary-buffer)
-	(when (setq headers (gnus-summary-article-header (car articles)))
-	  ;; Put the article in a buffer.
-	  (set-buffer tmp-buf)
-	  (when (gnus-request-article-this-buffer
-		 (car articles) gnus-newsgroup-name)
-	    (save-restriction
-	      (message-narrow-to-head)
-	      (message-remove-header gnus-soup-ignored-headers t))
-	    (gnus-soup-store gnus-soup-directory prefix headers
-			     gnus-soup-encoding-type
-			     gnus-soup-index-type)
-	    (gnus-soup-area-set-number
-	     area (1+ (or (gnus-soup-area-number area) 0)))))
+	;; Put the article in a buffer.
+	(set-buffer tmp-buf)
+	(when (gnus-request-article-this-buffer
+	       (car articles) gnus-newsgroup-name)
+	  (setq headers (nnheader-parse-head t))
+	  (save-restriction
+	    (message-narrow-to-head)
+	    (message-remove-header gnus-soup-ignored-headers t))
+	  (gnus-soup-store gnus-soup-directory prefix headers
+			   gnus-soup-encoding-type
+			   gnus-soup-index-type)
+	  (gnus-soup-area-set-number
+	   area (1+ (or (gnus-soup-area-number area) 0))))
 	;; Mark article as read.
 	(set-buffer gnus-summary-buffer)
 	(gnus-summary-remove-process-mark (car articles))
@@ -170,11 +168,11 @@
   "Make a SOUP packet from the SOUP areas."
   (interactive)
   (gnus-soup-read-areas)
-  (unless (file-exists-p gnus-soup-directory)
-    (message "No such directory: %s" gnus-soup-directory))
-  (when (null (directory-files gnus-soup-directory nil "\\.MSG$"))
-    (message "No files to pack."))
-  (gnus-soup-pack gnus-soup-directory gnus-soup-packer))
+  (if (file-exists-p gnus-soup-directory)
+      (if (directory-files gnus-soup-directory nil "\\.MSG$")
+	  (gnus-soup-pack gnus-soup-directory gnus-soup-packer)
+	(message "No files to pack."))
+    (message "No such directory: %s" gnus-soup-directory)))
 
 (defun gnus-group-brew-soup (n)
   "Make a soup packet from the current group.
@@ -249,7 +247,8 @@
       ;; a soup header.
       (setq head-line
 	    (cond
-	     ((= gnus-soup-encoding-type ?n)
+	     ((or (= gnus-soup-encoding-type ?u)
+		  (= gnus-soup-encoding-type ?n)) ;;Gnus back compatibility.
 	      (format "#! rnews %d\n" (buffer-size)))
 	     ((= gnus-soup-encoding-type ?m)
 	      (while (search-forward "\nFrom " nil t)
@@ -339,7 +338,8 @@
       (while (setq prefix (pop prefixes))
 	(erase-buffer)
 	(insert (format "(setq gnus-soup-prev-prefix %d)\n" (cdr prefix)))
-	(gnus-write-buffer (concat (car prefix) gnus-soup-prefix-file))))))
+	(let ((coding-system-for-write mm-text-coding-system))
+	  (gnus-write-buffer (concat (car prefix) gnus-soup-prefix-file)))))))
 
 (defun gnus-soup-pack (dir packer)
   (let* ((files (mapconcat 'identity
@@ -376,7 +376,7 @@
     (when (file-exists-p file)
       (save-excursion
 	(set-buffer (nnheader-find-file-noselect file 'force))
-	(buffer-disable-undo (current-buffer))
+	(buffer-disable-undo)
 	(goto-char (point-min))
 	(while (not (eobp))
 	  (push (vector (gnus-soup-field)
@@ -399,7 +399,7 @@
   (let (replies)
     (save-excursion
       (set-buffer (nnheader-find-file-noselect file))
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (goto-char (point-min))
       (while (not (eobp))
 	(push (vector (gnus-soup-field) (gnus-soup-field)
@@ -424,7 +424,7 @@
   "Write the AREAS file."
   (interactive)
   (when gnus-soup-areas
-    (nnheader-temp-write (concat gnus-soup-directory "AREAS")
+    (with-temp-file (concat gnus-soup-directory "AREAS")
       (let ((areas gnus-soup-areas)
 	    area)
 	(while (setq area (pop areas))
@@ -445,7 +445,7 @@
 
 (defun gnus-soup-write-replies (dir areas)
   "Write a REPLIES file in DIR containing AREAS."
-  (nnheader-temp-write (concat dir "REPLIES")
+  (with-temp-file (concat dir "REPLIES")
     (let (area)
       (while (setq area (pop areas))
 	(insert (format "%s\t%s\t%s\n"
@@ -517,9 +517,12 @@
 	       (tmp-buf (gnus-get-buffer-create " *soup send*"))
 	       beg end)
 	  (cond
-	   ((/= (gnus-soup-encoding-format
-		 (gnus-soup-reply-encoding (car replies)))
-		?n)
+	   ((and (/= (gnus-soup-encoding-format
+		      (gnus-soup-reply-encoding (car replies)))
+		     ?u)
+		 (/= (gnus-soup-encoding-format
+		      (gnus-soup-reply-encoding (car replies)))
+		     ?n)) ;; Gnus back compatibility.
 	    (error "Unsupported encoding"))
 	   ((null msg-buf)
 	    t)
--- a/lisp/gnus/gnus-spec.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-spec.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-spec.el --- format spec functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 
 ;;; Internal variables.
@@ -203,9 +202,7 @@
 		  (gnus-parse-format
 		   new-format
 		   (symbol-value
-		    (intern (format "gnus-%s-line-format-alist"
-				    (if (eq type 'article-mode)
-					'summary-mode type))))
+		    (intern (format "gnus-%s-line-format-alist" type)))
 		   (not (string-match "mode$" (symbol-name type))))))
 	  ;; Enter the new format spec into the list.
 	  (if entry
@@ -243,6 +240,12 @@
     (point) (progn ,@form (point))
     '(gnus-face t face ,(symbol-value (intern (format "gnus-face-%d" type))))))
 
+(defun gnus-balloon-face-function (form type)
+  `(gnus-put-text-property
+    (point) (progn ,@form (point))
+    'balloon-help
+    ,(intern (format "gnus-balloon-face-%d" type))))
+
 (defun gnus-tilde-max-form (el max-width)
   "Return a form that limits EL to MAX-WIDTH."
   (let ((max (abs max-width)))
@@ -289,8 +292,10 @@
   ;; SPEC-ALIST and returns a list that can be eval'ed to return the
   ;; string.  If the FORMAT string contains the specifiers %( and %)
   ;; the text between them will have the mouse-face text property.
+  ;; If the FORMAT string contains the specifiers %[ and %], the text between
+  ;; them will have the balloon-help text property.
   (if (string-match
-       "\\`\\(.*\\)%[0-9]?[{(]\\(.*\\)%[0-9]?[})]\\(.*\n?\\)\\'"
+       "\\`\\(.*\\)%[0-9]?[{(«]\\(.*\\)%[0-9]?[»})]\\(.*\n?\\)\\'"
        format)
       (gnus-parse-complex-format format spec-alist)
     ;; This is a simple format.
@@ -305,13 +310,17 @@
       (replace-match "\\\"" nil t))
     (goto-char (point-min))
     (insert "(\"")
-    (while (re-search-forward "%\\([0-9]+\\)?\\([{}()]\\)" nil t)
+    (while (re-search-forward "%\\([0-9]+\\)?\\([«»{}()]\\)" nil t)
       (let ((number (if (match-beginning 1)
 			(match-string 1) "0"))
 	    (delim (aref (match-string 2) 0)))
 	(if (or (= delim ?\()
-		(= delim ?\{))
-	    (replace-match (concat "\"(" (if (= delim ?\() "mouse" "face")
+		(= delim ?\{)
+		(= delim ?\«))
+	    (replace-match (concat "\"("
+				   (cond ((= delim ?\() "mouse")
+					 ((= delim ?\{) "face")
+					 (t "balloon"))
 				   " " number " \""))
 	  (replace-match "\")\""))))
     (goto-char (point-max))
@@ -392,9 +401,9 @@
 	     (t
 	      nil)))
 	;; User-defined spec -- find the spec name.
-	(when (= (setq spec (following-char)) ?u)
+	(when (eq (setq spec (char-after)) ?u)
 	  (forward-char 1)
-	  (setq user-defined (following-char)))
+	  (setq user-defined (char-after)))
 	(forward-char 1)
 	(delete-region spec-beg (point))
 
@@ -521,7 +530,7 @@
 		       (not (eq 'byte-code (car form)))
 		       ;; Under XEmacs, it's (funcall #<compiled-function ...>)
 		       (not (and (eq 'funcall (car form))
-				 (compiled-function-p (cadr form)))))
+				 (byte-code-function-p (cadr form)))))
 	      (fset 'gnus-tmp-func `(lambda () ,form))
 	      (byte-compile 'gnus-tmp-func)
 	      (setcar (cddr entry) (gnus-byte-code 'gnus-tmp-func))))))
@@ -537,8 +546,11 @@
 	(symbol-value (intern (format "gnus-%s-line-format" type)))
 	(symbol-value (intern (format "gnus-%s-line-format-alist" type)))
 	insertable)))
-	
 
 (provide 'gnus-spec)
 
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
+
 ;;; gnus-spec.el ends here
--- a/lisp/gnus/gnus-srvr.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-srvr.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-srvr.el --- virtual server support for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-spec)
 (require 'gnus-group)
@@ -137,6 +136,9 @@
     "D" gnus-server-deny-server
     "R" gnus-server-remove-denials
 
+    "n" next-line
+    "p" previous-line
+    
     "g" gnus-server-regenerate-server
 
     "\C-c\C-i" gnus-info-find-node
@@ -163,7 +165,7 @@
   (gnus-set-default-directory)
   (setq mode-line-process nil)
   (use-local-map gnus-server-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq truncate-lines t)
   (setq buffer-read-only t)
   (gnus-run-hooks 'gnus-server-mode-hook))
@@ -173,12 +175,12 @@
 	 (gnus-tmp-where (nth 1 method))
 	 (elem (assoc method gnus-opened-servers))
 	 (gnus-tmp-status (cond ((eq (nth 1 elem) 'denied)
-			"(denied)")
-		       ((or (gnus-server-opened method)
-			    (eq (nth 1 elem) 'ok))
-			"(opened)")
-		       (t
-			"(closed)"))))
+				 "(denied)")
+				((or (gnus-server-opened method)
+				     (eq (nth 1 elem) 'ok))
+				 "(opened)")
+				(t
+				 "(closed)"))))
     (beginning-of-line)
     (gnus-add-text-properties
      (point)
@@ -295,6 +297,18 @@
   (push (assoc server gnus-server-alist) gnus-server-killed-servers)
   (setq gnus-server-alist (delq (car gnus-server-killed-servers)
 				gnus-server-alist))
+  (let ((groups (gnus-groups-from-server server)))
+    (when (and groups
+	       (gnus-yes-or-no-p
+		(format "Kill all %s groups from this server? "
+			(length groups))))
+      (dolist (group groups)
+	(setq gnus-newsrc-alist
+	      (delq (assoc group gnus-newsrc-alist)
+		    gnus-newsrc-alist))
+	(when gnus-group-change-level-function
+	  (funcall gnus-group-change-level-function
+		   group gnus-level-killed 3)))))
   (gnus-server-position-point))
 
 (defun gnus-server-yank-server ()
@@ -508,28 +522,28 @@
   (suppress-keymap gnus-browse-mode-map)
 
   (gnus-define-keys
-   gnus-browse-mode-map
-   " " gnus-browse-read-group
-   "=" gnus-browse-select-group
-   "n" gnus-browse-next-group
-   "p" gnus-browse-prev-group
-   "\177" gnus-browse-prev-group
-   [delete] gnus-browse-prev-group
-   "N" gnus-browse-next-group
-   "P" gnus-browse-prev-group
-   "\M-n" gnus-browse-next-group
-   "\M-p" gnus-browse-prev-group
-   "\r" gnus-browse-select-group
-   "u" gnus-browse-unsubscribe-current-group
-   "l" gnus-browse-exit
-   "L" gnus-browse-exit
-   "q" gnus-browse-exit
-   "Q" gnus-browse-exit
-   "\C-c\C-c" gnus-browse-exit
-   "?" gnus-browse-describe-briefly
+      gnus-browse-mode-map
+    " " gnus-browse-read-group
+    "=" gnus-browse-select-group
+    "n" gnus-browse-next-group
+    "p" gnus-browse-prev-group
+    "\177" gnus-browse-prev-group
+    [delete] gnus-browse-prev-group
+    "N" gnus-browse-next-group
+    "P" gnus-browse-prev-group
+    "\M-n" gnus-browse-next-group
+    "\M-p" gnus-browse-prev-group
+    "\r" gnus-browse-select-group
+    "u" gnus-browse-unsubscribe-current-group
+    "l" gnus-browse-exit
+    "L" gnus-browse-exit
+    "q" gnus-browse-exit
+    "Q" gnus-browse-exit
+    "\C-c\C-c" gnus-browse-exit
+    "?" gnus-browse-describe-briefly
 
-   "\C-c\C-i" gnus-info-find-node
-   "\C-c\C-b" gnus-bug))
+    "\C-c\C-i" gnus-info-find-node
+    "\C-c\C-b" gnus-bug))
 
 (defun gnus-browse-make-menu-bar ()
   (gnus-turn-off-edit-menu 'browse)
@@ -552,9 +566,9 @@
 
 (defun gnus-browse-foreign-server (server &optional return-buffer)
   "Browse the server SERVER."
-  (setq gnus-browse-current-method server)
+  (setq gnus-browse-current-method (gnus-server-to-method server))
   (setq gnus-browse-return-buffer return-buffer)
-  (let* ((method (gnus-server-to-method server))
+  (let* ((method gnus-browse-current-method)
 	 (gnus-select-method method)
 	 groups group)
     (gnus-message 5 "Connecting to %s..." (nth 1 method))
@@ -577,7 +591,7 @@
       (when gnus-carpal
 	(gnus-carpal-setup-buffer 'browse))
       (gnus-configure-windows 'browse)
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (let ((buffer-read-only nil))
 	(erase-buffer))
       (gnus-browse-mode)
@@ -591,22 +605,38 @@
 	  (goto-char (point-min))
 	  (unless (string= gnus-ignored-newsgroups "")
 	    (delete-matching-lines gnus-ignored-newsgroups))
-	  (while (re-search-forward
-		  "\\(^[^ \t]+\\)[ \t]+[0-9]+[ \t]+[0-9]+" nil t)
-	    (goto-char (match-end 1))
-	    (condition-case ()
-		(push (cons (match-string 1)
-			    (max 0 (- (1+ (read cur)) (read cur))))
-		      groups)
-	      (error nil)))))
+	  (while (not (eobp)) 
+	    (ignore-errors
+	      (push (cons 
+		     (if (eq (char-after) ?\")
+			 (read cur)
+		       (let ((p (point)) (name ""))
+			 (skip-chars-forward "^ \t\\\\")
+			 (setq name (buffer-substring p (point)))
+			 (while (eq (char-after) ?\\)
+			   (setq p (1+ (point)))
+			   (forward-char 2)
+			   (skip-chars-forward "^ \t\\\\")
+			   (setq name (concat name (buffer-substring
+						    p (point)))))
+			 name))
+		     (max 0 (- (1+ (read cur)) (read cur))))
+		    groups))
+	    (forward-line))))
       (setq groups (sort groups
 			 (lambda (l1 l2)
 			   (string< (car l1) (car l2)))))
-      (let ((buffer-read-only nil))
+      (let ((buffer-read-only nil) charset)
 	(while groups
 	  (setq group (car groups))
-	  (insert
-	   (format "K%7d: %s\n" (cdr group) (car group)))
+	  (setq charset (gnus-group-name-charset method group))
+	  (gnus-add-text-properties
+	   (point)
+	   (prog1 (1+ (point))
+	     (insert
+	      (format "K%7d: %s\n" (cdr group)
+		      (gnus-group-name-decode (car group) charset))))
+	   (list 'gnus-group (car group)))
 	  (setq groups (cdr groups))))
       (switch-to-buffer (current-buffer))
       (goto-char (point-min))
@@ -638,7 +668,7 @@
   (setq mode-name "Browse Server")
   (setq mode-line-process nil)
   (use-local-map gnus-browse-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq truncate-lines t)
   (gnus-set-default-directory)
   (setq buffer-read-only t)
@@ -651,12 +681,12 @@
     (if (or (not (gnus-get-info group))
 	    (gnus-ephemeral-group-p group))
 	(unless (gnus-group-read-ephemeral-group
-		 group gnus-browse-current-method nil
+		 (gnus-group-real-name group) gnus-browse-current-method nil
 		 (cons (current-buffer) 'browse))
 	  (error "Couldn't enter %s" group))
       (unless (gnus-group-read-group nil no-article group)
 	(error "Couldn't enter %s" group)))))
-      
+
 (defun gnus-browse-select-group ()
   "Select the current group."
   (interactive)
@@ -694,11 +724,12 @@
 (defun gnus-browse-group-name ()
   (save-excursion
     (beginning-of-line)
-    (when (re-search-forward ": \\(.*\\)$" (gnus-point-at-eol) t)
-      (gnus-group-prefixed-name
-       ;; Remove text props.
-       (format "%s" (match-string 1))
-       gnus-browse-current-method))))
+    (let ((name (get-text-property (point) 'gnus-group)))
+      (when (re-search-forward ": \\(.*\\)$" (gnus-point-at-eol) t)
+	(gnus-group-prefixed-name
+	 (or name
+	     (match-string-no-properties 1))
+	 gnus-browse-current-method)))))
 
 (defun gnus-browse-unsubscribe-group ()
   "Toggle subscription of the current group in the browse buffer."
@@ -708,7 +739,7 @@
     (save-excursion
       (beginning-of-line)
       ;; If this group it killed, then we want to subscribe it.
-      (when (= (following-char) ?K)
+      (when (eq (char-after) ?K)
 	(setq sub t))
       (setq group (gnus-browse-group-name))
       (when (and sub
@@ -725,7 +756,8 @@
 		   nil nil (if (gnus-server-equal
 				gnus-browse-current-method "native")
 			       nil
-			     gnus-browse-current-method))
+			     (gnus-method-simplify 
+			      gnus-browse-current-method)))
 	     gnus-level-default-subscribed gnus-level-killed
 	     (and (car (nth 1 gnus-newsrc-alist))
 		  (gnus-gethash (car (nth 1 gnus-newsrc-alist))
--- a/lisp/gnus/gnus-start.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-start.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-start.el --- startup functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -52,7 +53,7 @@
 	       (directory-file-name installation-directory))
 	      "site-lisp/gnus-init")
     (error nil))
-  "*The site-wide Gnus Emacs-Lisp startup file name, or nil if none.
+  "The site-wide Gnus Emacs-Lisp startup file name, or nil if none.
 If a file with the `.el' or `.elc' suffixes exists, it will be read instead."
   :group 'gnus-start
   :type '(choice file (const nil)))
@@ -142,27 +143,19 @@
 		 (const some)
 		 (const t)))
 
-(defcustom gnus-level-subscribed 5
-  "*Groups with levels less than or equal to this variable are subscribed."
-  :group 'gnus-group-levels
-  :type 'integer)
+(defconst gnus-level-subscribed 5
+  "Groups with levels less than or equal to this variable are subscribed.")
 
-(defcustom gnus-level-unsubscribed 7
-  "*Groups with levels less than or equal to this variable are unsubscribed.
+(defconst gnus-level-unsubscribed 7
+  "Groups with levels less than or equal to this variable are unsubscribed.
 Groups with levels less than `gnus-level-subscribed', which should be
-less than this variable, are subscribed."
-  :group 'gnus-group-levels
-  :type 'integer)
+less than this variable, are subscribed.")
 
-(defcustom gnus-level-zombie 8
-  "*Groups with this level are zombie groups."
-  :group 'gnus-group-levels
-  :type 'integer)
+(defconst gnus-level-zombie 8
+  "Groups with this level are zombie groups.")
 
-(defcustom gnus-level-killed 9
-  "*Groups with this level are killed."
-  :group 'gnus-group-levels
-  :type 'integer)
+(defconst gnus-level-killed 9
+  "Groups with this level are killed.")
 
 (defcustom gnus-level-default-subscribed 3
   "*New subscribed groups will be subscribed at this level."
@@ -197,6 +190,16 @@
   :type '(choice integer
 		 (const :tag "none" nil)))
 
+(defcustom gnus-read-newsrc-file t
+  "*Non-nil means that Gnus will read the `.newsrc' file.
+Gnus always reads its own startup file, which is called
+\".newsrc.eld\".  The file called \".newsrc\" is in a format that can
+be readily understood by other newsreaders.  If you don't plan on
+using other newsreaders, set this variable to nil to save some time on
+entry."
+  :group 'gnus-newsrc
+  :type 'boolean)
+
 (defcustom gnus-save-newsrc-file t
   "*Non-nil means that Gnus will save the `.newsrc' file.
 Gnus always saves its own startup file, which is called
@@ -223,12 +226,12 @@
   :type 'boolean)
 
 (defcustom gnus-ignored-newsgroups
-  (purecopy (mapconcat 'identity
-		       '("^to\\."	; not "real" groups
-			 "^[0-9. \t]+ " ; all digits in name
-			 "[][\"#'()]"	; bogus characters
-			 )
-		       "\\|"))
+  (mapconcat 'identity
+	     '("^to\\."			; not "real" groups
+	       "^[0-9. \t]+ "		; all digits in name
+	       "^[\"][]\"[#'()]"	; bogus characters
+	       )
+	     "\\|")
   "*A regexp to match uninteresting newsgroups in the active file.
 Any lines in the active file matching this regular expression are
 removed from the newsgroup list before anything else is done to it,
@@ -244,7 +247,9 @@
 alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
 in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
 for your decision; `gnus-subscribe-killed' kills all new groups;
-`gnus-subscribe-zombies' will make all new groups into zombies."
+`gnus-subscribe-zombies' will make all new groups into zombies;
+`gnus-subscribe-topics' will enter groups into the topics that
+claim them."
   :group 'gnus-group-new
   :type '(radio (function-item gnus-subscribe-randomly)
 		(function-item gnus-subscribe-alphabetically)
@@ -252,6 +257,7 @@
 		(function-item gnus-subscribe-interactively)
 		(function-item gnus-subscribe-killed)
 		(function-item gnus-subscribe-zombies)
+		(function-item gnus-subscribe-topics)
 		function))
 
 (defcustom gnus-subscribe-options-newsgroup-method
@@ -360,7 +366,7 @@
 (defcustom gnus-after-getting-new-news-hook
   (when (gnus-boundp 'display-time-timer)
     '(display-time-event-handler))
-  "*A hook run after Gnus checks for new news."
+  "*A hook run after Gnus checks for new news when Gnus is already running."
   :group 'gnus-group-new
   :type 'hook)
 
@@ -382,16 +388,13 @@
   :type 'hook)
 
 (defcustom gnus-always-read-dribble-file nil
-  "Uncoditionally read the dribble file."
+  "Unconditionally read the dribble file."
   :group 'gnus-newsrc
   :type 'boolean)
 
 (defvar gnus-startup-file-coding-system 'binary
   "*Coding system for startup file.")
 
-(defvar gnus-startup-file-coding-system 'binary
-  "*Coding system for startup file.")
-
 ;;; Internal variables
 
 (defvar gnus-newsrc-file-version nil)
@@ -618,6 +621,7 @@
 	gnus-newsgroup-unreads nil
 	nnoo-state-alist nil
 	gnus-current-select-method nil
+	nnmail-split-history nil
 	gnus-ephemeral-servers nil)
   (gnus-shutdown 'gnus)
   ;; Kill the startup file.
@@ -729,17 +733,14 @@
 
 ;;;###autoload
 (defun gnus-unload ()
-  "Unload all Gnus features."
+  "Unload all Gnus features.
+\(For some value of `all' or `Gnus'.)  Currently, features whose names
+have prefixes `gnus-', `nn', `mm-' or `rfc' are unloaded.  Use
+cautiously -- unloading may cause trouble."
   (interactive)
-  (unless (boundp 'load-history)
-    (error "Sorry, `gnus-unload' is not implemented in this Emacs version"))
-  (let ((history load-history)
-	feature)
-    (while history
-      (and (string-match "^\\(gnus\\|nn\\)" (caar history))
-	   (setq feature (cdr (assq 'provide (car history))))
-	   (unload-feature feature 'force))
-      (setq history (cdr history)))))
+  (dolist (feature features)
+    (if (string-match "^\\(gnus-\\|nn\\|mm-\\|rfc\\)" (symbol-name feature))
+	(unload-feature feature 'force))))
 
 
 ;;;
@@ -788,7 +789,7 @@
       (erase-buffer)
       (setq buffer-file-name dribble-file)
       (auto-save-mode t)
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (bury-buffer (current-buffer))
       (set-buffer-modified-p nil)
       (let ((auto (make-auto-save-file-name))
@@ -858,7 +859,11 @@
   "Setup news information.
 If RAWFILE is non-nil, the .newsrc file will also be read.
 If LEVEL is non-nil, the news will be set up at level LEVEL."
-  (let ((init (not (and gnus-newsrc-alist gnus-active-hashtb (not rawfile)))))
+  (require 'nnmail)
+  (let ((init (not (and gnus-newsrc-alist gnus-active-hashtb (not rawfile))))
+	;; Binding this variable will inhibit multiple fetchings
+	;; of the same mail source.
+	(nnmail-fetched-sources (list t)))
 
     (when init
       ;; Clear some variables to re-initialize news information.
@@ -942,7 +947,7 @@
 
 (defun gnus-find-new-newsgroups (&optional arg)
   "Search for new newsgroups and add them.
-Each new newsgroup will be treated with `gnus-subscribe-newsgroup-method.'
+Each new newsgroup will be treated with `gnus-subscribe-newsgroup-method'.
 The `-n' option line from .newsrc is respected.
 
 With 1 C-u, use the `ask-server' method to query the server for new
@@ -953,16 +958,16 @@
   (let* ((gnus-subscribe-newsgroup-method
 	  gnus-subscribe-newsgroup-method)
 	 (check (cond
-		((or (and (= (or arg 1) 4)
-			  (not (listp gnus-check-new-newsgroups)))
-		     (null gnus-read-active-file)
-		     (eq gnus-read-active-file 'some))
-		 'ask-server)
-		((= (or arg 1) 16)
-		 (setq gnus-subscribe-newsgroup-method
-		       'gnus-subscribe-zombies)
-		 t)
-		(t gnus-check-new-newsgroups))))
+		 ((or (and (= (or arg 1) 4)
+			   (not (listp gnus-check-new-newsgroups)))
+		      (null gnus-read-active-file)
+		      (eq gnus-read-active-file 'some))
+		  'ask-server)
+		 ((= (or arg 1) 16)
+		  (setq gnus-subscribe-newsgroup-method
+			'gnus-subscribe-zombies)
+		  t)
+		 (t gnus-check-new-newsgroups))))
     (unless (gnus-check-first-time-used)
       (if (or (consp check)
 	      (eq check 'ask-server))
@@ -1097,34 +1102,40 @@
 	 hashtb))
       (when new-newsgroups
 	(gnus-subscribe-hierarchical-interactive new-newsgroups)))
-     (if (> groups 0)
-	 (gnus-message 5 "%d new newsgroup%s arrived"
-		       groups (if (> groups 1) "s have" " has"))
-       (gnus-message 5 "No new newsgroups"))
+    (if (> groups 0)
+	(gnus-message 5 "%d new newsgroup%s arrived"
+		      groups (if (> groups 1) "s have" " has"))
+      (gnus-message 5 "No new newsgroups"))
     (when got-new
       (setq gnus-newsrc-last-checked-date new-date))
     got-new))
 
 (defun gnus-check-first-time-used ()
-  (if (or (> (length gnus-newsrc-alist) 1)
-	  (file-exists-p gnus-startup-file)
-	  (file-exists-p (concat gnus-startup-file ".el"))
-	  (file-exists-p (concat gnus-startup-file ".eld")))
-      nil
+  (catch 'ended
+    ;; First check if any of the following files exist.  If they do,
+    ;; it's not the first time the user has used Gnus.
+    (dolist (file (list gnus-current-startup-file
+			(concat gnus-current-startup-file ".el")
+			(concat gnus-current-startup-file ".eld")
+			gnus-startup-file
+			(concat gnus-startup-file ".el")
+			(concat gnus-startup-file ".eld")))
+      (when (file-exists-p file)
+	(throw 'ended nil)))
     (gnus-message 6 "First time user; subscribing you to default groups")
     (unless (gnus-read-active-file-p)
       (let ((gnus-read-active-file t))
 	(gnus-read-active-file)))
     (setq gnus-newsrc-last-checked-date (current-time-string))
-    (let ((groups gnus-default-subscribed-newsgroups)
+    ;; Subscribe to the default newsgroups.
+    (let ((groups (or gnus-default-subscribed-newsgroups
+		      gnus-backup-default-subscribed-newsgroups))
 	  group)
-      (if (eq groups t)
-	  nil
-	(setq groups (or groups gnus-backup-default-subscribed-newsgroups))
+      (when (eq groups t)
+	;; If t, we subscribe (or not) all groups as if they were new.
 	(mapatoms
 	 (lambda (sym)
-	   (if (null (setq group (symbol-name sym)))
-	       ()
+	   (when (setq group (symbol-name sym))
 	     (let ((do-sub (gnus-matches-options-n group)))
 	       (cond
 		((eq do-sub 'subscribe)
@@ -1135,23 +1146,25 @@
 		(t
 		 (push group gnus-killed-list))))))
 	 gnus-active-hashtb)
-	(while groups
-	  (when (gnus-active (car groups))
+	(dolist (group groups)
+	  ;; Only subscribe the default groups that are activated.
+	  (when (gnus-active group)
 	    (gnus-group-change-level
-	     (car groups) gnus-level-default-subscribed gnus-level-killed))
-	  (setq groups (cdr groups)))
+	     group gnus-level-default-subscribed gnus-level-killed)))
 	(save-excursion
 	  (set-buffer gnus-group-buffer)
 	  (gnus-group-make-help-group))
 	(when gnus-novice-user
 	  (gnus-message 7 "`A k' to list killed groups"))))))
 
-(defun gnus-subscribe-group (group previous &optional method)
+(defun gnus-subscribe-group (group &optional previous method)
+  "Subcribe GROUP and put it after PREVIOUS."
   (gnus-group-change-level
    (if method
        (list t group gnus-level-default-subscribed nil nil method)
      group)
-   gnus-level-default-subscribed gnus-level-killed previous t))
+   gnus-level-default-subscribed gnus-level-killed previous t)
+  t)
 
 ;; `gnus-group-change-level' is the fundamental function for changing
 ;; subscription levels of newsgroups.  This might mean just changing
@@ -1246,14 +1259,14 @@
 	    (setq active (gnus-active group))
 	    (setq num
 		  (if active (- (1+ (cdr active)) (car active)) t))
-	    ;; Check whether the group is foreign.  If so, the
-	    ;; foreign select method has to be entered into the
-	    ;; info.
-	    (let ((method (or gnus-override-subscribe-method
-			      (gnus-group-method group))))
-	      (if (eq method gnus-select-method)
-		  (setq info (list group level nil))
-		(setq info (list group level nil nil method)))))
+	    ;; Shorten the select method if possible, if we need to
+	    ;; store it at all (native groups).
+	    (let ((method (gnus-method-simplify
+			   (or gnus-override-subscribe-method
+			       (gnus-group-method group)))))
+	      (if method
+		  (setq info (list group level nil nil method))
+		(setq info (list group level nil)))))
 	  (unless previous
 	    (setq previous
 		  (let ((p gnus-newsrc-alist))
@@ -1371,7 +1384,7 @@
 	   t)
 	 (condition-case ()
 	     (inline (gnus-request-group group dont-check method))
-	   (error nil)
+	   ;;(error nil)
 	   (quit nil))
 	 (setq active (gnus-parse-active))
 	 ;; If there are no articles in the group, the GROUP
@@ -1443,7 +1456,7 @@
 	;; Then we want to peel off any elements that are higher
 	;; than the upper active limit.
 	(let ((srange range))
-	  ;; Go past all legal elements.
+	  ;; Go past all valid elements.
 	  (while (and (cdr srange)
 		      (<= (or (and (atom (cadr srange))
 				   (cadr srange))
@@ -1451,7 +1464,7 @@
 			  (cdr active)))
 	    (setq srange (cdr srange)))
 	  (when (cdr srange)
-	    ;; Nuke all remaining illegal elements.
+	    ;; Nuke all remaining invalid elements.
 	    (setcdr srange nil))
 
 	  ;; Adjust the final element.
@@ -1485,7 +1498,7 @@
 		  gnus-activate-foreign-newsgroups)
 		 (t 0))
 	   level))
-	 info group active method)
+	 scanned-methods info group active method retrievegroups)
     (gnus-message 5 "Checking new news...")
 
     (while newsrc
@@ -1497,6 +1510,13 @@
       ;; be reached) we just set the number of unread articles in this
       ;; newsgroup to t.  This means that Gnus thinks that there are
       ;; unread articles, but it has no idea how many.
+
+      ;; To be more explicit:
+      ;; >0 for an active group with messages
+      ;; 0 for an active group with no unread messages
+      ;; nil for non-foreign groups that the user has requested not be checked
+      ;; t for unchecked foreign groups or bogus groups, or groups that can't
+      ;;   be checked, for one reason or other.
       (if (and (setq method (gnus-info-method info))
 	       (not (inline
 		      (gnus-server-equal
@@ -1504,8 +1524,8 @@
 		       (setq method (gnus-server-get-method nil method)))))
 	       (not (gnus-secondary-method-p method)))
 	  ;; These groups are foreign.  Check the level.
-	  (when (<= (gnus-info-level info) foreign-level)
-	    (setq active (gnus-activate-group group 'scan))
+	  (when (and (<= (gnus-info-level info) foreign-level)
+                     (setq active (gnus-activate-group group 'scan)))
 	    ;; Let the Gnus agent save the active file.
 	    (when (and gnus-agent gnus-plugged active)
 	      (gnus-agent-save-group-info
@@ -1516,18 +1536,76 @@
 					   "-request-update-info")))
 	      (inline (gnus-request-update-info info method))))
 	;; These groups are native or secondary.
-	(when (and (<= (gnus-info-level info) level)
-		   (not gnus-read-active-file))
-	  (setq active (gnus-activate-group group 'scan))
-	  (inline (gnus-close-group group))))
+	(cond
+	 ;; We don't want these groups.
+	 ((> (gnus-info-level info) level)
+	  (setq active 'ignore))
+	 ;; Activate groups.
+	 ((not gnus-read-active-file)
+	  (if (gnus-check-backend-function 'retrieve-groups group)
+	      ;; if server support gnus-retrieve-groups we push
+	      ;; the group onto retrievegroups for later checking
+	      (if (assoc method retrievegroups)
+		  (setcdr (assoc method retrievegroups)
+			  (cons group (cdr (assoc method retrievegroups))))
+		(push (list method group) retrievegroups))
+	    ;; hack: `nnmail-get-new-mail' changes the mail-source depending
+	    ;; on the group, so we must perform a scan for every group
+	    ;; if the users has any directory mail sources.
+	    ;; hack: if `nnmail-scan-directory-mail-source-once' is non-nil,
+	    ;; for it scan all spool files even when the groups are
+	    ;; not required.
+	    (if (and
+		 (or nnmail-scan-directory-mail-source-once
+		     (null (assq 'directory
+				 (or mail-sources
+				     (if (listp nnmail-spool-file)
+					 nnmail-spool-file
+				       (list nnmail-spool-file))))))
+		 (member method scanned-methods))
+		(setq active (gnus-activate-group group))
+	      (setq active (gnus-activate-group group 'scan))
+	      (push method scanned-methods))
+            (when active
+              (gnus-close-group group))))))
 
       ;; Get the number of unread articles in the group.
-      (if active
-	  (inline (gnus-get-unread-articles-in-group info active t))
+      (cond
+       ((eq active 'ignore)
+	;; Don't do anything.
+	)
+       (active
+	(inline (gnus-get-unread-articles-in-group info active t)))
+       (t
 	;; The group couldn't be reached, so we nix out the number of
 	;; unread articles and stuff.
 	(gnus-set-active group nil)
-	(setcar (gnus-gethash group gnus-newsrc-hashtb) t)))
+	(let ((tmp (gnus-gethash group gnus-newsrc-hashtb)))
+	  (if tmp (setcar tmp t))))))
+
+    ;; iterate through groups on methods which support gnus-retrieve-groups
+    ;; and fetch a partial active file and use it to find new news.
+    (while retrievegroups
+      (let* ((mg (pop retrievegroups))
+	     (method (or (car mg) gnus-select-method))
+	     (groups (cdr mg)))
+	(when (gnus-check-server method)
+          ;; Request that the backend scan its incoming messages.
+          (when (gnus-check-backend-function 'request-scan (car method))
+            (gnus-request-scan nil method))
+          (gnus-read-active-file-2 (mapcar (lambda (group)
+                                             (gnus-group-real-name group))
+                                           groups) method)
+          (dolist (group groups)
+            (cond
+             ((setq active (gnus-active (gnus-info-group
+                                         (setq info (gnus-get-info group)))))
+              (inline (gnus-get-unread-articles-in-group info active t)))
+             (t
+              ;; The group couldn't be reached, so we nix out the number of
+              ;; unread articles and stuff.
+              (gnus-set-active group nil)
+              (setcar (gnus-gethash group gnus-newsrc-hashtb) t)))))))
 
     (gnus-message 5 "Checking new news...done")))
 
@@ -1635,85 +1713,90 @@
 (defun gnus-read-active-file (&optional force not-native)
   (gnus-group-set-mode-line)
   (let ((methods
-	 (append
-	  (if (and (not not-native)
-		   (gnus-check-server gnus-select-method))
-	      ;; The native server is available.
-	      (cons gnus-select-method gnus-secondary-select-methods)
-	    ;; The native server is down, so we just do the
-	    ;; secondary ones.
-	    gnus-secondary-select-methods)
-	  ;; Also read from the archive server.
-	  (when (gnus-archive-server-wanted-p)
-	    (list "archive"))))
-	list-type)
+	 (mapcar
+	  (lambda (m) (if (stringp m) (gnus-server-get-method nil m) m))
+	  (append
+	   (if (and (not not-native)
+		    (gnus-check-server gnus-select-method))
+	       ;; The native server is available.
+	       (cons gnus-select-method gnus-secondary-select-methods)
+	     ;; The native server is down, so we just do the
+	     ;; secondary ones.
+	     gnus-secondary-select-methods)
+	   ;; Also read from the archive server.
+	   (when (gnus-archive-server-wanted-p)
+	     (list "archive")))))
+	method)
     (setq gnus-have-read-active-file nil)
     (save-excursion
       (set-buffer nntp-server-buffer)
-      (while methods
-	(let* ((method (if (stringp (car methods))
-			   (gnus-server-get-method nil (car methods))
-			 (car methods)))
-	       (where (nth 1 method))
-	       (mesg (format "Reading active file%s via %s..."
-			     (if (and where (not (zerop (length where))))
-				 (concat " from " where) "")
-			     (car method))))
+      (while (setq method (pop methods))
+	;; Only do each method once, in case the methods appear more
+	;; than once in this list.
+	(unless (member method methods)
+	  (condition-case ()
+	      (gnus-read-active-file-1 method force)
+	    ;; We catch C-g so that we can continue past servers
+	    ;; that do not respond.
+	    (quit nil)))))))
+
+(defun gnus-read-active-file-1 (method force)
+  (let (where mesg)
+    (setq where (nth 1 method)
+	  mesg (format "Reading active file%s via %s..."
+		       (if (and where (not (zerop (length where))))
+			   (concat " from " where) "")
+		       (car method)))
+    (gnus-message 5 mesg)
+    (when (gnus-check-server method)
+      ;; Request that the backend scan its incoming messages.
+      (when (gnus-check-backend-function 'request-scan (car method))
+	(gnus-request-scan nil method))
+      (cond
+       ((and (eq gnus-read-active-file 'some)
+	     (gnus-check-backend-function 'retrieve-groups (car method))
+	     (not force))
+	(let ((newsrc (cdr gnus-newsrc-alist))
+	      (gmethod (gnus-server-get-method nil method))
+	      groups info)
+	  (while (setq info (pop newsrc))
+	    (when (inline
+		    (gnus-server-equal
+		     (inline
+		       (gnus-find-method-for-group
+			(gnus-info-group info) info))
+		     gmethod))
+	      (push (gnus-group-real-name (gnus-info-group info))
+		    groups)))
+	  (gnus-read-active-file-2 groups method)))
+       ((null method)
+	t)
+       (t
+	(if (not (gnus-request-list method))
+	    (unless (equal method gnus-message-archive-method)
+	      (gnus-error 1 "Cannot read active file from %s server"
+			  (car method)))
 	  (gnus-message 5 mesg)
-	  (when (gnus-check-server method)
-	    ;; Request that the backend scan its incoming messages.
-	    (when (gnus-check-backend-function 'request-scan (car method))
-	      (gnus-request-scan nil method))
-	    (cond
-	     ((and (eq gnus-read-active-file 'some)
-		   (gnus-check-backend-function 'retrieve-groups (car method))
-		   (not force))
-	      (let ((newsrc (cdr gnus-newsrc-alist))
-		    (gmethod (gnus-server-get-method nil method))
-		    groups info)
-		(while (setq info (pop newsrc))
-		  (when (inline
-			  (gnus-server-equal
-			   (inline
-			     (gnus-find-method-for-group
-			      (gnus-info-group info) info))
-			   gmethod))
-		    (push (gnus-group-real-name (gnus-info-group info))
-			  groups)))
-		(when groups
-		  (gnus-check-server method)
-		  (setq list-type (gnus-retrieve-groups groups method))
-		  (cond
-		   ((not list-type)
-		    (gnus-error
-		     1.2 "Cannot read partial active file from %s server."
-		     (car method)))
-		   ((eq list-type 'active)
-		    (gnus-active-to-gnus-format
-		     method gnus-active-hashtb nil t))
-		   (t
-		    (gnus-groups-to-gnus-format
-		     method gnus-active-hashtb t))))))
-	     ((null method)
-	      t)
-	     (t
-	      (if (not (gnus-request-list method))
-		  (unless (equal method gnus-message-archive-method)
-		    (gnus-error 1 "Cannot read active file from %s server"
-				(car method)))
-		(gnus-message 5 mesg)
-		(gnus-active-to-gnus-format method gnus-active-hashtb nil t)
-		;; We mark this active file as read.
-		(push method gnus-have-read-active-file)
-		(gnus-message 5 "%sdone" mesg))))))
-	(setq methods (cdr methods))))))
+	  (gnus-active-to-gnus-format method gnus-active-hashtb nil t)
+	  ;; We mark this active file as read.
+	  (push method gnus-have-read-active-file)
+	  (gnus-message 5 "%sdone" mesg)))))))
 
-
-(defun gnus-ignored-newsgroups-has-to-p ()
-  "Non-nil iff gnus-ignored-newsgroups includes \"^to\\\\.\" as an element."
-  ;; note this regexp is the same as:
-  ;; (concat (regexp-quote "^to\\.") "\\($\\|" (regexp-quote "\\|") "\\)")
-  (string-match "\\^to\\\\\\.\\($\\|\\\\|\\)" gnus-ignored-newsgroups))
+(defun gnus-read-active-file-2 (groups method)
+  "Read an active file for GROUPS in METHOD using gnus-retrieve-groups."
+  (when groups
+    (save-excursion
+      (set-buffer nntp-server-buffer)
+      (gnus-check-server method)
+      (let ((list-type (gnus-retrieve-groups groups method)))
+	(cond ((not list-type)
+	       (gnus-error
+		1.2 "Cannot read partial active file from %s server."
+		(car method)))
+	      ((eq list-type 'active)
+	       (gnus-active-to-gnus-format method gnus-active-hashtb nil t))
+	      (t
+	       (gnus-groups-to-gnus-format method gnus-active-hashtb t)))))))
 
 ;; Read an active file and place the results in `gnus-active-hashtb'.
 (defun gnus-active-to-gnus-format (&optional method hashtb ignore-errors
@@ -1732,22 +1815,22 @@
 			      (gnus-make-hashtable 4096)))))))
     ;; Delete unnecessary lines.
     (goto-char (point-min))
-    (cond ((gnus-ignored-newsgroups-has-to-p)
-	   (delete-matching-lines gnus-ignored-newsgroups))
-	  ((string= gnus-ignored-newsgroups "")
-	   (delete-matching-lines "^to\\."))
-	  (t
-	   (delete-matching-lines (concat "^to\\.\\|"
-					  gnus-ignored-newsgroups))))
+    (cond
+     ((string= gnus-ignored-newsgroups "")
+      (delete-matching-lines "^to\\."))
+     (t
+      (delete-matching-lines (concat "^to\\.\\|" gnus-ignored-newsgroups))))
 
-    ;; Make the group names readable as a lisp expression even if they
-    ;; contain special characters.
-    (goto-char (point-max))
-    (while (re-search-backward "[][';?()#]" nil t)
-      (insert ?\\))
+    (goto-char (point-min))
+    (unless (re-search-forward "[\\\"]" nil t)
+      ;; Make the group names readable as a lisp expression even if they
+      ;; contain special characters.
+      (goto-char (point-max))
+      (while (re-search-backward "[][';?()#]" nil t)
+	(insert ?\\)))
 
     ;; Let the Gnus agent save the active file.
-    (when (and gnus-agent real-active)
+    (when (and gnus-agent real-active gnus-plugged)
       (gnus-agent-save-active method))
 
     ;; If these are groups from a foreign select method, we insert the
@@ -1758,30 +1841,37 @@
       (let ((prefix (gnus-group-prefixed-name "" method)))
 	(goto-char (point-min))
 	(while (and (not (eobp))
-		    (progn (insert prefix)
-			   (zerop (forward-line 1)))))))
+		    (progn
+		      (when (= (following-char) ?\")
+			(forward-char 1))
+		      (insert prefix)
+		      (zerop (forward-line 1)))))))
     ;; Store the active file in a hash table.
     (goto-char (point-min))
     (let (group max min)
       (while (not (eobp))
-	(condition-case ()
+	(condition-case err
 	    (progn
 	      (narrow-to-region (point) (gnus-point-at-eol))
 	      ;; group gets set to a symbol interned in the hash table
 	      ;; (what a hack!!) - jwz
 	      (setq group (let ((obarray hashtb)) (read cur)))
+	      ;; ### The extended group name scheme makes
+	      ;; the previous optimization strategy sort of pointless...
+	      (when (stringp group)
+		(setq group (intern group hashtb)))
 	      (if (and (numberp (setq max (read cur)))
 		       (numberp (setq min (read cur)))
 		       (progn
 			 (skip-chars-forward " \t")
 			 (not
-			  (or (= (following-char) ?=)
-			      (= (following-char) ?x)
-			      (= (following-char) ?j)))))
+			  (or (eq (char-after) ?=)
+			      (eq (char-after) ?x)
+			      (eq (char-after) ?j)))))
 		  (progn
 		    (set group (cons min max))
 		    ;; if group is moderated, stick in moderation table
-		    (when (= (following-char) ?m)
+		    (when (eq (char-after) ?m)
 		      (unless gnus-moderated-hashtb
 			(setq gnus-moderated-hashtb (gnus-make-hashtable)))
 		      (gnus-sethash (symbol-name group) t
@@ -1792,7 +1882,7 @@
 		(symbolp group)
 		(set group nil))
 	   (unless ignore-errors
-	     (gnus-message 3 "Warning - illegal active: %s"
+	     (gnus-message 3 "Warning - invalid active: %s"
 			   (buffer-substring
 			    (gnus-point-at-bol) (gnus-point-at-eol))))))
 	(widen)
@@ -1814,39 +1904,44 @@
 		     (gnus-group-prefixed-name "" method))))
 
     ;; Let the Gnus agent save the active file.
-    (when (and gnus-agent real-active)
-      (gnus-agent-save-groups method))
-    
-    (goto-char (point-min))
-    ;; We split this into to separate loops, one with the prefix
-    ;; and one without to speed the reading up somewhat.
-    (if prefix
-	(let (min max opoint group)
+    (if (and gnus-agent
+	     real-active
+	     gnus-plugged
+	     (gnus-agent-method-p method))
+	(progn
+	  (gnus-agent-save-groups method)
+	  (gnus-active-to-gnus-format method hashtb nil real-active))
+
+      (goto-char (point-min))
+      ;; We split this into to separate loops, one with the prefix
+      ;; and one without to speed the reading up somewhat.
+      (if prefix
+	  (let (min max opoint group)
+	    (while (not (eobp))
+	      (condition-case ()
+		  (progn
+		    (read cur) (read cur)
+		    (setq min (read cur)
+			  max (read cur)
+			  opoint (point))
+		    (skip-chars-forward " \t")
+		    (insert prefix)
+		    (goto-char opoint)
+		    (set (let ((obarray hashtb)) (read cur))
+			 (cons min max)))
+		(error (and group (symbolp group) (set group nil))))
+	      (forward-line 1)))
+	(let (min max group)
 	  (while (not (eobp))
 	    (condition-case ()
-		(progn
+		(when (eq (char-after) ?2)
 		  (read cur) (read cur)
 		  (setq min (read cur)
-			max (read cur)
-			opoint (point))
-		  (skip-chars-forward " \t")
-		  (insert prefix)
-		  (goto-char opoint)
-		  (set (let ((obarray hashtb)) (read cur))
+			max (read cur))
+		  (set (setq group (let ((obarray hashtb)) (read cur)))
 		       (cons min max)))
 	      (error (and group (symbolp group) (set group nil))))
-	    (forward-line 1)))
-      (let (min max group)
-	(while (not (eobp))
-	  (condition-case ()
-	      (when (= (following-char) ?2)
-		(read cur) (read cur)
-		(setq min (read cur)
-		      max (read cur))
-		(set (setq group (let ((obarray hashtb)) (read cur)))
-		     (cons min max)))
-	    (error (and group (symbolp group) (set group nil))))
-	  (forward-line 1))))))
+	    (forward-line 1)))))))
 
 (defun gnus-read-newsrc-file (&optional force)
   "Read startup file.
@@ -1864,7 +1959,8 @@
       ;; file (ticked articles, killed groups, foreign methods, etc.)
       (gnus-read-newsrc-el-file quick-file)
 
-      (when (and (file-exists-p gnus-current-startup-file)
+      (when (and gnus-read-newsrc-file
+		 (file-exists-p gnus-current-startup-file)
 		 (or force
 		     (and (file-newer-than-file-p newsrc-file quick-file)
 			  (file-newer-than-file-p newsrc-file
@@ -1880,7 +1976,7 @@
 	(save-excursion
 	  (gnus-message 5 "Reading %s..." newsrc-file)
 	  (set-buffer (nnheader-find-file-noselect newsrc-file))
-	  (buffer-disable-undo (current-buffer))
+	  (buffer-disable-undo)
 	  (gnus-newsrc-to-gnus-format)
 	  (kill-buffer (current-buffer))
 	  (gnus-message 5 "Reading %s...done" newsrc-file)))
@@ -2056,7 +2152,7 @@
 	(unless (boundp symbol)
 	  (set symbol nil))
 	;; It was a group name.
-	(setq subscribed (= (following-char) ?:)
+	(setq subscribed (eq (char-after) ?:)
 	      group (symbol-name symbol)
 	      reads nil)
 	(if (eolp)
@@ -2080,7 +2176,7 @@
 			   (read buf)))
 	      (widen)
 	      ;; If the next character is a dash, then this is a range.
-	      (if (= (following-char) ?-)
+	      (if (eq (char-after) ?-)
 		  (progn
 		    ;; We read the upper bound of the range.
 		    (forward-char 1)
@@ -2102,8 +2198,8 @@
 		(push num1 reads))
 	      ;; If the next char in ?\n, then we have reached the end
 	      ;; of the line and return nil.
-	      (/= (following-char) ?\n))
-	     ((= (following-char) ?\n)
+	      (not (eq (char-after) ?\n)))
+	     ((eq (char-after) ?\n)
 	      ;; End of line, so we end.
 	      nil)
 	     (t
@@ -2117,7 +2213,7 @@
 			    (buffer-substring (gnus-point-at-bol)
 					      (gnus-point-at-eol))))
 	      nil))
-	  ;; Skip past ", ".  Spaces are illegal in these ranges, but
+	  ;; Skip past ", ".  Spaces are invalid in these ranges, but
 	  ;; we allow them, because it's a common mistake to put a
 	  ;; space after the comma.
 	  (skip-chars-forward ", "))
@@ -2229,7 +2325,7 @@
 		  (gnus-point-at-eol)))
 	;; Search for all "words"...
 	(while (re-search-forward "[^ \t,\n]+" eol t)
-	  (if (= (char-after (match-beginning 0)) ?!)
+	  (if (eq (char-after (match-beginning 0)) ?!)
 	      ;; If the word begins with a bang (!), this is a "not"
 	      ;; spec.  We put this spec (minus the bang) and the
 	      ;; symbol `ignore' into the list.
@@ -2277,7 +2373,7 @@
 	  (setq buffer-file-name
 		(concat gnus-current-startup-file ".eld"))
 	  (setq default-directory (file-name-directory buffer-file-name))
-	  (buffer-disable-undo (current-buffer))
+	  (buffer-disable-undo)
 	  (erase-buffer)
 	  (gnus-message 5 "Saving %s.eld..." gnus-current-startup-file)
 	  (gnus-gnus-to-quick-newsrc-format)
@@ -2294,6 +2390,7 @@
   "Insert Gnus variables such as gnus-newsrc-alist in lisp format."
   (let ((print-quoted t)
 	(print-escape-newlines t))
+
     (insert ";; -*- emacs-lisp -*-\n")
     (insert ";; Gnus startup file.\n")
     (insert "\
@@ -2341,7 +2438,7 @@
 	  info ranges range method)
       (setq buffer-file-name gnus-current-startup-file)
       (setq default-directory (file-name-directory buffer-file-name))
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (erase-buffer)
       ;; Write options.
       (when gnus-newsrc-options
@@ -2404,12 +2501,13 @@
   (save-excursion
     (set-buffer gnus-dribble-buffer)
     (let ((slave-name
-	   (make-temp-file (concat gnus-current-startup-file "-slave-")))
+	   (make-temp-name (concat gnus-current-startup-file "-slave-")))
 	  (modes (ignore-errors
 		   (file-modes (concat gnus-current-startup-file ".eld")))))
+      (let ((coding-system-for-write gnus-startup-file-coding-system))
+	(gnus-write-buffer slave-name))
       (when modes
-	(set-file-modes slave-name modes))
-      (gnus-write-buffer slave-name))))
+	(set-file-modes slave-name modes)))))
 
 (defun gnus-master-read-slave-newsrc ()
   (let ((slave-files
@@ -2427,7 +2525,6 @@
       (gnus-message 7 "Reading slave newsrcs...")
       (save-excursion
 	(set-buffer (gnus-get-buffer-create " *gnus slave*"))
-	(buffer-disable-undo (current-buffer))
 	(setq slave-files
 	      (sort (mapcar (lambda (file)
 			      (list (nth 5 (file-attributes file)) file))
@@ -2438,7 +2535,7 @@
 	(while slave-files
 	  (erase-buffer)
 	  (setq file (nth 1 (car slave-files)))
-	  (insert-file-contents file)
+	  (nnheader-insert-file-contents file)
 	  (when (condition-case ()
 		    (progn
 		      (eval-buffer (current-buffer))
@@ -2485,6 +2582,8 @@
 
     (gnus-message 5 "Reading descriptions file via %s..." (car method))
     (cond
+     ((null (gnus-get-function method 'request-list-newsgroups t))
+      t)
      ((not (gnus-check-server method))
       (gnus-message 1 "Couldn't open server")
       nil)
@@ -2529,12 +2628,13 @@
 	      (let ((str (buffer-substring
 			  (point) (progn (end-of-line) (point))))
 		    (coding
-		     (and (boundp 'enable-multibyte-characters)
-			  enable-multibyte-characters
+		     (and (or gnus-xemacs
+			      (and (boundp 'enable-multibyte-characters)
+				   enable-multibyte-characters))
 			  (fboundp 'gnus-mule-get-coding-system)
 			  (gnus-mule-get-coding-system (symbol-name group)))))
-		(if coding
-		    (setq str (gnus-decode-coding-string str (car coding))))
+		(when coding
+		  (setq str (mm-decode-coding-string str (car coding))))
 		(set group str)))
 	    (forward-line 1))))
       (gnus-message 5 "Reading descriptions file...done")
@@ -2554,7 +2654,8 @@
   "Declare backend NAME with ABILITIES as a Gnus backend."
   (setq gnus-valid-select-methods
 	(nconc gnus-valid-select-methods
-	       (list (apply 'list name abilities)))))
+	       (list (apply 'list name abilities))))
+  (gnus-redefine-select-method-widget))
 
 (defun gnus-set-default-directory ()
   "Set the default directory in the current buffer to `gnus-default-directory'.
--- a/lisp/gnus/gnus-sum.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-sum.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-group)
 (require 'gnus-spec)
@@ -36,6 +35,7 @@
 (require 'gnus-int)
 (require 'gnus-undo)
 (require 'gnus-util)
+(require 'mm-decode)
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
 
 (defcustom gnus-kill-summary-on-exit t
@@ -169,10 +169,15 @@
   :type 'string)
 
 (defcustom gnus-summary-goto-unread t
-  "*If t, marking commands will go to the next unread article.
-If `never', commands that usually go to the next unread article, will
-go to the next article, whether it is read or not.
-If nil, only the marking commands will go to the next (un)read article."
+  "*If t, many commands will go to the next unread article.
+This applies to marking commands as well as other commands that
+\"naturally\" select the next article, like, for instance, `SPC' at
+the end of an article.
+
+If nil, the marking commands do NOT go to the next unread article
+(they go to the next article instead).  If `never', commands that
+usually go to the next unread article, will go to the next article,
+whether it is read or not."
   :group 'gnus-summary-marks
   :link '(custom-manual "(gnus)Setting Marks")
   :type '(choice (const :tag "off" nil)
@@ -254,8 +259,12 @@
 (defcustom gnus-auto-select-first t
   "*If nil, don't select the first unread article when entering a group.
 If this variable is `best', select the highest-scored unread article
-in the group.  If neither nil nor `best', select the first unread
-article.
+in the group.  If t, select the first unread article.
+
+This variable can also be a function to place point on a likely
+subject line.  Useful values include `gnus-summary-first-unread-subject',
+`gnus-summary-first-unread-article' and
+`gnus-summary-best-unread-article'.
 
 If you want to prevent automatic selection of the first unread article
 in some newsgroups, set the variable to nil in
@@ -263,7 +272,10 @@
   :group 'gnus-group-select
   :type '(choice (const :tag "none" nil)
 		 (const best)
-		 (sexp :menu-tag "first" t)))
+		 (sexp :menu-tag "first" t)
+		 (function-item gnus-summary-first-unread-subject)
+		 (function-item gnus-summary-first-unread-article)
+		 (function-item gnus-summary-best-unread-article)))
 
 (defcustom gnus-auto-select-next t
   "*If non-nil, offer to go to the next group from the end of the previous.
@@ -304,6 +316,7 @@
   :group 'gnus-summary-maneuvering
   :type '(choice (const :tag "none" nil)
 		 (const vertical)
+		 (integer :tag "height")
 		 (sexp :menu-tag "both" t)))
 
 (defcustom gnus-show-all-headers nil
@@ -330,13 +343,6 @@
   :group 'gnus-article-various
   :type 'boolean)
 
-(defcustom gnus-show-mime nil
-  "*If non-nil, do mime processing of articles.
-The articles will simply be fed to the function given by
-`gnus-show-mime-method'."
-  :group 'gnus-article-mime
-  :type 'boolean)
-
 (defcustom gnus-move-split-methods nil
   "*Variable used to suggest where articles are to be moved to.
 It uses the same syntax as the `gnus-split-methods' variable."
@@ -345,7 +351,7 @@
 			 (cons :value ("" "") regexp (repeat string))
 			 (sexp :value nil))))
 
-(defcustom gnus-unread-mark ? ;space
+(defcustom gnus-unread-mark ?  ;Whitespace
   "*Mark used for unread articles."
   :group 'gnus-summary-marks
   :type 'character)
@@ -460,7 +466,7 @@
   :group 'gnus-summary-marks
   :type 'character)
 
-(defcustom gnus-empty-thread-mark ? ;space
+(defcustom gnus-empty-thread-mark ?  ;Whitespace
   "*There is no thread under the article."
   :group 'gnus-summary-marks
   :type 'character)
@@ -475,6 +481,19 @@
   :group 'gnus-extract-view
   :type 'boolean)
 
+(defcustom gnus-auto-expirable-marks
+  (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
+	gnus-low-score-mark gnus-ancient-mark gnus-read-mark
+	gnus-souped-mark gnus-duplicate-mark)
+  "*The list of marks converted into expiration if a group is auto-expirable."
+  :group 'gnus-summary
+  :type '(repeat character))
+
+(defcustom gnus-inhibit-user-auto-expire t
+  "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
+  :group 'gnus-summary
+  :type 'boolean)
+
 (defcustom gnus-view-pseudos nil
   "*If `automatic', pseudo-articles will be viewed automatically.
 If `not-confirm', pseudos will be viewed automatically, and the user
@@ -506,7 +525,7 @@
   :group 'gnus-threading
   :type 'string)
 
-(defcustom gnus-summary-mode-line-format "Gnus: %%b [%A] %Z"
+(defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
   "*The format specification for the summary mode line.
 It works along the same lines as a normal formatting string,
 with some simple extensions:
@@ -529,6 +548,15 @@
   :group 'gnus-summary-format
   :type 'string)
 
+(defcustom gnus-list-identifiers nil
+  "Regexp that matches list identifiers to be removed from subject.
+This can also be a list of regexps."
+  :group 'gnus-summary-format
+  :group 'gnus-article-hiding
+  :type '(choice (const :tag "none" nil)
+		 (regexp :value ".*")
+		 (repeat :value (".*") regexp)))
+
 (defcustom gnus-summary-mark-below 0
   "*Mark all articles with a score below this variable as read.
 This variable is local to each summary buffer and usually set by the
@@ -593,7 +621,7 @@
 \"thread score\" is.
 
 This variable is local to the summary buffers."
-  :group 'gnus-treading
+  :group 'gnus-threading
   :group 'gnus-score-default
   :type '(choice (const :tag "off" nil)
 		 integer))
@@ -665,38 +693,14 @@
   :group 'gnus-summary-visual
   :type 'hook)
 
-(defcustom gnus-structured-field-decoder
-  (if (and (featurep 'mule)
-	   (boundp 'enable-multibyte-characters))
-      (lambda (string)
-	(if (and enable-multibyte-characters gnus-mule-coding-system)
-	    (decode-coding-string string gnus-mule-coding-system)
-	  string))
-    'identity)
-  "Function to decode non-ASCII characters in structured field for summary."
-  :group 'gnus-various
-  :type 'function)
-
-(defcustom gnus-unstructured-field-decoder
-  (if (and (featurep 'mule)
-	   (boundp 'enable-multibyte-characters))
-      (lambda (string)
-	(if (and enable-multibyte-characters gnus-mule-coding-system)
-	    (decode-coding-string string gnus-mule-coding-system)
-	  string))
-    'identity)
-  "Function to decode non-ASCII characters in unstructured field for summary."
-  :group 'gnus-various
-  :type 'function)
-
-(defcustom gnus-parse-headers-hook
-  (list 'gnus-hack-decode-rfc1522 'gnus-decode-rfc1522)
+(defcustom gnus-parse-headers-hook nil
   "*A hook called before parsing the headers."
   :group 'gnus-various
   :type 'hook)
 
 (defcustom gnus-exit-group-hook nil
-  "*A hook called when exiting (not quitting) summary mode."
+  "*A hook called when exiting summary mode.
+This hook is not called from the non-updating exit commands like `Q'."
   :group 'gnus-various
   :type 'hook)
 
@@ -795,10 +799,99 @@
 The function is called with one parameter, the article header vector,
 which it may alter in any way.")
 
+(defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
+  "Variable that says which function should be used to decode a string with encoded words.")
+
+(defcustom gnus-extra-headers nil
+  "*Extra headers to parse."
+  :group 'gnus-summary
+  :type '(repeat symbol))
+
+(defcustom gnus-ignored-from-addresses
+  (and user-mail-address (regexp-quote user-mail-address))
+  "*Regexp of From headers that may be suppressed in favor of To headers."
+  :group 'gnus-summary
+  :type 'regexp)
+
+(defcustom gnus-group-charset-alist
+  '(("^hk\\>\\|^tw\\>\\|\\<big5\\>" cn-big5)
+    ("^cn\\>\\|\\<chinese\\>" cn-gb-2312)
+    ("^fj\\>\\|^japan\\>" iso-2022-jp-2)
+    ("^tnn\\>\\|^pin\\>\\|^sci.lang.japan" iso-2022-7bit)
+    ("^relcom\\>" koi8-r)
+    ("^fido7\\>" koi8-r)
+    ("^\\(cz\\|hun\\|pl\\|sk\\|hr\\)\\>" iso-8859-2)
+    ("^israel\\>" iso-8859-1)
+    ("^han\\>" euc-kr)
+    ("^alt.chinese.text.big5\\>" chinese-big5)
+    ("^soc.culture.vietnamese\\>" vietnamese-viqr)
+    ("^\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1)
+    (".*" iso-8859-1))
+  "Alist of regexps (to match group names) and default charsets to be used when reading."
+  :type '(repeat (list (regexp :tag "Group")
+		       (symbol :tag "Charset")))
+  :group 'gnus-charset)
+
+(defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
+  "List of charsets that should be ignored.
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead."
+  :type '(repeat symbol)
+  :group 'gnus-charset)
+
+(defcustom gnus-group-ignored-charsets-alist
+  '(("alt\\.chinese\\.text" iso-8859-1))
+  "Alist of regexps (to match group names) and charsets that should be ignored.
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead."
+  :type '(repeat (cons (regexp :tag "Group")
+		       (repeat symbol)))
+  :group 'gnus-charset)
+
+(defcustom gnus-group-highlight-words-alist nil
+  "Alist of group regexps and highlight regexps.
+This variable uses the same syntax as `gnus-emphasis-alist'."
+  :type '(repeat (cons (regexp :tag "Group")
+		       (repeat (list (regexp :tag "Highlight regexp")
+				     (number :tag "Group for entire word" 0)
+				     (number :tag "Group for displayed part" 0)
+				     (symbol :tag "Face"
+					     gnus-emphasis-highlight-words)))))
+  :group 'gnus-summary-visual)
+
+(defcustom gnus-summary-show-article-charset-alist
+  nil
+  "Alist of number and charset.
+The article will be shown with the charset corresponding to the
+numbered argument.
+For example: ((1 . cn-gb-2312) (2 . big5))."
+  :type '(repeat (cons (number :tag "Argument" 1)
+		       (symbol :tag "Charset")))
+  :group 'gnus-charset)
+
+(defcustom gnus-preserve-marks t
+  "Whether marks are preserved when moving, copying and respooling messages."
+  :type 'boolean
+  :group 'gnus-summary-marks)
+
+(defcustom gnus-alter-articles-to-read-function nil
+  "Function to be called to alter the list of articles to be selected."
+  :type 'function
+  :group 'gnus-summary)
+
+(defcustom gnus-orphan-score nil
+  "*All orphans get this score added.  Set in the score file."
+  :group 'gnus-score-default
+  :type '(choice (const nil)
+		 integer))
+
 ;;; Internal variables
 
+(defvar gnus-article-mime-handles nil)
+(defvar gnus-article-decoded-p nil)
 (defvar gnus-scores-exclude-files nil)
 (defvar gnus-page-broken nil)
+(defvar gnus-inhibit-mime-unbuttonizing nil)
 
 (defvar gnus-original-article nil)
 (defvar gnus-article-internal-prepare-hook nil)
@@ -806,6 +899,8 @@
 
 (defvar gnus-thread-indent-array nil)
 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
+(defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
+  "Function called to sort the articles within a thread after it has been gathered together.")
 
 ;; Avoid highlighting in kill files.
 (defvar gnus-summary-inhibit-highlight nil)
@@ -853,6 +948,7 @@
     (?l (bbb-grouplens-score gnus-tmp-header) ?s)
     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
     (?U gnus-tmp-unread ?c)
+    (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header) ?s)
     (?t (gnus-summary-number-of-articles-in-thread
 	 (and (boundp 'thread) (car thread)) gnus-tmp-level)
 	?d)
@@ -861,9 +957,9 @@
 	?c)
     (?u gnus-tmp-user-defined ?s)
     (?P (gnus-pick-line-number) ?d))
-  "An alist of format specifications that can appear in summary lines,
-and what variables they correspond with, along with the type of the
-variable (string, integer, character, etc).")
+  "An alist of format specifications that can appear in summary lines.
+These are paired with what variables they correspond with, along with
+the type of the variable (string, integer, character, etc).")
 
 (defvar gnus-summary-dummy-line-format-alist
   `((?S gnus-tmp-subject ?s)
@@ -979,6 +1075,9 @@
 (defvar gnus-have-all-headers nil)
 (defvar gnus-last-article nil)
 (defvar gnus-newsgroup-history nil)
+(defvar gnus-newsgroup-charset nil)
+(defvar gnus-newsgroup-ephemeral-charset nil)
+(defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
 
 (defconst gnus-summary-local-variables
   '(gnus-newsgroup-name
@@ -1000,8 +1099,10 @@
     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
     gnus-newsgroup-scored gnus-newsgroup-kill-headers
     gnus-thread-expunge-below
-    gnus-score-alist gnus-current-score-file gnus-summary-expunge-below
+    gnus-score-alist gnus-current-score-file
+    (gnus-summary-expunge-below . global)
     (gnus-summary-mark-below . global)
+    (gnus-orphan-score . global)
     gnus-newsgroup-active gnus-scores-exclude-files
     gnus-newsgroup-history gnus-newsgroup-ancient
     gnus-newsgroup-sparse gnus-newsgroup-process-stack
@@ -1010,16 +1111,55 @@
     (gnus-newsgroup-expunged-tally . 0)
     gnus-cache-removable-articles gnus-newsgroup-cached
     gnus-newsgroup-data gnus-newsgroup-data-reverse
-    gnus-newsgroup-limit gnus-newsgroup-limits)
+    gnus-newsgroup-limit gnus-newsgroup-limits
+    gnus-newsgroup-charset)
   "Variables that are buffer-local to the summary buffers.")
 
 ;; Byte-compiler warning.
 (defvar gnus-article-mode-map)
 
+;; MIME stuff.
+
+(defvar gnus-decode-encoded-word-methods
+  '(mail-decode-encoded-word-string)
+  "List of methods used to decode encoded words.
+
+This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item is
+FUNCTION, FUNCTION will be apply to all newsgroups.  If item is a
+(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
+whose names match REGEXP.
+
+For example:
+((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
+ mail-decode-encoded-word-string
+ (\"chinese\" . rfc1843-decode-string))")
+
+(defvar gnus-decode-encoded-word-methods-cache nil)
+
+(defun gnus-multi-decode-encoded-word-string (string)
+  "Apply the functions from `gnus-encoded-word-methods' that match."
+  (unless (and gnus-decode-encoded-word-methods-cache
+	       (eq gnus-newsgroup-name
+		   (car gnus-decode-encoded-word-methods-cache)))
+    (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
+    (mapcar (lambda (x)
+	      (if (symbolp x)
+		  (nconc gnus-decode-encoded-word-methods-cache (list x))
+		(if (and gnus-newsgroup-name
+			 (string-match (car x) gnus-newsgroup-name))
+		    (nconc gnus-decode-encoded-word-methods-cache
+			   (list (cdr x))))))
+	  gnus-decode-encoded-word-methods))
+  (let ((xlist gnus-decode-encoded-word-methods-cache))
+    (pop xlist)
+    (while xlist
+      (setq string (funcall (pop xlist) string))))
+  string)
+
 ;; Subject simplification.
 
 (defun gnus-simplify-whitespace (str)
-  "Remove excessive whitespace."
+  "Remove excessive whitespace from STR."
   (let ((mystr str))
     ;; Multiple spaces.
     (while (string-match "[ \t][ \t]+" mystr)
@@ -1064,7 +1204,7 @@
 (defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
   (goto-char (point-min))
   (while (re-search-forward regexp nil t)
-      (replace-match (or newtext ""))))
+    (replace-match (or newtext ""))))
 
 (defun gnus-simplify-buffer-fuzzy ()
   "Simplify string in the buffer fuzzily.
@@ -1072,7 +1212,7 @@
 It is assumed to be a single-line subject.
 Whitespace is generally cleaned up, and miscellaneous leading/trailing
 matter is removed.  Additional things can be deleted by setting
-gnus-simplify-subject-fuzzy-regexp."
+`gnus-simplify-subject-fuzzy-regexp'."
   (let ((case-fold-search t)
 	(modified-tick))
     (gnus-simplify-buffer-fuzzy-step "\t" " ")
@@ -1196,6 +1336,8 @@
     "\M-\C-h" gnus-summary-hide-thread
     "\M-\C-f" gnus-summary-next-thread
     "\M-\C-b" gnus-summary-prev-thread
+    [(meta down)] gnus-summary-next-thread
+    [(meta up)] gnus-summary-prev-thread
     "\M-\C-u" gnus-summary-up-thread
     "\M-\C-d" gnus-summary-down-thread
     "&" gnus-summary-execute-command
@@ -1206,6 +1348,7 @@
     "\C-c\M-\C-s" gnus-summary-limit-include-expunged
     "\C-c\C-s\C-n" gnus-summary-sort-by-number
     "\C-c\C-s\C-l" gnus-summary-sort-by-lines
+    "\C-c\C-s\C-c" gnus-summary-sort-by-chars
     "\C-c\C-s\C-a" gnus-summary-sort-by-author
     "\C-c\C-s\C-s" gnus-summary-sort-by-subject
     "\C-c\C-s\C-d" gnus-summary-sort-by-date
@@ -1215,7 +1358,6 @@
     "\M-g" gnus-summary-rescan-group
     "w" gnus-summary-stop-page-breaking
     "\C-c\C-r" gnus-summary-caesar-message
-    "\M-t" gnus-summary-toggle-mime
     "f" gnus-summary-followup
     "F" gnus-summary-followup-with-original
     "C" gnus-summary-cancel-article
@@ -1237,13 +1379,14 @@
     "a" gnus-summary-post-news
     "x" gnus-summary-limit-to-unread
     "s" gnus-summary-isearch-article
-    "t" gnus-article-hide-headers
+    "t" gnus-summary-toggle-header
     "g" gnus-summary-show-article
     "l" gnus-summary-goto-last-article
     "\C-c\C-v\C-v" gnus-uu-decode-uu-view
     "\C-d" gnus-summary-enter-digest-group
     "\M-\C-d" gnus-summary-read-document
     "\M-\C-e" gnus-summary-edit-parameters
+    "\M-\C-a" gnus-summary-customize-parameters
     "\C-c\C-b" gnus-bug
     "*" gnus-cache-enter-article
     "\M-*" gnus-cache-remove-article
@@ -1254,6 +1397,9 @@
     "\M-i" gnus-symbolic-argument
     "h" gnus-summary-select-article-buffer
 
+    "b" gnus-article-view-part
+    "\M-t" gnus-summary-toggle-display-buttonized
+
     "V" gnus-summary-score-map
     "X" gnus-uu-extract-map
     "S" gnus-summary-send-map)
@@ -1295,12 +1441,14 @@
     "a" gnus-summary-limit-to-author
     "u" gnus-summary-limit-to-unread
     "m" gnus-summary-limit-to-marks
+    "M" gnus-summary-limit-exclude-marks
     "v" gnus-summary-limit-to-score
     "*" gnus-summary-limit-include-cached
     "D" gnus-summary-limit-include-dormant
     "T" gnus-summary-limit-include-thread
     "d" gnus-summary-limit-exclude-dormant
     "t" gnus-summary-limit-to-age
+    "x" gnus-summary-limit-to-extra
     "E" gnus-summary-limit-include-expunged
     "c" gnus-summary-limit-exclude-childless-dormant
     "C" gnus-summary-limit-mark-excluded-as-read)
@@ -1371,11 +1519,13 @@
     "e" gnus-summary-end-of-article
     "^" gnus-summary-refer-parent-article
     "r" gnus-summary-refer-parent-article
+    "D" gnus-summary-enter-digest-group
     "R" gnus-summary-refer-references
     "T" gnus-summary-refer-thread
     "g" gnus-summary-show-article
     "s" gnus-summary-isearch-article
-    "P" gnus-summary-print-article)
+    "P" gnus-summary-print-article
+    "t" gnus-article-babel)
 
   (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
     "b" gnus-article-add-buttons
@@ -1383,15 +1533,19 @@
     "o" gnus-article-treat-overstrike
     "e" gnus-article-emphasize
     "w" gnus-article-fill-cited-article
+    "Q" gnus-article-fill-long-lines
+    "C" gnus-article-capitalize-sentences
     "c" gnus-article-remove-cr
     "q" gnus-article-de-quoted-unreadable
+    "6" gnus-article-de-base64-unreadable
+    "Z" gnus-article-decode-HZ
+    "h" gnus-article-wash-html
     "f" gnus-article-display-x-face
     "l" gnus-summary-stop-page-breaking
     "r" gnus-summary-caesar-message
-    "t" gnus-article-hide-headers
+    "t" gnus-summary-toggle-header
     "v" gnus-summary-verbose-headers
-    "m" gnus-summary-toggle-mime
-    "h" gnus-article-treat-html
+    "H" gnus-article-strip-headers-in-body
     "d" gnus-article-treat-dumbquotes)
 
   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
@@ -1401,7 +1555,9 @@
     "s" gnus-article-hide-signature
     "c" gnus-article-hide-citation
     "C" gnus-article-hide-citation-in-followups
+    "l" gnus-article-hide-list-identifiers
     "p" gnus-article-hide-pgp
+    "B" gnus-article-strip-banner
     "P" gnus-article-hide-pem
     "\C-c" gnus-article-hide-citation-maybe)
 
@@ -1411,6 +1567,12 @@
     "c" gnus-article-highlight-citation
     "s" gnus-article-highlight-signature)
 
+  (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
+    "w" gnus-article-decode-mime-words
+    "c" gnus-article-decode-charset
+    "v" gnus-mime-view-all-parts
+    "b" gnus-article-view-part)
+
   (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
     "z" gnus-article-date-ut
     "u" gnus-article-date-ut
@@ -1426,7 +1588,8 @@
     "m" gnus-article-strip-multiple-blank-lines
     "a" gnus-article-strip-blank-lines
     "A" gnus-article-strip-all-blank-lines
-    "s" gnus-article-strip-leading-space)
+    "s" gnus-article-strip-leading-space
+    "e" gnus-article-strip-trailing-space)
 
   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
     "v" gnus-version
@@ -1440,6 +1603,7 @@
     "\M-\C-e" gnus-summary-expire-articles-now
     "\177" gnus-summary-delete-article
     [delete] gnus-summary-delete-article
+    [backspace] gnus-summary-delete-article
     "m" gnus-summary-move-article
     "r" gnus-summary-respool-article
     "w" gnus-summary-edit-article
@@ -1460,7 +1624,17 @@
     "h" gnus-summary-save-article-folder
     "v" gnus-summary-save-article-vm
     "p" gnus-summary-pipe-output
-    "s" gnus-soup-add-article))
+    "s" gnus-soup-add-article)
+
+  (gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
+    "b" gnus-summary-display-buttonized
+    "m" gnus-summary-repair-multipart
+    "v" gnus-article-view-part
+    "o" gnus-article-save-part
+    "c" gnus-article-copy-part
+    "e" gnus-article-externalize-part
+    "i" gnus-article-inline-part
+    "|" gnus-article-pipe-part))
 
 (defun gnus-summary-make-menu-bar ()
   (gnus-turn-off-edit-menu 'summary)
@@ -1503,13 +1677,21 @@
               ["Headers" gnus-article-hide-headers t]
               ["Signature" gnus-article-hide-signature t]
               ["Citation" gnus-article-hide-citation t]
+	      ["List identifiers" gnus-article-hide-list-identifiers t]
               ["PGP" gnus-article-hide-pgp t]
+	      ["Banner" gnus-article-strip-banner t]
               ["Boring headers" gnus-article-hide-boring-headers t])
              ("Highlight"
               ["All" gnus-article-highlight t]
               ["Headers" gnus-article-highlight-headers t]
               ["Signature" gnus-article-highlight-signature t]
               ["Citation" gnus-article-highlight-citation t])
+	     ("MIME"
+	      ["Words" gnus-article-decode-mime-words t]
+	      ["Charset" gnus-article-decode-charset t]
+	      ["QP" gnus-article-de-quoted-unreadable t]
+	      ["Base64" gnus-article-de-base64-unreadable t]
+	      ["View all" gnus-mime-view-all-parts t])
              ("Date"
               ["Local" gnus-article-date-local t]
               ["ISO8601" gnus-article-date-iso8601 t]
@@ -1524,23 +1706,27 @@
                ["Trailing" gnus-article-remove-trailing-blank-lines t]
                ["All of the above" gnus-article-strip-blank-lines t]
                ["All" gnus-article-strip-all-blank-lines t]
-               ["Leading space" gnus-article-strip-leading-space t])
+               ["Leading space" gnus-article-strip-leading-space t]
+	       ["Trailing space" gnus-article-strip-trailing-space t])
               ["Overstrike" gnus-article-treat-overstrike t]
               ["Dumb quotes" gnus-article-treat-dumbquotes t]
               ["Emphasis" gnus-article-emphasize t]
               ["Word wrap" gnus-article-fill-cited-article t]
+	      ["Fill long lines" gnus-article-fill-long-lines t]
+	      ["Capitalize sentences" gnus-article-capitalize-sentences t]
               ["CR" gnus-article-remove-cr t]
               ["Show X-Face" gnus-article-display-x-face t]
               ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
-              ["UnHTMLize" gnus-article-treat-html t]
+              ["Base64" gnus-article-de-base64-unreadable t]
               ["Rot 13" gnus-summary-caesar-message t]
               ["Unix pipe" gnus-summary-pipe-message t]
               ["Add buttons" gnus-article-add-buttons t]
               ["Add buttons to head" gnus-article-add-buttons-to-head t]
               ["Stop page breaking" gnus-summary-stop-page-breaking t]
-              ["Toggle MIME" gnus-summary-toggle-mime t]
               ["Verbose header" gnus-summary-verbose-headers t]
-              ["Toggle header" gnus-summary-toggle-header t])
+              ["Toggle header" gnus-summary-toggle-header t]
+	      ["Html" gnus-article-wash-html t]
+	      ["HZ" gnus-article-decode-HZ t])
              ("Output"
               ["Save in default format" gnus-summary-save-article t]
               ["Save in file" gnus-summary-save-article-file t]
@@ -1584,6 +1770,7 @@
              ("Cache"
               ["Enter article" gnus-cache-enter-article t]
               ["Remove article" gnus-cache-remove-article t])
+	     ["Translate" gnus-article-babel t]
              ["Select article buffer" gnus-summary-select-article-buffer t]
              ["Enter digest buffer" gnus-summary-enter-digest-group t]
              ["Isearch article..." gnus-summary-isearch-article t]
@@ -1618,8 +1805,7 @@
        ["Mark thread as read" gnus-summary-kill-thread t]
        ["Lower thread score" gnus-summary-lower-thread t]
        ["Raise thread score" gnus-summary-raise-thread t]
-       ["Rethread current" gnus-summary-rethread-current t]
-       ))
+       ["Rethread current" gnus-summary-rethread-current t]))
 
     (easy-menu-define
      gnus-summary-post-menu gnus-summary-mode-map ""
@@ -1674,6 +1860,7 @@
 	["Subject..." gnus-summary-limit-to-subject t]
 	["Author..." gnus-summary-limit-to-author t]
 	["Age..." gnus-summary-limit-to-age t]
+	["Extra..." gnus-summary-limit-to-extra t]
 	["Score" gnus-summary-limit-to-score t]
 	["Unread" gnus-summary-limit-to-unread t]
 	["Non-dormant" gnus-summary-limit-exclude-dormant t]
@@ -1683,6 +1870,7 @@
 	["Hide childless dormant"
 	 gnus-summary-limit-exclude-childless-dormant t]
 	;;["Hide thread" gnus-summary-limit-exclude-thread t]
+	["Hide marked" gnus-summary-limit-exclude-marks t]
 	["Show expunged" gnus-summary-show-all-expunged t])
        ("Process Mark"
 	["Set mark" gnus-summary-mark-as-processable t]
@@ -1729,7 +1917,8 @@
 	["Sort by subject" gnus-summary-sort-by-subject t]
 	["Sort by date" gnus-summary-sort-by-date t]
 	["Sort by score" gnus-summary-sort-by-score t]
-	["Sort by lines" gnus-summary-sort-by-lines t])
+	["Sort by lines" gnus-summary-sort-by-lines t]
+	["Sort by characters" gnus-summary-sort-by-chars t])
        ("Help"
 	["Fetch group FAQ" gnus-summary-fetch-faq t]
 	["Describe group" gnus-summary-describe-group t]
@@ -1753,6 +1942,7 @@
        ["Edit local kill file" gnus-summary-edit-local-kill t]
        ["Edit main kill file" gnus-summary-edit-global-kill t]
        ["Edit group parameters" gnus-summary-edit-parameters t]
+       ["Customize group parameters" gnus-summary-customize-parameters t]
        ["Send a bug report" gnus-bug t]
        ("Exit"
 	["Catchup and exit" gnus-summary-catchup-and-exit t]
@@ -1783,6 +1973,7 @@
 		     ("article body" "body" string)
 		     ("article head" "head" string)
 		     ("xref" "xref" string)
+		     ("extra header" "extra" string)
 		     ("lines" "lines" number)
 		     ("followups to author" "followup" string)))
 	  (types '((number ("less than" <)
@@ -1837,7 +2028,8 @@
 					       (list 'gnus-summary-header
 						     (nth 1 header)))
 					     (list 'quote (nth 1 (car ts)))
-					     (list 'gnus-score-default nil)
+					     (list 'gnus-score-delta-default
+						   nil)
 					     (nth 1 (car ps))
 					     t)
 					    t)
@@ -1884,7 +2076,7 @@
   (setq mode-name "Summary")
   (make-local-variable 'minor-mode-alist)
   (use-local-map gnus-summary-mode-map)
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (setq buffer-read-only t)		;Disable modification
   (setq truncate-lines t)
   (setq selective-display t)
@@ -1897,19 +2089,17 @@
   (make-local-variable 'gnus-summary-dummy-line-format)
   (make-local-variable 'gnus-summary-dummy-line-format-spec)
   (make-local-variable 'gnus-summary-mark-positions)
-  (make-local-hook 'post-command-hook)
-  (add-hook 'post-command-hook 'gnus-clear-inboxes-moved nil t)
   (make-local-hook 'pre-command-hook)
   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
   (gnus-run-hooks 'gnus-summary-mode-hook)
+  (mm-enable-multibyte)
   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
   (gnus-update-summary-mark-positions))
 
 (defun gnus-summary-make-local-variables ()
   "Make all the local summary buffer variables."
-  (let ((locals gnus-summary-local-variables)
-	global local)
-    (while (setq local (pop locals))
+  (let (global)
+    (dolist (local gnus-summary-local-variables)
       (if (consp local)
 	  (progn
 	    (if (eq (cdr local) 'global)
@@ -1917,11 +2107,9 @@
 		(setq global (symbol-value (car local)))
 	      ;; Use the value from the list.
 	      (setq global (eval (cdr local))))
-	    (make-local-variable (car local))
-	    (set (car local) global))
+	    (set (make-local-variable (car local)) global))
 	;; Simple nil-valued local variable.
-	(make-local-variable local)
-	(set local nil)))))
+	(set (make-local-variable local) nil)))))
 
 (defun gnus-summary-clear-local-variables ()
   (let ((locals gnus-summary-local-variables))
@@ -2215,26 +2403,6 @@
 	     ,@forms)
 	 (gnus-restore-hidden-threads-configuration ,config)))))
 
-(defun gnus-hidden-threads-configuration ()
-  "Return the current hidden threads configuration."
-  (save-excursion
-    (let (config)
-      (goto-char (point-min))
-      (while (search-forward "\r" nil t)
-	(push (1- (point)) config))
-      config)))
-
-(defun gnus-restore-hidden-threads-configuration (config)
-  "Restore hidden threads configuration from CONFIG."
-  (let (point buffer-read-only)
-    (while (setq point (pop config))
-      (when (and (< point (point-max))
-		 (goto-char point)
-		 (= (following-char) ?\n))
-	(subst-char-in-region point (1+ point) ?\n ?\r)))))
-
-;; This needs to be put here because it uses the
-;; gnus-save-hidden-threads macro
 (defun gnus-data-compute-positions ()
   "Compute the positions of all articles."
   (setq gnus-newsgroup-data-reverse nil)
@@ -2250,6 +2418,25 @@
 	  (setq data (cdr data))
 	  (forward-line 1))))))
 
+(defun gnus-hidden-threads-configuration ()
+  "Return the current hidden threads configuration."
+  (save-excursion
+    (let (config)
+      (goto-char (point-min))
+      (while (search-forward "\r" nil t)
+	(push (1- (point)) config))
+      config)))
+
+(defun gnus-restore-hidden-threads-configuration (config)
+  "Restore hidden threads configuration from CONFIG."
+  (save-excursion
+    (let (point buffer-read-only)
+      (while (setq point (pop config))
+	(when (and (< point (point-max))
+		   (goto-char point)
+		   (eq (char-after) ?\n))
+	  (subst-char-in-region point (1+ point) ?\n ?\r))))))
+
 ;; Various summary mode internalish functions.
 
 (defun gnus-mouse-pick-article (e)
@@ -2258,9 +2445,10 @@
   (gnus-summary-next-page nil t))
 
 (defun gnus-summary-set-display-table ()
-  ;; Change the display table.  Odd characters have a tendency to mess
-  ;; up nicely formatted displays - we make all possible glyphs
-  ;; display only a single character.
+  "Change the display table.
+Odd characters have a tendency to mess
+up nicely formatted displays - we make all possible glyphs
+display only a single character."
 
   ;; We start from the standard display table, if any.
   (let ((table (or (copy-sequence standard-display-table)
@@ -2304,9 +2492,9 @@
       t)))
 
 (defun gnus-set-global-variables ()
-  ;; Set the global equivalents of the summary buffer-local variables
-  ;; to the latest values they had.  These reflect the summary buffer
-  ;; that was in action when the last article was fetched.
+  "Set the global equivalents of the buffer-local variables.
+They are set to the latest values they had.  These reflect the summary
+buffer that was in action when the last article was fetched."
   (when (eq major-mode 'gnus-summary-mode)
     (setq gnus-summary-buffer (current-buffer))
     (let ((name gnus-newsgroup-name)
@@ -2319,7 +2507,8 @@
 	  (original gnus-original-article-buffer)
 	  (gac gnus-article-current)
 	  (reffed gnus-reffed-article-number)
-	  (score-file gnus-current-score-file))
+	  (score-file gnus-current-score-file)
+	  (default-charset gnus-newsgroup-charset))
       (save-excursion
 	(set-buffer gnus-group-buffer)
 	(setq gnus-newsgroup-name name
@@ -2332,7 +2521,8 @@
 	      gnus-article-buffer article-buffer
 	      gnus-original-article-buffer original
 	      gnus-reffed-article-number reffed
-	      gnus-current-score-file score-file)
+	      gnus-current-score-file score-file
+	      gnus-newsgroup-charset default-charset)
 	;; The article buffer also has local variables.
 	(when (gnus-buffer-live-p gnus-article-buffer)
 	  (set-buffer gnus-article-buffer)
@@ -2351,7 +2541,8 @@
 (defun gnus-summary-last-article-p (&optional article)
   "Return whether ARTICLE is the last article in the buffer."
   (if (not (setq article (or article (gnus-summary-article-number))))
-      t		; All non-existent numbers are the last article.  :-)
+      ;; All non-existent numbers are the last article.  :-)
+      t
     (not (cdr (gnus-data-find-list article)))))
 
 (defun gnus-make-thread-indent-array ()
@@ -2381,7 +2572,7 @@
 	(let ((gnus-summary-line-format-spec spec)
 	      (gnus-newsgroup-downloadable '((0 . t))))
 	  (gnus-summary-insert-line
-	   [0 "" "" "" "" "" 0 0 ""]  0 nil 128 t nil "" nil 1)
+	   [0 "" "" "" "" "" 0 0 "" nil]  0 nil 128 t nil "" nil 1)
 	  (goto-char (point-min))
 	  (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
 					     (- (point) 2)))))
@@ -2405,6 +2596,33 @@
    (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
    (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
 
+(defun gnus-summary-from-or-to-or-newsgroups (header)
+  (let ((to (cdr (assq 'To (mail-header-extra header))))
+	(newsgroups (cdr (assq 'Newsgroups (mail-header-extra header))))
+	(mail-parse-charset gnus-newsgroup-charset)
+	(mail-parse-ignored-charsets
+	 (save-excursion (set-buffer gnus-summary-buffer)
+			 gnus-newsgroup-ignored-charsets)))
+    (cond
+     ((and to
+	   gnus-ignored-from-addresses
+	   (string-match gnus-ignored-from-addresses
+			 (mail-header-from header)))
+      (concat "-> "
+	      (or (car (funcall gnus-extract-address-components
+				(funcall
+				 gnus-decode-encoded-word-function to)))
+		  (funcall gnus-decode-encoded-word-function to))))
+     ((and newsgroups
+	   gnus-ignored-from-addresses
+	   (string-match gnus-ignored-from-addresses
+			 (mail-header-from header)))
+      (concat "=> " newsgroups))
+     (t
+      (or (car (funcall gnus-extract-address-components
+			(mail-header-from header)))
+	  (mail-header-from header))))))
+
 (defun gnus-summary-insert-line (gnus-tmp-header
 				 gnus-tmp-level gnus-tmp-current
 				 gnus-tmp-unread gnus-tmp-replied
@@ -2418,7 +2636,7 @@
 	  (if (or (null gnus-summary-default-score)
 		  (<= (abs (- gnus-tmp-score gnus-summary-default-score))
 		      gnus-summary-zcore-fuzz))
-	      ? ;space
+	      ?  ;Whitespace
 	    (if (< gnus-tmp-score gnus-summary-default-score)
 		gnus-score-below-mark gnus-score-over-mark)))
 	 (gnus-tmp-replied
@@ -2451,7 +2669,7 @@
       (setq gnus-tmp-name gnus-tmp-from))
     (unless (numberp gnus-tmp-lines)
       (setq gnus-tmp-lines 0))
-    (gnus-put-text-property-excluding-characters-with-faces
+    (gnus-put-text-property
      (point)
      (progn (eval gnus-summary-line-format-spec) (point))
      'gnus-number gnus-tmp-number)
@@ -2461,7 +2679,7 @@
       (forward-line 1))))
 
 (defun gnus-summary-update-line (&optional dont-update)
-  ;; Update summary line after change.
+  "Update summary line after change."
   (when (and gnus-summary-default-score
 	     (not gnus-summary-inhibit-highlight))
     (let* ((gnus-summary-inhibit-highlight t) ; Prevent recursion.
@@ -2483,7 +2701,7 @@
 	 (if (or (null gnus-summary-default-score)
 		 (<= (abs (- score gnus-summary-default-score))
 		     gnus-summary-zcore-fuzz))
-	     ? ;space
+	     ?  ;Whitespace
 	   (if (< score gnus-summary-default-score)
 	       gnus-score-below-mark gnus-score-over-mark))
 	 'score))
@@ -2552,7 +2770,7 @@
 				   kill-buffer no-display
 				   select-articles)
 				  (setq show-all nil
-				   select-articles nil)))))
+					select-articles nil)))))
 		(eq gnus-auto-select-next 'quietly))
       (set-buffer gnus-group-buffer)
       ;; The entry function called above goes to the next
@@ -2634,6 +2852,7 @@
       (gnus-summary-set-local-parameters gnus-newsgroup-name)
       (gnus-update-format-specifications
        nil 'summary 'summary-mode 'summary-dummy)
+      (gnus-update-summary-mark-positions)
       ;; Do score processing.
       (when gnus-use-scoring
 	(gnus-possibly-score-headers))
@@ -2646,6 +2865,7 @@
 	      (let ((gnus-newsgroup-dormant nil))
 		(gnus-summary-initial-limit show-all))
 	    (gnus-summary-initial-limit show-all))
+	;; When untreaded, all articles are always shown.
 	(setq gnus-newsgroup-limit
 	      (mapcar
 	       (lambda (header) (mail-header-number header))
@@ -2691,10 +2911,15 @@
 		 (not no-display)
 		 gnus-newsgroup-unreads
 		 gnus-auto-select-first)
-	    (unless (if (eq gnus-auto-select-first 'best)
-			(gnus-summary-best-unread-article)
-		      (gnus-summary-first-unread-article))
-	      (gnus-configure-windows 'summary))
+	    (progn
+	      (gnus-configure-windows 'summary)
+	      (cond
+	       ((eq gnus-auto-select-first 'best)
+		(gnus-summary-best-unread-article))
+	       ((eq gnus-auto-select-first t)
+		(gnus-summary-first-unread-article))
+	       ((gnus-functionp gnus-auto-select-first)
+		(funcall gnus-auto-select-first))))
 	  ;; Don't select any articles, just move point to the first
 	  ;; article in the group.
 	  (goto-char (point-min))
@@ -2839,12 +3064,12 @@
     result))
 
 (defun gnus-sort-gathered-threads (threads)
-  "Sort subtreads inside each gathered thread by article number."
+  "Sort subtreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
   (let ((result threads))
     (while threads
       (when (stringp (caar threads))
 	(setcdr (car threads)
-		(sort (cdar threads) 'gnus-thread-sort-by-number)))
+		(sort (cdar threads) gnus-sort-gathered-threads-function)))
       (setq threads (cdr threads)))
     result))
 
@@ -2900,7 +3125,7 @@
     threads))
 
 ;; Build the thread tree.
-(defun gnus-dependencies-add-header (header dependencies force-new)
+(defsubst gnus-dependencies-add-header (header dependencies force-new)
   "Enter HEADER into the DEPENDENCIES table if it is not already there.
 
 If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
@@ -2979,6 +3204,7 @@
 
 (defun gnus-build-sparse-threads ()
   (let ((headers gnus-newsgroup-headers)
+	(mail-parse-charset gnus-newsgroup-charset)
 	(gnus-summary-ignore-duplicates t)
 	header references generation relations
 	subject child end new-child date)
@@ -3031,7 +3257,8 @@
   ;; fetch the headers for the articles that aren't there.  This will
   ;; build complete threads - if the roots haven't been expired by the
   ;; server, that is.
-  (let (id heads)
+  (let ((mail-parse-charset gnus-newsgroup-charset)
+	id heads)
     (mapatoms
      (lambda (refs)
        (when (not (car (symbol-value refs)))
@@ -3046,24 +3273,6 @@
 	     (setq heads nil)))))
      gnus-newsgroup-dependencies)))
 
-;; The following macros and functions were written by Felix Lee
-;; <flee@cse.psu.edu>.
-
-(defmacro gnus-nov-read-integer ()
-  '(prog1
-       (if (= (following-char) ?\t)
-	   0
-	 (let ((num (ignore-errors (read buffer))))
-	   (if (numberp num) num 0)))
-     (unless (eobp)
-       (search-forward "\t" eol 'move))))
-
-(defmacro gnus-nov-skip-field ()
-  '(search-forward "\t" eol 'move))
-
-(defmacro gnus-nov-field ()
-  '(buffer-substring (point) (if (gnus-nov-skip-field) (1- (point)) eol)))
-
 ;; This function has to be called with point after the article number
 ;; on the beginning of the line.
 (defsubst gnus-nov-parse-line (number dependencies &optional force-new)
@@ -3081,18 +3290,18 @@
 	  (setq header
 		(make-full-mail-header
 		 number			; number
-		 (funcall
-		  gnus-unstructured-field-decoder (gnus-nov-field)) ; subject
-		 (funcall
-		  gnus-structured-field-decoder (gnus-nov-field)) ; from
-		 (gnus-nov-field)	; date
-		 (or (gnus-nov-field)
-		     (nnheader-generate-fake-message-id)) ; id
-		 (gnus-nov-field)	; refs
-		 (gnus-nov-read-integer) ; chars
-		 (gnus-nov-read-integer) ; lines
-		 (unless (= (following-char) ?\n)
-		   (gnus-nov-field)))))	; misc
+		 (funcall gnus-decode-encoded-word-function
+			  (nnheader-nov-field))	; subject
+		 (funcall gnus-decode-encoded-word-function
+			  (nnheader-nov-field))	; from
+		 (nnheader-nov-field)	; date
+		 (nnheader-nov-read-message-id)	; id
+		 (nnheader-nov-field)	; refs
+		 (nnheader-nov-read-integer) ; chars
+		 (nnheader-nov-read-integer) ; lines
+		 (unless (eobp)
+		   (nnheader-nov-field)) ; misc
+		 (nnheader-nov-parse-extra)))) ; extra
 
       (widen))
 
@@ -3101,9 +3310,9 @@
     (gnus-dependencies-add-header header dependencies force-new)))
 
 (defun gnus-build-get-header (id)
-  ;; Look through the buffer of NOV lines and find the header to
-  ;; ID.  Enter this line into the dependencies hash table, and return
-  ;; the id of the parent article (if any).
+  "Look through the buffer of NOV lines and find the header to ID.
+Enter this line into the dependencies hash table, and return
+the id of the parent article (if any)."
   (let ((deps gnus-newsgroup-dependencies)
 	found header)
     (prog1
@@ -3138,6 +3347,7 @@
 (defun gnus-build-all-threads ()
   "Read all the headers."
   (let ((gnus-summary-ignore-duplicates t)
+	(mail-parse-charset gnus-newsgroup-charset)
 	(dependencies gnus-newsgroup-dependencies)
 	header article)
     (save-excursion
@@ -3147,8 +3357,7 @@
 	(while (not (eobp))
 	  (ignore-errors
 	    (setq article (read (current-buffer))
-		  header (gnus-nov-parse-line
-			  article dependencies)))
+		  header (gnus-nov-parse-line article dependencies)))
 	  (when header
 	    (save-excursion
 	      (set-buffer gnus-summary-buffer)
@@ -3185,17 +3394,19 @@
        (memq article gnus-newsgroup-expirable)
        ;; Only insert the Subject string when it's different
        ;; from the previous Subject string.
-       (if (gnus-subject-equal
-	    (condition-case ()
-		(mail-header-subject
-		 (gnus-data-header
-		  (cadr
-		   (gnus-data-find-list
-		    article
-		    (gnus-data-list t)))))
-	      ;; Error on the side of excessive subjects.
-	      (error ""))
-	    (mail-header-subject header))
+       (if (and
+	    gnus-show-threads
+	    (gnus-subject-equal
+	     (condition-case ()
+		 (mail-header-subject
+		  (gnus-data-header
+		   (cadr
+		    (gnus-data-find-list
+		     article
+		     (gnus-data-list t)))))
+	       ;; Error on the side of excessive subjects.
+	       (error ""))
+	     (mail-header-subject header)))
 	   ""
 	 (mail-header-subject header))
        nil (cdr (assq article gnus-newsgroup-scored))
@@ -3409,7 +3620,6 @@
 		  (while thread
 		    (gnus-remove-thread-1 (car thread))
 		    (setq thread (cdr thread))))
-	      (gnus-summary-show-all-threads)
 	      (gnus-remove-thread-1 thread))))))))
 
 (defun gnus-remove-thread-1 (thread)
@@ -3421,6 +3631,7 @@
       (gnus-remove-thread-1 (pop thread)))
     (when (setq d (gnus-data-find number))
       (goto-char (gnus-data-pos d))
+      (gnus-summary-show-thread)
       (gnus-data-remove
        number
        (- (gnus-point-at-bol)
@@ -3428,13 +3639,22 @@
 	      (1+ (gnus-point-at-eol))
 	    (gnus-delete-line)))))))
 
+(defun gnus-sort-threads-1 (threads func)
+  (sort (mapcar (lambda (thread)
+		  (cons (car thread)
+			(and (cdr thread)
+			     (gnus-sort-threads-1 (cdr thread) func))))
+		threads) func))
+
 (defun gnus-sort-threads (threads)
   "Sort THREADS."
   (if (not gnus-thread-sort-functions)
       threads
     (gnus-message 8 "Sorting threads...")
     (prog1
-	(sort threads (gnus-make-sort-function gnus-thread-sort-functions))
+	(gnus-sort-threads-1 
+	 threads 
+	 (gnus-make-sort-function gnus-thread-sort-functions))
       (gnus-message 8 "Sorting threads...done"))))
 
 (defun gnus-sort-articles (articles)
@@ -3449,12 +3669,12 @@
 
 ;; Written by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
 (defmacro gnus-thread-header (thread)
-  ;; Return header of first article in THREAD.
-  ;; Note that THREAD must never, ever be anything else than a variable -
-  ;; using some other form will lead to serious barfage.
+  "Return header of first article in THREAD.
+Note that THREAD must never, ever be anything else than a variable -
+using some other form will lead to serious barfage."
   (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread)))
   ;; (8% speedup to gnus-summary-prepare, just for fun :-)
-  (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207" ;
+  (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207"
 	(vector thread) 2))
 
 (defsubst gnus-article-sort-by-number (h1 h2)
@@ -3477,6 +3697,16 @@
   (gnus-article-sort-by-lines
    (gnus-thread-header h1) (gnus-thread-header h2)))
 
+(defsubst gnus-article-sort-by-chars (h1 h2)
+  "Sort articles by octet length."
+  (< (mail-header-chars h1)
+     (mail-header-chars h2)))
+
+(defun gnus-thread-sort-by-chars (h1 h2)
+  "Sort threads by root article octet length."
+  (gnus-article-sort-by-chars
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
 (defsubst gnus-article-sort-by-author (h1 h2)
   "Sort articles by root author."
   (string-lessp
@@ -3507,7 +3737,7 @@
 
 (defsubst gnus-article-sort-by-date (h1 h2)
   "Sort articles by root article date."
-  (gnus-time-less
+  (time-less-p
    (gnus-date-get-time (mail-header-date h1))
    (gnus-date-get-time (mail-header-date h2))))
 
@@ -3537,7 +3767,7 @@
   (> (gnus-thread-total-score h1) (gnus-thread-total-score h2)))
 
 (defun gnus-thread-total-score (thread)
-  ;;  This function find the total score of THREAD.
+  ;; This function find the total score of THREAD.
   (cond ((null thread)
 	 0)
 	((consp thread)
@@ -3568,6 +3798,12 @@
 (defvar gnus-tmp-root-expunged nil)
 (defvar gnus-tmp-dummy-line nil)
 
+(defvar gnus-tmp-header)
+(defun gnus-extra-header (type &optional header)
+  "Return the extra header of TYPE."
+  (or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
+      ""))
+
 (defun gnus-summary-prepare-threads (threads)
   "Prepare summary buffer from THREADS and indentation LEVEL.
 THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
@@ -3765,7 +4001,7 @@
 	     (if (or (null gnus-summary-default-score)
 		     (<= (abs (- gnus-tmp-score gnus-summary-default-score))
 			 gnus-summary-zcore-fuzz))
-		 ? ;space
+		 ?  ;Whitespace
 	       (if (< gnus-tmp-score gnus-summary-default-score)
 		   gnus-score-below-mark gnus-score-over-mark))
 	     gnus-tmp-replied
@@ -3795,7 +4031,7 @@
 	      (setq gnus-tmp-name gnus-tmp-from))
 	    (unless (numberp gnus-tmp-lines)
 	      (setq gnus-tmp-lines 0))
-	    (gnus-put-text-property-excluding-characters-with-faces
+	    (gnus-put-text-property
 	     (point)
 	     (progn (eval gnus-summary-line-format-spec) (point))
 	     'gnus-number number)
@@ -3849,6 +4085,24 @@
 	 (cdr (assq number gnus-newsgroup-scored))
 	 (memq number gnus-newsgroup-processable))))))
 
+(defun gnus-summary-remove-list-identifiers ()
+  "Remove list identifiers in `gnus-list-identifiers' from articles in the current group."
+  (let ((regexp (if (stringp gnus-list-identifiers)
+		    gnus-list-identifiers
+		  (mapconcat 'identity gnus-list-identifiers " *\\|"))))
+    (dolist (header gnus-newsgroup-headers)
+      (when (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp 
+				  " *\\)\\)+\\(Re: +\\)?\\)")
+			  (mail-header-subject header))
+	(mail-header-set-subject
+	 header (concat (substring (mail-header-subject header)
+				   0 (match-beginning 1))
+			(or
+			 (match-string 3 (mail-header-subject header))
+			 (match-string 5 (mail-header-subject header)))
+			(substring (mail-header-subject header)
+				   (match-end 1))))))))
+
 (defun gnus-select-newsgroup (group &optional read-all select-articles)
   "Select newsgroup GROUP.
 If READ-ALL is non-nil, all articles in the group are selected.
@@ -3884,6 +4138,7 @@
     (setq gnus-newsgroup-name group)
     (setq gnus-newsgroup-unselected nil)
     (setq gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
+    (gnus-summary-setup-default-charset)
 
     ;; Adjust and set lists of article marks.
     (when info
@@ -3918,6 +4173,7 @@
       ;; Init the dependencies hash table.
       (setq gnus-newsgroup-dependencies
 	    (gnus-make-hashtable (length articles)))
+      (gnus-set-global-variables)
       ;; Retrieve the headers and read them in.
       (gnus-message 5 "Fetching headers for %s..." gnus-newsgroup-name)
       (setq gnus-newsgroup-headers
@@ -3966,6 +4222,9 @@
       ;; Let the Gnus agent mark articles as read.
       (when gnus-agent
 	(gnus-agent-get-undownloaded-list))
+      ;; Remove list identifiers from subject
+      (when gnus-list-identifiers
+	(gnus-summary-remove-list-identifiers))
       ;; Check whether auto-expire is to be done in this group.
       (setq gnus-newsgroup-auto-expire
 	    (gnus-group-auto-expirable-p group))
@@ -3983,7 +4242,7 @@
       (or gnus-newsgroup-headers t)))))
 
 (defun gnus-articles-to-read (group &optional read-all)
-  ;; Find out what articles the user wants to read.
+  "Find out what articles the user wants to read."
   (let* ((articles
 	  ;; Select all articles if `read-all' is non-nil, or if there
 	  ;; are no unread articles.
@@ -3992,7 +4251,9 @@
 		       (zerop (length gnus-newsgroup-unreads)))
 		  (eq (gnus-group-find-parameter group 'display)
 		      'all))
-	      (gnus-uncompress-range (gnus-active group))
+	      (or
+	       (gnus-uncompress-range (gnus-active group))
+	       (gnus-cache-articles-in-group group))
 	    (sort (append gnus-newsgroup-dormant gnus-newsgroup-marked
 			  (copy-sequence gnus-newsgroup-unreads))
 		  '<)))
@@ -4048,6 +4309,12 @@
 	    (gnus-sorted-intersection
 	     gnus-newsgroup-unreads
 	     (gnus-sorted-complement gnus-newsgroup-unreads articles)))
+      (when gnus-alter-articles-to-read-function
+	(setq gnus-newsgroup-unreads
+	      (sort 
+	       (funcall gnus-alter-articles-to-read-function
+			gnus-newsgroup-name gnus-newsgroup-unreads)
+	       '<)))
       articles)))
 
 (defun gnus-killed-articles (killed articles)
@@ -4070,7 +4337,7 @@
     out))
 
 (defun gnus-adjust-marked-articles (info)
-  "Set all article lists and remove all marks that are no longer legal."
+  "Set all article lists and remove all marks that are no longer valid."
   (let* ((marked-lists (gnus-info-marks info))
 	 (active (gnus-active (gnus-info-group info)))
 	 (min (car active))
@@ -4128,15 +4395,16 @@
   (let ((types gnus-article-mark-lists)
 	(info (gnus-get-info gnus-newsgroup-name))
 	(uncompressed '(score bookmark killed))
-	type list newmarked symbol)
+	type list newmarked symbol delta-marks)
     (when info
-      ;; Add all marks lists that are non-nil to the list of marks lists.
+      ;; Add all marks lists to the list of marks lists.
       (while (setq type (pop types))
-	(when (setq list (symbol-value
-			  (setq symbol
-				(intern (format "gnus-newsgroup-%s"
-						(car type))))))
-
+	(setq list (symbol-value
+		    (setq symbol
+			  (intern (format "gnus-newsgroup-%s"
+					  (car type))))))
+
+	(when list
 	  ;; Get rid of the entries of the articles that have the
 	  ;; default score.
 	  (when (and (eq (cdr type) 'score)
@@ -4151,14 +4419,38 @@
 		    (setcdr prev (cdr arts))
 		  (setq prev arts))
 		(setq arts (cdr arts)))
-	      (setq list (cdr all))))
-
-	  (push (cons (cdr type)
-		      (if (memq (cdr type) uncompressed) list
-			(gnus-compress-sequence
-			 (set symbol (sort list '<)) t)))
-		newmarked)))
-
+	      (setq list (cdr all)))))
+
+	(unless (memq (cdr type) uncompressed)
+	  (setq list (gnus-compress-sequence (set symbol (sort list '<)) t)))
+       
+	(when (gnus-check-backend-function
+	       'request-set-mark gnus-newsgroup-name)
+	  ;; propagate flags to server, with the following exceptions:
+	  ;; uncompressed:s are not proper flags (they are cons cells)
+	  ;; cache is a internal gnus flag
+	  ;; download are local to one gnus installation (well)
+	  ;; unsend are for nndraft groups only
+	  ;; xxx: generality of this?  this suits nnimap anyway
+	  (unless (memq (cdr type) (append '(cache download unsend)
+					   uncompressed))
+	    (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
+		   (del (gnus-remove-from-range (gnus-copy-sequence old) list))
+		   (add (gnus-remove-from-range
+			 (gnus-copy-sequence list) old)))
+	      (when add
+		(push (list add 'add (list (cdr type))) delta-marks))
+	      (when del
+		(push (list del 'del (list (cdr type))) delta-marks)))))
+	  
+	(when list
+	  (push (cons (cdr type) list) newmarked)))
+
+      (when delta-marks
+	(unless (gnus-check-group gnus-newsgroup-name)
+	  (error "Can't open server for %s" gnus-newsgroup-name))
+	(gnus-request-set-mark gnus-newsgroup-name delta-marks))
+	  
       ;; Enter these new marks into the info of the group.
       (if (nthcdr 3 info)
 	  (setcar (nthcdr 3 info) newmarked)
@@ -4174,10 +4466,12 @@
 	    (setcdr (nthcdr i info) nil)))))))
 
 (defun gnus-set-mode-line (where)
-  "This function sets the mode line of the article or summary buffers.
+  "Set the mode line of the article or summary buffers.
 If WHERE is `summary', the summary mode line format will be used."
   ;; Is this mode line one we keep updated?
-  (when (memq where gnus-updated-mode-lines)
+  (when (and (memq where gnus-updated-mode-lines)
+	     (symbol-value
+	      (intern (format "gnus-%s-mode-line-format-spec" where))))
     (let (mode-string)
       (save-excursion
 	;; We evaluate this in the summary buffer since these
@@ -4188,7 +4482,11 @@
 	(let* ((mformat (symbol-value
 			 (intern
 			  (format "gnus-%s-mode-line-format-spec" where))))
-	       (gnus-tmp-group-name gnus-newsgroup-name)
+	       (gnus-tmp-group-name (gnus-group-name-decode 
+				     gnus-newsgroup-name
+				     (gnus-group-name-charset 
+				      nil
+				      gnus-newsgroup-name)))
 	       (gnus-tmp-article-number (or gnus-current-article 0))
 	       (gnus-tmp-unread gnus-newsgroup-unreads)
 	       (gnus-tmp-unread-and-unticked (length gnus-newsgroup-unreads))
@@ -4227,7 +4525,7 @@
 	  ;; We might have to chop a bit of the string off...
 	  (when (> (length mode-string) max-len)
 	    (setq mode-string
-		  (concat (gnus-truncate-string mode-string (- max-len 3))
+		  (concat (truncate-string-to-width mode-string (- max-len 3))
 			  "...")))
 	  ;; Pad the mode string a bit.
 	  (setq mode-string (format (format "%%-%ds" max-len) mode-string))))
@@ -4305,7 +4603,7 @@
 	 (active (gnus-active group))
 	 ninfo)
     (when entry
-      ;; First peel off all illegal article numbers.
+      ;; First peel off all invalid article numbers.
       (when active
 	(let ((ids articles)
 	      id first)
@@ -4374,15 +4672,6 @@
 	;; Update the group buffer.
 	(gnus-group-update-group group t)))))
 
-(defun gnus-methods-equal-p (m1 m2)
-  (let ((m1 (or m1 gnus-select-method))
-	(m2 (or m2 gnus-select-method)))
-    (or (equal m1 m2)
-	(and (eq (car m1) (car m2))
-	     (or (not (memq 'address (assoc (symbol-name (car m1))
-					    gnus-valid-select-methods)))
-		 (equal (nth 1 m1) (nth 1 m2)))))))
-
 (defvar gnus-newsgroup-none-id 0)
 
 (defun gnus-get-newsgroup-headers (&optional dependencies force-new)
@@ -4391,11 +4680,18 @@
 	 (or dependencies
 	     (save-excursion (set-buffer gnus-summary-buffer)
 			     gnus-newsgroup-dependencies)))
-	headers id end ref)
+	headers id end ref
+	(mail-parse-charset gnus-newsgroup-charset)
+	(mail-parse-ignored-charsets
+	 (save-excursion (condition-case nil
+			     (set-buffer gnus-summary-buffer)
+			   (error))
+			 gnus-newsgroup-ignored-charsets)))
     (save-excursion
       (set-buffer nntp-server-buffer)
       ;; Translate all TAB characters into SPACE characters.
       (subst-char-in-region (point-min) (point-max) ?\t ?  t)
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (let ((case-fold-search t)
 	    in-reply-to header p lines chars)
@@ -4427,15 +4723,15 @@
 	    (progn
 	      (goto-char p)
 	      (if (search-forward "\nsubject: " nil t)
-		  (funcall
-		   gnus-unstructured-field-decoder (nnheader-header-value))
+		  (funcall gnus-decode-encoded-word-function
+			   (nnheader-header-value))
 		"(none)"))
 	    ;; From.
 	    (progn
 	      (goto-char p)
 	      (if (search-forward "\nfrom: " nil t)
-		  (funcall
-		   gnus-structured-field-decoder (nnheader-header-value))
+		  (funcall gnus-decode-encoded-word-function
+			   (nnheader-header-value))
 		"(nobody)"))
 	    ;; Date.
 	    (progn
@@ -4505,7 +4801,19 @@
 	    (progn
 	      (goto-char p)
 	      (and (search-forward "\nxref: " nil t)
-		   (nnheader-header-value)))))
+		   (nnheader-header-value)))
+	    ;; Extra.
+	    (when gnus-extra-headers
+	      (let ((extra gnus-extra-headers)
+		    out)
+		(while extra
+		  (goto-char p)
+		  (when (search-forward
+			 (concat "\n" (symbol-name (car extra)) ": ") nil t)
+		    (push (cons (car extra) (nnheader-header-value))
+			  out))
+		  (pop extra))
+		out))))
 	  (when (equal id ref)
 	    (setq ref nil))
 
@@ -4526,16 +4834,20 @@
 (defun gnus-get-newsgroup-headers-xover (sequence &optional
 						  force-new dependencies
 						  group also-fetch-heads)
-  "Parse the news overview data in the server buffer, and return a
-list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
+  "Parse the news overview data in the server buffer.
+Return a list of headers that match SEQUENCE (see
+`nntp-retrieve-headers')."
   ;; Get the Xref when the users reads the articles since most/some
   ;; NNTP servers do not include Xrefs when using XOVER.
   (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
-  (let ((cur nntp-server-buffer)
+  (let ((mail-parse-charset gnus-newsgroup-charset)
+	(mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+	(cur nntp-server-buffer)
 	(dependencies (or dependencies gnus-newsgroup-dependencies))
 	number headers header)
     (save-excursion
       (set-buffer nntp-server-buffer)
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
       ;; Allow the user to mangle the headers before parsing them.
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (goto-char (point-min))
@@ -4589,7 +4901,8 @@
 	  (save-restriction
 	    (nnheader-narrow-to-headers)
 	    (goto-char (point-min))
-	    (when (or (and (eq (downcase (following-char)) ?x)
+	    (when (or (and (not (eobp))
+			   (eq (downcase (char-after)) ?x)
 			   (looking-at "Xref:"))
 		      (search-forward "\nXref:" nil t))
 	      (goto-char (1+ (match-end 0)))
@@ -4604,14 +4917,14 @@
   (let* ((line (and (numberp old-header) old-header))
 	 (old-header (and (vectorp old-header) old-header))
 	 (header (cond ((and old-header use-old-header)
-		       old-header)
-		      ((and (numberp id)
-			    (gnus-number-to-header id))
-		       (gnus-number-to-header id))
-		      (t
-		       (gnus-read-header id))))
-	(number (and (numberp id) id))
-	d)
+			old-header)
+		       ((and (numberp id)
+			     (gnus-number-to-header id))
+			(gnus-number-to-header id))
+		       (t
+			(gnus-read-header id))))
+	 (number (and (numberp id) id))
+	 d)
     (when header
       ;; Rebuild the thread that this article is part of and go to the
       ;; article we have fetched.
@@ -4706,7 +5019,8 @@
     `(let ((,articles (gnus-summary-work-articles ,arg)))
        (while ,articles
 	 (gnus-summary-goto-subject (car ,articles))
-	 ,@forms))))
+	 ,@forms
+	 (pop ,articles)))))
 
 (put 'gnus-summary-iterate 'lisp-indent-function 1)
 (put 'gnus-summary-iterate 'edebug-form-spec '(form body))
@@ -4851,9 +5165,12 @@
 displayed, no centering will be performed."
   ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
   ;; Recenter only when requested.  Suggested by popovich@park.cs.columbia.edu.
+  (interactive)
   (let* ((top (cond ((< (window-height) 4) 0)
 		    ((< (window-height) 7) 1)
-		    (t 2)))
+		    (t (if (numberp gnus-auto-center-summary)
+			   gnus-auto-center-summary
+			 2))))
 	 (height (1- (window-height)))
 	 (bottom (save-excursion (goto-char (point-max))
 				 (forward-line (- height))
@@ -4868,7 +5185,8 @@
 	;; whichever is the least.
 	(set-window-start
 	 window (min bottom (save-excursion
-			      (forward-line (- top)) (point)))))
+			      (forward-line (- top)) (point)))
+	 t))
       ;; Do horizontal recentering while we're at it.
       (when (and (get-buffer-window (current-buffer) t)
 		 (not (eq gnus-auto-center-summary 'vertical)))
@@ -4908,7 +5226,10 @@
       ;; If the range of read articles is a single range, then the
       ;; first unread article is the article after the last read
       ;; article.  Sounds logical, doesn't it?
-      (if (not (listp (cdr read)))
+      (if (and (not (listp (cdr read)))
+	       (or (< (car read) (car active))
+		   (progn (setq read (list read))
+			  nil)))
 	  (setq first (max (car active) (1+ (cdr read))))
 	;; `read' is a list of ranges.
 	(when (/= (setq nlast (or (and (numberp (car read)) (car read))
@@ -4965,8 +5286,7 @@
 	  (key-binding
 	   (read-key-sequence
 	    (substitute-command-keys
-	     "\\<gnus-summary-mode-map>\\[gnus-summary-universal-argument]"
-	     ))))
+	     "\\<gnus-summary-mode-map>\\[gnus-summary-universal-argument]"))))
 	 'undefined)
 	(gnus-error 1 "Undefined key")
       (save-excursion
@@ -5062,9 +5382,16 @@
 
 (defun gnus-summary-exit (&optional temporary)
   "Exit reading current newsgroup, and then return to group selection mode.
-gnus-exit-group-hook is called with no arguments if that value is non-nil."
+`gnus-exit-group-hook' is called with no arguments if that value is non-nil."
   (interactive)
   (gnus-set-global-variables)
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (save-excursion
+      (set-buffer gnus-article-buffer)
+      (mm-destroy-parts gnus-article-mime-handles)
+      ;; Set it to nil for safety reason.
+      (setq gnus-article-mime-handle-alist nil)
+      (setq gnus-article-mime-handles nil)))
   (gnus-kill-save-kill-buffer)
   (gnus-async-halt-prefetch)
   (let* ((group gnus-newsgroup-name)
@@ -5072,6 +5399,12 @@
 	 (mode major-mode)
          (group-point nil)
 	 (buf (current-buffer)))
+    (unless quit-config
+      ;; Do adaptive scoring, and possibly save score files.
+      (when gnus-newsgroup-adaptive
+	(gnus-score-adaptive))
+      (when gnus-use-scoring
+	(gnus-score-save)))
     (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
     ;; If we have several article buffers, we kill them at exit.
     (unless gnus-single-article-buffer
@@ -5085,17 +5418,14 @@
       (gnus-dup-enter-articles))
     (when gnus-use-trees
       (gnus-tree-close group))
+    (when gnus-use-cache
+      (gnus-cache-write-active))
     ;; Remove entries for this group.
     (nnmail-purge-split-history (gnus-group-real-name group))
     ;; Make all changes in this group permanent.
     (unless quit-config
       (gnus-run-hooks 'gnus-exit-group-hook)
-      (gnus-summary-update-info)
-      ;; Do adaptive scoring, and possibly save score files.
-      (when gnus-newsgroup-adaptive
-	(gnus-score-adaptive))
-      (when gnus-use-scoring
-	(gnus-score-save)))
+      (gnus-summary-update-info))
     (gnus-close-group group)
     ;; Make sure where we were, and go to next newsgroup.
     (set-buffer gnus-group-buffer)
@@ -5153,7 +5483,16 @@
 	      gnus-expert-user
 	      (gnus-y-or-n-p "Discard changes to this group and exit? "))
       (gnus-async-halt-prefetch)
-      (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
+      (mapcar 'funcall
+	      (delq 'gnus-summary-expire-articles
+		    (copy-sequence gnus-summary-prepare-exit-hook)))
+      (when (gnus-buffer-live-p gnus-article-buffer)
+	(save-excursion
+	  (set-buffer gnus-article-buffer)
+	  (mm-destroy-parts gnus-article-mime-handles)
+	  ;; Set it to nil for safety reason.
+	  (setq gnus-article-mime-handle-alist nil)
+	  (setq gnus-article-mime-handles nil)))
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
 	(gnus-kill-buffer gnus-article-buffer)
@@ -5261,7 +5600,8 @@
       (rename-buffer
        (concat (substring name 0 (match-beginning 0)) "Dead "
 	       (substring name (match-beginning 0)))
-       t))))
+       t)
+      (bury-buffer))))
 
 (defun gnus-kill-or-deaden-summary (buffer)
   "Kill or deaden the summary BUFFER."
@@ -5322,8 +5662,7 @@
 (defun gnus-summary-describe-briefly ()
   "Describe summary mode commands briefly."
   (interactive)
-  (gnus-message 6
-		(substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select  \\[gnus-summary-next-unread-article]:Forward  \\[gnus-summary-prev-unread-article]:Backward  \\[gnus-summary-exit]:Exit  \\[gnus-info-find-node]:Run Info	 \\[gnus-summary-describe-briefly]:This help")))
+  (gnus-message 6 (substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select  \\[gnus-summary-next-unread-article]:Forward  \\[gnus-summary-prev-unread-article]:Backward  \\[gnus-summary-exit]:Exit  \\[gnus-info-find-node]:Run Info	 \\[gnus-summary-describe-briefly]:This help")))
 
 ;; Walking around group mode buffer from summary mode.
 
@@ -5429,8 +5768,8 @@
 		(if backward
 		    (gnus-summary-find-prev unread)
 		  (gnus-summary-find-next unread)))
-      (gnus-summary-show-thread)
-      (setq n (1- n)))
+      (unless (zerop (setq n (1- n)))
+	(gnus-summary-show-thread)))
     (when (/= 0 n)
       (gnus-message 7 "No more%s articles"
 		    (if unread " unread" "")))
@@ -5521,35 +5860,41 @@
     (set-buffer gnus-summary-buffer))
   (let ((article (or article (gnus-summary-article-number)))
 	(all-headers (not (not all-headers))) ;Must be T or NIL.
-	gnus-summary-display-article-function
-	did)
+	gnus-summary-display-article-function)
     (and (not pseudo)
 	 (gnus-summary-article-pseudo-p article)
 	 (error "This is a pseudo-article"))
-    (prog1
-	(save-excursion
-	  (set-buffer gnus-summary-buffer)
-	  (if (or (and gnus-single-article-buffer
-		       (or (null gnus-current-article)
-			   (null gnus-article-current)
-			   (null (get-buffer gnus-article-buffer))
-			   (not (eq article (cdr gnus-article-current)))
-			   (not (equal (car gnus-article-current)
-				       gnus-newsgroup-name))))
-		  (and (not gnus-single-article-buffer)
-		       (or (null gnus-current-article)
-			   (not (eq gnus-current-article article))))
-		  force)
-	      ;; The requested article is different from the current article.
-	      (prog1
-		  (gnus-summary-display-article article all-headers)
-		(setq did article))
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (if (or (and gnus-single-article-buffer
+		   (or (null gnus-current-article)
+		       (null gnus-article-current)
+		       (null (get-buffer gnus-article-buffer))
+		       (not (eq article (cdr gnus-article-current)))
+		       (not (equal (car gnus-article-current)
+				   gnus-newsgroup-name))))
+	      (and (not gnus-single-article-buffer)
+		   (or (null gnus-current-article)
+		       (not (eq gnus-current-article article))))
+	      force)
+	  ;; The requested article is different from the current article.
+	  (progn
+	    (when (gnus-buffer-live-p gnus-article-buffer)
+	      (with-current-buffer gnus-article-buffer
+		(mm-enable-multibyte)))
+	    (gnus-summary-display-article article all-headers)
+	    (when (gnus-buffer-live-p gnus-article-buffer)
+	      (with-current-buffer gnus-article-buffer
+		(if (not gnus-article-decoded-p) ;; a local variable
+		    (mm-disable-multibyte))))
 	    (when (or all-headers gnus-show-all-headers)
 	      (gnus-article-show-all-headers))
-	    'old))
-      (when did
-	(gnus-article-set-window-start
-	 (cdr (assq article gnus-newsgroup-bookmarks)))))))
+	    (gnus-article-set-window-start
+	     (cdr (assq article gnus-newsgroup-bookmarks)))
+	    article)
+	(when (or all-headers gnus-show-all-headers)
+	  (gnus-article-show-all-headers))
+	'old))))
 
 (defun gnus-summary-set-current-mark (&optional current-mark)
   "Obsolete function."
@@ -5821,15 +6166,25 @@
 	(gnus-summary-display-article (gnus-summary-article-number)))
     (gnus-summary-position-point)))
 
+(defun gnus-summary-first-unread-subject ()
+  "Place the point on the subject line of the first unread article.
+Return nil if there are no unread articles."
+  (interactive)
+  (prog1
+      (when (gnus-summary-first-subject t)
+	(gnus-summary-show-thread)
+	(gnus-summary-first-subject t))
+    (gnus-summary-position-point)))
+
 (defun gnus-summary-first-article ()
   "Select the first article.
 Return nil if there are no articles."
   (interactive)
   (prog1
       (when (gnus-summary-first-subject)
-      (gnus-summary-show-thread)
-      (gnus-summary-first-subject)
-      (gnus-summary-display-article (gnus-summary-article-number)))
+	(gnus-summary-show-thread)
+	(gnus-summary-first-subject)
+	(gnus-summary-display-article (gnus-summary-article-number)))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-best-unread-article ()
@@ -5951,16 +6306,32 @@
   "Limit the summary buffer to articles that are older than (or equal) AGE days.
 If YOUNGER-P (the prefix) is non-nil, limit the summary buffer to
 articles that are younger than AGE days."
-  (interactive "nTime in days: \nP")
+  (interactive
+   (let ((younger current-prefix-arg)
+	 (days-got nil)
+	 days)
+     (while (not days-got)
+       (setq days (if younger
+		      (read-string "Limit to articles within (in days): ")
+		    (read-string "Limit to articles old than (in days): ")))
+       (when (> (length days) 0)
+	 (setq days (read days)))
+       (if (numberp days)
+	   (setq days-got t)
+	 (message "Please enter a number.")
+	 (sleep-for 1)))
+     (list days younger)))
   (prog1
       (let ((data gnus-newsgroup-data)
-	    (cutoff (nnmail-days-to-time age))
+	    (cutoff (days-to-time age))
 	    articles d date is-younger)
 	(while (setq d (pop data))
 	  (when (and (vectorp (gnus-data-header d))
 		     (setq date (mail-header-date (gnus-data-header d))))
-	    (setq is-younger (nnmail-time-less
-			      (nnmail-time-since (nnmail-date-to-time date))
+	    (setq is-younger (time-less-p
+			      (time-since (condition-case ()
+					      (date-to-time date)
+					    (error '(0 0))))
 			      cutoff))
 	    (when (if younger-p
 		      is-younger
@@ -5969,6 +6340,30 @@
 	(gnus-summary-limit (nreverse articles)))
     (gnus-summary-position-point)))
 
+(defun gnus-summary-limit-to-extra (header regexp)
+  "Limit the summary buffer to articles that match an 'extra' header."
+  (interactive
+   (let ((header
+	  (intern
+	   (gnus-completing-read
+	    (symbol-name (car gnus-extra-headers))
+	    "Limit extra header:"
+	    (mapcar (lambda (x)
+		      (cons (symbol-name x) x))
+		    gnus-extra-headers)
+	    nil
+	    t))))
+     (list header
+	   (read-string (format "Limit to header %s (regexp): " header)))))
+  (when (not (equal "" regexp))
+    (prog1
+	(let ((articles (gnus-summary-find-matching
+			 (cons 'extra header) regexp 'all)))
+	  (unless articles
+	    (error "Found no matches for \"%s\"" regexp))
+	  (gnus-summary-limit articles))
+      (gnus-summary-position-point))))
+
 (defalias 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
 (make-obsolete
  'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
@@ -6166,6 +6561,7 @@
   "Go forwards in the thread until we find an article that we want to display."
   (when (or (eq gnus-fetch-old-headers 'some)
 	    (eq gnus-fetch-old-headers 'invisible)
+	    (numberp gnus-fetch-old-headers)
 	    (eq gnus-build-sparse-threads 'some)
 	    (eq gnus-build-sparse-threads 'more))
     ;; Deal with old-fetched headers and sparse threads.
@@ -6195,6 +6591,7 @@
   "Cut off all uninteresting articles from the beginning of threads."
   (when (or (eq gnus-fetch-old-headers 'some)
 	    (eq gnus-fetch-old-headers 'invisible)
+	    (numberp gnus-fetch-old-headers)
 	    (eq gnus-build-sparse-threads 'some)
 	    (eq gnus-build-sparse-threads 'more))
     (let ((th threads))
@@ -6212,6 +6609,7 @@
   (if (or gnus-inhibit-limiting
 	  (and (null gnus-newsgroup-dormant)
 	       (not (eq gnus-fetch-old-headers 'some))
+	       (not (numberp gnus-fetch-old-headers))
 	       (not (eq gnus-fetch-old-headers 'invisible))
 	       (null gnus-summary-expunge-below)
 	       (not (eq gnus-build-sparse-threads 'some))
@@ -6265,7 +6663,8 @@
 		 (zerop children))
 	    ;; If this is "fetch-old-headered" and there is no
 	    ;; visible children, then we don't want this article.
-	    (and (eq gnus-fetch-old-headers 'some)
+	    (and (or (eq gnus-fetch-old-headers 'some)
+		     (numberp gnus-fetch-old-headers))
 		 (gnus-summary-article-ancient-p number)
 		 (zerop children))
 	    ;; If this is "fetch-old-headered" and `invisible', then
@@ -6416,11 +6815,9 @@
       (gnus-message 5 "Fetching headers for %s...done" gnus-newsgroup-name))
     (gnus-summary-limit-include-thread id)))
 
-(defun gnus-summary-refer-article (message-id &optional arg)
-  "Fetch an article specified by MESSAGE-ID.
-If ARG (the prefix), fetch the article using `gnus-refer-article-method'
-or `gnus-select-method', no matter what backend the article comes from."
-  (interactive "sMessage-ID: \nP")
+(defun gnus-summary-refer-article (message-id)
+  "Fetch an article specified by MESSAGE-ID."
+  (interactive "sMessage-ID: ")
   (when (and (stringp message-id)
 	     (not (zerop (length message-id))))
     ;; Construct the correct Message-ID if necessary.
@@ -6434,7 +6831,8 @@
 			(gnus-summary-article-sparse-p
 			 (mail-header-number header))
 			(memq (mail-header-number header)
-			      gnus-newsgroup-limit))))
+			      gnus-newsgroup-limit)))
+	   number)
       (cond
        ;; If the article is present in the buffer we just go to it.
        ((and header
@@ -6447,28 +6845,48 @@
 	  (when sparse
 	    (gnus-summary-update-article (mail-header-number header)))))
        (t
-	;; We fetch the article
-	(let ((gnus-override-method
-	       (cond ((gnus-news-group-p gnus-newsgroup-name)
-		      gnus-refer-article-method)
-		     (arg
-		      (or gnus-refer-article-method gnus-select-method))
-		     (t nil)))
-	      number)
-	  ;; Start the special refer-article method, if necessary.
-	  (when (and gnus-refer-article-method
-		     (gnus-news-group-p gnus-newsgroup-name))
-	    (gnus-check-server gnus-refer-article-method))
-	  ;; Fetch the header, and display the article.
-	  (if (setq number (gnus-summary-insert-subject message-id))
+	;; We fetch the article.
+	(catch 'found
+	  (dolist (gnus-override-method (gnus-refer-article-methods))
+	    (gnus-check-server gnus-override-method)
+	    ;; Fetch the header, and display the article.
+	    (when (setq number (gnus-summary-insert-subject message-id))
 	      (gnus-summary-select-article nil nil nil number)
-	    (gnus-message 3 "Couldn't fetch article %s" message-id))))))))
+	      (throw 'found t)))
+	  (gnus-message 3 "Couldn't fetch article %s" message-id)))))))
+
+(defun gnus-refer-article-methods ()
+  "Return a list of referrable methods."
+  (cond
+   ;; No method, so we default to current and native.
+   ((null gnus-refer-article-method)
+    (list gnus-current-select-method gnus-select-method))
+   ;; Current.
+   ((eq 'current gnus-refer-article-method)
+    (list gnus-current-select-method))
+   ;; List of select methods.
+   ((not (stringp (cadr gnus-refer-article-method)))
+    (let (out)
+      (dolist (method gnus-refer-article-method)
+	(push (if (eq 'current method)
+		  gnus-current-select-method
+		method)
+	      out))
+      (nreverse out)))
+   ;; One single select method.
+   (t
+    (list gnus-refer-article-method))))
 
 (defun gnus-summary-edit-parameters ()
   "Edit the group parameters of the current group."
   (interactive)
   (gnus-group-edit-group gnus-newsgroup-name 'params))
 
+(defun gnus-summary-customize-parameters ()
+  "Customize the group parameters of the current group."
+  (interactive)
+  (gnus-group-customize gnus-newsgroup-name))
+
 (defun gnus-summary-enter-digest-group (&optional force)
   "Enter an nndoc group based on the current article.
 If FORCE, force a digest interpretation.  If not, try
@@ -6490,8 +6908,14 @@
 			   (list (cons 'save-article-group ogroup))))
 	   (case-fold-search t)
 	   (buf (current-buffer))
-	   dig)
+	   dig to-address)
       (save-excursion
+	(set-buffer gnus-original-article-buffer)
+	;; Have the digest group inherit the main mail address of
+	;; the parent article.
+	(when (setq to-address (or (message-fetch-field "reply-to")
+				   (message-fetch-field "from")))
+	  (setq params (append (list (cons 'to-address to-address)))))
 	(setq dig (nnheader-set-temp-buffer " *gnus digest buffer*"))
 	(insert-buffer-substring gnus-original-article-buffer)
 	;; Remove lines that may lead nndoc to misinterpret the
@@ -6500,14 +6924,17 @@
 	 (goto-char (point-min))
 	 (or (search-forward "\n\n" nil t) (point)))
 	(goto-char (point-min))
-	(delete-matching-lines "^\\(Path\\):\\|^From ")
+	(delete-matching-lines "^Path:\\|^From ")
 	(widen))
       (unwind-protect
-          (if (gnus-group-read-ephemeral-group
-               name `(nndoc ,name (nndoc-address ,(get-buffer dig))
-                            (nndoc-article-type
-                             ,(if force 'digest 'guess))) t)
-              ;; Make all postings to this group go to the parent group.
+          (if (let ((gnus-newsgroup-ephemeral-charset gnus-newsgroup-charset)
+		    (gnus-newsgroup-ephemeral-ignored-charsets
+		     gnus-newsgroup-ignored-charsets))
+		(gnus-group-read-ephemeral-group
+		 name `(nndoc ,name (nndoc-address ,(get-buffer dig))
+			      (nndoc-article-type
+			       ,(if force 'mbox 'guess))) t))
+	      ;; Make all postings to this group go to the parent group.
               (nconc (gnus-info-params (gnus-get-info name))
                      params)
             ;; Couldn't select this doc group.
@@ -6533,7 +6960,7 @@
       (gnus-summary-remove-process-mark article)
       (when (gnus-summary-display-article article)
 	(save-excursion
-	  (nnheader-temp-write nil
+	  (with-temp-buffer
 	    (insert-buffer-substring gnus-original-article-buffer)
 	    ;; Remove some headers that may lead nndoc to make
 	    ;; the wrong guess.
@@ -6613,18 +7040,21 @@
   ;; We have to require this here to make sure that the following
   ;; dynamic binding isn't shadowed by autoloading.
   (require 'gnus-async)
+  (require 'gnus-art)
   (let ((gnus-select-article-hook nil)	;Disable hook.
-	(gnus-article-display-hook nil)
+	(gnus-article-prepare-hook nil)
 	(gnus-mark-article-hook nil)	;Inhibit marking as read.
 	(gnus-use-article-prefetch nil)
 	(gnus-xmas-force-redisplay nil)	;Inhibit XEmacs redisplay.
 	(gnus-use-trees nil)		;Inhibit updating tree buffer.
 	(sum (current-buffer))
+	(gnus-display-mime-function nil)
 	(found nil)
 	point)
     (gnus-save-hidden-threads
       (gnus-summary-select-article)
       (set-buffer gnus-article-buffer)
+      (goto-char (window-point (get-buffer-window (current-buffer))))
       (when backward
 	(forward-line -1))
       (while (not found)
@@ -6640,6 +7070,9 @@
 	       (get-buffer-window (current-buffer))
 	       (point))
 	      (forward-line 1)
+	      (set-window-point
+	       (get-buffer-window (current-buffer))
+	       (point))
 	      (set-buffer sum)
 	      (setq point (point)))
 	  ;; We didn't find it, so we go to the next article.
@@ -6678,11 +7111,18 @@
   (let ((data (if (eq backward 'all) gnus-newsgroup-data
 		(gnus-data-find-list
 		 (gnus-summary-article-number) (gnus-data-list backward))))
-	(func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
 	(case-fold-search (not not-case-fold))
-	articles d)
-    (unless (fboundp (intern (concat "mail-header-" header)))
-      (error "%s is not a valid header" header))
+	articles d func)
+    (if (consp header)
+	(if (eq (car header) 'extra)
+	    (setq func
+		  `(lambda (h)
+		     (or (cdr (assq ',(cdr header) (mail-header-extra h)))
+			 "")))
+	  (error "%s is an invalid header" header))
+      (unless (fboundp (intern (concat "mail-header-" header)))
+	(error "%s is not a valid header" header))
+      (setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h))))
     (while data
       (setq d (car data))
       (and (or (not unread)		; We want all articles...
@@ -6751,7 +7191,7 @@
 If N is negative, print the N previous articles.  If N is nil and articles
 have been marked with the process mark, print these instead.
 
-If the optional second argument FILENAME is nil, send the image to the
+If the optional first argument FILENAME is nil, send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
 that name.  If FILENAME is a number, prompt the user for the name of the file
 to save in."
@@ -6784,20 +7224,42 @@
 
 (defun gnus-summary-show-article (&optional arg)
   "Force re-fetching of the current article.
-If ARG (the prefix) is non-nil, show the raw article without any
-article massaging functions being run."
+If ARG (the prefix) is a number, show the article with the charset
+defined in `gnus-summary-show-article-charset-alist', or the charset
+inputed.
+If ARG (the prefix) is non-nil and not a number, show the raw article
+without any article massaging functions being run."
   (interactive "P")
-  (if (not arg)
-      ;; Select the article the normal way.
-      (gnus-summary-select-article nil 'force)
+  (cond
+   ((numberp arg)
+    (let ((gnus-newsgroup-charset
+	   (or (cdr (assq arg gnus-summary-show-article-charset-alist))
+	       (read-coding-system "Charset: ")))
+	  (gnus-newsgroup-ignored-charsets 'gnus-all))
+      (gnus-summary-select-article nil 'force)))
+   ((not arg)
+    ;; Select the article the normal way.
+    (gnus-summary-select-article nil 'force))
+   (t
+    ;; We have to require this here to make sure that the following
+    ;; dynamic binding isn't shadowed by autoloading.
+    (require 'gnus-async)
+    (require 'gnus-art)
     ;; Bind the article treatment functions to nil.
     (let ((gnus-have-all-headers t)
-	  gnus-article-display-hook
 	  gnus-article-prepare-hook
-	  gnus-break-pages
-	  gnus-show-mime
-	  gnus-visual)
-      (gnus-summary-select-article nil 'force)))
+	  gnus-article-decode-hook
+	  gnus-display-mime-function
+	  gnus-break-pages)
+      ;; Destroy any MIME parts.
+      (when (gnus-buffer-live-p gnus-article-buffer)
+	(save-excursion
+	  (set-buffer gnus-article-buffer)
+	  (mm-destroy-parts gnus-article-mime-handles)
+	  ;; Set it to nil for safety reason.
+	  (setq gnus-article-mime-handle-alist nil)
+	  (setq gnus-article-mime-handles nil)))
+      (gnus-summary-select-article nil 'force))))
   (gnus-summary-goto-subject gnus-current-article)
   (gnus-summary-position-point))
 
@@ -6821,40 +7283,42 @@
   (interactive "P")
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (let* ((buffer-read-only nil)
-	   (inhibit-point-motion-hooks t)
-	   (hidden (text-property-any
-		    (goto-char (point-min)) (search-forward "\n\n")
-		    'invisible t))
-	   e)
-      (goto-char (point-min))
-      (when (search-forward "\n\n" nil t)
-	(delete-region (point-min) (1- (point))))
-      (goto-char (point-min))
-      (save-excursion
-	(set-buffer gnus-original-article-buffer)
+    (save-restriction
+      (let* ((buffer-read-only nil)
+	     (inhibit-point-motion-hooks t)
+	     hidden e)
+	(setq hidden
+	      (if (numberp arg)
+		  (>= arg 0)
+		(save-restriction
+		  (article-narrow-to-head)
+		  (gnus-article-hidden-text-p 'headers))))
+	(goto-char (point-min))
+	(when (search-forward "\n\n" nil t)
+	  (delete-region (point-min) (1- (point))))
 	(goto-char (point-min))
-	(setq e (1- (or (search-forward "\n\n" nil t) (point-max)))))
-      (insert-buffer-substring gnus-original-article-buffer 1 e)
-      (let ((article-inhibit-hiding t))
-	(gnus-run-hooks 'gnus-article-display-hook))
-      (when (or (not hidden) (and (numberp arg) (< arg 0)))
-	(gnus-article-hide-headers)))))
+	(save-excursion
+	  (set-buffer gnus-original-article-buffer)
+	  (goto-char (point-min))
+	  (setq e (1- (or (search-forward "\n\n" nil t) (point-max)))))
+	(insert-buffer-substring gnus-original-article-buffer 1 e)
+	(save-restriction
+	  (narrow-to-region (point-min) (point))
+	  (article-decode-encoded-words)
+	  (if  hidden
+	      (let ((gnus-treat-hide-headers nil)
+		    (gnus-treat-hide-boring-headers nil))
+		(setq gnus-article-wash-types
+		      (delq 'headers gnus-article-wash-types))
+		(gnus-treat-article 'head))
+	    (gnus-treat-article 'head)))
+	(gnus-set-mode-line 'article)))))
 
 (defun gnus-summary-show-all-headers ()
   "Make all header lines visible."
   (interactive)
   (gnus-article-show-all-headers))
 
-(defun gnus-summary-toggle-mime (&optional arg)
-  "Toggle MIME processing.
-If ARG is a positive number, turn MIME processing on."
-  (interactive "P")
-  (setq gnus-show-mime
-	(if (null arg) (not gnus-show-mime)
-	  (> (prefix-numeric-value arg) 0)))
-  (gnus-summary-select-article t 'force))
-
 (defun gnus-summary-caesar-message (&optional arg)
   "Caesar rotate the current article by 13.
 The numerical prefix specifies how many places to rotate each letter
@@ -6895,7 +7359,9 @@
 
 For this function to work, both the current newsgroup and the
 newsgroup that you want to move to have to support the `request-move'
-and `request-accept' functions."
+and `request-accept' functions.
+
+ACTION can be either `move' (the default), `crosspost' or `copy'."
   (interactive "P")
   (unless action
     (setq action 'move))
@@ -6913,7 +7379,10 @@
 		    'request-replace-article gnus-newsgroup-name)))
 	 (error "The current group does not support article editing")))
   (let ((articles (gnus-summary-work-articles n))
-	(prefix (gnus-group-real-prefix gnus-newsgroup-name))
+	(prefix (if (gnus-check-backend-function
+		    'request-move-article gnus-newsgroup-name)
+		    (gnus-group-real-prefix gnus-newsgroup-name)
+		  ""))
 	(names '((move "Move" "Moving")
 		 (copy "Copy" "Copying")
 		 (crosspost "Crosspost" "Crossposting")))
@@ -6932,7 +7401,8 @@
 	     articles prefix))
       (set (intern (format "gnus-current-%s-group" action)) to-newsgroup))
     (setq to-method (or select-method
-			(gnus-group-name-to-method to-newsgroup)))
+			(gnus-server-to-method
+			 (gnus-group-method to-newsgroup))))
     ;; Check the method we are to move this article to...
     (unless (gnus-check-backend-function
 	     'request-accept-article (car to-method))
@@ -6958,7 +7428,7 @@
 		  gnus-newsgroup-name)) ; Server
 	  (list 'gnus-request-accept-article
 		to-newsgroup (list 'quote select-method)
-		(not articles))		; Accept form
+		(not articles) t)	; Accept form
 	  (not articles)))		; Only save nov last time
 	;; Copy the article.
 	((eq action 'copy)
@@ -6966,7 +7436,7 @@
 	   (set-buffer copy-buf)
 	   (when (gnus-request-article-this-buffer article gnus-newsgroup-name)
 	     (gnus-request-accept-article
-	      to-newsgroup select-method (not articles)))))
+	      to-newsgroup select-method (not articles) t))))
 	;; Crosspost the article.
 	((eq action 'crosspost)
 	 (let ((xref (message-tokenize-header
@@ -6999,19 +7469,21 @@
 	       art-group))))))
       (cond
        ((not art-group)
-	(gnus-message 1 "Couldn't %s article %s"
-		      (cadr (assq action names)) article))
-       ((and (eq art-group 'junk)
-	     (eq action 'move))
-	(gnus-summary-mark-article article gnus-canceled-mark)
-	(gnus-message 4 "Deleted article %s" article))
+	(gnus-message 1 "Couldn't %s article %s: %s"
+		      (cadr (assq action names)) article
+		      (nnheader-get-report (car to-method))))
+       ((eq art-group 'junk)
+	(when (eq action 'move)
+	  (gnus-summary-mark-article article gnus-canceled-mark)
+	  (gnus-message 4 "Deleted article %s" article)))
        (t
 	(let* ((pto-group (gnus-group-prefixed-name
 			   (car art-group) to-method))
 	       (entry
 		(gnus-gethash pto-group gnus-newsrc-hashtb))
 	       (info (nth 2 entry))
-	       (to-group (gnus-info-group info)))
+               (to-group (gnus-info-group info))
+	       to-marks)
 	  ;; Update the group that has been moved to.
 	  (when (and info
 		     (memq action '(move copy)))
@@ -7019,49 +7491,54 @@
 	      (push to-group to-groups))
 
 	    (unless (memq article gnus-newsgroup-unreads)
+	      (push 'read to-marks)
 	      (gnus-info-set-read
 	       info (gnus-add-to-range (gnus-info-read info)
 				       (list (cdr art-group)))))
 
-	    ;; Copy any marks over to the new group.
+	    ;; See whether the article is to be put in the cache.
 	    (let ((marks gnus-article-mark-lists)
 		  (to-article (cdr art-group)))
 
-	      ;; See whether the article is to be put in the cache.
+	      ;; Enter the article into the cache in the new group,
+	      ;; if that is required.
 	      (when gnus-use-cache
 		(gnus-cache-possibly-enter-article
 		 to-group to-article
-		 (let ((header (copy-sequence
-				(gnus-summary-article-header article))))
-		   (mail-header-set-number header to-article)
-		   header)
 		 (memq article gnus-newsgroup-marked)
 		 (memq article gnus-newsgroup-dormant)
 		 (memq article gnus-newsgroup-unreads)))
 
-	      (when (and (equal to-group gnus-newsgroup-name)
-			 (not (memq article gnus-newsgroup-unreads)))
-		;; Mark this article as read in this group.
-		(push (cons to-article gnus-read-mark) gnus-newsgroup-reads)
-		(setcdr (gnus-active to-group) to-article)
-		(setcdr gnus-newsgroup-active to-article))
-
-	      (while marks
-		(when (memq article (symbol-value
-				     (intern (format "gnus-newsgroup-%s"
-						     (caar marks)))))
-		  ;; If the other group is the same as this group,
-		  ;; then we have to add the mark to the list.
-		  (when (equal to-group gnus-newsgroup-name)
-		    (set (intern (format "gnus-newsgroup-%s" (caar marks)))
-			 (cons to-article
-			       (symbol-value
-				(intern (format "gnus-newsgroup-%s"
-						(caar marks)))))))
-		  ;; Copy the marks to other group.
-		  (gnus-add-marked-articles
-		   to-group (cdar marks) (list to-article) info))
-		(setq marks (cdr marks)))
+	      (when gnus-preserve-marks
+		;; Copy any marks over to the new group.
+		(when (and (equal to-group gnus-newsgroup-name)
+			   (not (memq article gnus-newsgroup-unreads)))
+		  ;; Mark this article as read in this group.
+		  (push (cons to-article gnus-read-mark) gnus-newsgroup-reads)
+		  (setcdr (gnus-active to-group) to-article)
+		  (setcdr gnus-newsgroup-active to-article))
+
+		(while marks
+		  (when (memq article (symbol-value
+				       (intern (format "gnus-newsgroup-%s"
+						       (caar marks)))))
+		    (push (cdar marks) to-marks)
+		    ;; If the other group is the same as this group,
+		    ;; then we have to add the mark to the list.
+		    (when (equal to-group gnus-newsgroup-name)
+		      (set (intern (format "gnus-newsgroup-%s" (caar marks)))
+			   (cons to-article
+				 (symbol-value
+				  (intern (format "gnus-newsgroup-%s"
+						  (caar marks)))))))
+		    ;; Copy the marks to other group.
+		    (gnus-add-marked-articles
+		     to-group (cdar marks) (list to-article) info))
+		  (setq marks (cdr marks)))
+
+		(gnus-request-set-mark to-group (list (list (list to-article)
+							    'set
+							    to-marks))))
 
 	      (gnus-dribble-enter
 	       (concat "(gnus-group-set-info '"
@@ -7174,9 +7651,8 @@
 	(error "Can't read %s" file))
     (save-excursion
       (set-buffer (gnus-get-buffer-create " *import file*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (insert-file-contents file)
+      (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (unless (nnheader-article-p)
 	;; This doesn't look like an article, so we fudge some headers.
@@ -7184,10 +7660,7 @@
 	      lines (count-lines (point-min) (point-max)))
 	(insert "From: " (read-string "From: ") "\n"
 		"Subject: " (read-string "Subject: ") "\n"
-		"Date: " (timezone-make-date-arpa-standard
-			  (current-time-string (nth 5 atts))
-			  (current-time-zone now)
-			  (current-time-zone now))
+		"Date: " (message-make-date (nth 5 atts))
 		"\n"
 		"Message-ID: " (message-make-message-id) "\n"
 		"Lines: " (int-to-string lines) "\n"
@@ -7196,12 +7669,11 @@
       (kill-buffer (current-buffer)))))
 
 (defun gnus-summary-article-posted-p ()
-  "Say whether the current (mail) article is available from `gnus-select-method' as well.
+  "Say whether the current (mail) article is available from news as well.
 This will be the case if the article has both been mailed and posted."
   (interactive)
   (let ((id (mail-header-references (gnus-summary-article-header)))
-	(gnus-override-method
-	 (or gnus-refer-article-method gnus-select-method)))
+	(gnus-override-method (car (gnus-refer-article-methods))))
     (if (gnus-request-head id "")
 	(gnus-message 2 "The current message was found on %s"
 		      gnus-override-method)
@@ -7229,11 +7701,16 @@
 	   (expiry-wait (if now 'immediate
 			  (gnus-group-find-parameter
 			   gnus-newsgroup-name 'expiry-wait)))
+	   (nnmail-expiry-target
+	    (or (gnus-group-find-parameter gnus-newsgroup-name 'expiry-target)
+		nnmail-expiry-target))
 	   es)
       (when expirable
 	;; There are expirable articles in this group, so we run them
 	;; through the expiry process.
 	(gnus-message 6 "Expiring articles...")
+	(unless (gnus-check-group gnus-newsgroup-name)
+	  (error "Can't open server for %s" gnus-newsgroup-name))
 	;; The list of articles that weren't expired is returned.
 	(save-excursion
 	  (if expiry-wait
@@ -7281,6 +7758,8 @@
   (unless (gnus-check-backend-function 'request-expire-articles
 				       gnus-newsgroup-name)
     (error "The current newsgroup does not support article deletion"))
+  (unless (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
+    (error "Couldn't open server"))
   ;; Compute the list of articles to delete.
   (let ((articles (sort (copy-sequence (gnus-summary-work-articles n)) '<))
 	not-deleted)
@@ -7307,28 +7786,63 @@
     (gnus-set-mode-line 'summary)
     not-deleted))
 
-(defun gnus-summary-edit-article (&optional force)
+(defun gnus-summary-edit-article (&optional arg)
   "Edit the current article.
 This will have permanent effect only in mail groups.
-If FORCE is non-nil, allow editing of articles even in read-only
+If ARG is nil, edit the decoded articles.
+If ARG is 1, edit the raw articles. 
+If ARG is 2, edit the raw articles even in read-only groups.
+Otherwise, allow editing of articles even in read-only
 groups."
   (interactive "P")
-  (save-excursion
-    (set-buffer gnus-summary-buffer)
-    (gnus-set-global-variables)
-    (when (and (not force)
-	       (gnus-group-read-only-p))
-      (error "The current newsgroup does not support article editing"))
-    ;; Select article if needed.
-    (unless (eq (gnus-summary-article-number)
-		gnus-current-article)
-      (gnus-summary-select-article t))
-    (gnus-article-date-original)
-    (gnus-article-edit-article
-     `(lambda (no-highlight)
-	(gnus-summary-edit-article-done
-	 ,(or (mail-header-references gnus-current-headers) "")
-	 ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight)))))
+  (let (force raw)
+    (cond 
+     ((null arg))
+     ((eq arg 1) (setq raw t))
+     ((eq arg 2) (setq raw t
+		       force t))
+     (t (setq force t)))
+    (if (and raw (not force) (equal gnus-newsgroup-name "nndraft:drafts"))
+	(error "Can't edit the raw article in group nndraft:drafts."))
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (let ((mail-parse-charset gnus-newsgroup-charset)
+	    (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
+	(gnus-set-global-variables)
+	(when (and (not force)
+		   (gnus-group-read-only-p))
+	  (error "The current newsgroup does not support article editing"))
+	(gnus-summary-show-article t)
+	(when (and (not raw) (gnus-buffer-live-p gnus-article-buffer))
+	  (with-current-buffer gnus-article-buffer
+	    (mm-enable-multibyte)))
+	(if (equal gnus-newsgroup-name "nndraft:drafts")
+	    (setq raw t))
+	(gnus-article-edit-article
+	 (if raw 'ignore 
+	   #'(lambda () 
+	       (let ((mbl mml-buffer-list))
+		 (setq mml-buffer-list nil)
+		 (mime-to-mml)
+		 (make-local-hook 'kill-buffer-hook)
+		 (let ((mml-buffer-list mml-buffer-list))
+		   (setq mml-buffer-list mbl)
+		   (make-local-variable 'mml-buffer-list))
+		 (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))))
+	 `(lambda (no-highlight)
+	    (let ((mail-parse-charset ',gnus-newsgroup-charset)
+		  (mail-parse-ignored-charsets 
+		   ',gnus-newsgroup-ignored-charsets))
+	      ,(if (not raw) '(progn 
+				(mml-to-mime)
+				(mml-destroy-buffers)
+				(remove-hook 'kill-buffer-hook 
+					     'mml-destroy-buffers t)
+				(kill-local-variable 'mml-buffer-list)))
+	      (gnus-summary-edit-article-done
+	       ,(or (mail-header-references gnus-current-headers) "")
+	       ,(gnus-group-read-only-p) 
+	       ,gnus-summary-buffer no-highlight))))))))
 
 (defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit)
 
@@ -7338,12 +7852,12 @@
   (interactive)
   ;; Replace the article.
   (let ((buf (current-buffer)))
-    (nnheader-temp-write nil
-      (insert-buffer buf)
+    (with-temp-buffer
+      (insert-buffer-substring buf)
       (if (and (not read-only)
 	       (not (gnus-request-replace-article
 		     (cdr gnus-article-current) (car gnus-article-current)
-		     (current-buffer))))
+		     (current-buffer) t)))
 	  (error "Couldn't replace article")
 	;; Update the summary buffer.
 	(if (and references
@@ -7356,7 +7870,7 @@
 		(message-narrow-to-head)
 		(let ((head (buffer-string))
 		      header)
-		  (nnheader-temp-write nil
+		  (with-temp-buffer
 		    (insert (format "211 %d Article retrieved.\n"
 				    (cdr gnus-article-current)))
 		    (insert head)
@@ -7381,7 +7895,8 @@
 	(unless no-highlight
 	  (save-excursion
 	    (set-buffer gnus-article-buffer)
-	    (gnus-run-hooks 'gnus-article-display-hook)
+	    ;;;!!! Fix this -- article should be rehighlighted.
+	    ;;;(gnus-run-hooks 'gnus-article-display-hook)
 	    (set-buffer gnus-original-article-buffer)
 	    (gnus-request-article
 	     (cdr gnus-article-current)
@@ -7544,7 +8059,7 @@
   "Mark ARTICLE replied and update the summary line."
   (push article gnus-newsgroup-replied)
   (let ((buffer-read-only nil))
-    (when (gnus-summary-goto-subject article)
+    (when (gnus-summary-goto-subject article nil t)
       (gnus-summary-update-secondary-mark article))))
 
 (defun gnus-summary-set-bookmark (article)
@@ -7624,8 +8139,10 @@
   "Mark N articles as read forwards.
 If N is negative, mark backwards instead.  Mark with MARK, ?r by default.
 The difference between N and the actual number of articles marked is
-returned."
+returned.
+Iff NO-EXPIRE, auto-expiry will be inhibited."
   (interactive "p")
+  (gnus-summary-show-thread)
   (let ((backward (< n 0))
 	(gnus-summary-goto-unread
 	 (and gnus-summary-goto-unread
@@ -7663,11 +8180,7 @@
     (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     ;; Check for auto-expiry.
     (when (and gnus-newsgroup-auto-expire
-	       (or (= mark gnus-killed-mark) (= mark gnus-del-mark)
-		   (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
-		   (= mark gnus-ancient-mark)
-		   (= mark gnus-read-mark) (= mark gnus-souped-mark)
-		   (= mark gnus-duplicate-mark)))
+	       (memq mark gnus-auto-expirable-marks))
       (setq mark gnus-expirable-mark)
       ;; Let the backend know about the mark change.
       (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
@@ -7706,7 +8219,6 @@
 	     (save-excursion
 	       (gnus-cache-possibly-enter-article
 		gnus-newsgroup-name article
-		(gnus-summary-article-header article)
 		(= mark gnus-ticked-mark)
 		(= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
 
@@ -7718,25 +8230,22 @@
   "Mark ARTICLE with MARK.  MARK can be any character.
 Four MARK strings are reserved: `? ' (unread), `?!' (ticked),
 `??' (dormant) and `?E' (expirable).
-If MARK is nil, then the default character `?D' is used.
+If MARK is nil, then the default character `?r' is used.
 If ARTICLE is nil, then the article on the current line will be
-marked."
+marked.
+Iff NO-EXPIRE, auto-expiry will be inhibited."
   ;; The mark might be a string.
   (when (stringp mark)
     (setq mark (aref mark 0)))
   ;; If no mark is given, then we check auto-expiring.
-  (and (not no-expire)
-       gnus-newsgroup-auto-expire
-       (or (not mark)
-	   (and (gnus-characterp mark)
-		(or (= mark gnus-killed-mark) (= mark gnus-del-mark)
-		    (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
-		    (= mark gnus-read-mark) (= mark gnus-souped-mark)
-		    (= mark gnus-duplicate-mark))))
-       (setq mark gnus-expirable-mark))
-  (let* ((mark (or mark gnus-del-mark))
-	 (article (or article (gnus-summary-article-number)))
-	 (old-mark (gnus-summary-article-mark article)))
+  (when (null mark)
+    (setq mark gnus-del-mark))
+  (when (and (not no-expire)
+	     gnus-newsgroup-auto-expire
+ 	     (memq mark gnus-auto-expirable-marks))
+    (setq mark gnus-expirable-mark))
+  (let ((article (or article (gnus-summary-article-number)))
+	(old-mark (gnus-summary-article-mark article)))
     ;; Allow the backend to change the mark.
     (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     (if (eq mark old-mark)
@@ -7756,7 +8265,6 @@
 	     (save-excursion
 	       (gnus-cache-possibly-enter-article
 		gnus-newsgroup-name article
-		(gnus-summary-article-header article)
 		(= mark gnus-ticked-mark)
 		(= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
 
@@ -7788,19 +8296,19 @@
   (let ((forward (cdr (assq type gnus-summary-mark-positions)))
         (buffer-read-only nil))
     (re-search-backward "[\n\r]" (gnus-point-at-bol) 'move-to-limit)
-    (when (looking-at "\r")
-      (incf forward))
-    (when (and forward
-               (<= (+ forward (point)) (point-max)))
-      ;; Go to the right position on the line.
-      (goto-char (+ forward (point)))
-      ;; Replace the old mark with the new mark.
-      (subst-char-in-region (point) (1+ (point)) (following-char) mark)
-      ;; Optionally update the marks by some user rule.
-      (when (eq type 'unread)
-        (gnus-data-set-mark
-         (gnus-data-find (gnus-summary-article-number)) mark)
-        (gnus-summary-update-line (eq mark gnus-unread-mark))))))
+    (when forward
+      (when (looking-at "\r")
+	(incf forward))
+      (when (<= (+ forward (point)) (point-max))
+	;; Go to the right position on the line.
+	(goto-char (+ forward (point)))
+	;; Replace the old mark with the new mark.
+	(subst-char-in-region (point) (1+ (point)) (char-after) mark)
+	;; Optionally update the marks by some user rule.
+	(when (eq type 'unread)
+	  (gnus-data-set-mark
+	   (gnus-data-find (gnus-summary-article-number)) mark)
+	  (gnus-summary-update-line (eq mark gnus-unread-mark)))))))
 
 (defun gnus-mark-article-as-read (article &optional mark)
   "Enter ARTICLE in the pertinent lists and remove it from others."
@@ -7881,14 +8389,15 @@
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
-  (gnus-summary-mark-forward n gnus-del-mark t))
+  (gnus-summary-mark-forward n gnus-del-mark gnus-inhibit-user-auto-expire))
 
 (defun gnus-summary-mark-as-read-backward (n)
   "Mark the N articles as read backwards.
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
-  (gnus-summary-mark-forward (- n) gnus-del-mark t))
+  (gnus-summary-mark-forward
+   (- n) gnus-del-mark gnus-inhibit-user-auto-expire))
 
 (defun gnus-summary-mark-as-read (&optional article mark)
   "Mark current article as read.
@@ -8069,7 +8578,7 @@
   (gnus-summary-catchup t quietly))
 
 (defun gnus-summary-catchup-and-exit (&optional all quietly)
-  "Mark all articles not marked as unread in this newsgroup as read, then exit.
+  "Mark all unread articles in this group as read, then exit.
 If prefix argument ALL is non-nil, all articles are marked as read."
   (interactive "P")
   (when (gnus-summary-catchup all quietly nil 'fast)
@@ -8084,7 +8593,6 @@
   (interactive "P")
   (gnus-summary-catchup-and-exit t quietly))
 
-;; Suggested by "Arne Eofsson" <arne@hodgkin.mbi.ucla.edu>.
 (defun gnus-summary-catchup-and-goto-next-group (&optional all)
   "Mark all articles in this group as read and select the next group.
 If given a prefix, mark all articles, unread as well as ticked, as
@@ -8092,7 +8600,38 @@
   (interactive "P")
   (save-excursion
     (gnus-summary-catchup all))
-  (gnus-summary-next-article t nil nil t))
+  (gnus-summary-next-group))
+
+;;;
+;;; with article
+;;;
+
+(defmacro gnus-with-article (article &rest forms)
+  "Select ARTICLE and perform FORMS in the original article buffer.
+Then replace the article with the result."
+  `(progn
+     ;; We don't want the article to be marked as read.
+     (let (gnus-mark-article-hook)
+       (gnus-summary-select-article t t nil ,article))
+     (set-buffer gnus-original-article-buffer)
+     ,@forms
+     (if (not (gnus-check-backend-function
+	       'request-replace-article (car gnus-article-current)))
+	 (gnus-message 5 "Read-only group; not replacing")
+       (unless (gnus-request-replace-article
+		,article (car gnus-article-current)
+		(current-buffer) t)
+	 (error "Couldn't replace article")))
+     ;; The cache and backlog have to be flushed somewhat.
+     (when gnus-keep-backlog
+       (gnus-backlog-remove-article
+	(car gnus-article-current) (cdr gnus-article-current)))
+     (when gnus-use-cache
+       (gnus-cache-update-article
+	(car gnus-article-current) (cdr gnus-article-current)))))
+
+(put 'gnus-with-article 'lisp-indent-function 1)
+(put 'gnus-with-article 'edebug-form-spec '(form body))
 
 ;; Thread-based commands.
 
@@ -8171,25 +8710,17 @@
 			 (gnus-summary-article-header parent-article))))
 	(unless (and message-id (not (equal message-id "")))
 	  (error "No message-id in desired parent"))
-	;; We don't want the article to be marked as read.
-	(let (gnus-mark-article-hook)
-	  (gnus-summary-select-article t t nil current-article))
-	(set-buffer gnus-original-article-buffer)
-	(let ((buf (format "%s" (buffer-string))))
-	  (nnheader-temp-write nil
-	    (insert buf)
+	(gnus-with-article current-article
+	  (save-restriction
 	    (goto-char (point-min))
+	    (message-narrow-to-head)
 	    (if (re-search-forward "^References: " nil t)
 		(progn
 		  (re-search-forward "^[^ \t]" nil t)
 		  (forward-line -1)
 		  (end-of-line)
 		  (insert " " message-id))
-	      (insert "References: " message-id "\n"))
-	    (unless (gnus-request-replace-article
-		     current-article (car gnus-article-current)
-		     (current-buffer))
-	      (error "Couldn't replace article"))))
+	      (insert "References: " message-id "\n"))))
 	(set-buffer gnus-summary-buffer)
 	(gnus-summary-unmark-all-processable)
 	(gnus-summary-update-article current-article)
@@ -8264,9 +8795,7 @@
 		(subst-char-in-region start (point) ?\n ?\^M)
 		(gnus-summary-goto-subject article))
 	    (goto-char start)
-	    nil)
-	;;(gnus-summary-position-point)
-	))))
+	    nil)))))
 
 (defun gnus-summary-go-to-next-thread (&optional previous)
   "Go to the same level (or less) next thread.
@@ -8398,14 +8927,14 @@
 
 (defun gnus-summary-sort-by-author (&optional reverse)
   "Sort the summary buffer by author name alphabetically.
-If case-fold-search is non-nil, case of letters is ignored.
+If `case-fold-search' is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
   (gnus-summary-sort 'author reverse))
 
 (defun gnus-summary-sort-by-subject (&optional reverse)
   "Sort the summary buffer by subject alphabetically.  `Re:'s are ignored.
-If case-fold-search is non-nil, case of letters is ignored.
+If `case-fold-search' is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
   (gnus-summary-sort 'subject reverse))
@@ -8423,27 +8952,33 @@
   (gnus-summary-sort 'score reverse))
 
 (defun gnus-summary-sort-by-lines (&optional reverse)
+  "Sort the summary buffer by the number of lines.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'lines reverse))
+
+(defun gnus-summary-sort-by-chars (&optional reverse)
   "Sort the summary buffer by article length.
 Argument REVERSE means reverse order."
   (interactive "P")
-  (gnus-summary-sort 'lines reverse))
+  (gnus-summary-sort 'chars reverse))
 
 (defun gnus-summary-sort (predicate reverse)
   "Sort summary buffer by PREDICATE.  REVERSE means reverse order."
   (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
 	 (article (intern (format "gnus-article-sort-by-%s" predicate)))
 	 (gnus-thread-sort-functions
-	  (list
-	   (if (not reverse)
-	       thread
-	     `(lambda (t1 t2)
-		(,thread t2 t1)))))
+	  (if (not reverse)
+	      thread
+	    `(lambda (t1 t2)
+	       (,thread t2 t1))))
+	 (gnus-sort-gathered-threads-function
+	  gnus-thread-sort-functions)
 	 (gnus-article-sort-functions
-	  (list
-	   (if (not reverse)
-	       article
-	     `(lambda (t1 t2)
-		(,article t2 t1)))))
+	  (if (not reverse)
+	      article
+	    `(lambda (t1 t2)
+	       (,article t2 t1))))
 	 (buffer-read-only)
 	 (gnus-summary-prepare-hook nil))
     ;; We do the sorting by regenerating the threads.
@@ -8466,10 +9001,9 @@
 	 (save-buffer (save-excursion
 			(nnheader-set-temp-buffer " *Gnus Save*")))
 	 (num (length articles))
-	 header article file)
-    (while articles
-      (setq header (gnus-summary-article-header
-		    (setq article (pop articles))))
+	 header file)
+    (dolist (article articles)
+      (setq header (gnus-summary-article-header article))
       (if (not (vectorp header))
 	  ;; This is a pseudo-article.
 	  (if (assq 'name header)
@@ -8599,16 +9133,14 @@
 			   split-name))
 		    ((consp result)
 		     (setq split-name (append result split-name)))))))))
-    split-name))
+    (nreverse split-name)))
 
 (defun gnus-valid-move-group-p (group)
   (and (boundp group)
        (symbol-name group)
-       (memq 'respool
-	     (assoc (symbol-name
-		     (car (gnus-find-method-for-group
-			   (symbol-name group))))
-		    gnus-valid-select-methods))))
+       (symbol-value group)
+       (gnus-get-function (gnus-find-method-for-group
+			   (symbol-name group)) 'request-accept-article t)))
 
 (defun gnus-read-move-group-name (prompt default articles prefix)
   "Read a group name."
@@ -8639,7 +9171,8 @@
 				  (mapcar (lambda (el) (list el))
 					  (nreverse split-name))
 				  nil nil nil
-				  'gnus-group-history)))))
+				  'gnus-group-history))))
+         (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
     (when to-newsgroup
       (if (or (string= to-newsgroup "")
 	      (string= to-newsgroup prefix))
@@ -8647,18 +9180,56 @@
       (unless to-newsgroup
 	(error "No group name entered"))
       (or (gnus-active to-newsgroup)
-	  (gnus-activate-group to-newsgroup)
+	  (gnus-activate-group to-newsgroup nil nil to-method)
 	  (if (gnus-y-or-n-p (format "No such group: %s.  Create it? "
 				     to-newsgroup))
-	      (or (and (gnus-request-create-group
-			to-newsgroup (gnus-group-name-to-method to-newsgroup))
-		       (gnus-activate-group to-newsgroup nil nil
-					    (gnus-group-name-to-method
-					     to-newsgroup)))
+	      (or (and (gnus-request-create-group to-newsgroup to-method)
+		       (gnus-activate-group
+			to-newsgroup nil nil to-method)
+		       (gnus-subscribe-group to-newsgroup))
 		  (error "Couldn't create group %s" to-newsgroup)))
 	  (error "No such group: %s" to-newsgroup)))
     to-newsgroup))
 
+(defun gnus-summary-save-parts (type dir n &optional reverse)
+  "Save parts matching TYPE to DIR.
+If REVERSE, save parts that do not match TYPE."
+  (interactive
+   (list (read-string "Save parts of type: " "image/.*")
+	 (read-file-name "Save to directory: " nil nil t)
+	 current-prefix-arg))
+  (gnus-summary-iterate n
+    (let ((gnus-display-mime-function nil)
+	  (gnus-inhibit-treatment t))
+      (gnus-summary-select-article))
+    (save-excursion
+      (set-buffer gnus-article-buffer)
+      (let ((handles (or gnus-article-mime-handles
+			 (mm-dissect-buffer) (mm-uu-dissect))))
+	(when handles
+	  (gnus-summary-save-parts-1 type dir handles reverse)
+	  (unless gnus-article-mime-handles ;; Don't destroy this case.
+	    (mm-destroy-parts handles)))))))
+
+(defun gnus-summary-save-parts-1 (type dir handle reverse)
+  (if (stringp (car handle))
+      (mapcar (lambda (h) (gnus-summary-save-parts-1 type dir h reverse))
+	      (cdr handle))
+    (when (if reverse
+	      (not (string-match type (mm-handle-media-type handle)))
+	    (string-match type (mm-handle-media-type handle)))
+      (let ((file (expand-file-name
+		   (file-name-nondirectory
+		    (or
+		     (mail-content-type-get
+		      (mm-handle-disposition handle) 'filename)
+		     (concat gnus-newsgroup-name
+			     "." (number-to-string
+				  (cdr gnus-article-current)))))
+		   dir)))
+	(unless (file-exists-p file)
+	  (mm-save-part-to-file handle file))))))
+
 ;; Summary extract commands
 
 (defun gnus-summary-insert-pseudos (pslist &optional not-view)
@@ -8694,7 +9265,7 @@
 				(lambda (f)
 				  (if (equal f " ")
 				      f
-				    (gnus-quote-arg-for-sh-or-csh f)))
+				    (mm-quote-arg f)))
 				files " ")))))
 	  (setq ps (cdr ps)))))
     (if (and gnus-view-pseudos (not not-view))
@@ -8771,8 +9342,10 @@
   "Read the headers of article ID and enter them into the Gnus system."
   (let ((group gnus-newsgroup-name)
 	(gnus-override-method
-	 (and (gnus-news-group-p gnus-newsgroup-name)
-	      gnus-refer-article-method))
+	 (or
+	  gnus-override-method
+	  (and (gnus-news-group-p gnus-newsgroup-name)
+	       (car (gnus-refer-article-methods)))))
 	where)
     ;; First we check to see whether the header in question is already
     ;; fetched.
@@ -8846,8 +9419,8 @@
 ;;;
 
 (defun gnus-highlight-selected-summary ()
+  "Highlight selected article in summary buffer."
   ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
-  ;; Highlight selected article in summary buffer
   (when gnus-summary-selected-face
     (save-excursion
       (let* ((beg (progn (beginning-of-line) (point)))
@@ -8938,19 +9511,38 @@
 	(setq unread (cdr unread)))
       (when (<= prev (cdr active))
 	(push (cons prev (cdr active)) read))
+      (setq read (if (> (length read) 1) (nreverse read) read))
       (if compute
-	  (if (> (length read) 1) (nreverse read) read)
+	  read
 	(save-excursion
-	  (set-buffer gnus-group-buffer)
-	  (gnus-undo-register
-	    `(progn
-	       (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
-	       (gnus-info-set-read ',info ',(gnus-info-read info))
-	       (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
-	       (gnus-group-update-group ,group t))))
+	  (let (setmarkundo)
+	    ;; Propagate the read marks to the backend.
+	    (when (gnus-check-backend-function 'request-set-mark group)
+	      (let ((del (gnus-remove-from-range (gnus-info-read info) read))
+		    (add (gnus-remove-from-range read (gnus-info-read info))))
+		(when (or add del)
+		  (unless (gnus-check-group group)
+		    (error "Can't open server for %s" group))
+		  (gnus-request-set-mark
+		   group (delq nil (list (if add (list add 'add '(read)))
+					 (if del (list del 'del '(read))))))
+		  (setq setmarkundo
+			`(gnus-request-set-mark
+			  ,group
+			  ',(delq nil (list
+				       (if del (list del 'add '(read)))
+				       (if add (list add 'del '(read))))))))))
+	    (set-buffer gnus-group-buffer)
+	    (gnus-undo-register
+	      `(progn
+		 (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
+		 (gnus-info-set-read ',info ',(gnus-info-read info))
+		 (gnus-get-unread-articles-in-group ',info 
+						    (gnus-active ,group))
+		 (gnus-group-update-group ,group t)
+		 ,setmarkundo))))
 	;; Enter this list into the group info.
-	(gnus-info-set-read
-	 info (if (> (length read) 1) (nreverse read) read))
+	(gnus-info-set-read info read)
 	;; Set the number of unread articles in gnus-newsrc-hashtb.
 	(gnus-get-unread-articles-in-group info (gnus-active group))
 	t))))
@@ -8983,6 +9575,165 @@
 	   (gnus-summary-exit))
 	 buffers)))))
 
+(defun gnus-summary-setup-default-charset ()
+  "Setup newsgroup default charset."
+  (if (equal gnus-newsgroup-name "nndraft:drafts")
+      (setq gnus-newsgroup-charset nil)
+    (let* ((name (and gnus-newsgroup-name
+		      (gnus-group-real-name gnus-newsgroup-name)))
+	   (ignored-charsets
+	    (or gnus-newsgroup-ephemeral-ignored-charsets
+		(append
+		 (and gnus-newsgroup-name
+		      (or (gnus-group-find-parameter gnus-newsgroup-name
+						     'ignored-charsets t)
+			  (let ((alist gnus-group-ignored-charsets-alist)
+				elem (charsets nil))
+			    (while (setq elem (pop alist))
+			      (when (and name
+					 (string-match (car elem) name))
+				(setq alist nil
+				      charsets (cdr elem))))
+			    charsets)))
+		 gnus-newsgroup-ignored-charsets))))
+      (setq gnus-newsgroup-charset
+	    (or gnus-newsgroup-ephemeral-charset
+		(and gnus-newsgroup-name
+		     (or (gnus-group-find-parameter gnus-newsgroup-name 'charset)
+			 (let ((alist gnus-group-charset-alist)
+			       elem charset)
+			   (while (setq elem (pop alist))
+			     (when (and name
+					(string-match (car elem) name))
+			       (setq alist nil
+				     charset (cadr elem))))
+			   charset)))
+		gnus-default-charset))
+      (set (make-local-variable 'gnus-newsgroup-ignored-charsets)
+	   ignored-charsets))))
+
+;;;
+;;; Mime Commands
+;;;
+
+(defun gnus-summary-display-buttonized (&optional show-all-parts)
+  "Display the current article buffer fully MIME-buttonized.
+If SHOW-ALL-PARTS (the prefix) is non-nil, all multipart/* parts are
+treated as multipart/mixed."
+  (interactive "P")
+  (require 'gnus-art)
+  (let ((gnus-unbuttonized-mime-types nil)
+	(gnus-mime-display-multipart-as-mixed show-all-parts))
+    (gnus-summary-show-article)))
+
+(defun gnus-summary-repair-multipart (article)
+  "Add a Content-Type header to a multipart article without one."
+  (interactive (list (gnus-summary-article-number)))
+  (gnus-with-article article
+    (message-narrow-to-head)
+    (goto-char (point-max))
+    (widen)
+    (when (search-forward "\n--" nil t)
+      (let ((separator (buffer-substring (point) (gnus-point-at-eol))))
+	(message-narrow-to-head)
+	(message-remove-header "Mime-Version")
+	(message-remove-header "Content-Type")
+	(goto-char (point-max))
+	(insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
+			separator))
+	(insert "Mime-Version: 1.0\n")
+	(widen))))
+  (let (gnus-mark-article-hook)
+    (gnus-summary-select-article t t nil article)))
+
+(defun gnus-summary-toggle-display-buttonized ()
+  "Toggle the buttonizing of the article buffer."
+  (interactive)
+  (require 'gnus-art)
+  (if (setq gnus-inhibit-mime-unbuttonizing
+	    (not gnus-inhibit-mime-unbuttonizing))
+      (let ((gnus-unbuttonized-mime-types nil))
+	(gnus-summary-show-article))
+    (gnus-summary-show-article)))
+
+;;;
+;;; Generic summary marking commands
+;;;
+
+(defvar gnus-summary-marking-alist
+  '((read gnus-del-mark "d")
+    (unread gnus-unread-mark "u")
+    (ticked gnus-ticked-mark "!")
+    (dormant gnus-dormant-mark "?")
+    (expirable gnus-expirable-mark "e"))
+  "An alist of names/marks/keystrokes.")
+
+(defvar gnus-summary-generic-mark-map (make-sparse-keymap))
+(defvar gnus-summary-mark-map)
+
+(defun gnus-summary-make-all-marking-commands ()
+  (define-key gnus-summary-mark-map "M" gnus-summary-generic-mark-map)
+  (dolist (elem gnus-summary-marking-alist)
+    (apply 'gnus-summary-make-marking-command elem)))
+
+(defun gnus-summary-make-marking-command (name mark keystroke)
+  (let ((map (make-sparse-keymap)))
+    (define-key gnus-summary-generic-mark-map keystroke map)
+    (dolist (lway `((next "next" next nil "n")
+		    (next-unread "next unread" next t "N")
+		    (prev "previous" prev nil "p")
+		    (prev-unread "previous unread" prev t "P")
+		    (nomove "" nil nil ,keystroke)))
+      (let ((func (gnus-summary-make-marking-command-1
+		   mark (car lway) lway name)))
+	(setq func (eval func))
+	(define-key map (nth 4 lway) func)))))
+      
+(defun gnus-summary-make-marking-command-1 (mark way lway name)
+  `(defun ,(intern
+	    (format "gnus-summary-put-mark-as-%s%s"
+		    name (if (eq way 'nomove)
+			     ""
+			   (concat "-" (symbol-name way)))))
+     (n)
+     ,(format
+       "Mark the current article as %s%s.
+If N, the prefix, then repeat N times.
+If N is negative, move in reverse order.
+The difference between N and the actual number of articles marked is
+returned."
+       name (cadr lway))
+     (interactive "p")
+     (gnus-summary-generic-mark n ,mark ',(nth 2 lway) ,(nth 3 lway))))
+    
+(defun gnus-summary-generic-mark (n mark move unread)
+  "Mark N articles with MARK."
+  (unless (eq major-mode 'gnus-summary-mode)
+    (error "This command can only be used in the summary buffer"))
+  (gnus-summary-show-thread)
+  (let ((nummove
+	 (cond
+	  ((eq move 'next) 1)
+	  ((eq move 'prev) -1)
+	  (t 0))))
+    (if (zerop nummove)
+	(setq n 1)
+      (when (< n 0)
+	(setq n (abs n)
+	      nummove (* -1 nummove))))
+    (while (and (> n 0)
+		(gnus-summary-mark-article nil mark)
+		(zerop (gnus-summary-next-subject nummove unread t)))
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    n))
+
+(gnus-summary-make-all-marking-commands)
+
 (gnus-ems-redefine)
 
 (provide 'gnus-sum)
--- a/lisp/gnus/gnus-topic.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-topic.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-topic.el --- a folding minor mode for Gnus group buffers
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Ilja Weis <kult@uni-paderborn.de>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,8 +29,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-group)
 (require 'gnus-start)
@@ -151,11 +150,20 @@
       (gnus-group-topic group))))
 
 (defun gnus-topic-goto-topic (topic)
-  "Go to TOPIC."
   (when topic
     (gnus-goto-char (text-property-any (point-min) (point-max)
 				       'gnus-topic (intern topic)))))
 
+(defun gnus-topic-jump-to-topic (topic)
+  "Go to TOPIC."
+  (interactive
+   (list (completing-read "Go to topic: "
+			  (mapcar 'list (gnus-topic-list))
+			  nil t)))
+  (dolist (topic (gnus-current-topics topic))
+    (gnus-topic-fold t))
+  (gnus-topic-goto-topic topic))
+  
 (defun gnus-current-topic ()
   "Return the name of the current topic."
   (let ((result
@@ -205,16 +213,17 @@
 			 (if (member group gnus-zombie-list)
 			     gnus-level-zombie gnus-level-killed))))
       (and
-       unread				; nil means that the group is dead.
+       info				; nil means that the group is dead.
        (<= clevel level)
        (>= clevel lowest)		; Is inside the level we want.
        (or all
-	   (if (eq unread t)
+	   (if (or (eq unread t)
+		   (eq unread nil))
 	       gnus-group-list-inactive-groups
 	     (> unread 0))
 	   (and gnus-list-groups-with-ticked-articles
 		(cdr (assq 'tick (gnus-info-marks info))))
-					; Has right readedness.
+	   ;; Has right readedness.
 	   ;; Check for permanent visibility.
 	   (and gnus-permanently-visible-groups
 		(string-match gnus-permanently-visible-groups group))
@@ -363,7 +372,8 @@
 
 ;;; Generating group buffers
 
-(defun gnus-group-prepare-topics (level &optional all lowest regexp list-topic topic-level)
+(defun gnus-group-prepare-topics (level &optional all lowest
+					regexp list-topic topic-level)
   "List all newsgroups with unread articles of level LEVEL or lower.
 Use the `gnus-group-topics' to sort the groups.
 If ALL is non-nil, list groups that have no unread articles.
@@ -418,7 +428,7 @@
 	 (entries (gnus-topic-find-groups
 		   (car type) list-level
 		   (or all
-		       (cdr (assq 'visible 
+		       (cdr (assq 'visible
 				  (gnus-topic-hierarchical-parameters
 				   (car type)))))
 		   lowest))
@@ -446,7 +456,8 @@
 	(if (stringp entry)
 	    ;; Dead groups.
 	    (gnus-group-insert-group-line
-	     entry (if (member entry gnus-zombie-list) gnus-level-zombie gnus-level-killed)
+	     entry (if (member entry gnus-zombie-list)
+		       gnus-level-zombie gnus-level-killed)
 	     nil (- (1+ (cdr (setq active (gnus-active entry))))
 		    (car active))
 	     nil)
@@ -494,7 +505,7 @@
       (let ((data (cadr (gnus-topic-find-topology topic))))
 	(setcdr data
 		(list (if insert 'visible 'invisible)
-		      (if hide 'hide nil)
+		      (caddr data)
 		      (cadddr data))))
       (if total-remove
 	  (setq gnus-topic-alist
@@ -507,9 +518,9 @@
    (car gnus-group-list-mode) (cdr gnus-group-list-mode)
    nil nil topic level))
 
-(defun gnus-topic-fold (&optional insert)
+(defun gnus-topic-fold (&optional insert topic)
   "Remove/insert the current topic."
-  (let ((topic (gnus-group-topic-name)))
+  (let ((topic (or topic (gnus-group-topic-name))))
     (when topic
       (save-excursion
 	(if (not (gnus-group-active-topic-p))
@@ -533,15 +544,16 @@
     (gnus-topic-update-unreads name unread)
     (beginning-of-line)
     ;; Insert the text.
-    (gnus-add-text-properties
-     (point)
-     (prog1 (1+ (point))
-       (eval gnus-topic-line-format-spec))
-     (list 'gnus-topic (intern name)
-	   'gnus-topic-level level
-	   'gnus-topic-unread unread
-	   'gnus-active active-topic
-	   'gnus-topic-visible visiblep))))
+    (if shownp
+	(gnus-add-text-properties
+	 (point)
+	 (prog1 (1+ (point))
+	   (eval gnus-topic-line-format-spec))
+	 (list 'gnus-topic (intern name)
+	       'gnus-topic-level level
+	       'gnus-topic-unread unread
+	       'gnus-active active-topic
+	       'gnus-topic-visible visiblep)))))
 
 (defun gnus-topic-update-unreads (topic unreads)
   (setq gnus-topic-unreads (delq (assoc topic gnus-topic-unreads)
@@ -584,7 +596,8 @@
   (let* ((topic (gnus-group-topic group))
 	 (groups (cdr (assoc topic gnus-topic-alist)))
 	 (g (cdr (member group groups)))
-	 (unfound t))
+	 (unfound t)
+	 entry)
     ;; Try to jump to a visible group.
     (while (and g (not (gnus-group-goto-group (car g) t)))
       (pop g))
@@ -598,8 +611,20 @@
       (when (and unfound
 		 topic
 		 (not (gnus-topic-goto-missing-topic topic)))
-	(gnus-topic-insert-topic-line
-	 topic t t (car (gnus-topic-find-topology topic)) nil 0)))))
+	(let* ((top (gnus-topic-find-topology topic))
+	       (children (cddr top))
+	       (type (cadr top))
+	       (unread 0)
+	       (entries (gnus-topic-find-groups
+			 (car type) (car gnus-group-list-mode)
+			 (cdr gnus-group-list-mode))))
+	  (while children
+	    (incf unread (gnus-topic-unread (caar (pop children)))))
+	  (while (setq entry (pop entries))
+	    (when (numberp (car entry))
+	      (incf unread (car entry))))
+	  (gnus-topic-insert-topic-line
+	   topic t t (car (gnus-topic-find-topology topic)) nil unread))))))
 
 (defun gnus-topic-goto-missing-topic (topic)
   (if (gnus-topic-goto-topic topic)
@@ -608,15 +633,18 @@
     (let* ((top (gnus-topic-find-topology
 		 (gnus-topic-parent-topic topic)))
 	   (tp (reverse (cddr top))))
-      (while (not (equal (caaar tp) topic))
-	(setq tp (cdr tp)))
-      (pop tp)
-      (while (and tp
-		  (not (gnus-topic-goto-topic (caaar tp))))
-	(pop tp))
-      (if tp
-	  (gnus-topic-forward-topic 1)
-	(gnus-topic-goto-missing-topic (caadr top))))
+      (if (not top)
+	  (gnus-topic-insert-topic-line
+	   topic t t (car (gnus-topic-find-topology topic)) nil 0)
+	(while (not (equal (caaar tp) topic))
+	  (setq tp (cdr tp)))
+	(pop tp)
+	(while (and tp
+		    (not (gnus-topic-goto-topic (caaar tp))))
+	  (pop tp))
+	(if tp
+	    (gnus-topic-forward-topic 1)
+	  (gnus-topic-goto-missing-topic (caadr top)))))
     nil))
 
 (defun gnus-topic-update-topic-line (topic-name &optional reads)
@@ -908,6 +936,7 @@
     "=" gnus-topic-select-group
     "\r" gnus-topic-select-group
     " " gnus-topic-read-group
+    "\C-c\C-x" gnus-topic-expire-articles
     "\C-k" gnus-topic-kill-group
     "\C-y" gnus-topic-yank-group
     "\M-g" gnus-topic-get-new-news-this-topic
@@ -931,6 +960,7 @@
     "c" gnus-topic-copy-group
     "h" gnus-topic-hide-topic
     "s" gnus-topic-show-topic
+    "j" gnus-topic-jump-to-topic
     "M" gnus-topic-move-matching
     "C" gnus-topic-copy-matching
     "\C-i" gnus-topic-indent
@@ -962,6 +992,7 @@
 	["Copy matching" gnus-topic-copy-matching t]
 	["Move matching" gnus-topic-move-matching t])
        ("Topics"
+	["Goto" gnus-topic-jump-to-topic t]
 	["Show" gnus-topic-show-topic t]
 	["Hide" gnus-topic-hide-topic t]
 	["Delete" gnus-topic-delete t]
@@ -969,6 +1000,7 @@
 	["Create" gnus-topic-create-topic t]
 	["Mark" gnus-topic-mark-topic t]
 	["Indent" gnus-topic-indent t]
+	["Sort" gnus-topic-sort-topics t]
 	["Toggle hide empty" gnus-topic-toggle-display-empty-topics t]
 	["Edit parameters" gnus-topic-edit-parameters t])
        ["List active" gnus-topic-list-active t]))))
@@ -982,12 +1014,15 @@
 	  (if (null arg) (not gnus-topic-mode)
 	    (> (prefix-numeric-value arg) 0)))
     ;; Infest Gnus with topics.
-     (if (not gnus-topic-mode)
+    (if (not gnus-topic-mode)
  	(setq gnus-goto-missing-group-function nil)
       (when (gnus-visual-p 'topic-menu 'menu)
 	(gnus-topic-make-menu-bar))
       (gnus-set-format 'topic t)
-      (gnus-add-minor-mode 'gnus-topic-mode " Topic" gnus-topic-mode-map)
+      (gnus-add-minor-mode 'gnus-topic-mode " Topic"
+			   gnus-topic-mode-map nil (lambda (&rest junk)
+						     (interactive)
+						     (gnus-topic-mode nil t)))
       (add-hook 'gnus-group-catchup-group-hook 'gnus-topic-update-topic)
       (set (make-local-variable 'gnus-group-prepare-function)
 	   'gnus-group-prepare-topics)
@@ -1032,7 +1067,8 @@
   (if (gnus-group-topic-p)
       (let ((gnus-group-list-mode
 	     (if all (cons (if (numberp all) all 7) t) gnus-group-list-mode)))
-	(gnus-topic-fold all))
+	(gnus-topic-fold all)
+	(gnus-dribble-touch))
     (gnus-group-select-group all)))
 
 (defun gnus-mouse-pick-topic (e)
@@ -1041,6 +1077,19 @@
   (mouse-set-point e)
   (gnus-topic-read-group nil))
 
+(defun gnus-topic-expire-articles (topic)
+  "Expire articles in this topic or group."
+  (interactive (list (gnus-group-topic-name)))
+  (if (not topic)
+      (call-interactively 'gnus-group-expire-articles)
+    (save-excursion
+      (gnus-message 5 "Expiring groups in %s..." topic)
+      (let ((gnus-group-marked
+	     (mapcar (lambda (entry) (car (nth 2 entry)))
+		     (gnus-topic-find-groups topic gnus-level-killed t))))
+	(gnus-group-expire-articles nil))
+      (gnus-message 5 "Expiring groups in %s...done" topic))))
+
 (defun gnus-topic-read-group (&optional all no-article group)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
@@ -1086,44 +1135,60 @@
   (gnus-group-list-groups)
   (gnus-topic-goto-topic topic))
 
+;; FIXME: 
+;;  1. When the marked groups are overlapped with the process 
+;;     region, the behavior of move or remove is not right.
+;;  2. Can't process on several marked groups with a same name, 
+;;     because gnus-group-marked only keeps one copy.
+
 (defun gnus-topic-move-group (n topic &optional copyp)
   "Move the next N groups to TOPIC.
 If COPYP, copy the groups instead."
   (interactive
    (list current-prefix-arg
 	 (completing-read "Move to topic: " gnus-topic-alist nil t)))
-  (let ((groups (gnus-group-process-prefix n))
+  (let ((use-marked (and (not n) (not (gnus-region-active-p)) 
+			 gnus-group-marked t))
+	(groups (gnus-group-process-prefix n))
 	(topicl (assoc topic gnus-topic-alist))
+	(start-topic (gnus-group-topic-name))
 	(start-group (progn (forward-line 1) (gnus-group-group-name)))
-	(start-topic (gnus-group-topic-name))
 	entry)
+    (if (and (not groups) (not copyp) start-topic)
+	(gnus-topic-move start-topic topic)
+      (mapcar
+       (lambda (g)
+	 (gnus-group-remove-mark g use-marked)
+	 (when (and
+		(setq entry (assoc (gnus-current-topic) gnus-topic-alist))
+		(not copyp))
+	   (setcdr entry (gnus-delete-first g (cdr entry))))
+	 (nconc topicl (list g)))
+       groups)
+      (gnus-topic-enter-dribble)
+      (if start-group
+	  (gnus-group-goto-group start-group)
+	(gnus-topic-goto-topic start-topic))
+      (gnus-group-list-groups))))
+
+(defun gnus-topic-remove-group (&optional n)
+  "Remove the current group from the topic."
+  (interactive "P")
+  (let ((use-marked (and (not n) (not (gnus-region-active-p)) 
+			 gnus-group-marked t))
+	(groups (gnus-group-process-prefix n)))
     (mapcar
-     (lambda (g)
-       (gnus-group-remove-mark g)
-       (when (and
-	      (setq entry (assoc (gnus-current-topic) gnus-topic-alist))
-	      (not copyp))
-	 (setcdr entry (gnus-delete-first g (cdr entry))))
-       (nconc topicl (list g)))
+     (lambda (group)
+       (gnus-group-remove-mark group use-marked)
+       (let ((topicl (assoc (gnus-current-topic) gnus-topic-alist))
+	     (buffer-read-only nil))
+	 (when (and topicl group)
+	   (gnus-delete-line)
+	   (gnus-delete-first group topicl))
+	 (gnus-topic-update-topic)))
      groups)
     (gnus-topic-enter-dribble)
-    (if start-group
-	(gnus-group-goto-group start-group)
-      (gnus-topic-goto-topic start-topic))
-    (gnus-group-list-groups)))
-
-(defun gnus-topic-remove-group (&optional arg)
-  "Remove the current group from the topic."
-  (interactive "P")
-  (gnus-group-iterate arg
-    (lambda (group)
-      (let ((topicl (assoc (gnus-current-topic) gnus-topic-alist))
-	    (buffer-read-only nil))
-	(when (and topicl group)
-	  (gnus-delete-line)
-	  (gnus-delete-first group topicl))
-	(gnus-topic-update-topic)
-	(gnus-group-position-point)))))
+    (gnus-group-position-point)))
 
 (defun gnus-topic-copy-group (n topic)
   "Copy the current group to a topic."
@@ -1145,7 +1210,12 @@
 	(gnus-topic-find-topology topic nil nil gnus-topic-topology)
 	(gnus-topic-enter-dribble))
     (gnus-group-kill-group n discard)
-    (gnus-topic-update-topic)))
+    (if (not (gnus-group-topic-p))
+	(gnus-topic-update-topic)
+      ;; Move up one line so that we update the right topic.
+      (forward-line -1)
+      (gnus-topic-update-topic)
+      (forward-line 1))))
 
 (defun gnus-topic-yank-group (&optional arg)
   "Yank the last topic."
@@ -1195,18 +1265,32 @@
 	    (setq alist (cdr alist))))))
     (gnus-topic-update-topic)))
 
-(defun gnus-topic-hide-topic ()
-  "Hide the current topic."
-  (interactive)
+(defun gnus-topic-hide-topic (&optional permanent)
+  "Hide the current topic.
+If PERMANENT, make it stay hidden in subsequent sessions as well."
+  (interactive "P")
   (when (gnus-current-topic)
     (gnus-topic-goto-topic (gnus-current-topic))
-    (gnus-topic-remove-topic nil nil 'hidden)))
+    (if permanent
+	(setcar (cddr 
+		 (cadr
+		  (gnus-topic-find-topology (gnus-current-topic))))
+		'hidden))
+    (gnus-topic-remove-topic nil nil)))
 
-(defun gnus-topic-show-topic ()
-  "Show the hidden topic."
-  (interactive)
+(defun gnus-topic-show-topic (&optional permanent)
+  "Show the hidden topic.
+If PERMANENT, make it stay shown in subsequent sessions as well."
+  (interactive "P")
   (when (gnus-group-topic-p)
-    (gnus-topic-remove-topic t nil 'shown)))
+    (if (not permanent)
+	(gnus-topic-remove-topic t nil)
+      (let ((topic 
+	     (gnus-topic-find-topology 
+	      (completing-read "Show topic: " gnus-topic-alist nil t))))
+	(setcar (cddr (cadr topic)) nil)
+	(setcar (cdr (cadr topic)) 'visible)
+	(gnus-group-list-groups)))))
 
 (defun gnus-topic-mark-topic (topic &optional unmark)
   "Mark all groups in the topic with the process mark."
@@ -1450,6 +1534,68 @@
   (interactive "P")
   (gnus-topic-sort-groups 'gnus-group-sort-by-method reverse))
 
+(defun gnus-topic-sort-topics-1 (top reverse)
+  (if (cdr top)
+      (let ((subtop
+	     (mapcar `(lambda (top)
+			(gnus-topic-sort-topics-1 top ,reverse))
+		     (sort (cdr top)
+			   '(lambda (t1 t2) 
+			      (string-lessp (caar t1) (caar t2)))))))
+	(setcdr top (if reverse (reverse subtop) subtop))))
+  top)
+
+(defun gnus-topic-sort-topics (&optional topic reverse)
+  "Sort topics in TOPIC alphabeticaly by topic name.
+If REVERSE, reverse the sorting order."
+  (interactive 
+   (list (completing-read "Sort topics in : " gnus-topic-alist nil t 
+			  (gnus-current-topic))
+	 current-prefix-arg))
+  (let ((topic-topology (or (and topic (cdr (gnus-topic-find-topology topic)))
+			    gnus-topic-topology)))
+    (gnus-topic-sort-topics-1 topic-topology reverse)
+    (gnus-topic-enter-dribble)
+    (gnus-group-list-groups)
+    (gnus-topic-goto-topic topic)))
+
+(defun gnus-topic-move (current to)
+  "Move the CURRENT topic to TO."
+  (interactive 
+   (list 
+    (gnus-group-topic-name)
+    (completing-read "Move to topic: " gnus-topic-alist nil t)))
+  (unless (and current to)
+    (error "Can't find topic"))
+  (let ((current-top (cdr (gnus-topic-find-topology current)))
+	(to-top (cdr (gnus-topic-find-topology to))))
+    (unless current-top
+      (error "Can't find topic `%s'" current))
+    (unless to-top
+      (error "Can't find topic `%s'" to))
+    (if (gnus-topic-find-topology to current-top 0);; Don't care the level
+	(error "Can't move `%s' to its sub-level" current))
+    (gnus-topic-find-topology current nil nil 'delete)
+    (while (cdr to-top)
+      (setq to-top (cdr to-top)))
+    (setcdr to-top (list current-top))
+    (gnus-topic-enter-dribble)
+    (gnus-group-list-groups)
+    (gnus-topic-goto-topic current)))
+
+(defun gnus-subscribe-topics (newsgroup)
+  (catch 'end
+    (let (match gnus-group-change-level-function)
+      (dolist (topic (gnus-topic-list))
+	(when (and (setq match (cdr (assq 'subscribe
+					  (gnus-topic-parameters topic))))
+		   (string-match match newsgroup))
+	  ;; Just subscribe the group.
+	  (gnus-subscribe-alphabetically newsgroup)
+	  ;; Add the group to the topic.
+	  (nconc (assoc topic gnus-topic-alist) (list newsgroup))
+	  (throw 'end t))))))
+	  
 (provide 'gnus-topic)
 
 ;;; gnus-topic.el ends here
--- a/lisp/gnus/gnus-undo.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-undo.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; gnus-undo.el --- minor mode for undoing in Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -46,8 +48,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus-util)
 (require 'gnus)
 (require 'custom)
@@ -86,11 +86,11 @@
   (setq gnus-undo-mode-map (make-sparse-keymap))
 
   (gnus-define-keys gnus-undo-mode-map
-   "\M-\C-_"     gnus-undo
-   "\C-_"        gnus-undo
-   "\C-xu"       gnus-undo
-   ;; many people are used to type `C-/' on X terminals and get `C-_'.
-   [(control /)] gnus-undo))
+    "\M-\C-_"     gnus-undo
+    "\C-_"        gnus-undo
+    "\C-xu"       gnus-undo
+    ;; many people are used to type `C-/' on X terminals and get `C-_'.
+    [(control /)] gnus-undo))
 
 (defun gnus-undo-make-menu-bar ()
   ;; This is disabled for the time being.
--- a/lisp/gnus/gnus-util.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-util.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-util.el --- utility functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -33,12 +34,10 @@
 (require 'custom)
 (eval-when-compile (require 'cl))
 (require 'nnheader)
-(require 'timezone)
 (require 'message)
-(eval-when-compile (require 'rmail))
+(require 'time-date)
 
 (eval-and-compile
-  (autoload 'nnmail-date-to-time "nnmail")
   (autoload 'rmail-insert-rmail-file-header "rmail")
   (autoload 'rmail-count-new-messages "rmail")
   (autoload 'rmail-show-message "rmail"))
@@ -76,9 +75,6 @@
 	 (set symbol nil))
      symbol))
 
-(defun gnus-truncate-string (str width)
-  (substring str 0 width))
-
 ;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>.  A safe way
 ;; to limit the length of a string.  This function is necessary since
 ;; `(substr "abc" 0 30)' pukes with "Args out of range".
@@ -107,25 +103,15 @@
      (when (gnus-buffer-exists-p buf)
        (kill-buffer buf))))
 
-(if (fboundp 'point-at-bol)
-    (fset 'gnus-point-at-bol 'point-at-bol)
-  (defun gnus-point-at-bol ()
-    "Return point at the beginning of the line."
-    (let ((p (point)))
-      (beginning-of-line)
-      (prog1
-	  (point)
-	(goto-char p)))))
+(defalias 'gnus-point-at-bol
+  (if (fboundp 'point-at-bol)
+      'point-at-bol
+    'line-beginning-position))
 
-(if (fboundp 'point-at-eol)
-    (fset 'gnus-point-at-eol 'point-at-eol)
-  (defun gnus-point-at-eol ()
-    "Return point at the end of the line."
-    (let ((p (point)))
-      (end-of-line)
-      (prog1
-	  (point)
-	(goto-char p)))))
+(defalias 'gnus-point-at-eol
+  (if (fboundp 'point-at-eol)
+      'point-at-eol
+    'line-end-position))
 
 (defun gnus-delete-first (elt list)
   "Delete by side effect the first occurrence of ELT as a member of LIST."
@@ -179,8 +165,8 @@
 	(and (string-match "(.*" from)
 	     (setq name (substring from (1+ (match-beginning 0))
 				   (match-end 0)))))
-    ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
-    (list (or name from) (or address from))))
+    (list (if (string= name "") nil name) (or address from))))
+
 
 (defun gnus-fetch-field (field)
   "Return the value of the header FIELD of current article."
@@ -232,43 +218,6 @@
 
 ;;; Time functions.
 
-(defun gnus-days-between (date1 date2)
-  ;; Return the number of days between date1 and date2.
-  (- (gnus-day-number date1) (gnus-day-number date2)))
-
-(defun gnus-day-number (date)
-  (let ((dat (mapcar (lambda (s) (and s (string-to-int s)) )
-		     (timezone-parse-date date))))
-    (timezone-absolute-from-gregorian
-     (nth 1 dat) (nth 2 dat) (car dat))))
-
-(defun gnus-time-to-day (time)
-  "Convert TIME to day number."
-  (let ((tim (decode-time time)))
-    (timezone-absolute-from-gregorian
-     (nth 4 tim) (nth 3 tim) (nth 5 tim))))
-
-(defun gnus-encode-date (date)
-  "Convert DATE to internal time."
-  (let* ((parse (timezone-parse-date date))
-	 (date (mapcar (lambda (d) (and d (string-to-int d))) parse))
-	 (time (mapcar 'string-to-int (timezone-parse-time (aref parse 3)))))
-    (encode-time (caddr time) (cadr time) (car time)
-		 (caddr date) (cadr date) (car date)
-		 (* 60 (timezone-zone-to-minute (nth 4 date))))))
-
-(defun gnus-time-minus (t1 t2)
-  "Subtract two internal times."
-  (let ((borrow (< (cadr t1) (cadr t2))))
-    (list (- (car t1) (car t2) (if borrow 1 0))
-	  (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
-
-(defun gnus-time-less (t1 t2)
-  "Say whether time T1 is less than time T2."
-  (or (< (car t1) (car t2))
-      (and (= (car t1) (car t2))
-	   (< (nth 1 t1) (nth 1 t2)))))
-
 (defun gnus-file-newer-than (file date)
   (let ((fdate (nth 5 (file-attributes file))))
     (or (> (car fdate) (car date))
@@ -343,20 +292,9 @@
 
 (defun gnus-dd-mmm (messy-date)
   "Return a string like DD-MMM from a big messy string."
-  (let ((datevec (ignore-errors (timezone-parse-date messy-date))))
-    (if (or (not datevec)
-	    (string-equal "0" (aref datevec 1)))
-	"??-???"
-      (format "%2s-%s"
-	      (condition-case ()
-		  ;; Make sure leading zeroes are stripped.
-		  (number-to-string (string-to-number (aref datevec 2)))
-		(error "??"))
-	      (capitalize
-	       (or (car
-		    (nth (1- (string-to-number (aref datevec 1)))
-			 timezone-months-assoc))
-		   "???"))))))
+  (condition-case ()
+      (format-time-string "%d-%b" (safe-date-to-time messy-date))
+    (error "  -   ")))
 
 (defmacro gnus-date-get-time (date)
   "Convert DATE string to Emacs time.
@@ -367,7 +305,7 @@
 	 '(0 0)
        (or (get-text-property 0 'gnus-time d)
 	   ;; or compute the value...
-	   (let ((time (nnmail-date-to-time d)))
+	   (let ((time (safe-date-to-time d)))
 	     ;; and store it back in the string.
 	     (put-text-property 0 1 'gnus-time time d)
 	     time)))))
@@ -451,12 +389,14 @@
 	    ids))
     (nreverse ids)))
 
-(defun gnus-parent-id (references &optional n)
+(defsubst gnus-parent-id (references &optional n)
   "Return the last Message-ID in REFERENCES.
 If N, return the Nth ancestor instead."
   (when references
     (let ((ids (inline (gnus-split-references references))))
-      (car (last ids (or n 1))))))
+      (while (nthcdr (or n 1) ids)
+	(setq ids (cdr ids)))
+      (car ids))))
 
 (defsubst gnus-buffer-live-p (buffer)
   "Say whether BUFFER is alive or not."
@@ -496,20 +436,8 @@
     (cons (and (numberp event) event) event)))
 
 (defun gnus-sortable-date (date)
-  "Make sortable string by string-lessp from DATE.
-Timezone package is used."
-  (condition-case ()
-      (progn
-	(setq date (inline (timezone-fix-time
-			    date nil
-			    (aref (inline (timezone-parse-date date)) 4))))
-	(inline
-	  (timezone-make-sortable-date
-	   (aref date 0) (aref date 1) (aref date 2)
-	   (inline
-	     (timezone-make-time-string
-	      (aref date 3) (aref date 4) (aref date 5))))))
-    (error "")))
+  "Make string suitable for sorting from DATE."
+  (gnus-time-iso8601 (date-to-time date)))
 
 (defun gnus-copy-file (file &optional to)
   "Copy FILE to TO."
@@ -541,7 +469,7 @@
 	(erase-buffer))
     (set-buffer (gnus-get-buffer-create gnus-work-buffer))
     (kill-all-local-variables)
-    (buffer-disable-undo (current-buffer))))
+    (mm-enable-multibyte)))
 
 (defmacro gnus-group-real-name (group)
   "Find the real name of a foreign newsgroup."
@@ -553,21 +481,41 @@
 (defun gnus-make-sort-function (funs)
   "Return a composite sort condition based on the functions in FUNC."
   (cond
-   ((not (listp funs)) funs)
+   ;; Just a simple function.
+   ((gnus-functionp funs) funs)
+   ;; No functions at all.
    ((null funs) funs)
-   ((cdr funs)
+   ;; A list of functions.
+   ((or (cdr funs)
+	(listp (car funs)))
     `(lambda (t1 t2)
        ,(gnus-make-sort-function-1 (reverse funs))))
+   ;; A list containing just one function.
    (t
     (car funs))))
 
 (defun gnus-make-sort-function-1 (funs)
   "Return a composite sort condition based on the functions in FUNC."
-  (if (cdr funs)
-      `(or (,(car funs) t1 t2)
-	   (and (not (,(car funs) t2 t1))
-		,(gnus-make-sort-function-1 (cdr funs))))
-    `(,(car funs) t1 t2)))
+  (let ((function (car funs))
+	(first 't1)
+	(last 't2))
+    (when (consp function)
+      (cond
+       ;; Reversed spec.
+       ((eq (car function) 'not)
+	(setq function (cadr function)
+	      first 't2
+	      last 't1))
+       ((gnus-functionp function)
+	;; Do nothing.
+	)
+       (t
+	(error "Invalid sort spec: %s" function))))
+    (if (cdr funs)
+	`(or (,function ,first ,last)
+	     (and (not (,function ,last ,first))
+		  ,(gnus-make-sort-function-1 (cdr funs))))
+      `(,function ,first ,last))))
 
 (defun gnus-turn-off-edit-menu (type)
   "Turn off edit menu in `gnus-TYPE-mode-map'."
@@ -591,17 +539,19 @@
 
 (defun gnus-make-directory (directory)
   "Make DIRECTORY (and all its parents) if it doesn't exist."
-  (when (and directory
-	     (not (file-exists-p directory)))
-    (make-directory directory t))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+    (when (and directory
+	       (not (file-exists-p directory)))
+      (make-directory directory t)))
   t)
 
 (defun gnus-write-buffer (file)
   "Write the current buffer's contents to FILE."
   ;; Make sure the directory exists.
   (gnus-make-directory (file-name-directory file))
-  ;; Write the buffer.
-  (write-region (point-min) (point-max) file nil 'quietly))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
+    ;; Write the buffer.
+    (write-region (point-min) (point-max) file nil 'quietly)))
 
 (defun gnus-delete-file (file)
   "Delete FILE if it exists."
@@ -614,13 +564,13 @@
     (setq string (replace-match "" t t string)))
   string)
 
-(defun gnus-put-text-property-excluding-newlines (beg end prop val)
+(defsubst gnus-put-text-property-excluding-newlines (beg end prop val)
   "The same as `put-text-property', but don't put this prop on any newlines in the region."
   (save-match-data
     (save-excursion
       (save-restriction
 	(goto-char beg)
-	(while (re-search-forward "[ \t]*\n" end 'move)
+	(while (re-search-forward gnus-emphasize-whitespace-regexp end 'move)
 	  (gnus-put-text-property beg (match-beginning 0) prop val)
 	  (setq beg (point)))
 	(gnus-put-text-property beg (point) prop val)))))
@@ -733,7 +683,8 @@
 		(save-excursion
 		  (set-buffer file-buffer)
 		  (rmail-insert-rmail-file-header)
-		  (let ((require-final-newline nil))
+		  (let ((require-final-newline nil)
+			(coding-system-for-write mm-text-coding-system))
 		    (gnus-write-buffer filename)))
 		(kill-buffer file-buffer))
 	    (error "Output file does not exist")))
@@ -744,7 +695,7 @@
       ;; Decide whether to append to a file or to an Emacs buffer.
       (let ((outbuf (get-file-buffer filename)))
 	(if (not outbuf)
-	    (append-to-file (point-min) (point-max) filename)
+	    (mm-append-to-file (point-min) (point-max) filename)
 	  ;; File has been visited, in buffer OUTBUF.
 	  (set-buffer outbuf)
 	  (let ((buffer-read-only nil)
@@ -784,7 +735,8 @@
 	    (let ((file-buffer (create-file-buffer filename)))
 	      (save-excursion
 		(set-buffer file-buffer)
-		(let ((require-final-newline nil))
+		(let ((require-final-newline nil)
+		      (coding-system-for-write mm-text-coding-system))
 		  (gnus-write-buffer filename)))
 	      (kill-buffer file-buffer))
 	  (error "Output file does not exist")))
@@ -812,7 +764,7 @@
 		    (insert "\n"))
 		  (insert "\n"))
 		(goto-char (point-max))
-		(append-to-file (point-min) (point-max) filename)))
+		(mm-append-to-file (point-min) (point-max) filename)))
 	  ;; File has been visited, in buffer OUTBUF.
 	  (set-buffer outbuf)
 	  (let ((buffer-read-only nil))
@@ -853,84 +805,84 @@
 ;;; .netrc and .authinforc parsing
 ;;;
 
-(defvar gnus-netrc-syntax-table
-  (let ((table (copy-syntax-table text-mode-syntax-table)))
-    (modify-syntax-entry ?@ "w" table)
-    (modify-syntax-entry ?- "w" table)
-    (modify-syntax-entry ?_ "w" table)
-    (modify-syntax-entry ?! "w" table)
-    (modify-syntax-entry ?. "w" table)
-    (modify-syntax-entry ?, "w" table)
-    (modify-syntax-entry ?: "w" table)
-    (modify-syntax-entry ?\; "w" table)
-    (modify-syntax-entry ?% "w" table)
-    (modify-syntax-entry ?) "w" table)
-    (modify-syntax-entry ?( "w" table)
-    table)
-  "Syntax table when parsing .netrc files.")
-
 (defun gnus-parse-netrc (file)
   "Parse FILE and return an list of all entries in the file."
-  (if (not (file-exists-p file))
-      ()
-    (save-excursion
+  (when (file-exists-p file)
+    (with-temp-buffer
       (let ((tokens '("machine" "default" "login"
-		      "password" "account" "macdef" "force"))
+		      "password" "account" "macdef" "force"
+		      "port"))
 	    alist elem result pair)
-	(nnheader-set-temp-buffer " *netrc*")
-	(unwind-protect
-	    (progn
-	      (set-syntax-table gnus-netrc-syntax-table)
-	      (insert-file-contents file)
-	      (goto-char (point-min))
-	      ;; Go through the file, line by line.
-	      (while (not (eobp))
-		(narrow-to-region (point) (gnus-point-at-eol))
-		;; For each line, get the tokens and values.
-		(while (not (eobp))
-		  (skip-chars-forward "\t ")
-		  (unless (eobp)
-		    (setq elem (buffer-substring
-				(point) (progn (forward-sexp 1) (point))))
-		    (cond
-		     ((equal elem "macdef")
-		      ;; We skip past the macro definition.
-		      (widen)
-		      (while (and (zerop (forward-line 1))
-				  (looking-at "$")))
-		      (narrow-to-region (point) (point)))
-		     ((member elem tokens)
-		      ;; Tokens that don't have a following value are ignored,
-		      ;; except "default".
-		      (when (and pair (or (cdr pair)
-					  (equal (car pair) "default")))
-			(push pair alist))
-		      (setq pair (list elem)))
-		     (t
-		      ;; Values that haven't got a preceding token are ignored.
-		      (when pair
-			(setcdr pair elem)
-			(push pair alist)
-			(setq pair nil))))))
-		(if alist
-		    (push (nreverse alist) result))
-		(setq alist nil
-		      pair nil)
-		(widen)
-		(forward-line 1))
-	      (nreverse result))
-	  (kill-buffer " *netrc*"))))))
+	(insert-file-contents file)
+	(goto-char (point-min))
+	;; Go through the file, line by line.
+	(while (not (eobp))
+	  (narrow-to-region (point) (gnus-point-at-eol))
+	  ;; For each line, get the tokens and values.
+	  (while (not (eobp))
+	    (skip-chars-forward "\t ")
+	    ;; Skip lines that begin with a "#".
+	    (if (eq (char-after) ?#)
+		(goto-char (point-max))
+	      (unless (eobp)
+		(setq elem
+		      (if (= (following-char) ?\")
+			  (read (current-buffer))
+			(buffer-substring
+			 (point) (progn (skip-chars-forward "^\t ")
+					(point)))))
+		(cond
+		 ((equal elem "macdef")
+		  ;; We skip past the macro definition.
+		  (widen)
+		  (while (and (zerop (forward-line 1))
+			      (looking-at "$")))
+		  (narrow-to-region (point) (point)))
+		 ((member elem tokens)
+		  ;; Tokens that don't have a following value are ignored,
+		  ;; except "default".
+		  (when (and pair (or (cdr pair)
+				      (equal (car pair) "default")))
+		    (push pair alist))
+		  (setq pair (list elem)))
+		 (t
+		  ;; Values that haven't got a preceding token are ignored.
+		  (when pair
+		    (setcdr pair elem)
+		    (push pair alist)
+		    (setq pair nil)))))))
+	  (when alist
+	    (push (nreverse alist) result))
+	  (setq alist nil
+		pair nil)
+	  (widen)
+	  (forward-line 1))
+	(nreverse result)))))
 
-(defun gnus-netrc-machine (list machine)
-  "Return the netrc values from LIST for MACHINE or for the default entry."
-  (let ((rest list))
-    (while (and list
-		(not (equal (cdr (assoc "machine" (car list))) machine)))
+(defun gnus-netrc-machine (list machine &optional port defaultport)
+  "Return the netrc values from LIST for MACHINE or for the default entry.
+If PORT specified, only return entries with matching port tokens.
+Entries without port tokens default to DEFAULTPORT."
+  (let ((rest list)
+	result)
+    (while list
+      (when (equal (cdr (assoc "machine" (car list))) machine)
+	(push (car list) result))
       (pop list))
-    (car (or list
-	     (progn (while (and rest (not (assoc "default" (car rest))))
-		      (pop rest))
-		    rest)))))
+    (unless result
+      ;; No machine name matches, so we look for default entries.
+      (while rest
+	(when (assoc "default" (car rest))
+	  (push (car rest) result))
+	(pop rest)))
+    (when result
+      (setq result (nreverse result))
+      (while (and result
+		  (not (equal (or port defaultport "nntp")
+			      (or (gnus-netrc-get (car result) "port")
+				  defaultport "nntp"))))
+	(pop result))
+      (car result))))
 
 (defun gnus-netrc-get (alist type)
   "Return the value of token TYPE from ALIST."
@@ -938,7 +890,7 @@
 
 ;;; Various
 
-(defvar gnus-group-buffer) ; Compiler directive
+(defvar gnus-group-buffer)		; Compiler directive
 (defun gnus-alive-p ()
   "Say whether Gnus is running or not."
   (and (boundp 'gnus-group-buffer)
@@ -971,11 +923,12 @@
       (setq alist (delq entry alist)))
     alist))
 
-(defmacro gnus-pull (key alist)
+(defmacro gnus-pull (key alist &optional assoc-p)
   "Modify ALIST to be without KEY."
   (unless (symbolp alist)
     (error "Not a symbol: %s" alist))
-  `(setq ,alist (delq (assq ,key ,alist) ,alist)))
+  (let ((fun (if assoc-p 'assoc 'assq)))
+    `(setq ,alist (delq (,fun ,key ,alist) ,alist))))
 
 (defun gnus-globalify-regexp (re)
   "Returns a regexp that matches a whole line, iff RE matches a part of it."
@@ -983,6 +936,52 @@
 	  re
 	  (unless (string-match "\\$$" re) ".*$")))
 
+(defun gnus-set-window-start (&optional point)
+  "Set the window start to POINT, or (point) if nil."
+  (let ((win (get-buffer-window (current-buffer) t)))
+    (when win
+      (set-window-start win (or point (point))))))
+
+(defun gnus-annotation-in-region-p (b e)
+  (if (= b e)
+      (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t)
+    (text-property-any b e 'gnus-undeletable t)))
+
+(defun gnus-or (&rest elems)
+  "Return non-nil if any of the elements are non-nil."
+  (catch 'found
+    (while elems
+      (when (pop elems)
+	(throw 'found t)))))
+
+(defun gnus-and (&rest elems)
+  "Return non-nil if all of the elements are non-nil."
+  (catch 'found
+    (while elems
+      (unless (pop elems)
+	(throw 'found nil)))
+    t))
+
+(defun gnus-write-active-file (file hashtb &optional full-names)
+  (let ((coding-system-for-write nnmail-active-file-coding-system))
+    (with-temp-file file
+      (mapatoms
+       (lambda (sym)
+	 (when (and sym
+		    (boundp sym)
+		    (symbol-value sym))
+	   (insert (format "%S %d %d y\n"
+			   (if full-names
+			       sym
+			     (intern (gnus-group-real-name (symbol-name sym))))
+			   (or (cdr (symbol-value sym))
+			       (car (symbol-value sym)))
+			   (car (symbol-value sym))))))
+       hashtb)
+      (goto-char (point-max))
+      (while (search-backward "\\." nil t)
+	(delete-char 1)))))
+
 (provide 'gnus-util)
 
 ;;; gnus-util.el ends here
--- a/lisp/gnus/gnus-uu.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-uu.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; 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
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Created: 2 Oct 1993
@@ -28,12 +29,11 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 (require 'gnus-art)
 (require 'message)
 (require 'gnus-msg)
+(require 'mm-decode)
 
 (defgroup gnus-extract nil
   "Extracting encoded files."
@@ -217,9 +217,12 @@
 
 ;; Various variables users may set
 
-(defcustom gnus-uu-tmp-dir temporary-file-directory
+(defcustom gnus-uu-tmp-dir
+  (cond ((fboundp 'temp-directory) (temp-directory))
+	((boundp 'temporary-file-directory) temporary-file-directory)
+	("/tmp/"))
   "*Variable saying where gnus-uu is to do its work.
-Defaults to `temporary-file-directory'."
+Default is \"/tmp/\"."
   :group 'gnus-extract
   :type 'directory)
 
@@ -292,7 +295,9 @@
 
 (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."
   :group 'gnus-extract
@@ -330,7 +335,8 @@
 (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-7][0-7][0-7][ \t]+\\(\\(\\w\\|\\.\\)*\\b\\)")
 
 (defvar gnus-uu-postscript-begin-string "^%!PS-")
 (defvar gnus-uu-postscript-end-string "^%%EOF$")
@@ -345,6 +351,7 @@
 
 (defvar gnus-uu-default-dir gnus-article-save-directory)
 (defvar gnus-uu-digest-from-subject nil)
+(defvar gnus-uu-digest-buffer nil)
 
 ;; Keymaps
 
@@ -370,7 +377,7 @@
 
 (gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
   ;;"x" gnus-uu-extract-any
-  ;;"m" gnus-uu-extract-mime
+  "m" gnus-summary-save-parts
   "u" gnus-uu-decode-uu
   "U" gnus-uu-decode-uu-and-save
   "s" gnus-uu-decode-unshar
@@ -383,17 +390,17 @@
   "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)
+    (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)
 
 
 ;; Commands.
@@ -450,7 +457,7 @@
 			  gnus-uu-default-dir
 			  gnus-uu-default-dir))))
   (setq gnus-uu-binhex-article-name
-	(make-temp-file (concat gnus-uu-work-dir "binhex")))
+	(make-temp-name (concat gnus-uu-work-dir "binhex")))
   (gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
 
 (defun gnus-uu-decode-uu-view (&optional n)
@@ -490,7 +497,7 @@
   (interactive
    (list current-prefix-arg
 	 (read-file-name  (if gnus-uu-save-separate-articles
-			      "Save articles in dir: "
+			      "Save articles is dir: "
 			    "Save articles in file: ")
 			  gnus-uu-default-dir gnus-uu-default-dir)))
   (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
@@ -503,7 +510,7 @@
 	 (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-file (concat gnus-uu-work-dir "binhex")))
+	(make-temp-name (concat gnus-uu-work-dir "binhex")))
   (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
     (gnus-uu-decode-binhex n file)))
 
@@ -514,15 +521,20 @@
   "Digests and forwards all articles in this series."
   (interactive "P")
   (let ((gnus-uu-save-in-digest t)
-	(file (make-temp-file (nnheader-concat gnus-uu-tmp-dir "forward")))
-	buf subject from)
+	(file (make-temp-name (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))
     (gnus-setup-message 'forward
       (setq gnus-uu-digest-from-subject nil)
+      (setq gnus-uu-digest-buffer 
+	    (gnus-get-buffer-create " *gnus-uu-forward*"))
       (gnus-uu-decode-save n file)
-      (setq buf (switch-to-buffer
-		 (gnus-get-buffer-create " *gnus-uu-forward*")))
-      (erase-buffer)
-      (insert-file file)
+      (switch-to-buffer gnus-uu-digest-buffer)
       (let ((fs gnus-uu-digest-from-subject))
 	(when fs
 	  (setq from (caar fs)
@@ -552,9 +564,7 @@
       (when (re-search-forward "^From: ")
 	(delete-region (point) (gnus-point-at-eol))
 	(insert from))
-      (message-forward post))
-    (delete-file file)
-    (kill-buffer buf)
+      (message-forward post t))
     (setq gnus-uu-digest-from-subject nil)))
 
 (defun gnus-uu-digest-post-forward (&optional n)
@@ -565,8 +575,10 @@
 ;; Process marking.
 
 (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): ")))
+  "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")
   (let ((articles (gnus-uu-find-articles-matching regexp)))
     (while articles
       (if unmark
@@ -575,9 +587,10 @@
     (message ""))
   (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 ()
@@ -620,10 +633,12 @@
 (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 ()
@@ -652,7 +667,7 @@
 (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
@@ -808,8 +823,9 @@
    (gnus-uu-save-separate-articles
     (save-excursion
       (set-buffer buffer)
-      (gnus-write-buffer
-       (concat gnus-uu-saved-article-name gnus-current-article))
+      (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))
@@ -835,14 +851,20 @@
 	      (eq in-state 'first-and-last))
 	  (progn
 	    (setq state (list 'begin))
-	    (save-excursion (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
-			    (erase-buffer))
+	    (save-excursion
+	      (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
+	      (erase-buffer))
 	    (save-excursion
 	      (set-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"
+		       (current-time-string) name name))
+	      (when (and message-forward-as-mime gnus-uu-digest-buffer)
+		;; The default part in multipart/digest is message/rfc822.
+		;; Subject is a fake head.
+		(insert "<#part type=text/plain>\nSubject: Topics\n\n"))
+	      (insert "Topics:\n")))
 	(when (not (eq in-state 'end))
 	  (setq state (list 'middle))))
       (save-excursion
@@ -856,14 +878,20 @@
 	      ;; 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 "- ")))
+	    (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))
@@ -881,30 +909,66 @@
 					  (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)))
+	  (setq subj (buffer-substring (match-beginning 1) (match-end 1))))
+	(when subj
 	  (save-excursion
 	    (set-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 "*gnus-uu-pre*")
+	      (goto-char (point-max))
+	      (insert-buffer "*gnus-uu-body*"))
+	  (save-excursion
+	    (set-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 "*gnus-uu-pre*"))
+	      (let ((coding-system-for-write mm-text-coding-system))
+		(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"))
+	    (if gnus-uu-digest-buffer
+		(with-current-buffer gnus-uu-digest-buffer
+		  (goto-char (point-max))
+		  (insert-buffer "*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))
@@ -951,7 +1015,7 @@
 	(beginning-of-line)
 	(forward-line 1)
 	(when (file-exists-p gnus-uu-binhex-article-name)
-	  (append-to-file start-char (point) gnus-uu-binhex-article-name))))
+	  (mm-append-to-file start-char (point) gnus-uu-binhex-article-name))))
     (if (memq 'begin state)
 	(cons gnus-uu-binhex-article-name state)
       state)))
@@ -1026,7 +1090,7 @@
   ;; finally just replaces the next to last number with "[0-9]+".
   (save-excursion
     (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
-    (buffer-disable-undo (current-buffer))
+    (buffer-disable-undo)
     (erase-buffer)
     (insert (regexp-quote string))
 
@@ -1126,7 +1190,7 @@
 	string)
     (save-excursion
       (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (while string-list
 	(erase-buffer)
 	(insert (caar string-list))
@@ -1201,9 +1265,10 @@
 				       &optional sloppy limit no-errors)
   (let ((state 'first)
 	(gnus-asynchronous nil)
+	(gnus-inhibit-treatment t)
 	has-been-begin article result-file result-files process-state
 	gnus-summary-display-article-function
-	gnus-article-display-hook gnus-article-prepare-hook
+	gnus-article-prepare-hook gnus-display-mime-function
 	article-series files)
 
     (while (and articles
@@ -1394,7 +1459,7 @@
 	  ;; We replace certain characters that could make things messy.
 	  (setq gnus-uu-file-name
 		(let ((nnheader-file-name-translation-alist
-		       '((?/ . ?,) (? . ?_) (?* . ?_) (?$ . ?_))))
+		       '((?/ . ?,) (?  . ?_) (?* . ?_) (?$ . ?_))))
 		  (nnheader-translate-file-chars (match-string 1))))
           (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
 
@@ -1471,6 +1536,21 @@
 	  (cons (if (= (length files) 1) (car files) files) state)
 	state))))
 
+(defvar gnus-uu-unshar-warning
+  "*** WARNING ***
+
+Shell archives are an archaic method of bundling files for distribution
+across computer networks.  During the unpacking process, arbitrary commands
+are executed on your system, and all kinds of nasty things can happen.
+Please examine the archive very carefully before you instruct Emacs to
+unpack it.  You can browse the archive buffer using \\[scroll-other-window].
+
+If you are unsure what to do, please answer \"no\"."
+  "Text of warning message displayed by `gnus-uu-unshar-article'.
+Make sure that this text consists only of few text lines.  Otherwise,
+Gnus might fail to display all of it.")
+
+
 ;; This function is used by `gnus-uu-grab-articles' to treat
 ;; a shared article.
 (defun gnus-uu-unshar-article (process-buffer in-state)
@@ -1481,14 +1561,31 @@
       (goto-char (point-min))
       (if (not (re-search-forward gnus-uu-shar-begin-string nil t))
 	  (setq state (list 'wrong-type))
-	(beginning-of-line)
-	(setq start-char (point))
-	(call-process-region
-	 start-char (point-max) shell-file-name nil
-	 (gnus-get-buffer-create gnus-uu-output-buffer-name) nil
-	 shell-command-switch
-	 (concat "cd " gnus-uu-work-dir " "
-		 gnus-shell-command-separator  " sh"))))
+	(save-window-excursion
+	  (save-excursion
+	    (switch-to-buffer (current-buffer))
+	    (delete-other-windows)
+	    (let ((buffer (get-buffer-create (generate-new-buffer-name
+					      "*Warning*"))))
+	      (unless
+		  (unwind-protect
+		      (with-current-buffer buffer
+			(insert (substitute-command-keys 
+				 gnus-uu-unshar-warning))
+			(goto-char (point-min))
+			(display-buffer buffer)
+			(yes-or-no-p "This is a shell archive, unshar it? "))
+		    (kill-buffer buffer))
+		(setq state (list 'error))))))
+	(unless (memq 'error state)
+	  (beginning-of-line)
+	  (setq start-char (point))
+	  (call-process-region
+	   start-char (point-max) shell-file-name nil
+	   (gnus-get-buffer-create gnus-uu-output-buffer-name) nil
+	   shell-command-switch
+	   (concat "cd " gnus-uu-work-dir " "
+		   gnus-shell-command-separator  " sh")))))
     state))
 
 ;; Returns the name of what the shar file is going to unpack.
@@ -1678,7 +1775,8 @@
 		 gnus-uu-tmp-dir)))
 
       (setq gnus-uu-work-dir
-	    (make-temp-file (concat gnus-uu-tmp-dir "gnus") t))
+	    (make-temp-name (concat gnus-uu-tmp-dir "gnus")))
+      (gnus-make-directory gnus-uu-work-dir)
       (set-file-modes gnus-uu-work-dir 448)
       (setq gnus-uu-work-dir (file-name-as-directory gnus-uu-work-dir))
       (push (cons gnus-newsgroup-name gnus-uu-work-dir)
@@ -1695,23 +1793,11 @@
     (when (setq buf (get-buffer gnus-uu-output-buffer-name))
       (kill-buffer buf))))
 
-(defun gnus-quote-arg-for-sh-or-csh (arg)
-  (let ((pos 0) new-pos accum)
-    ;; *** bug: we don't handle newline characters properly
-    (while (setq new-pos (string-match "[;!`\"$\\& \t{}]" arg pos))
-      (push (substring arg pos new-pos) accum)
-      (push "\\" accum)
-      (push (list (aref arg new-pos)) accum)
-      (setq pos (1+ new-pos)))
-    (if (= pos 0)
-        arg
-      (apply 'concat (nconc (nreverse accum) (list (substring arg pos)))))))
-
 ;; Inputs an action and a filename and returns a full command, making sure
 ;; that the filename will be treated as a single argument when the shell
 ;; executes the command.
 (defun gnus-uu-command (action file)
-  (let ((quoted-file (gnus-quote-arg-for-sh-or-csh file)))
+  (let ((quoted-file (mm-quote-arg file)))
     (if (string-match "%s" action)
 	(format action quoted-file)
       (concat action " " quoted-file))))
@@ -1807,7 +1893,9 @@
 
   (gnus-summary-post-news)
 
-  (use-local-map (copy-keymap (current-local-map)))
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map (current-local-map))
+    (use-local-map map))
   (local-set-key "\C-c\C-c" 'gnus-summary-edit-article-done)
   (local-set-key "\C-c\C-c" 'gnus-uu-post-news-inews)
   (local-set-key "\C-c\C-s" 'gnus-uu-post-news-inews)
--- a/lisp/gnus/gnus-vm.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-vm.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,7 +1,9 @@
 ;;; gnus-vm.el --- vm interface for Gnus
-;; Copyright (C) 1994,95,96,97,98 Free Software Foundation, Inc.
 
-;; Author: Per Persson <pp@gnu.org>
+;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
+
+;; Author: Per Persson <pp@gnu.ai.mit.edu>
 ;; Keywords: news, mail
 
 ;; This file is part of GNU Emacs.
@@ -36,6 +38,7 @@
 (require 'gnus-msg)
 
 (eval-when-compile
+  (require 'cl)
   (autoload 'vm-mode "vm")
   (autoload 'vm-save-message "vm")
   (autoload 'vm-forward-message "vm")
@@ -46,11 +49,10 @@
   "Inhibit loading `win-vm' if using a window-system.
 Has to be set before gnus-vm is loaded.")
 
-(or gnus-vm-inhibit-window-system
-    (condition-case nil
-	(when window-system
-	  (require 'win-vm))
-      (error nil)))
+(unless gnus-vm-inhibit-window-system
+  (ignore-errors
+    (when window-system
+      (require 'win-vm))))
 
 (when (not (featurep 'vm))
   (load "vm"))
--- a/lisp/gnus/gnus-win.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus-win.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus-win.el --- window configuration functions for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -27,8 +28,6 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'gnus)
 
 (defgroup gnus-windows nil
@@ -87,9 +86,9 @@
 		  (article 1.0)))
       (t
        '(vertical 1.0
-		 (summary 0.25 point)
-		 (if gnus-carpal '(summary-carpal 4))
-		 (article 1.0)))))
+		  (summary 0.25 point)
+		  (if gnus-carpal '(summary-carpal 4))
+		  (article 1.0)))))
     (server
      (vertical 1.0
 	       (server 1.0 point)
@@ -288,7 +287,7 @@
 (defun gnus-configure-frame (split &optional window)
   "Split WINDOW according to SPLIT."
   (unless window
-    (setq window (get-buffer-window (current-buffer))))
+    (setq window (or (get-buffer-window (current-buffer)) (selected-window))))
   (select-window window)
   ;; This might be an old-stylee buffer config.
   (when (vectorp split)
@@ -320,9 +319,11 @@
       (let ((buffer (cond ((stringp type) type)
 			  (t (cdr (assq type gnus-window-to-buffer))))))
 	(unless buffer
-	  (error "Illegal buffer type: %s" type))
-	(switch-to-buffer (gnus-get-buffer-create
-			   (gnus-window-to-buffer-helper buffer)))
+	  (error "Invalid buffer type: %s" type))
+	(let ((buf (gnus-get-buffer-create
+ 		    (gnus-window-to-buffer-helper buffer))))
+ 	  (if (eq buf (window-buffer (selected-window))) (set-buffer buf)
+ 	    (switch-to-buffer buf)))
 	(when (memq 'frame-focus split)
 	  (setq gnus-window-frame-focus window))
 	;; We return the window if it has the `point' spec.
@@ -375,7 +376,7 @@
 		  ((integerp size)
 		   (setq s size))
 		  (t
-		   (error "Illegal size: %s" size)))
+		   (error "Invalid size: %s" size)))
 	    ;; Try to make sure that we are inside the safe limits.
 	    (cond ((zerop s))
 		  ((eq type 'horizontal)
@@ -410,48 +411,50 @@
 (defvar gnus-frame-split-p nil)
 
 (defun gnus-configure-windows (setting &optional force)
-  (setq gnus-current-window-configuration setting)
-  (setq force (or force gnus-always-force-window-configuration))
-  (setq setting (gnus-windows-old-to-new setting))
-  (let ((split (if (symbolp setting)
-		   (cadr (assq setting gnus-buffer-configuration))
-		 setting))
-	all-visible)
-
-    (setq gnus-frame-split-p nil)
+  (if (window-configuration-p setting)
+      (set-window-configuration setting)
+    (setq gnus-current-window-configuration setting)
+    (setq force (or force gnus-always-force-window-configuration))
+    (setq setting (gnus-windows-old-to-new setting))
+    (let ((split (if (symbolp setting)
+		     (cadr (assq setting gnus-buffer-configuration))
+		   setting))
+	  all-visible)
 
-    (unless split
-      (error "No such setting: %s" setting))
+      (setq gnus-frame-split-p nil)
+
+      (unless split
+	(error "No such setting in `gnus-buffer-configuration': %s" setting))
 
-    (if (and (setq all-visible (gnus-all-windows-visible-p split))
-	     (not force))
-	;; All the windows mentioned are already visible, so we just
-	;; put point in the assigned buffer, and do not touch the
-	;; winconf.
-	(select-window all-visible)
+      (if (and (setq all-visible (gnus-all-windows-visible-p split))
+	       (not force))
+	  ;; All the windows mentioned are already visible, so we just
+	  ;; put point in the assigned buffer, and do not touch the
+	  ;; winconf.
+	  (select-window all-visible)
 
-      ;; Either remove all windows or just remove all Gnus windows.
-      (let ((frame (selected-frame)))
-	(unwind-protect
-	    (if gnus-use-full-window
-		;; We want to remove all other windows.
-		(if (not gnus-frame-split-p)
-		    ;; This is not a `frame' split, so we ignore the
-		    ;; other frames.
-		    (delete-other-windows)
-		  ;; This is a `frame' split, so we delete all windows
-		  ;; on all frames.
-		  (gnus-delete-windows-in-gnusey-frames))
-	      ;; Just remove some windows.
-	      (gnus-remove-some-windows)
-	      (switch-to-buffer nntp-server-buffer))
-	  (select-frame frame)))
+	;; Either remove all windows or just remove all Gnus windows.
+	(let ((frame (selected-frame)))
+	  (unwind-protect
+	      (if gnus-use-full-window
+		  ;; We want to remove all other windows.
+		  (if (not gnus-frame-split-p)
+		      ;; This is not a `frame' split, so we ignore the
+		      ;; other frames.
+		      (delete-other-windows)
+		    ;; This is a `frame' split, so we delete all windows
+		    ;; on all frames.
+		    (gnus-delete-windows-in-gnusey-frames))
+		;; Just remove some windows.
+		(gnus-remove-some-windows)
+		(switch-to-buffer nntp-server-buffer))
+	    (select-frame frame)))
 
-      (switch-to-buffer nntp-server-buffer)
-      (let (gnus-window-frame-focus)
-	(gnus-configure-frame split (get-buffer-window (current-buffer)))
-	(when gnus-window-frame-focus
-	  (select-frame (window-frame gnus-window-frame-focus)))))))
+	(let (gnus-window-frame-focus)
+	  (switch-to-buffer nntp-server-buffer)
+	  (gnus-configure-frame split)
+	  (when gnus-window-frame-focus
+	    (select-frame (window-frame gnus-window-frame-focus))))))))
 
 (defun gnus-delete-windows-in-gnusey-frames ()
   "Do a `delete-other-windows' in all frames that have Gnus windows."
@@ -502,11 +505,11 @@
 	(setq buffer (cond ((stringp type) type)
 			   (t (cdr (assq type gnus-window-to-buffer)))))
 	(unless buffer
-	  (error "Illegal buffer type: %s" type))
+	  (error "Invalid buffer type: %s" type))
 	(if (and (setq buf (get-buffer (gnus-window-to-buffer-helper buffer)))
 		 (setq win (get-buffer-window buf t)))
 	    (if (memq 'point split)
-	      (setq all-visible win))
+		(setq all-visible win))
 	  (setq all-visible nil)))
        (t
 	(when (eq type 'frame)
--- a/lisp/gnus/gnus.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/gnus.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; gnus.el --- a newsreader for GNU Emacs
-;; Copyright (C) 1987,88,89,90,93,94,95,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
+;;        1997, 1998, 2000 Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -29,13 +30,8 @@
 (eval '(run-hooks 'gnus-load-hook))
 
 (eval-when-compile (require 'cl))
-
-(eval-when-compile (require 'cl))
-
-(require 'custom)
-(eval-and-compile
-  (if (< emacs-major-version 20)
-      (require 'gnus-load)))
+(require 'mm-util)
+
 (require 'message)
 
 (defgroup gnus nil
@@ -43,6 +39,12 @@
   :group 'news
   :group 'mail)
 
+(defgroup gnus-charset nil
+  "Group character set issues."
+  :link '(custom-manual "(gnus)Charsets")
+  :version "21.1"
+  :group 'gnus)
+
 (defgroup gnus-cache nil
   "Cache interface."
   :group 'gnus)
@@ -247,12 +249,16 @@
   :link '(custom-manual "(gnus)Various Various")
   :group 'gnus)
 
+(defgroup gnus-mime nil
+  "Variables for controlling the Gnus MIME interface."
+  :group 'gnus)
+
 (defgroup gnus-exit nil
   "Exiting gnus."
   :link '(custom-manual "(gnus)Exiting Gnus")
   :group 'gnus)
 
-(defconst gnus-version-number "5.7"
+(defconst gnus-version-number "5.8.8"
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Gnus v%s" gnus-version-number)
@@ -270,8 +276,6 @@
   :group 'gnus-start
   :type 'boolean)
 
-;;; Kludges to help the transition from the old `custom.el'.
-
 (unless (featurep 'gnus-xmas)
   (defalias 'gnus-make-overlay 'make-overlay)
   (defalias 'gnus-delete-overlay 'delete-overlay)
@@ -287,11 +291,33 @@
   (defalias 'gnus-character-to-event 'identity)
   (defalias 'gnus-add-text-properties 'add-text-properties)
   (defalias 'gnus-put-text-property 'put-text-property)
-  (defalias 'gnus-mode-line-buffer-identification 'identity)
+  (defvar gnus-mode-line-image-cache t)
+  (if (fboundp 'find-image)
+      (defun gnus-mode-line-buffer-identification (line)
+	(let ((str (car-safe line)))
+	  (if (and (stringp str)
+		   (string-match "^Gnus:" str))
+	      (progn (add-text-properties
+		      0 5
+		      (list 'display
+			    (if (eq t gnus-mode-line-image-cache)
+				(setq gnus-mode-line-image-cache
+				      (find-image
+				       '((:type xpm :file "gnus-pointer.xpm"
+						:ascent 100)
+					 (:type xbm :file "gnus-pointer.xbm"
+						:ascent 100))))
+			      gnus-mode-line-image-cache)
+			    'help-echo "This is Gnus")
+		      str)
+		     (list str))
+	    line)))
+    (defalias 'gnus-mode-line-buffer-identification 'identity))
   (defalias 'gnus-characterp 'numberp)
   (defalias 'gnus-deactivate-mark 'deactivate-mark)
   (defalias 'gnus-window-edges 'window-edges)
-  (defalias 'gnus-key-press-event-p 'numberp))
+  (defalias 'gnus-key-press-event-p 'numberp)
+  (defalias 'gnus-decode-rfc1522 'ignore))
 
 ;; We define these group faces here to avoid the display
 ;; update forced when creating new faces.
@@ -362,6 +388,72 @@
      ()))
   "Level 3 empty newsgroup face.")
 
+(defface gnus-group-news-4-face
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 4 newsgroup face.")
+
+(defface gnus-group-news-4-empty-face
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 4 empty newsgroup face.")
+
+(defface gnus-group-news-5-face
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 5 newsgroup face.")
+
+(defface gnus-group-news-5-empty-face
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 5 empty newsgroup face.")
+
+(defface gnus-group-news-6-face
+  '((((class color)
+      (background dark))
+     (:bold t))
+    (((class color)
+      (background light))
+     (:bold t))
+    (t
+     ()))
+  "Level 6 newsgroup face.")
+
+(defface gnus-group-news-6-empty-face
+  '((((class color)
+      (background dark))
+     ())
+    (((class color)
+      (background light))
+     ())
+    (t
+     ()))
+  "Level 6 empty newsgroup face.")
+
 (defface gnus-group-news-low-face
   '((((class color)
       (background dark))
@@ -639,13 +731,13 @@
 (defface gnus-splash-face
   '((((class color)
       (background dark))
-     (:foreground "ForestGreen"))
+     (:foreground "Brown"))
     (((class color)
       (background light))
-     (:foreground "ForestGreen"))
+     (:foreground "Brown"))
     (t
      ()))
-  "Level 1 newsgroup face.")
+  "Face of the splash screen.")
 
 (defun gnus-splash ()
   (save-excursion
@@ -677,8 +769,28 @@
   "Insert startup message in current buffer."
   ;; Insert the message.
   (erase-buffer)
-  (insert
-   (format "              %s
+  (cond
+   ((and
+     (fboundp 'find-image)
+     (display-graphic-p)
+     (let ((image (find-image
+		   `((:type xpm :file "gnus.xpm")
+		     (:type xbm :file "gnus.xbm"
+			    ;; Account for the xbm's blackground.
+			    :background ,(face-foreground 'gnus-splash-face)
+			    :foreground ,(face-background 'default))))))
+       (when image
+	 (let ((size (image-size image)))
+	   (insert-char ?\n (max 0 (round (- (window-height)
+					     (or y (cdr size)) 1) 2)))
+	   (insert-char ?\  (max 0 (round (- (window-width)
+					     (or x (car size))) 2)))
+	   (insert-image image))
+	 (setq gnus-simple-splash nil)
+	 t))))
+   (t
+    (insert
+     (format "              %s
           _    ___ _             _
           _ ___ __ ___  __    _ ___
           __   _     ___    __  ___
@@ -698,21 +810,21 @@
           __
 
 "
-           ""))
-  ;; And then hack it.
-  (gnus-indent-rigidly (point-min) (point-max)
-		       (/ (max (- (window-width) (or x 46)) 0) 2))
-  (goto-char (point-min))
-  (forward-line 1)
-  (let* ((pheight (count-lines (point-min) (point-max)))
-	 (wheight (window-height))
-	 (rest (- wheight pheight)))
-    (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
-  ;; Fontify some.
-  (put-text-property (point-min) (point-max) 'face 'gnus-splash-face)
+	     ""))
+    ;; And then hack it.
+    (gnus-indent-rigidly (point-min) (point-max)
+			 (/ (max (- (window-width) (or x 46)) 0) 2))
+    (goto-char (point-min))
+    (forward-line 1)
+    (let* ((pheight (count-lines (point-min) (point-max)))
+	   (wheight (window-height))
+	   (rest (- wheight pheight)))
+      (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
+    ;; Fontify some.
+    (put-text-property (point-min) (point-max) 'face 'gnus-splash-face)
+    (setq gnus-simple-splash t)))
   (goto-char (point-min))
   (setq mode-line-buffer-identification (concat " " gnus-version))
-  (setq gnus-simple-splash t)
   (set-buffer-modified-p t))
 
 (eval-when (load)
@@ -784,31 +896,30 @@
       (and (file-readable-p gnus-nntpserver-file)
 	   (save-excursion
 	     (set-buffer (gnus-get-buffer-create " *gnus nntp*"))
-	     (buffer-disable-undo (current-buffer))
 	     (insert-file-contents gnus-nntpserver-file)
 	     (let ((name (buffer-string)))
 	       (prog1
-		   (if (string-match "^[ \t\n]*$" name)
+		   (if (string-match "\\'[ \t\n]*$" name)
 		       nil
 		     name)
 		 (kill-buffer (current-buffer))))))))
 
 (defcustom gnus-select-method
   (condition-case nil
-    (nconc
-     (list 'nntp (or (condition-case nil
-			 (gnus-getenv-nntpserver)
-		       (error nil))
-		     (when (and gnus-default-nntp-server
-				(not (string= gnus-default-nntp-server "")))
-		       gnus-default-nntp-server)
-		     "news"))
-     (if (or (null gnus-nntp-service)
-	     (equal gnus-nntp-service "nntp"))
-	 nil
-       (list gnus-nntp-service)))
+      (nconc
+       (list 'nntp (or (condition-case nil
+			   (gnus-getenv-nntpserver)
+			 (error nil))
+		       (when (and gnus-default-nntp-server
+				  (not (string= gnus-default-nntp-server "")))
+			 gnus-default-nntp-server)
+		       "news"))
+       (if (or (null gnus-nntp-service)
+	       (equal gnus-nntp-service "nntp"))
+	   nil
+	 (list gnus-nntp-service)))
     (error nil))
-  "*Default method for selecting a newsgroup.
+  "Default method for selecting a newsgroup.
 This variable should be a list, where the first element is how the
 news is to be fetched, the second is the address.
 
@@ -839,7 +950,7 @@
   "*Method used for archiving messages you've sent.
 This should be a mail method.
 
-It's probably not a very effective to change this variable once you've
+It's probably not very effective to change this variable once you've
 run Gnus once.  After doing that, you must edit this server from the
 server buffer."
   :group 'gnus-server
@@ -868,6 +979,7 @@
 \"nnml+private:mail.misc\", for instance."
   :group 'gnus-message
   :type '(choice (const :tag "none" nil)
+		 function
 		 sexp
 		 string))
 
@@ -895,8 +1007,8 @@
 you could set this variable:
 
 \(setq gnus-secondary-select-methods '((nnml \"\")))"
-:group 'gnus-server
-:type '(repeat gnus-select-method))
+  :group 'gnus-server
+  :type '(repeat gnus-select-method))
 
 (defvar gnus-backup-default-subscribed-newsgroups
   '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
@@ -925,10 +1037,23 @@
 nntp method, you might get acceptable results.
 
 The value of this variable must be a valid select method as discussed
-in the documentation of `gnus-select-method'."
+in the documentation of `gnus-select-method'.
+
+It can also be a list of select methods, as well as the special symbol
+`current', which means to use the current select method.  If it is a
+list, Gnus will try all the methods in the list until it finds a match."
   :group 'gnus-server
   :type '(choice (const :tag "default" nil)
-		 gnus-select-method))
+		 (const :tag "DejaNews" (nnweb "refer" (nnweb-type dejanews)))
+		 gnus-select-method
+		 (repeat :menu-tag "Try multiple"
+			 :tag "Multiple"
+			 :value (current (nnweb "refer" (nnweb-type dejanews)))
+			 (choice :tag "Method"
+				 (const current)
+				 (const :tag "DejaNews"
+					(nnweb "refer" (nnweb-type dejanews)))
+				 gnus-select-method))))
 
 (defcustom gnus-group-faq-directory
   '("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
@@ -987,11 +1112,6 @@
   :group 'gnus-summary-marks
   :type 'character)
 
-(defcustom gnus-asynchronous nil
-  "*If non-nil, Gnus will supply backends with data needed for async article fetching."
-  :group 'gnus-asynchronous
-  :type 'boolean)
-
 (defcustom gnus-large-newsgroup 200
   "*The number of articles which indicates a large newsgroup.
 If the number of articles in a newsgroup is greater than this value,
@@ -1083,18 +1203,13 @@
   :group 'gnus-meta
   :type 'boolean)
 
-(defcustom gnus-use-demon nil
-  "If non-nil, Gnus might use some demons."
-  :group 'gnus-meta
-  :type 'boolean)
-
 (defcustom gnus-use-scoring t
   "*If non-nil, enable scoring."
   :group 'gnus-meta
   :type 'boolean)
 
 (defcustom gnus-use-picons nil
-  "*If non-nil, display picons."
+  "*If non-nil, display picons in a frame of their own."
   :group 'gnus-meta
   :type 'boolean)
 
@@ -1167,8 +1282,12 @@
     ("nnfolder" mail respool address)
     ("nngateway" post-mail address prompt-address physical-address)
     ("nnweb" none)
+    ("nnslashdot" post)
+    ("nnultimate" none)
+    ("nnwarchive" none)
     ("nnlistserv" none)
-    ("nnagent" post-mail))
+    ("nnagent" post-mail)
+    ("nnimap" post-mail address prompt-address physical-address))
   "*An alist of valid select methods.
 The first element of each list lists should be a string with the name
 of the select method.  The other elements may be the category of
@@ -1189,18 +1308,28 @@
 				   (const :format "%v " virtual)
 				   (const respool)))))
 
-(define-widget 'gnus-select-method 'list
-  "Widget for entering a select method."
-  :args `((choice :tag "Method"
-		  ,@(mapcar (lambda (entry)
-			      (list 'const :format "%v\n"
-				    (intern (car entry))))
-			    gnus-valid-select-methods))
-	  (string :tag "Address")
-	  (editable-list  :inline t
-			  (list :format "%v"
-				variable
-				(sexp :tag "Value")))))
+(defun gnus-redefine-select-method-widget ()
+  "Recomputes the select-method widget based on the value of
+`gnus-valid-select-methods'."
+  (define-widget 'gnus-select-method 'list
+    "Widget for entering a select method."
+    :value '(nntp "")
+    :tag "Select Method"
+    :args `((choice :tag "Method"
+		    ,@(mapcar (lambda (entry)
+				(list 'const :format "%v\n"
+				      (intern (car entry))))
+			      gnus-valid-select-methods)
+		    (symbol :tag "other"))
+	    (string :tag "Address")
+	    (repeat :tag "Options"
+		    :inline t
+		    (list :format "%v"
+			  variable
+			  (sexp :tag "Value"))))
+    ))
+
+(gnus-redefine-select-method-widget)
 
 (defcustom gnus-updated-mode-lines '(group article summary tree)
   "List of buffers that should update their mode lines.
@@ -1283,7 +1412,7 @@
 (defcustom gnus-group-change-level-function nil
   "Function run when a group level is changed.
 It is called with three parameters -- GROUP, LEVEL and OLDLEVEL."
-  :group 'gnus-group-level
+  :group 'gnus-group-levels
   :type 'function)
 
 ;;; Face thingies.
@@ -1345,60 +1474,6 @@
   :group 'gnus-visual
   :type 'face)
 
-(defcustom gnus-article-display-hook
-  (if (and (string-match "XEmacs" emacs-version)
-	   (featurep 'xface))
-      '(gnus-article-hide-headers-if-wanted
-	gnus-article-hide-boring-headers
-	gnus-article-treat-overstrike
-	gnus-article-maybe-highlight
-	gnus-article-display-x-face)
-    '(gnus-article-hide-headers-if-wanted
-      gnus-article-hide-boring-headers
-      gnus-article-treat-overstrike
-      gnus-article-maybe-highlight))
-  "*Controls how the article buffer will look.
-
-If you leave the list empty, the article will appear exactly as it is
-stored on the disk.  The list entries will hide or highlight various
-parts of the article, making it easier to find the information you
-want."
-  :group 'gnus-article-highlight
-  :group 'gnus-visual
-  :type 'hook
-  :options '(gnus-article-add-buttons
-	     gnus-article-add-buttons-to-head
-	     gnus-article-emphasize
-	     gnus-article-fill-cited-article
-	     gnus-article-remove-cr
-	     gnus-article-de-quoted-unreadable
-	     gnus-summary-stop-page-breaking
-	     ;; gnus-summary-caesar-message
-	     ;; gnus-summary-verbose-headers
-	     gnus-summary-toggle-mime
-	     gnus-article-hide
-	     gnus-article-hide-headers
-	     gnus-article-hide-boring-headers
-	     gnus-article-hide-signature
-	     gnus-article-hide-citation
-	     gnus-article-hide-pgp
-	     gnus-article-hide-pem
-	     gnus-article-highlight
-	     gnus-article-highlight-headers
-	     gnus-article-highlight-citation
-	     gnus-article-highlight-signature
-	     gnus-article-date-ut
-	     gnus-article-date-local
-	     gnus-article-date-lapsed
-	     gnus-article-date-original
-	     gnus-article-remove-trailing-blank-lines
-	     gnus-article-strip-leading-blank-lines
-	     gnus-article-strip-multiple-blank-lines
-	     gnus-article-strip-blank-lines
-	     gnus-article-treat-overstrike
-	     gnus-article-display-x-face
-	     gnus-smiley-display))
-
 (defcustom gnus-article-save-directory gnus-directory
   "*Name of the directory articles will be saved in (default \"~/News\")."
   :group 'gnus-article-saving
@@ -1407,9 +1482,27 @@
 (defvar gnus-plugged t
   "Whether Gnus is plugged or not.")
 
+(defcustom gnus-default-charset 'iso-8859-1
+  "Default charset assumed to be used when viewing non-ASCII characters.
+This variable is overridden on a group-to-group basis by the
+gnus-group-charset-alist variable and is only used on groups not
+covered by that variable."
+  :type 'symbol
+  :group 'gnus-charset)
+
+(defcustom gnus-default-posting-charset nil
+  "Default charset assumed to be used when posting non-ASCII characters.
+This variable is overridden on a group-to-group basis by the
+gnus-group-posting-charset-alist variable and is only used on groups not
+covered by that variable.
+If nil, no default charset is assumed when posting."
+  :type 'symbol
+  :group 'gnus-charset)
+
 
 ;;; Internal variables
 
+(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
 (defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
 (defvar gnus-original-article-buffer " *Original Article*")
 (defvar gnus-newsgroup-name nil)
@@ -1457,7 +1550,7 @@
       ,(nnheader-concat gnus-cache-directory "active"))))
   "List of predefined (convenience) servers.")
 
-(defvar gnus-topic-indentation "") ;; Obsolete variable.
+(defvar gnus-topic-indentation "");; Obsolete variable.
 
 (defconst gnus-article-mark-lists
   '((marked . tick) (replied . reply)
@@ -1485,7 +1578,6 @@
   '((gnus-group-mode "(gnus)The Group Buffer")
     (gnus-summary-mode "(gnus)The Summary Buffer")
     (gnus-article-mode "(gnus)The Article Buffer")
-    (mime/viewer-mode "(gnus)The Article Buffer")
     (gnus-server-mode "(gnus)The Server Buffer")
     (gnus-browse-mode "(gnus)Browse Foreign Server")
     (gnus-tree-mode "(gnus)Tree Display"))
@@ -1504,11 +1596,11 @@
 
 (defvar gnus-variable-list
   '(gnus-newsrc-options gnus-newsrc-options-n
-    gnus-newsrc-last-checked-date
-    gnus-newsrc-alist gnus-server-alist
-    gnus-killed-list gnus-zombie-list
-    gnus-topic-topology gnus-topic-alist
-    gnus-format-specs)
+			gnus-newsrc-last-checked-date
+			gnus-newsrc-alist gnus-server-alist
+			gnus-killed-list gnus-zombie-list
+			gnus-topic-topology gnus-topic-alist
+			gnus-format-specs)
   "Gnus variables saved in the quick startup file.")
 
 (defvar gnus-newsrc-alist nil
@@ -1549,6 +1641,9 @@
 
 (defvar gnus-dead-summary nil)
 
+(defvar gnus-invalid-group-regexp "[: `'\"/]\\|^$"
+  "Regexp matching invalid groups.")
+
 ;;; End of variables.
 
 ;; Define some autoload functions Gnus might use.
@@ -1565,24 +1660,22 @@
 	    (when (consp function)
 	      (setq keymap (car (memq 'keymap function)))
 	      (setq function (car function)))
-	    (autoload function (car package) nil interactive keymap)))
+	    (unless (fboundp function)
+	      (autoload function (car package) nil interactive keymap))))
 	(if (eq (nth 1 package) ':interactive)
-	    (cdddr package)
+	    (nthcdr 3 package)
 	  (cdr package)))))
-   '(("metamail" metamail-buffer)
-     ("info" Info-goto-node)
-     ("hexl" hexl-hex-string-to-integer)
+   '(("info" :interactive t Info-goto-node)
      ("pp" pp pp-to-string pp-eval-expression)
+     ("qp" quoted-printable-decode-region quoted-printable-decode-string)
      ("ps-print" ps-print-preprint)
-     ("mail-extr" mail-extract-address-components)
-     ("browse-url" browse-url)
+     ("browse-url" :interactive t browse-url)
      ("message" :interactive t
       message-send-and-exit message-yank-original)
-     ("nnmail" nnmail-split-fancy nnmail-article-group nnmail-date-to-time)
+     ("babel" babel-as-string)
+     ("nnmail" nnmail-split-fancy nnmail-article-group)
      ("nnvirtual" nnvirtual-catchup-group nnvirtual-convert-headers)
-     ("timezone" timezone-make-date-arpa-standard timezone-fix-time
-      timezone-make-sortable-date timezone-make-time-string)
-     ("rmailout" rmail-output)
+     ("rmailout" rmail-output rmail-output-to-rmail-file)
      ("rmail" rmail-insert-rmail-file-header rmail-count-new-messages
       rmail-show-message rmail-summary-exists
       rmail-select-summary rmail-update-summary)
@@ -1615,35 +1708,36 @@
       gnus-article-hide-citation-in-followups)
      ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
       gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
-      gnus-execute gnus-expunge)
+      gnus-execute gnus-expunge gnus-batch-kill gnus-batch-score)
      ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
       gnus-cache-possibly-remove-articles gnus-cache-request-article
       gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
       gnus-cache-enter-remove-article gnus-cached-article-p
-      gnus-cache-open gnus-cache-close gnus-cache-update-article)
-      ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
-       gnus-cache-remove-article gnus-summary-insert-cached-articles)
-      ("gnus-score" :interactive t
-       gnus-summary-increase-score gnus-summary-set-score
-       gnus-summary-raise-thread gnus-summary-raise-same-subject
-       gnus-summary-raise-score gnus-summary-raise-same-subject-and-select
-       gnus-summary-lower-thread gnus-summary-lower-same-subject
-       gnus-summary-lower-score gnus-summary-lower-same-subject-and-select
-       gnus-summary-current-score gnus-score-default
-       gnus-score-flush-cache gnus-score-close
-       gnus-possibly-score-headers gnus-score-followup-article
-       gnus-score-followup-thread)
-      ("gnus-score"
-       (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
+      gnus-cache-open gnus-cache-close gnus-cache-update-article
+      gnus-cache-articles-in-group)
+     ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
+      gnus-cache-remove-article gnus-summary-insert-cached-articles)
+     ("gnus-score" :interactive t
+      gnus-summary-increase-score gnus-summary-set-score
+      gnus-summary-raise-thread gnus-summary-raise-same-subject
+      gnus-summary-raise-score gnus-summary-raise-same-subject-and-select
+      gnus-summary-lower-thread gnus-summary-lower-same-subject
+      gnus-summary-lower-score gnus-summary-lower-same-subject-and-select
+      gnus-summary-current-score gnus-score-delta-default
+      gnus-score-flush-cache gnus-score-close
+      gnus-possibly-score-headers gnus-score-followup-article
+      gnus-score-followup-thread)
+     ("gnus-score"
+      (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
       gnus-current-score-file-nondirectory gnus-score-adaptive
       gnus-score-find-trace gnus-score-file-name)
      ("gnus-cus" :interactive t gnus-group-customize gnus-score-customize)
      ("gnus-topic" :interactive t gnus-topic-mode)
-     ("gnus-topic" gnus-topic-remove-group gnus-topic-set-parameters)
+     ("gnus-topic" gnus-topic-remove-group gnus-topic-set-parameters
+      gnus-subscribe-topics)
      ("gnus-salt" :interactive t gnus-pick-mode gnus-binary-mode)
      ("gnus-uu" (gnus-uu-extract-map keymap) (gnus-uu-mark-map keymap))
      ("gnus-uu" :interactive t
-      gnus-uu-post-news
       gnus-uu-digest-mail-forward gnus-uu-digest-post-forward
       gnus-uu-mark-series gnus-uu-mark-region gnus-uu-mark-buffer
       gnus-uu-mark-by-regexp gnus-uu-mark-all
@@ -1654,17 +1748,11 @@
       gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
       gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
       gnus-uu-decode-binhex-view gnus-uu-unmark-thread
-      gnus-uu-mark-over gnus-uu-post-news gnus-uu-post-news)
-     ("gnus-uu" gnus-uu-delete-work-dir gnus-quote-arg-for-sh-or-csh
-      gnus-uu-unmark-thread)
+      gnus-uu-mark-over gnus-uu-post-news)
+     ("gnus-uu" gnus-uu-delete-work-dir gnus-uu-unmark-thread)
      ("gnus-msg" (gnus-summary-send-map keymap)
       gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
      ("gnus-msg" :interactive t
-      gnus-summary-wide-reply
-      gnus-summary-wide-reply-with-original
-      gnus-summary-followup-to-mail
-      gnus-summary-followup-to-mail-with-original
-      gnus-summary-post-forward
       gnus-group-post-news gnus-group-mail gnus-summary-post-news
       gnus-summary-followup gnus-summary-followup-with-original
       gnus-summary-cancel-article gnus-summary-supersede-article
@@ -1679,6 +1767,7 @@
      ("gnus-picon" :interactive t gnus-article-display-picons
       gnus-group-display-picons gnus-picons-article-display-x-face
       gnus-picons-display-x-face)
+     ("gnus-picon" gnus-picons-buffer-name)
      ("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p
       gnus-grouplens-mode)
      ("smiley" :interactive t gnus-smiley-display)
@@ -1694,8 +1783,7 @@
       gnus-group-set-mode-line gnus-group-set-info gnus-group-save-newsrc
       gnus-group-setup-buffer gnus-group-get-new-news
       gnus-group-make-help-group gnus-group-update-group
-      gnus-clear-inboxes-moved gnus-group-iterate
-      gnus-group-group-name)
+      gnus-group-iterate gnus-group-group-name)
      ("gnus-bcklg" gnus-backlog-request-article gnus-backlog-enter-article
       gnus-backlog-remove-article)
      ("gnus-art" gnus-article-read-summary-keys gnus-article-save
@@ -1703,20 +1791,24 @@
       gnus-article-next-page gnus-article-prev-page
       gnus-request-article-this-buffer gnus-article-mode
       gnus-article-setup-buffer gnus-narrow-to-page
-      gnus-article-delete-invisible-text gnus-hack-decode-rfc1522)
+      gnus-article-delete-invisible-text gnus-treat-article)
      ("gnus-art" :interactive t
       gnus-article-hide-headers gnus-article-hide-boring-headers
-      gnus-article-treat-overstrike gnus-article-word-wrap
+      gnus-article-treat-overstrike
       gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
       gnus-article-display-x-face gnus-article-de-quoted-unreadable
-      gnus-article-mime-decode-quoted-printable gnus-article-hide-pgp
+      gnus-article-de-base64-unreadable
+      gnus-article-decode-HZ
+      gnus-article-wash-html
+      gnus-article-hide-pgp
       gnus-article-hide-pem gnus-article-hide-signature
       gnus-article-strip-leading-blank-lines gnus-article-date-local
       gnus-article-date-original gnus-article-date-lapsed
       gnus-article-show-all-headers
       gnus-article-edit-mode gnus-article-edit-article
-      gnus-article-edit-done gnus-decode-rfc1522 article-decode-rfc1522
-      gnus-start-date-timer gnus-stop-date-timer)
+      gnus-article-edit-done gnus-article-decode-encoded-words
+      gnus-start-date-timer gnus-stop-date-timer
+      gnus-mime-view-all-parts)
      ("gnus-int" gnus-request-type)
      ("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
       gnus-dribble-enter gnus-read-init-file gnus-dribble-touch)
@@ -1739,7 +1831,10 @@
       gnus-unplugged gnus-agentize gnus-agent-batch)
      ("gnus-vm" :interactive t gnus-summary-save-in-vm
       gnus-summary-save-article-vm)
-     ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-drafts))))
+     ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-drafts)
+     ("gnus-mlspl" gnus-group-split gnus-group-split-fancy)
+     ("gnus-mlspl" :interactive t gnus-group-split-setup
+      gnus-group-split-update))))
 
 ;;; gnus-sum.el thingies
 
@@ -1757,6 +1852,7 @@
 %a   Extracted name of the poster (string)
 %A   Extracted address of the poster (string)
 %F   Contents of the From: header (string)
+%f   Contents of the From: or To: headers (string)
 %x   Contents of the Xref: header (string)
 %D   Date of the article (string)
 %d   Date of the article (string) in DD-MMM format
@@ -1795,7 +1891,7 @@
 The %U (status), %R (replied) and %z (zcore) specs have to be handled
 with care.  For reasons of efficiency, Gnus will compute what column
 these characters will end up in, and \"hard-code\" that.  This means that
-it is illegal to have these specs after a variable-length spec.	 Well,
+it is invalid to have these specs after a variable-length spec.	 Well,
 you might not be arrested, but your summary buffer will look strange,
 which is bad enough.
 
@@ -1817,7 +1913,7 @@
       (define-key keymap (pop keys) 'undefined))))
 
 (defvar gnus-article-mode-map
-  (let ((keymap (make-keymap)))
+  (let ((keymap (make-sparse-keymap)))
     (gnus-suppress-keymap keymap)
     keymap))
 (defvar gnus-summary-mode-map
@@ -2012,14 +2108,13 @@
       (string-to-number
        (if (zerop major)
 	   (format "%s00%02d%02d"
-		   (cond
-		    ((member alpha '("(ding)" "d")) "4.99")
-		    ((member alpha '("September" "s")) "5.01")
-		    ((member alpha '("Red" "r")) "5.03")
-		    ((member alpha '("Quassia" "q")) "5.05")
-		    ((member alpha '("p")) "5.07")
-		    ((member alpha '("o")) "5.09")
-		    ((member alpha '("n")) "5.11"))
+		   (if (member alpha '("(ding)" "d"))
+		       "4.99"
+		     (+ 5 (* 0.02
+			     (abs
+			      (- (mm-char-int (aref (downcase alpha) 0))
+				 (mm-char-int ?t))))
+			-0.01))
 		   minor least)
 	 (format "%d.%02d%02d" major minor least))))))
 
@@ -2307,7 +2402,14 @@
 		 (not (equal server (format "%s:%s" (caaar opened)
 					    (cadaar opened)))))
        (pop opened))
-     (caar opened))))
+     (caar opened))
+   ;; It could be a named method, search all servers
+   (let ((servers gnus-secondary-select-methods))
+     (while (and servers
+		 (not (equal server (format "%s:%s" (caar servers)
+					    (cadar servers)))))
+       (pop servers))
+     (car servers))))
 
 (defmacro gnus-method-equal (ss1 ss2)
   "Say whether two servers are equal."
@@ -2320,6 +2422,15 @@
 		  (setq s1 (cdr s1)))
 		(null s1))))))
 
+(defun gnus-methods-equal-p (m1 m2)
+  (let ((m1 (or m1 gnus-select-method))
+	(m2 (or m2 gnus-select-method)))
+    (or (equal m1 m2)
+	(and (eq (car m1) (car m2))
+	     (or (not (memq 'address (assoc (symbol-name (car m1))
+					    gnus-valid-select-methods)))
+		 (equal (nth 1 m1) (nth 1 m2)))))))
+
 (defun gnus-server-equal (m1 m2)
   "Say whether two methods are equal."
   (let ((m1 (cond ((null m1) gnus-select-method)
@@ -2401,16 +2512,32 @@
 	    possible
 	    (list backend server))))))
 
+(defsubst gnus-native-method-p (method)
+  "Return whether METHOD is the native select method."
+  (gnus-method-equal method gnus-select-method))
+
 (defsubst gnus-secondary-method-p (method)
   "Return whether METHOD is a secondary select method."
   (let ((methods gnus-secondary-select-methods)
 	(gmethod (gnus-server-get-method nil method)))
     (while (and methods
-		(not (equal (gnus-server-get-method nil (car methods))
-			    gmethod)))
+		(not (gnus-method-equal
+		      (gnus-server-get-method nil (car methods))
+		      gmethod)))
       (setq methods (cdr methods)))
     methods))
 
+(defun gnus-method-simplify (method)
+  "Return the shortest uniquely identifying string or method for METHOD."
+  (cond ((stringp method)
+	 method)
+	((gnus-native-method-p method)
+	 nil)
+	((gnus-secondary-method-p method)
+	 (format "%s:%s" (nth 0 method) (nth 1 method)))
+	(t
+	 method)))
+
 (defun gnus-groups-from-server (server)
   "Return a list of all groups that are fetched from SERVER."
   (let ((alist (cdr gnus-newsrc-alist))
@@ -2510,7 +2637,6 @@
     (when info
       (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
 
-;; Function written by Stainless Steel Rat <ratinox@peorth.gweep.net>
 (defun gnus-short-group-name (group &optional levels)
   "Collapse GROUP name LEVELS.
 Select methods are stripped and any remote host name is stripped down to
@@ -2520,40 +2646,51 @@
 	 (depth 0)
 	 (skip 1)
 	 (levels (or levels
+		     gnus-group-uncollapsed-levels
 		     (progn
 		       (while (string-match "\\." group skip)
 			 (setq skip (match-end 0)
 			       depth (+ depth 1)))
 		       depth))))
-    ;; separate foreign select method from group name and collapse.
-    ;; if method contains a server, collapse to non-domain server name,
-    ;; otherwise collapse to select method
-    (when (string-match ":" group)
-      (cond ((string-match "+" group)
-	     (let* ((plus (string-match "+" group))
-		    (colon (string-match ":" group (or plus 0)))
-		    (dot (string-match "\\." group)))
-	       (setq foreign (concat
-			      (substring group (+ 1 plus)
-					 (cond ((null dot) colon)
-					       ((< colon dot) colon)
-					       ((< dot colon) dot)))
-			      ":")
-		     group (substring group (+ 1 colon)))))
-	    (t
-	     (let* ((colon (string-match ":" group)))
-	       (setq foreign (concat (substring group 0 (+ 1 colon)))
-		     group (substring group (+ 1 colon)))))))
-    ;; collapse group name leaving LEVELS uncollapsed elements
-    (while group
-      (if (and (string-match "\\." group) (> levels 0))
-	  (setq name (concat name (substring group 0 1))
-		group (substring group (match-end 0))
-		levels (- levels 1)
-		name (concat name "."))
-	(setq name (concat foreign name group)
-	      group nil)))
-    name))
+    ;; Separate foreign select method from group name and collapse.
+    ;; If method contains a server, collapse to non-domain server name,
+    ;; otherwise collapse to select method.
+    (let* ((colon (string-match ":" group))
+	   (server (and colon (substring group 0 colon)))
+	   (plus (and server (string-match "+" server))))
+      (when server
+	(if plus
+	    (setq foreign (substring server (+ 1 plus)
+				     (string-match "\\." server))
+		  group (substring group (+ 1 colon)))
+	  (setq foreign server
+		group (substring group (+ 1 colon))))
+	(setq foreign (concat foreign ":")))
+      ;; Collapse group name leaving LEVELS uncollapsed elements
+      (let* ((slist (split-string group "/"))
+	     (slen (length slist))
+	     (dlist (split-string group "\\."))
+	     (dlen (length dlist))
+	     glist
+	     glen
+	     gsep
+	     res)
+	(if (> slen dlen)
+	    (setq glist slist
+		  glen slen
+		  gsep "/")
+	  (setq glist dlist
+		glen dlen
+		gsep "."))
+	(setq levels (- glen levels))
+	(dolist (g glist)
+	  (push (if (>= (decf levels) 0)
+		    (if (zerop (length g))
+			""
+		      (substring g 0 1))
+		  g)
+		res))
+	(concat foreign (mapconcat 'identity (nreverse res) gsep))))))
 
 (defun gnus-narrow-to-body ()
   "Narrow to the body of an article."
@@ -2631,6 +2768,7 @@
   (let ((opened gnus-opened-servers))
     (while (and method opened)
       (when (and (equal (cadr method) (cadaar opened))
+		 (equal (car method) (caaar opened))
 		 (not (equal method (caar opened))))
 	(setq method nil))
       (pop opened))
@@ -2667,6 +2805,8 @@
   (or gnus-override-method
       (and (not group)
 	   gnus-select-method)
+      (and (not (gnus-group-entry group));; a new group
+	   (gnus-group-name-to-method group))
       (let ((info (or info (gnus-get-info group)))
 	    method)
 	(if (or (not info)
@@ -2699,16 +2839,16 @@
 
 (defun gnus-read-group (prompt &optional default)
   "Prompt the user for a group name.
-Disallow illegal group names."
+Disallow invalid group names."
   (let ((prefix "")
 	group)
     (while (not group)
-      (when (string-match
-	     "[: `'\"/]\\|^$"
+      (when (string-match 
+	     gnus-invalid-group-regexp
 	     (setq group (read-string (concat prefix prompt)
 				      (cons (or default "") 0)
 				      'gnus-group-history)))
-	(setq prefix (format "Illegal group name: \"%s\".  " group)
+	(setq prefix (format "Invalid group name: \"%s\".  " group)
 	      group nil)))
     group))
 
@@ -2717,6 +2857,9 @@
 Allow completion over sensible values."
   (let* ((servers
 	  (append gnus-valid-select-methods
+		  (mapcar (lambda (i) (list (format "%s:%s" (caar i)
+						    (cadar i))))
+			  gnus-opened-servers)
 		  gnus-predefined-server-alist
 		  gnus-server-alist))
 	 (method
@@ -2727,11 +2870,18 @@
      ((equal method "")
       (setq method gnus-select-method))
      ((assoc method gnus-valid-select-methods)
-      (list (intern method)
-	    (if (memq 'prompt-address
-		      (assoc method gnus-valid-select-methods))
-		(read-string "Address: ")
-	      "")))
+      (let ((address (if (memq 'prompt-address
+			       (assoc method gnus-valid-select-methods))
+			 (read-string "Address: ")
+		       "")))
+	(or (let ((opened gnus-opened-servers))
+	      (while (and opened
+			  (not (equal (format "%s:%s" method address)
+				      (format "%s:%s" (caaar opened)
+					      (cadaar opened)))))
+		(pop opened))
+	      (caar opened))
+	    (list (intern method) address))))
      ((assoc method servers)
       method)
      (t
@@ -2769,12 +2919,13 @@
   (let ((window (get-buffer-window gnus-group-buffer)))
     (cond (window
 	   (select-frame (window-frame window)))
-	  ((= (length (frame-list)) 1)
-	   (select-frame (make-frame)))
-	  (t
-	   (other-frame 1))))
+ 	  (t
+ 	   (select-frame (make-frame)))))
   (gnus arg))
 
+;;(setq thing ?				; this is a comment
+;;      more 'yes)
+
 ;;;###autoload
 (defun gnus (&optional arg dont-connect slave)
   "Read network news.
--- a/lisp/gnus/message.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/message.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; message.el --- composing mail and news messages
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: mail, news
@@ -29,16 +30,16 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
-
+(eval-when-compile
+  (require 'cl)
+  (defvar gnus-list-identifiers))	; gnus-sum is required where necessary
 (require 'mailheader)
 (require 'nnheader)
-(require 'timezone)
-(require 'easymenu)
-(require 'custom)
-(if (string-match "XEmacs\\|Lucid" emacs-version)
-    (require 'mail-abbrevs)
-  (require 'mailabbrev))
+;; This is apparently necessary even though things are autoloaded:
+(if (featurep 'xemacs)
+    (require 'mail-abbrevs))
+(require 'mail-parse)
+(require 'mml)
 
 (defgroup message '((user-mail-address custom-variable)
 		    (user-full-name custom-variable))
@@ -156,7 +157,7 @@
   :group 'message-headers)
 
 (defcustom message-syntax-checks nil
-  ; Guess this one shouldn't be easy to customize...
+  ;; Guess this one shouldn't be easy to customize...
   "*Controls what syntax checks should not be performed on outgoing posts.
 To disable checking of long signatures, for instance, add
  `(signature . disabled)' to this list.
@@ -164,19 +165,21 @@
 Don't touch this variable unless you really know what you're doing.
 
 Checks include subject-cmsg multiple-headers sendsys message-id from
-long-lines control-chars size new-text redirected-followup signature
-approved sender empty empty-headers message-id from subject
-shorten-followup-to existing-newsgroups buffer-file-name unchanged."
-  :group 'message-news)
+long-lines control-chars size new-text quoting-style
+redirected-followup signature approved sender empty empty-headers
+message-id from subject shorten-followup-to existing-newsgroups
+buffer-file-name unchanged newsgroups."
+  :group 'message-news
+  :type '(repeat sexp))
 
 (defcustom message-required-news-headers
   '(From Newsgroups Subject Date Message-ID
 	 (optional . Organization) Lines
-	 (optional . X-Newsreader))
+	 (optional . User-Agent))
   "*Headers to be generated or prompted for when posting an article.
 RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
 Message-ID.  Organization, Lines, In-Reply-To, Expires, and
-X-Newsreader are optional.  If don't you want message to insert some
+User-Agent are optional.  If don't you want message to insert some
 header, remove it from this list."
   :group 'message-news
   :group 'message-headers
@@ -184,10 +187,10 @@
 
 (defcustom message-required-mail-headers
   '(From Subject Date (optional . In-Reply-To) Message-ID Lines
-	 (optional . X-Mailer))
+	 (optional . User-Agent))
   "*Headers to be generated or prompted for when mailing a message.
 RFC822 required that From, Date, To, Subject and Message-ID be
-included.  Organization, Lines and X-Mailer are optional."
+included.  Organization, Lines and User-Agent are optional."
   :group 'message-mail
   :group 'message-headers
   :type '(repeat sexp))
@@ -210,7 +213,7 @@
   :group 'message-headers
   :type 'regexp)
 
-(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^X-Trace:\\|^X-Complaints-To:\\|^NNTP-Posting-Date:"
+(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:"
   "*Header lines matching this regexp will be deleted before posting.
 It's best to delete old Path and Date headers before posting to avoid
 any confusion."
@@ -228,7 +231,7 @@
   :type 'regexp
   :group 'message-various)
 
-(defcustom message-elide-elipsis "\n[...]\n\n"
+(defcustom message-elide-ellipsis "\n[...]\n\n"
   "*The string which is inserted for elided text."
   :type 'string
   :group 'message-various)
@@ -240,14 +243,15 @@
   :group 'message-mail
   :type 'boolean)
 
-(defcustom message-generate-new-buffers t
+(defcustom message-generate-new-buffers 'unique
   "*Non-nil means that a new message buffer will be created whenever `message-setup' is called.
 If this is a function, call that function with three parameters:  The type,
 the to address and the group name.  (Any of these may be nil.)  The function
 should return the new buffer name."
   :group 'message-buffers
   :type '(choice (const :tag "off" nil)
-		 (const :tag "on" t)
+		 (const :tag "unique" unique)
+		 (const :tag "unsent" unsent)
 		 (function fun)))
 
 (defcustom message-kill-buffer-on-exit nil
@@ -274,32 +278,9 @@
   :type 'file
   :group 'message-headers)
 
-(defcustom message-forward-start-separator
-  "------- Start of forwarded message -------\n"
-  "*Delimiter inserted before forwarded messages."
-  :group 'message-forwarding
-  :type 'string)
-
-(defcustom message-forward-end-separator
-  "------- End of forwarded message -------\n"
-  "*Delimiter inserted after forwarded messages."
-  :group 'message-forwarding
-  :type 'string)
-
-(defcustom message-signature-before-forwarded-message t
-  "*If non-nil, put the signature before any included forwarded message."
-  :group 'message-forwarding
-  :type 'boolean)
-
-(defcustom message-included-forward-headers
-  "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-\\|^Message-ID:\\|^References:\\|^Content-Transfer-Encoding:\\|^Content-Type:\\|^Mime-Version:"
-  "*Regexp matching headers to be included in forwarded messages."
-  :group 'message-forwarding
-  :type 'regexp)
-
 (defcustom message-make-forward-subject-function
   'message-forward-subject-author-subject
- "*A list of functions that are called to generate a subject header for forwarded messages.
+  "*A list of functions that are called to generate a subject header for forwarded messages.
 The subject generated by the previous function is passed into each
 successive function.
 
@@ -309,26 +290,47 @@
       newsgroup)), in brackets followed by the subject
 * message-forward-subject-fwd (Subject of article with 'Fwd:' prepended
       to it."
- :group 'message-forwarding
- :type '(radio (function-item message-forward-subject-author-subject)
-	       (function-item message-forward-subject-fwd)))
+  :group 'message-forwarding
+  :type '(radio (function-item message-forward-subject-author-subject)
+		(function-item message-forward-subject-fwd)))
+
+(defcustom message-forward-as-mime t
+  "*If non-nil, forward messages as an inline/rfc822 MIME section.  Otherwise, directly inline the old message in the forwarded message."
+  :group 'message-forwarding
+  :type 'boolean)
+
+(defcustom message-forward-show-mml t
+  "*If non-nil, forward messages are shown as mml.  Otherwise, forward messages are unchanged."
+  :group 'message-forwarding
+  :type 'boolean)
+
+(defcustom message-forward-before-signature t
+  "*If non-nil, put forwarded message before signature, else after."
+  :group 'message-forwarding
+  :type 'boolean)
 
 (defcustom message-wash-forwarded-subjects nil
   "*If non-nil, try to remove as much old cruft as possible from the subject of messages before generating the new subject of a forward."
   :group 'message-forwarding
   :type 'boolean)
 
-(defcustom message-ignored-resent-headers "^Return-receipt"
+(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:"
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :type 'regexp)
 
+(defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
+  "*All headers that match this regexp will be deleted when forwarding a message."
+  :group 'message-forwarding
+  :type '(choice (const :tag "None" nil)
+		 regexp))
+
 (defcustom message-ignored-cited-headers "."
   "*Delete these headers from the messages you yank."
   :group 'message-insertion
   :type 'regexp)
 
-(defcustom message-cancel-message "I am canceling my own article."
+(defcustom message-cancel-message "I am canceling my own article.\n"
   "Message to be inserted in the cancel message."
   :group 'message-interface
   :type 'string)
@@ -340,7 +342,7 @@
 The headers should be delimited by a line whose contents match the
 variable `mail-header-separator'.
 
-Legal values include `message-send-mail-with-sendmail' (the default),
+Valid values include `message-send-mail-with-sendmail' (the default),
 `message-send-mail-with-mh', `message-send-mail-with-qmail' and
 `smtpmail-send-it'."
   :type '(radio (function-item message-send-mail-with-sendmail)
@@ -391,10 +393,9 @@
 		 (const use)
 		 (const ask)))
 
-;; stuff relating to broken sendmail in MMDF
 (defcustom message-sendmail-f-is-evil nil
-  "*Non-nil means that \"-f username\" should not be added to the sendmail
-command line, because it is even more evil than leaving it out."
+  "*Non-nil means that \"-f username\" should not be added to the sendmail command line.
+Doing so would be even more evil than leaving it out."
   :group 'message-sending
   :type 'boolean)
 
@@ -414,6 +415,11 @@
   :group 'message-sending
   :type '(repeat string))
 
+(defvar message-cater-to-broken-inn t
+  "Non-nil means Gnus should not fold the `References' header.
+Folding `References' makes ancient versions of INN create incorrect
+NOV lines.")
+
 (defvar gnus-post-method)
 (defvar gnus-select-method)
 (defcustom message-post-method
@@ -444,6 +450,11 @@
   :group 'message-various
   :type 'hook)
 
+(defcustom message-cancel-hook nil
+  "Hook run when cancelling articles."
+  :group 'message-various
+  :type 'hook)
+
 (defcustom message-signature-setup-hook nil
   "Normal hook, run each time a new outgoing message is initialized.
 It is run after the headers have been inserted and before
@@ -474,8 +485,7 @@
 
 ;;;###autoload
 (defcustom message-yank-prefix "> "
-  "*Prefix inserted on the lines of yanked messages.
-nil means use indentation."
+  "*Prefix inserted on the lines of yanked messages."
   :type 'string
   :group 'message-insertion)
 
@@ -492,6 +502,7 @@
 `message-cite-original-without-signature'.
 Note that `message-cite-original' uses `mail-citation-hook' if that is non-nil."
   :type '(radio (function-item message-cite-original)
+		(function-item message-cite-original-without-signature)
 		(function-item sc-cite-original)
 		(function :tag "Other"))
   :group 'message-insertion)
@@ -580,8 +591,7 @@
   :type 'message-header-lines)
 
 (defcustom message-default-news-headers ""
-  "*A string of header lines to be inserted in outgoing news
-articles."
+  "*A string of header lines to be inserted in outgoing news articles."
   :group 'message-headers
   :group 'message-news
   :type 'message-header-lines)
@@ -613,14 +623,10 @@
   :group 'message-sending
   :type 'sexp)
 
-;; Ignore errors in case this is used in Emacs 19.
-;; Don't use ignore-errors because this is copied into loaddefs.el.
 ;;;###autoload
-(condition-case nil
-    (define-mail-user-agent 'message-user-agent
-      'message-mail 'message-send-and-exit
-      'message-kill-buffer 'message-send-hook)
-  (error nil))
+(define-mail-user-agent 'message-user-agent
+  'message-mail 'message-send-and-exit
+  'message-kill-buffer 'message-send-hook)
 
 (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
   "If non-nil, delete the deletable headers before feeding to mh.")
@@ -651,12 +657,34 @@
   :group 'message-buffers
   :type 'directory)
 
+(defcustom message-buffer-naming-style 'unique
+  "*The way new message buffers are named.
+Valid valued are `unique' and `unsent'."
+  :group 'message-buffers
+  :type '(choice (const :tag "unique" unique)
+		 (const :tag "unsent" unsent)))
+
+(defcustom message-default-charset nil
+  "Default charset used in non-MULE XEmacsen."
+  :group 'message
+  :type 'symbol)
+
+(defcustom message-dont-reply-to-names 
+  (and (boundp 'rmail-dont-reply-to-names) rmail-dont-reply-to-names)
+  "*A regexp specifying names to prune when doing wide replies.
+A value of nil means exclude your own name only."
+  :group 'message
+  :type '(choice (const :tag "Yourself" nil)
+		 regexp))
+
 ;;; Internal variables.
 ;;; Well, not really internal.
 
 (defvar message-mode-syntax-table
   (let ((table (copy-syntax-table text-mode-syntax-table)))
     (modify-syntax-entry ?% ". " table)
+    (modify-syntax-entry ?> ". " table)
+    (modify-syntax-entry ?< ". " table)
     table)
   "Syntax table used while in Message mode.")
 
@@ -776,6 +804,18 @@
   "Face used for displaying cited text names."
   :group 'message-faces)
 
+(defface message-mml-face
+  '((((class color)
+      (background dark))
+     (:foreground "ForestGreen"))
+    (((class color)
+      (background light))
+     (:foreground "ForestGreen"))
+    (t
+     (:bold t)))
+  "Face used for displaying MML."
+  :group 'message-faces)
+
 (defvar message-font-lock-keywords
   (let* ((cite-prefix "A-Za-z")
 	 (cite-suffix (concat cite-prefix "0-9_.@-"))
@@ -806,7 +846,9 @@
       (,(concat "^[ \t]*"
 		"\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
 		"[:>|}].*")
-       (0 'message-cited-text-face))))
+       (0 'message-cited-text-face))
+      ("<#/?\\(multipart\\|part\\|external\\|mml\\).*>"
+       (0 'message-mml-face))))
   "Additional expressions to highlight in Message mode.")
 
 ;; XEmacs does it like this.  For Emacs, we have to set the
@@ -846,12 +888,26 @@
 (defvar message-send-coding-system 'binary
   "Coding system to encode outgoing mail.")
 
+(defvar message-draft-coding-system
+  mm-auto-save-coding-system
+  "Coding system to compose mail.")
+
+(defcustom message-send-mail-partially-limit 1000000
+  "The limitation of messages sent as message/partial.
+The lower bound of message size in characters, beyond which the message 
+should be sent in several parts. If it is nil, the size is unlimited."
+  :group 'message-buffers
+  :type '(choice (const :tag "unlimited" nil)
+		 (integer 1000000)))
+
 ;;; Internal variables.
 
 (defvar message-buffer-list nil)
 (defvar message-this-is-news nil)
 (defvar message-this-is-mail nil)
 (defvar message-draft-article nil)
+(defvar message-mime-part nil)
+(defvar message-posting-charset nil)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
@@ -891,10 +947,10 @@
      "\\([^\0-\b\n-\r\^?].*\\)? "
 
      ;; The time the message was sent.
-     "\\([^\0-\r \^?]+\\) +"				; day of the week
-     "\\([^\0-\r \^?]+\\) +"				; month
-     "\\([0-3]?[0-9]\\) +"				; day of month
-     "\\([0-2][0-9]:[0-5][0-9]\\(:[0-6][0-9]\\)?\\) *"	; time of day
+     "\\([^\0-\r \^?]+\\) +"		; day of the week
+     "\\([^\0-\r \^?]+\\) +"		; month
+     "\\([0-3]?[0-9]\\) +"		; day of month
+     "\\([0-2][0-9]:[0-5][0-9]\\(:[0-6][0-9]\\)?\\) *" ; time of day
 
      ;; Perhaps a time zone, specified by an abbreviation, or by a
      ;; numeric offset.
@@ -919,6 +975,7 @@
 	  "^ *---+ +Original message +---+ *$\\|"
 	  "^ *--+ +begin message +--+ *$\\|"
 	  "^ *---+ +Original message follows +---+ *$\\|"
+	  "^ *---+ +Undelivered message follows +---+ *$\\|"
 	  "^|? *---+ +Message text follows: +---+ *|?$")
   "A regexp that matches the separator before the text of a failed message.")
 
@@ -937,8 +994,7 @@
     (Expires)
     (Message-ID)
     (References . message-shorten-references)
-    (X-Mailer)
-    (X-Newsreader))
+    (User-Agent))
   "Alist used for formatting headers.")
 
 (eval-and-compile
@@ -947,14 +1003,15 @@
   (autoload 'mh-send-letter "mh-comp")
   (autoload 'gnus-point-at-eol "gnus-util")
   (autoload 'gnus-point-at-bol "gnus-util")
+  (autoload 'gnus-output-to-rmail "gnus-util")
   (autoload 'gnus-output-to-mail "gnus-util")
-  (autoload 'gnus-output-to-rmail "gnus-util")
   (autoload 'mail-abbrev-in-expansion-header-p "mailabbrev")
   (autoload 'nndraft-request-associate-buffer "nndraft")
   (autoload 'nndraft-request-expire-articles "nndraft")
   (autoload 'gnus-open-server "gnus-int")
   (autoload 'gnus-request-post "gnus-int")
   (autoload 'gnus-alive-p "gnus-util")
+  (autoload 'gnus-group-name-charset "gnus-group")
   (autoload 'rmail-output "rmail"))
 
 
@@ -972,9 +1029,19 @@
   `(delete-region (progn (beginning-of-line) (point))
 		  (progn (forward-line ,(or n 1)) (point))))
 
+(defun message-unquote-tokens (elems)
+  "Remove double quotes (\") from strings in list."
+  (mapcar (lambda (item)
+            (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
+              (setq item (concat (match-string 1 item) 
+                                 (match-string 2 item))))
+            item)
+          elems))
+
 (defun message-tokenize-header (header &optional separator)
   "Split HEADER into a list of header elements.
-\",\" is used as the separator."
+SEPARATOR is a string of characters to be used as separators.  \",\"
+is used by default."
   (if (not header)
       nil
     (let ((regexp (format "[%s]+" (or separator ",")))
@@ -996,22 +1063,22 @@
 			       (not paren))))
 		 (push (buffer-substring beg (point)) elems)
 		 (setq beg (match-end 0)))
-		((= (following-char) ?\")
+		((eq (char-after) ?\")
 		 (setq quoted (not quoted)))
-		((and (= (following-char) ?\()
+		((and (eq (char-after) ?\()
 		      (not quoted))
 		 (setq paren t))
-		((and (= (following-char) ?\))
+		((and (eq (char-after) ?\))
 		      (not quoted))
 		 (setq paren nil))))
-	(nreverse elems)))))
+        (nreverse elems)))))
 
 (defun message-mail-file-mbox-p (file)
   "Say whether FILE looks like a Unix mbox file."
   (when (and (file-exists-p file)
 	     (file-readable-p file)
 	     (file-regular-p file))
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (looking-at message-unix-mail-delimiter))))
@@ -1019,9 +1086,27 @@
 (defun message-fetch-field (header &optional not-all)
   "The same as `mail-fetch-field', only remove all newlines."
   (let* ((inhibit-point-motion-hooks t)
+	 (case-fold-search t)
 	 (value (mail-fetch-field header nil (not not-all))))
     (when value
-      (nnheader-replace-chars-in-string value ?\n ? ))))
+      (while (string-match "\n[\t ]+" value)
+	(setq value (replace-match " " t t value)))
+      (set-text-properties 0 (length value) nil value)
+      value)))
+
+(defun message-narrow-to-field ()
+  "Narrow the buffer to the header on the current line."
+  (beginning-of-line)
+  (narrow-to-region
+   (point)
+   (progn
+     (forward-line 1)
+     (if (re-search-forward "^[^ \n\t]" nil t)
+	 (progn
+	   (beginning-of-line)
+	   (point))
+       (point-max))))
+  (goto-char (point-min)))
 
 (defun message-add-header (&rest headers)
   "Add the HEADERS to the message header, skipping those already present."
@@ -1030,12 +1115,13 @@
       (unless (string-match "^\\([^:]+\\):[ \t]*[^ \t]" (car headers))
 	(error "Invalid header `%s'" (car headers)))
       (setq hclean (match-string 1 (car headers)))
-    (save-restriction
-      (message-narrow-to-headers)
-      (unless (re-search-forward (concat "^" (regexp-quote hclean) ":") nil t)
-	(insert (car headers) ?\n))))
+      (save-restriction
+	(message-narrow-to-headers)
+	(unless (re-search-forward (concat "^" (regexp-quote hclean) ":") nil t)
+	  (insert (car headers) ?\n))))
     (setq headers (cdr headers))))
 
+
 (defun message-fetch-reply-field (header)
   "Fetch FIELD from the message we're replying to."
   (when (and message-reply-buffer
@@ -1051,7 +1137,7 @@
 	(erase-buffer))
     (set-buffer (get-buffer-create " *message work*"))
     (kill-all-local-variables)
-    (buffer-disable-undo (current-buffer))))
+    (mm-enable-multibyte)))
 
 (defun message-functionp (form)
   "Return non-nil if FORM is funcallable."
@@ -1059,6 +1145,21 @@
       (and (listp form) (eq (car form) 'lambda))
       (byte-code-function-p form)))
 
+(defun message-strip-list-identifiers (subject)
+  "Remove list identifiers in `gnus-list-identifiers'."
+  (require 'gnus-sum)			; for gnus-list-identifiers
+  (let ((regexp (if (stringp gnus-list-identifiers)
+		    gnus-list-identifiers
+		  (mapconcat 'identity gnus-list-identifiers " *\\|"))))
+    (if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp 
+				" *\\)\\)+\\(Re: +\\)?\\)") subject)
+	(concat (substring subject 0 (match-beginning 1))
+		(or (match-string 3 subject)
+		    (match-string 5 subject))
+		(substring subject
+			   (match-end 1)))
+      subject)))
+
 (defun message-strip-subject-re (subject)
   "Remove \"Re:\" from subject lines."
   (if (string-match message-subject-re-regexp subject)
@@ -1096,9 +1197,21 @@
 	(forward-line 1)
 	(if (re-search-forward "^[^ \t]" nil t)
 	    (goto-char (match-beginning 0))
-	  (point-max))))
+	  (goto-char (point-max)))))
     number))
 
+(defun message-remove-first-header (header)
+  "Remove the first instance of HEADER if there is more than one."
+  (let ((count 0)
+	(regexp (concat "^" (regexp-quote header) ":")))
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward regexp nil t)
+	(incf count)))
+    (while (> count 1)
+      (message-remove-header header nil t)
+      (decf count))))
+
 (defun message-narrow-to-headers ()
   "Narrow the buffer to the head of the message."
   (widen)
@@ -1111,7 +1224,8 @@
   (goto-char (point-min)))
 
 (defun message-narrow-to-head ()
-  "Narrow the buffer to the head of the message."
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
   (widen)
   (narrow-to-region
    (goto-char (point-min))
@@ -1120,6 +1234,21 @@
      (point-max)))
   (goto-char (point-min)))
 
+(defun message-narrow-to-headers-or-head ()
+  "Narrow the buffer to the head of the message."
+  (widen)
+  (narrow-to-region
+   (goto-char (point-min))
+   (cond
+    ((re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
+     (match-beginning 0))
+    ((search-forward "\n\n" nil t)
+     (1- (point)))
+    (t
+     (point-max))))
+  (goto-char (point-min)))
+
 (defun message-news-p ()
   "Say whether the current buffer contains a news message."
   (and (not message-this-is-mail)
@@ -1152,6 +1281,7 @@
 (defun message-sort-headers-1 ()
   "Sort the buffer as headers using `message-rank' text props."
   (goto-char (point-min))
+  (require 'sort)
   (sort-subr
    nil 'message-next-header
    (lambda ()
@@ -1194,7 +1324,8 @@
 (defvar message-mode-map nil)
 
 (unless message-mode-map
-  (setq message-mode-map (copy-keymap text-mode-map))
+  (setq message-mode-map (make-keymap))
+  (set-keymap-parent message-mode-map text-mode-map)
   (define-key message-mode-map "\C-c?" 'describe-mode)
 
   (define-key message-mode-map "\C-c\C-f\C-t" 'message-goto-to)
@@ -1215,8 +1346,10 @@
   (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
 
   (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
+  (define-key message-mode-map "\C-c\M-\C-y" 'message-yank-buffer)
   (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
   (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
+  (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
   (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
   (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
   (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
@@ -1231,6 +1364,8 @@
   (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
   (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
 
+  (define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
+
   (define-key message-mode-map "\t" 'message-tab))
 
 (easy-menu-define
@@ -1248,6 +1383,7 @@
    ["Newline and Reformat" message-newline-and-reformat t]
    ["Rename buffer" message-rename-buffer t]
    ["Spellcheck" ispell-message t]
+   ["Attach file as MIME" mml-attach-file t]
    "----"
    ["Send Message" message-send-and-exit t]
    ["Abort Message" message-dont-send t]
@@ -1279,6 +1415,7 @@
   "Major mode for editing mail and news to be sent.
 Like Text Mode but with these additional commands:
 C-c C-s  message-send (send the message)    C-c C-c  message-send-and-exit
+C-c C-d  Pospone sending the message        C-c C-k  Kill the message
 C-c C-f  move to a header field (and create it if there isn't):
 	 C-c C-f C-t  move to To	C-c C-f C-s  move to Subject
 	 C-c C-f C-c  move to Cc	C-c C-f C-b  move to Bcc
@@ -1294,12 +1431,16 @@
 C-c C-y  message-yank-original (insert current message, if any).
 C-c C-q  message-fill-yanked-message (fill what was yanked).
 C-c C-e  message-elide-region (elide the text between point and mark).
+C-c C-v  message-delete-not-region (remove the text outside the region).
 C-c C-z  message-kill-to-signature (kill the text up to the signature).
-C-c C-r  message-caesar-buffer-body (rot13 the message body)."
+C-c C-r  message-caesar-buffer-body (rot13 the message body).
+C-c C-a  mml-attach-file (attach a file as MIME).
+M-RET    message-newline-and-reformat (break the line and reformat)."
   (interactive)
+  (if (local-variable-p 'mml-buffer-list (current-buffer))
+      (mml-destroy-buffers))
   (kill-all-local-variables)
-  (make-local-variable 'message-reply-buffer)
-  (setq message-reply-buffer nil)
+  (set (make-local-variable 'message-reply-buffer) nil)
   (make-local-variable 'message-send-actions)
   (make-local-variable 'message-exit-actions)
   (make-local-variable 'message-kill-actions)
@@ -1328,51 +1469,51 @@
   ;; lines that delimit forwarded messages.
   ;; Lines containing just >= 3 dashes, perhaps after whitespace,
   ;; are also sometimes used and should be separators.
-  (setq paragraph-start (concat (regexp-quote mail-header-separator)
- 				"$\\|[ \t]*[a-z0-9A-Z]*>+[ \t]*$\\|[ \t]*$\\|"
- 				"-- $\\|---+$\\|"
- 				page-delimiter))
+  (setq paragraph-start
+	(concat (regexp-quote mail-header-separator)
+		"$\\|[ \t]*[a-z0-9A-Z]*>+[ \t]*$\\|[ \t]*$\\|"
+		"-- $\\|---+$\\|"
+		page-delimiter
+		;;!!! Uhm... shurely this can't be right?
+		"[> " (regexp-quote message-yank-prefix) "]+$"))
   (setq paragraph-separate paragraph-start)
   (make-local-variable 'message-reply-headers)
   (setq message-reply-headers nil)
   (make-local-variable 'message-newsreader)
   (make-local-variable 'message-mailer)
   (make-local-variable 'message-post-method)
-  (make-local-variable 'message-sent-message-via)
-  (setq message-sent-message-via nil)
-  (make-local-variable 'message-checksum)
-  (setq message-checksum nil)
+  (set (make-local-variable 'message-sent-message-via) nil)
+  (set (make-local-variable 'message-checksum) nil)
+  (set (make-local-variable 'message-mime-part) 0)
   ;;(when (fboundp 'mail-hist-define-keys)
   ;;  (mail-hist-define-keys))
-  (when (string-match "XEmacs\\|Lucid" emacs-version)
-    (message-setup-toolbar))
+  (if (featurep 'xemacs)
+      (message-setup-toolbar)
+    (set (make-local-variable 'font-lock-defaults)
+	 '(message-font-lock-keywords t)))
   (easy-menu-add message-mode-menu message-mode-map)
   (easy-menu-add message-mode-field-menu message-mode-map)
-  (make-local-variable 'adaptive-fill-regexp)
-  (setq adaptive-fill-regexp
-	(concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|" adaptive-fill-regexp))
-  (make-local-variable 'adaptive-fill-first-line-regexp)
-  (setq adaptive-fill-first-line-regexp
-	(concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|"
-		adaptive-fill-first-line-regexp))
   ;; Allow mail alias things.
   (when (eq message-mail-alias-type 'abbrev)
     (if (fboundp 'mail-abbrevs-setup)
 	(mail-abbrevs-setup)
       (mail-aliases-setup)))
   (message-set-auto-save-file-name)
-  (unless (string-match "XEmacs" emacs-version)
-    (set (make-local-variable 'font-lock-defaults)
-	 '(message-font-lock-keywords t)))
   (make-local-variable 'adaptive-fill-regexp)
   (setq adaptive-fill-regexp
-	(concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|" adaptive-fill-regexp))
+	(concat "[ \t]*[-a-z0-9A-Z]*\\(>[ \t]*\\)+[ \t]*\\|" adaptive-fill-regexp))
   (unless (boundp 'adaptive-fill-first-line-regexp)
     (setq adaptive-fill-first-line-regexp nil))
   (make-local-variable 'adaptive-fill-first-line-regexp)
   (setq adaptive-fill-first-line-regexp
-	(concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|"
+	(concat "[ \t]*[-a-z0-9A-Z]*\\(>[ \t]*\\)+[ \t]*\\|"
 		adaptive-fill-first-line-regexp))
+  (make-local-variable 'auto-fill-inhibit-regexp)
+  (setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
+  (mm-enable-multibyte)
+  (make-local-variable 'indent-tabs-mode) ;Turn off tabs for indentation.
+  (setq indent-tabs-mode nil)
+  (mml-mode)
   (run-hooks 'text-mode-hook 'message-mode-hook))
 
 
@@ -1443,13 +1584,14 @@
   (interactive)
   (if (looking-at "[ \t]*\n") (expand-abbrev))
   (goto-char (point-min))
-  (search-forward (concat "\n" mail-header-separator "\n") nil t))
+  (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
+      (search-forward "\n\n" nil t)))
 
 (defun message-goto-eoh ()
   "Move point to the end of the headers."
   (interactive)
   (message-goto-body)
-  (forward-line -2))
+  (forward-line -1))
 
 (defun message-goto-signature ()
   "Move point to the beginning of the message signature.
@@ -1473,7 +1615,8 @@
   (let ((co (message-fetch-reply-field "mail-copies-to")))
     (when (and (null force)
 	       co
-	       (equal (downcase co) "never"))
+	       (or (equal (downcase co) "never")
+		   (equal (downcase co) "nobody")))
       (error "The user has requested not to have copies sent via mail")))
   (when (and (message-position-on-field "To")
 	     (mail-fetch-field "to")
@@ -1482,6 +1625,24 @@
   (insert (or (message-fetch-reply-field "reply-to")
 	      (message-fetch-reply-field "from") "")))
 
+(defun message-widen-reply ()
+  "Widen the reply to include maximum recipients."
+  (interactive)
+  (let ((follow-to
+	 (and message-reply-buffer
+	      (buffer-name message-reply-buffer)
+	      (save-excursion
+		(set-buffer message-reply-buffer)
+		(message-get-reply-headers t)))))
+    (save-excursion
+      (save-restriction
+	(message-narrow-to-headers)
+	(dolist (elem follow-to)
+	  (message-remove-header (symbol-name (car elem)))
+	  (goto-char (point-min))
+	  (insert (symbol-name (car elem)) ": "
+		  (cdr elem) "\n"))))))
+
 (defun message-insert-newsgroups ()
   "Insert the Newsgroups header from the article being replied to."
   (interactive)
@@ -1526,17 +1687,24 @@
 (defun message-newline-and-reformat ()
   "Insert four newlines, and then reformat if inside quoted text."
   (interactive)
-  (let ((point (point))
-	quoted)
-    (save-excursion
-      (beginning-of-line)
-      (setq quoted (looking-at (regexp-quote message-yank-prefix))))
-    (insert "\n\n\n\n")
+  (let ((prefix "[]>»|:}+ \t]*")
+	(supercite-thing "[-._a-zA-Z0-9]*[>]+[ \t]*")
+	quoted point)
+    (unless (bolp)
+      (save-excursion
+	(beginning-of-line)
+	(when (looking-at (concat prefix
+				  supercite-thing))
+	  (setq quoted (match-string 0))))
+      (insert "\n"))
+    (setq point (point))
+    (insert "\n\n\n")
+    (delete-region (point) (re-search-forward "[ \t]*"))
     (when quoted
-      (insert message-yank-prefix))
+      (insert quoted))
     (fill-paragraph nil)
     (goto-char point)
-    (forward-line 2)))
+    (forward-line 1)))
 
 (defun message-insert-signature (&optional force)
   "Insert a signature.  See documentation for the `message-signature' variable."
@@ -1547,8 +1715,7 @@
 		 (eq force 0))
 	    (save-excursion
 	      (goto-char (point-max))
-	      (not (re-search-backward
-		    message-signature-separator nil t))))
+	      (not (re-search-backward message-signature-separator nil t))))
 	   ((and (null message-signature)
 		 force)
 	    t)
@@ -1578,13 +1745,11 @@
 
 (defun message-elide-region (b e)
   "Elide the text between point and mark.
-An ellipsis (from `message-elide-elipsis') will be inserted where the
+An ellipsis (from `message-elide-ellipsis') will be inserted where the
 text was killed."
   (interactive "r")
   (kill-region b e)
-  (unless (bolp)
-    (insert "\n"))
-  (insert message-elide-elipsis))
+  (insert message-elide-ellipsis))
 
 (defvar message-caesar-translation-table nil)
 
@@ -1603,15 +1768,9 @@
     ;; We build the table, if necessary.
     (when (or (not message-caesar-translation-table)
 	      (/= (aref message-caesar-translation-table ?a) (+ ?a n)))
-	(setq message-caesar-translation-table
-	      (message-make-caesar-translation-table n)))
-    ;; Then we translate the region.  Do it this way to retain
-    ;; text properties.
-    (while (< b e)
-      (subst-char-in-region
-       b (1+ b) (char-after b)
-       (aref message-caesar-translation-table (char-after b)))
-      (incf b))))
+      (setq message-caesar-translation-table
+	    (message-make-caesar-translation-table n)))
+    (translate-region b e message-caesar-translation-table)))
 
 (defun message-make-caesar-translation-table (n)
   "Create a rot table with offset N."
@@ -1648,11 +1807,8 @@
     (save-restriction
       (when (message-goto-body)
         (narrow-to-region (point) (point-max)))
-      (let ((body (buffer-substring (point-min) (point-max))))
-        (unless (equal 0 (call-process-region
-                           (point-min) (point-max) program t t))
-            (insert body)
-            (message "%s failed." program))))))
+      (shell-command-on-region
+       (point-min) (point-max) program nil t))))
 
 (defun message-rename-buffer (&optional enter-string)
   "Rename the *message* buffer to \"*message* RECIPIENT\".
@@ -1686,8 +1842,7 @@
     (goto-char (point-min))
     (search-forward (concat "\n" mail-header-separator "\n") nil t)
     (let ((fill-prefix message-yank-prefix))
-      (fill-individual-paragraphs (point) (point-max) justifyp
-				  mail-citation-prefix-regexp))))
+      (fill-individual-paragraphs (point) (point-max) justifyp))))
 
 (defun message-indent-citation ()
   "Modify text just inserted from a message to be cited.
@@ -1758,6 +1913,24 @@
       (unless modified
 	(setq message-checksum (message-checksum))))))
 
+(defun message-yank-buffer (buffer)
+  "Insert BUFFER into the current buffer and quote it."
+  (interactive "bYank buffer: ")
+  (let ((message-reply-buffer buffer))
+    (save-window-excursion
+      (message-yank-original))))
+
+(defun message-buffers ()
+  "Return a list of active message buffers."
+  (let (buffers)
+    (save-excursion
+      (dolist (buffer (buffer-list t))
+	(set-buffer buffer)
+	(when (and (eq major-mode 'message-mode)
+		   (null message-sent-message-via))
+	  (push (buffer-name buffer) buffers))))
+    (nreverse buffers)))
+
 (defun message-cite-original-without-signature ()
   "Cite function in the standard Message manner."
   (let ((start (point))
@@ -1767,8 +1940,11 @@
 	   (if (listp message-indent-citation-function)
 	       message-indent-citation-function
 	     (list message-indent-citation-function)))))
+    (mml-quote-region start end)
+    ;; Allow undoing.
+    (undo-boundary)
     (goto-char end)
-    (when (re-search-backward "^-- $" start t)
+    (when (re-search-backward message-signature-separator start t)
       ;; Also peel off any blank lines before the signature.
       (forward-line -1)
       (while (looking-at "^[ \t]*$")
@@ -1783,25 +1959,27 @@
 	(insert "\n"))
       (funcall message-citation-line-function))))
 
-(defvar mail-citation-hook) ;Compiler directive
+(defvar mail-citation-hook)		;Compiler directive
 (defun message-cite-original ()
   "Cite function in the standard Message manner."
   (if (and (boundp 'mail-citation-hook)
- 	   mail-citation-hook)
+	   mail-citation-hook)
       (run-hooks 'mail-citation-hook)
     (let ((start (point))
- 	  (functions
- 	   (when message-indent-citation-function
- 	     (if (listp message-indent-citation-function)
- 		 message-indent-citation-function
- 	       (list message-indent-citation-function)))))
+	  (end (mark t))
+	  (functions
+	   (when message-indent-citation-function
+	     (if (listp message-indent-citation-function)
+		 message-indent-citation-function
+	       (list message-indent-citation-function)))))
+      (mml-quote-region start end)
       (goto-char start)
       (while functions
- 	(funcall (pop functions)))
+	(funcall (pop functions)))
       (when message-citation-line-function
- 	(unless (bolp)
- 	  (insert "\n"))
- 	(funcall message-citation-line-function)))))
+	(unless (bolp)
+	  (insert "\n"))
+	(funcall message-citation-line-function)))))
 
 (defun message-insert-citation-line ()
   "Function that inserts a simple citation line."
@@ -1910,51 +2088,50 @@
 
 (defun message-send (&optional arg)
   "Send the message in the current buffer.
-If `message-interactive' is non-nil, wait for success indication
-or error messages, and inform user.
-Otherwise any failure is reported in a message back to
-the user from the mailer."
+If `message-interactive' is non-nil, wait for success indication or
+error messages, and inform user.
+Otherwise any failure is reported in a message back to the user from
+the mailer.
+The usage of ARG is defined by the instance that called Message.
+It should typically alter the sending method in some way or other."
   (interactive "P")
-  ;; Disabled test.
-  (when (or (buffer-modified-p)
-	    (message-check-element 'unchanged)
-	    (y-or-n-p "No changes in the buffer; really send? "))
-    ;; Make it possible to undo the coming changes.
-    (undo-boundary)
-    (let ((inhibit-read-only t))
-      (put-text-property (point-min) (point-max) 'read-only nil))
-    (message-fix-before-sending)
-    (run-hooks 'message-send-hook)
-    (message "Sending...")
-    (let ((alist message-send-method-alist)
-	  (success t)
-	  elem sent)
-      (while (and success
-		  (setq elem (pop alist)))
-	(when (and (or (not (funcall (cadr elem)))
-		       (and (or (not (memq (car elem)
-					   message-sent-message-via))
-				(y-or-n-p
-				 (format
-				  "Already sent message via %s; resend? "
-				  (car elem))))
-			    (setq success (funcall (caddr elem) arg)))))
-	  (setq sent t)))
-      (when (and success sent)
-	(message-do-fcc)
-	;;(when (fboundp 'mail-hist-put-headers-into-history)
-	;; (mail-hist-put-headers-into-history))
-	(run-hooks 'message-sent-hook)
-	(message "Sending...done")
-	;; Mark the buffer as unmodified and delete auto-save.
-	(set-buffer-modified-p nil)
-	(delete-auto-save-file-if-necessary t)
-	(message-disassociate-draft)
-	;; Delete other mail buffers and stuff.
-	(message-do-send-housekeeping)
-	(message-do-actions message-send-actions)
-	;; Return success.
-	t))))
+  ;; Make it possible to undo the coming changes.
+  (undo-boundary)
+  (let ((inhibit-read-only t))
+    (put-text-property (point-min) (point-max) 'read-only nil))
+  (message-fix-before-sending)
+  (run-hooks 'message-send-hook)
+  (message "Sending...")
+  (let ((alist message-send-method-alist)
+	(success t)
+	elem sent)
+    (while (and success
+		(setq elem (pop alist)))
+      (when (or (not (funcall (cadr elem)))
+		(and (or (not (memq (car elem)
+				    message-sent-message-via))
+			 (y-or-n-p
+			  (format
+			   "Already sent message via %s; resend? "
+			   (car elem))))
+		     (setq success (funcall (caddr elem) arg))))
+	(setq sent t)))
+    (unless (or sent (not success))
+      (error "No methods specified to send by"))
+    (when (and success sent)
+      (message-do-fcc)
+      (save-excursion
+	(run-hooks 'message-sent-hook))
+      (message "Sending...done")
+      ;; Mark the buffer as unmodified and delete auto-save.
+      (set-buffer-modified-p nil)
+      (delete-auto-save-file-if-necessary t)
+      (message-disassociate-draft)
+      ;; Delete other mail buffers and stuff.
+      (message-do-send-housekeeping)
+      (message-do-actions message-send-actions)
+      ;; Return success.
+      t)))
 
 (defun message-send-via-mail (arg)
   "Send the current message via mail."
@@ -1964,18 +2141,28 @@
   "Send the current message via news."
   (funcall message-send-news-function arg))
 
+(defmacro message-check (type &rest forms)
+  "Eval FORMS if TYPE is to be checked."
+  `(or (message-check-element ,type)
+       (save-excursion
+	 ,@forms)))
+
+(put 'message-check 'lisp-indent-function 1)
+(put 'message-check 'edebug-form-spec '(form body))
+
 (defun message-fix-before-sending ()
   "Do various things to make the message nice before sending it."
   ;; Make sure there's a newline at the end of the message.
   (goto-char (point-max))
   (unless (bolp)
     (insert "\n"))
-  ;; Make all invisible text visible.
-  ;;(when (text-property-any (point-min) (point-max) 'invisible t)
-  ;;  (put-text-property (point-min) (point-max) 'invisible nil)
-  ;;  (unless (yes-or-no-p "Invisible text found and made visible; continue posting?")
-  ;;    (error "Invisible text found and made visible")))
-  )
+  ;; Delete all invisible text.
+  (message-check 'invisible-text
+    (when (text-property-any (point-min) (point-max) 'invisible t)
+      (put-text-property (point-min) (point-max) 'invisible nil)
+      (unless (yes-or-no-p
+	       "Invisible text found and made visible; continue posting? ")
+	(error "Invisible text found and made visible")))))
 
 (defun message-add-action (action &rest types)
   "Add ACTION to be performed when doing an exit of type TYPES."
@@ -1998,12 +2185,83 @@
 	(eval (car actions)))))
     (pop actions)))
 
+(defun message-send-mail-partially ()
+  "Sendmail as message/partial."
+  (let ((p (goto-char (point-min)))
+	(tembuf (message-generate-new-buffer-clone-locals " message temp"))
+	(curbuf (current-buffer))
+	(id (message-make-message-id)) (n 1)
+	plist total  header required-mail-headers)
+    (while (not (eobp))
+      (if (< (point-max) (+ p message-send-mail-partially-limit))
+	  (goto-char (point-max))
+	(goto-char (+ p message-send-mail-partially-limit))
+	(beginning-of-line)
+	(if (<= (point) p) (forward-line 1))) ;; In case of bad message.
+      (push p plist)
+      (setq p (point)))
+    (setq total (length plist))
+    (push (point-max) plist)
+    (setq plist (nreverse plist))
+    (unwind-protect
+	(save-excursion
+	  (setq p (pop plist))
+	  (while plist
+	    (set-buffer curbuf)
+	    (copy-to-buffer tembuf p (car plist))
+	    (set-buffer tembuf)
+	    (goto-char (point-min))
+	    (if header
+		(progn
+		  (goto-char (point-min))
+		  (narrow-to-region (point) (point))
+		  (insert header))
+	      (message-goto-eoh)
+	      (setq header (buffer-substring (point-min) (point)))
+	      (goto-char (point-min))
+	      (narrow-to-region (point) (point))
+	      (insert header)
+	      (message-remove-header "Mime-Version")
+	      (message-remove-header "Content-Type")
+	      (message-remove-header "Content-Transfer-Encoding")
+	      (message-remove-header "Message-ID")
+	      (message-remove-header "Lines")
+	      (goto-char (point-max))
+	      (insert "Mime-Version: 1.0\n")
+	      (setq header (buffer-substring (point-min) (point-max))))
+	    (goto-char (point-max))
+	    (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n"
+			    id n total))
+	    (let ((mail-header-separator ""))
+	      (when (memq 'Message-ID message-required-mail-headers)
+		(insert "Message-ID: " (message-make-message-id) "\n"))
+	      (when (memq 'Lines message-required-mail-headers)
+		(let ((mail-header-separator ""))
+		  (insert "Lines: " (message-make-lines) "\n")))
+	      (message-goto-subject)
+	      (end-of-line)
+	      (insert (format " (%d/%d)" n total))
+	      (goto-char (point-max))
+	      (insert "\n")
+	      (widen)
+	      (mm-with-unibyte-current-buffer
+		(funcall message-send-mail-function)))
+	    (setq n (+ n 1))
+	    (setq p (pop plist))
+	    (erase-buffer)))
+      (kill-buffer tembuf))))
+
 (defun message-send-mail (&optional arg)
   (require 'mail-utils)
-  (let ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
-	(case-fold-search nil)
-	(news (message-news-p))
-	(mailbuf (current-buffer)))
+  (let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
+	 (case-fold-search nil)
+	 (news (message-news-p))
+	 (mailbuf (current-buffer))
+	 (message-this-is-mail t)
+	 (message-posting-charset
+	  (if (fboundp 'gnus-setup-posting-charset)
+	      (gnus-setup-posting-charset nil)
+	    message-posting-charset)))
     (save-restriction
       (message-narrow-to-headers)
       ;; Insert some headers.
@@ -2022,19 +2280,37 @@
 			  (set-buffer mailbuf)
 			  (buffer-string))))
 	  ;; Remove some headers.
+	  (message-encode-message-body)
 	  (save-restriction
 	    (message-narrow-to-headers)
+	    ;; We (re)generate the Lines header.
+	    (when (memq 'Lines message-required-mail-headers)
+	      (message-generate-headers '(Lines)))
 	    ;; Remove some headers.
-	    (message-remove-header message-ignored-mail-headers t))
+	    (message-remove-header message-ignored-mail-headers t)
+	    (let ((mail-parse-charset message-default-charset))
+	      (mail-encode-encoded-word-buffer)))
 	  (goto-char (point-max))
 	  ;; require one newline at the end.
 	  (or (= (preceding-char) ?\n)
 	      (insert ?\n))
-	  (when (and news
+	  (when 
+	      (save-restriction
+		(message-narrow-to-headers)
+		(and news
 		     (or (message-fetch-field "cc")
-			 (message-fetch-field "to")))
+			 (message-fetch-field "to"))
+		     (string= "text/plain"
+			      (car
+			       (mail-header-parse-content-type
+				(message-fetch-field "content-type"))))))
 	    (message-insert-courtesy-copy))
-	  (funcall message-send-mail-function))
+	  (if (or (not message-send-mail-partially-limit)
+		  (< (point-max) message-send-mail-partially-limit)
+		  (not (y-or-n-p "The message size is too large, should it be sent partially?")))
+	      (mm-with-unibyte-current-buffer
+		(funcall message-send-mail-function))
+	    (message-send-mail-partially)))
       (kill-buffer tembuf))
     (set-buffer mailbuf)
     (push 'mail message-sent-message-via)))
@@ -2042,7 +2318,8 @@
 (defun message-send-mail-with-sendmail ()
   "Send off the prepared buffer with sendmail."
   (let ((errbuf (if message-interactive
-		    (generate-new-buffer " sendmail errors")
+		    (message-generate-new-buffer-clone-locals
+		     " sendmail errors")
 		  0))
 	resend-to-addresses delimline)
     (let ((case-fold-search t))
@@ -2067,7 +2344,7 @@
 	  (set-buffer errbuf)
 	  (erase-buffer))))
     (let ((default-directory "/")
- 	  (coding-system-for-write message-send-coding-system))
+	  (coding-system-for-write message-send-coding-system))
       (apply 'call-process-region
 	     (append (list (point-min) (point-max)
 			   (if (boundp 'sendmail-program)
@@ -2079,7 +2356,7 @@
 		     ;; But some systems are more broken with -f, so
 		     ;; we'll let users override this.
 		     (if (null message-sendmail-f-is-evil)
-			 (list "-f" (user-login-name)))
+			 (list "-f" (message-make-address)))
 		     ;; These mean "report errors by mail"
 		     ;; and "deliver in background".
 		     (if (null message-interactive) '("-oem" "-odb"))
@@ -2164,85 +2441,92 @@
     (mh-send-letter)))
 
 (defun message-send-news (&optional arg)
-  (let ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
-	(case-fold-search nil)
-	(method (if (message-functionp message-post-method)
-		    (funcall message-post-method arg)
-		  message-post-method))
-	(messbuf (current-buffer))
-	(message-syntax-checks
-	 (if arg
-	     (cons '(existing-newsgroups . disabled)
-		   message-syntax-checks)
-	   message-syntax-checks))
-	result)
-    (save-restriction
-      (message-narrow-to-headers)
-      ;; Insert some headers.
-      (message-generate-headers message-required-news-headers)
-      ;; Let the user do all of the above.
-      (run-hooks 'message-header-hook))
-    (message-cleanup-headers)
-    (if (not (message-check-news-syntax))
-	(progn
-	  ;;(message "Posting not performed")
-	  nil)
-      (unwind-protect
-	  (save-excursion
-	    (set-buffer tembuf)
-	    (buffer-disable-undo (current-buffer))
-	    (erase-buffer)
-	    ;; Avoid copying text props.
-	    (insert (format
-		     "%s" (save-excursion
-			    (set-buffer messbuf)
-			    (buffer-string))))
-	    ;; Remove some headers.
-	    (save-restriction
-	      (message-narrow-to-headers)
+  (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
+	 (case-fold-search nil)
+	 (method (if (message-functionp message-post-method)
+		     (funcall message-post-method arg)
+		   message-post-method))
+	 (group-name-charset (gnus-group-name-charset method ""))
+	 (rfc2047-header-encoding-alist
+	  (if group-name-charset
+	      (cons (cons "Newsgroups" group-name-charset)
+		    rfc2047-header-encoding-alist)
+	    rfc2047-header-encoding-alist))
+	 (messbuf (current-buffer))
+	 (message-syntax-checks
+	  (if arg
+	      (cons '(existing-newsgroups . disabled)
+		    message-syntax-checks)
+	    message-syntax-checks))
+	 (message-this-is-news t)
+	 (message-posting-charset (gnus-setup-posting-charset 
+				   (save-restriction
+				     (message-narrow-to-headers-or-head)
+				     (message-fetch-field "Newsgroups"))))
+	 result)
+    (if (not (message-check-news-body-syntax))
+	nil
+      (save-restriction
+	(message-narrow-to-headers)
+	;; Insert some headers.
+	(message-generate-headers message-required-news-headers)
+	;; Let the user do all of the above.
+	(run-hooks 'message-header-hook))
+      (if group-name-charset
+	  (setq message-syntax-checks
+	      (cons '(valid-newsgroups . disabled)
+		    message-syntax-checks)))
+      (message-cleanup-headers)
+      (if (not (message-check-news-syntax))
+	  nil
+	(unwind-protect
+	    (save-excursion
+	      (set-buffer tembuf)
+	      (buffer-disable-undo)
+	      (erase-buffer)
+	      ;; Avoid copying text props.
+	      (insert (format
+		       "%s" (save-excursion
+			      (set-buffer messbuf)
+			      (buffer-string))))
+	      (message-encode-message-body)
 	      ;; Remove some headers.
-	      (message-remove-header message-ignored-news-headers t))
-	    (goto-char (point-max))
-	    ;; require one newline at the end.
-	    (or (= (preceding-char) ?\n)
-		(insert ?\n))
-	    (let ((case-fold-search t))
-	      ;; Remove the delimiter.
-	      (goto-char (point-min))
-	      (re-search-forward
-	       (concat "^" (regexp-quote mail-header-separator) "\n"))
-	      (replace-match "\n")
-	      (backward-char 1))
-	    (run-hooks 'message-send-news-hook)
-	    ;;(require (car method))
-	    ;;(funcall (intern (format "%s-open-server" (car method)))
-	    ;;(cadr method) (cddr method))
-	    ;;(setq result
-	    ;;	  (funcall (intern (format "%s-request-post" (car method)))
-	    ;;		   (cadr method)))
-	    (gnus-open-server method)
-	    (setq result (gnus-request-post method)))
-	(kill-buffer tembuf))
-      (set-buffer messbuf)
-      (if result
-	  (push 'news message-sent-message-via)
-	(message "Couldn't send message via news: %s"
-		 (nnheader-get-report (car method)))
-	nil))))
+	      (save-restriction
+		(message-narrow-to-headers)
+		;; We (re)generate the Lines header.
+		(when (memq 'Lines message-required-mail-headers)
+		  (message-generate-headers '(Lines)))
+		;; Remove some headers.
+		(message-remove-header message-ignored-news-headers t)
+		(let ((mail-parse-charset message-default-charset))
+		  (mail-encode-encoded-word-buffer)))
+	      (goto-char (point-max))
+	      ;; require one newline at the end.
+	      (or (= (preceding-char) ?\n)
+		  (insert ?\n))
+	      (let ((case-fold-search t))
+		;; Remove the delimiter.
+		(goto-char (point-min))
+		(re-search-forward
+		 (concat "^" (regexp-quote mail-header-separator) "\n"))
+		(replace-match "\n")
+		(backward-char 1))
+	      (run-hooks 'message-send-news-hook)
+	      (gnus-open-server method)
+	      (setq result (let ((mail-header-separator ""))
+			     (gnus-request-post method))))
+	  (kill-buffer tembuf))
+	(set-buffer messbuf)
+	(if result
+	    (push 'news message-sent-message-via)
+	  (message "Couldn't send message via news: %s"
+		   (nnheader-get-report (car method)))
+	  nil)))))
 
 ;;;
 ;;; Header generation & syntax checking.
 ;;;
 
-(defmacro message-check (type &rest forms)
-  "Eval FORMS if TYPE is to be checked."
-  `(or (message-check-element ,type)
-       (save-excursion
-	 ,@forms)))
-
-(put 'message-check 'lisp-indent-function 1)
-(put 'message-check 'edebug-form-spec '(form body))
-
 (defun message-check-element (type)
   "Returns non-nil if this type is not to be checked."
   (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
@@ -2256,17 +2540,23 @@
   (save-excursion
     (save-restriction
       (widen)
-      (and
-       ;; We narrow to the headers and check them first.
-       (save-excursion
-	 (save-restriction
-	   (message-narrow-to-headers)
-	   (message-check-news-header-syntax)))
-       ;; Check the body.
-       (message-check-news-body-syntax)))))
+      ;; We narrow to the headers and check them first.
+      (save-excursion
+	(save-restriction
+	  (message-narrow-to-headers)
+	  (message-check-news-header-syntax))))))
 
 (defun message-check-news-header-syntax ()
   (and
+   ;; Check Newsgroups header.
+   (message-check 'newsgroups
+     (let ((group (message-fetch-field "newsgroups")))
+       (or
+	(and group
+	     (not (string-match "\\`[ \t]*\\'" group)))
+	(ignore
+	 (message
+	  "The newsgroups field is empty or missing.  Posting is denied.")))))
    ;; Check the Subject header.
    (message-check 'subject
      (let* ((case-fold-search t)
@@ -2429,12 +2719,15 @@
    (message-check 'from
      (let* ((case-fold-search t)
 	    (from (message-fetch-field "from"))
-	    (ad (nth 1 (mail-extract-address-components from))))
+	    ad)
        (cond
 	((not from)
 	 (message "There is no From line.  Posting is denied.")
 	 nil)
-	((or (not (string-match "@[^\\.]*\\." ad)) ;larsi@ifi
+	((or (not (string-match
+		   "@[^\\.]*\\."
+		   (setq ad (nth 1 (mail-extract-address-components
+				    from))))) ;larsi@ifi
 	     (string-match "\\.\\." ad) ;larsi@ifi..uio
 	     (string-match "@\\." ad)	;larsi@.ifi.uio
 	     (string-match "\\.$" ad)	;larsi@ifi.uio.
@@ -2475,7 +2768,7 @@
 	   (y-or-n-p "Empty article.  Really post? "))))
    ;; Check for control characters.
    (message-check 'control-chars
-     (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
+     (if (re-search-forward "[\000-\007\013\015-\032\034-\037\200-\237]" nil t)
 	 (y-or-n-p
 	  "The article contains control characters.  Really post? ")
        t))
@@ -2496,15 +2789,25 @@
    ;; Check the length of the signature.
    (message-check 'signature
      (goto-char (point-max))
-     (if (or (not (re-search-backward message-signature-separator nil t))
-	     (search-forward message-forward-end-separator nil t))
-	 t
-       (if (> (count-lines (point) (point-max)) 5)
-	   (y-or-n-p
-	    (format
-	     "Your .sig is %d lines; it should be max 4.  Really post? "
-	     (1- (count-lines (point) (point-max)))))
-	 t)))))
+     (if (> (count-lines (point) (point-max)) 5)
+	 (y-or-n-p
+	  (format
+	   "Your .sig is %d lines; it should be max 4.  Really post? "
+	   (1- (count-lines (point) (point-max)))))
+       t))
+   ;; Ensure that text follows last quoted portion.
+   (message-check 'quoting-style
+     (goto-char (point-max))
+     (let ((no-problem t))
+       (when (search-backward-regexp "^>[^\n]*\n>" nil t)
+	 (setq no-problem nil)
+	 (while (not (eobp))
+	   (when (and (not (eolp)) (looking-at "[^> \t]"))
+	     (setq no-problem t))
+	   (forward-line)))
+       (if no-problem
+	   t
+	 (y-or-n-p "Your text should follow quoted text.  Really post? "))))))
 
 (defun message-checksum ()
   "Return a \"checksum\" for the current buffer."
@@ -2516,7 +2819,7 @@
       (while (not (eobp))
 	(when (not (looking-at "[ \t\n]"))
  	  (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
- 			    (following-char))))
+ 			    (char-after))))
 	(forward-char 1)))
     sum))
 
@@ -2527,7 +2830,6 @@
 	list file)
     (save-excursion
       (set-buffer (get-buffer-create " *message temp*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
       (insert-buffer-substring buf)
       (save-restriction
@@ -2535,9 +2837,19 @@
 	(while (setq file (message-fetch-field "fcc"))
 	  (push file list)
 	  (message-remove-header "fcc" nil t)))
+      (message-encode-message-body)
+      (save-restriction
+	(message-narrow-to-headers)
+	(let ((mail-parse-charset message-default-charset)
+	      (rfc2047-header-encoding-alist
+	       (cons '("Newsgroups" . default)
+		     rfc2047-header-encoding-alist)))
+	  (mail-encode-encoded-word-buffer)))
       (goto-char (point-min))
-      (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
-      (replace-match "" t t)
+      (when (re-search-forward
+	     (concat "^" (regexp-quote mail-header-separator) "$")
+	     nil t)
+	(replace-match "" t t ))
       ;; Process FCC operations.
       (while list
 	(setq file (pop list))
@@ -2557,7 +2869,6 @@
 		(rmail-output file 1 nil t)
 	      (let ((mail-use-rfc822 t))
 		(rmail-output file 1 t t))))))
-
       (kill-buffer (current-buffer)))))
 
 (defun message-output (filename)
@@ -2599,11 +2910,24 @@
 	(when (re-search-forward ",+$" nil t)
 	  (replace-match "" t t))))))
 
-(defun message-make-date ()
-  "Make a valid data header."
-  (let ((now (current-time)))
-    (timezone-make-date-arpa-standard
-     (current-time-string now) (current-time-zone now))))
+(defun message-make-date (&optional now)
+  "Make a valid data header.
+If NOW, use that time instead."
+  (let* ((now (or now (current-time)))
+	 (zone (nth 8 (decode-time now)))
+	 (sign "+"))
+    (when (< zone 0)
+      (setq sign "-")
+      (setq zone (- zone)))
+    (concat
+     (format-time-string "%d" now)
+     ;; The month name of the %b spec is locale-specific.  Pfff.
+     (format " %s "
+	     (capitalize (car (rassoc (nth 4 (decode-time now))
+				      parse-time-months))))
+     (format-time-string "%Y %H:%M:%S " now)
+     ;; We do all of this because XEmacs doesn't have the %z spec.
+     (format "%s%02d%02d" sign (/ zone 3600) (/ (% zone 3600) 60)))))
 
 (defun message-make-message-id ()
   "Make a unique Message-ID."
@@ -2670,9 +2994,9 @@
   "Make an Organization header."
   (let* ((organization
 	  (when message-user-organization
-		(if (message-functionp message-user-organization)
-		    (funcall message-user-organization)
-		  message-user-organization))))
+	    (if (message-functionp message-user-organization)
+		(funcall message-user-organization)
+	      message-user-organization))))
     (save-excursion
       (message-set-work-buffer)
       (cond ((stringp organization)
@@ -2728,9 +3052,7 @@
     ;; Add the future to current.
     (setcar current (+ (car current) (round (/ future (expt 2 16)))))
     (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
-    ;; Return the date in the future in UT.
-    (timezone-make-date-arpa-standard
-     (current-time-string current) (current-time-zone current) '(0 "UT"))))
+    (message-make-date current)))
 
 (defun message-make-path ()
   "Return uucp path."
@@ -2868,9 +3190,7 @@
 	   (To nil)
 	   (Distribution (message-make-distribution))
 	   (Lines (message-make-lines))
-	   (X-Newsreader message-newsreader)
-	   (X-Mailer (and (not (message-fetch-field "X-Newsreader"))
-			  message-mailer))
+	   (User-Agent message-newsreader)
 	   (Expires (message-make-expires))
 	   (case-fold-search t)
 	   header value elem)
@@ -2909,9 +3229,9 @@
 		  (progn
 		    ;; The header was found.  We insert a space after the
 		    ;; colon, if there is none.
-		    (if (/= (following-char) ? ) (insert " ") (forward-char 1))
+		    (if (/= (char-after) ? ) (insert " ") (forward-char 1))
 		    ;; Find out whether the header is empty...
-		    (looking-at "[ \t]*$")))
+		    (looking-at "[ \t]*\n[^ \t]")))
 	  ;; So we find out what value we should insert.
 	  (setq value
 		(cond
@@ -2933,7 +3253,7 @@
 		  ;; The element is a symbol.  We insert the value
 		  ;; of this symbol, if any.
 		  (symbol-value header))
-		 (t
+		 ((not (message-check-element header))
 		  ;; We couldn't generate a value for this header,
 		  ;; so we just ask the user.
 		  (read-from-minibuffer
@@ -3018,7 +3338,7 @@
       (goto-char (point-min))
       (while (not (eobp))
 	(skip-chars-forward "^,\"" (point-max))
-	(if (or (= (following-char) ?,)
+	(if (or (eq (char-after) ?,)
 		(eobp))
 	    (when (not quoted)
 	      (if (and (> (current-column) 78)
@@ -3038,7 +3358,7 @@
 
 (defun message-fill-header (header value)
   (let ((begin (point))
-	(fill-column 990)
+	(fill-column 78)
 	(fill-prefix "\t"))
     (insert (capitalize (symbol-name header))
 	    ": "
@@ -3057,23 +3377,63 @@
 	(replace-match " " t t))
       (goto-char (point-max)))))
 
+(defun message-shorten-1 (list cut surplus)
+  ;; Cut SURPLUS elements out of LIST, beginning with CUTth one.
+  (setcdr (nthcdr (- cut 2) list)
+	  (nthcdr (+ (- cut 2) surplus 1) list)))
+
 (defun message-shorten-references (header references)
-  "Limit REFERENCES to be shorter than 988 characters."
-  (let ((max 988)
-	(cut 4)
+  "Trim REFERENCES to be less than 31 Message-ID long, and fold them.
+If folding is disallowed, also check that the REFERENCES are less
+than 988 characters long, and if they are not, trim them until they are."
+  (let ((maxcount 31)
+	(count 0)
+	(cut 6)
 	refs)
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (insert references)
       (goto-char (point-min))
+      ;; Cons a list of valid references.
       (while (re-search-forward "<[^>]+>" nil t)
 	(push (match-string 0) refs))
-      (setq refs (nreverse refs))
-      (while (> (length (mapconcat 'identity refs " ")) max)
-	(when (< (length refs) (1+ cut))
-	  (decf cut))
-	(setcdr (nthcdr cut refs) (cddr (nthcdr cut refs)))))
-    (insert (capitalize (symbol-name header)) ": "
-	    (mapconcat 'identity refs " ") "\n")))
+      (setq refs (nreverse refs)
+	    count (length refs)))
+
+    ;; If the list has more than MAXCOUNT elements, trim it by
+    ;; removing the CUTth element and the required number of
+    ;; elements that follow.
+    (when (> count maxcount)
+      (let ((surplus (- count maxcount)))
+	(message-shorten-1 refs cut surplus)
+	(decf count surplus)))
+
+    ;; If folding is disallowed, make sure the total length (including
+    ;; the spaces between) will be less than MAXSIZE characters.
+    ;;
+    ;; Only disallow folding for News messages. At this point the headers
+    ;; have not been generated, thus we use message-this-is-news directly.
+    (when (and message-this-is-news message-cater-to-broken-inn)
+      (let ((maxsize 988)
+	    (totalsize (+ (apply #'+ (mapcar #'length refs))
+			  (1- count)))
+	    (surplus 0)
+	    (ptr (nthcdr (1- cut) refs)))
+	;; Decide how many elements to cut off...
+	(while (> totalsize maxsize)
+	  (decf totalsize (1+ (length (car ptr))))
+	  (incf surplus)
+	  (setq ptr (cdr ptr)))
+	;; ...and do it.
+	(when (> surplus 0)
+	  (message-shorten-1 refs cut surplus))))
+
+    ;; Finally, collect the references back into a string and insert
+    ;; it into the buffer.
+    (let ((refstring (mapconcat #'identity refs " ")))
+      (if (and message-this-is-news message-cater-to-broken-inn)
+	  (insert (capitalize (symbol-name header)) ": "
+		  refstring "\n")
+	(message-fill-header header refstring)))))
 
 (defun message-position-point ()
   "Move point to where the user probably wants to find it."
@@ -3083,7 +3443,7 @@
     (search-backward ":" )
     (widen)
     (forward-char 1)
-    (if (= (following-char) ? )
+    (if (eq (char-after) ? )
 	(forward-char 1)
       (insert " ")))
    (t
@@ -3097,14 +3457,24 @@
 (defun message-buffer-name (type &optional to group)
   "Return a new (unique) buffer name based on TYPE and TO."
   (cond
+   ;; Generate a new buffer name The Message Way.
+   ((eq message-generate-new-buffers 'unique)
+    (generate-new-buffer-name
+     (concat "*" type
+	     (if to
+		 (concat " to "
+			 (or (car (mail-extract-address-components to))
+			     to) "")
+	       "")
+	     (if (and group (not (string= group ""))) (concat " on " group) "")
+	     "*")))
    ;; Check whether `message-generate-new-buffers' is a function,
    ;; and if so, call it.
    ((message-functionp message-generate-new-buffers)
     (funcall message-generate-new-buffers type to group))
-   ;; Generate a new buffer name The Message Way.
-   (message-generate-new-buffers
+   ((eq message-generate-new-buffers 'unsent)
     (generate-new-buffer-name
-     (concat "*" type
+     (concat "*unsent " type
 	     (if to
 		 (concat " to "
 			 (or (car (mail-extract-address-components to))
@@ -3147,7 +3517,7 @@
   ;; Rename the buffer.
   (if message-send-rename-function
       (funcall message-send-rename-function)
-    (when (string-match "\\`\\*" (buffer-name))
+    (when (string-match "\\`\\*\\(unsent \\)?" (buffer-name))
       (rename-buffer
        (concat "*sent " (substring (buffer-name) (match-end 0))) t)))
   ;; Push the current buffer onto the list.
@@ -3225,7 +3595,8 @@
       (setq buffer-file-name (expand-file-name "*message*"
 					       message-auto-save-directory))
       (setq buffer-auto-save-file-name (make-auto-save-file-name)))
-    (clear-visited-file-modtime)))
+    (clear-visited-file-modtime)
+    (setq buffer-file-coding-system message-draft-coding-system)))
 
 (defun message-disassociate-draft ()
   "Disassociate the message buffer from the drafts directory."
@@ -3233,6 +3604,23 @@
     (nndraft-request-expire-articles
      (list message-draft-article) "drafts" nil t)))
 
+(defun message-insert-headers ()
+  "Generate the headers for the article."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (when (message-news-p)
+	(message-generate-headers
+	 (delq 'Lines
+	       (delq 'Subject
+		     (copy-sequence message-required-news-headers)))))
+      (when (message-mail-p)
+	(message-generate-headers
+	 (delq 'Lines
+	       (delq 'Subject
+		     (copy-sequence message-required-mail-headers))))))))
+
 
 
 ;;;
@@ -3262,15 +3650,79 @@
     (message-setup `((Newsgroups . ,(or newsgroups ""))
 		     (Subject . ,(or subject ""))))))
 
+(defun message-get-reply-headers (wide &optional to-address)
+  (let (follow-to mct never-mct from to cc reply-to ccalist)
+    ;; Find all relevant headers we need.
+    (setq from (message-fetch-field "from")
+	  to (message-fetch-field "to")
+	  cc (message-fetch-field "cc")
+	  mct (message-fetch-field "mail-copies-to")
+	  reply-to (message-fetch-field "reply-to"))
+
+    ;; Handle special values of Mail-Copies-To.
+    (when mct
+      (cond ((or (equal (downcase mct) "never")
+		 (equal (downcase mct) "nobody"))
+	     (setq never-mct t)
+	     (setq mct nil))
+	    ((or (equal (downcase mct) "always")
+		 (equal (downcase mct) "poster"))
+	     (setq mct (or reply-to from)))))
+
+    (if (or (not wide)
+	    to-address)
+	(progn
+	  (setq follow-to (list (cons 'To (or to-address reply-to from))))
+	  (when (and wide mct)
+	    (push (cons 'Cc mct) follow-to)))
+      (let (ccalist)
+	(save-excursion
+	  (message-set-work-buffer)
+	  (unless never-mct
+	    (insert (or reply-to from "")))
+	  (insert (if to (concat (if (bolp) "" ", ") to "") ""))
+	  (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
+	  (insert (if cc (concat (if (bolp) "" ", ") cc) ""))
+	  (goto-char (point-min))
+	  (while (re-search-forward "[ \t]+" nil t)
+	    (replace-match " " t t))
+	  ;; Remove addresses that match `rmail-dont-reply-to-names'.
+	  (let ((rmail-dont-reply-to-names message-dont-reply-to-names))
+	    (insert (prog1 (rmail-dont-reply-to (buffer-string))
+		      (erase-buffer))))
+	  (goto-char (point-min))
+	  ;; Perhaps "Mail-Copies-To: never" removed the only address?
+	  (when (eobp)
+	    (insert (or reply-to from "")))
+	  (setq ccalist
+		(mapcar
+		 (lambda (addr)
+		   (cons (mail-strip-quoted-names addr) addr))
+		 (message-tokenize-header (buffer-string))))
+	  (let ((s ccalist))
+	    (while s
+	      (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
+	(setq follow-to (list (cons 'To (cdr (pop ccalist)))))
+	(when ccalist
+	  (let ((ccs (cons 'Cc (mapconcat
+				(lambda (addr) (cdr addr)) ccalist ", "))))
+	    (when (string-match "^ +" (cdr ccs))
+	      (setcdr ccs (substring (cdr ccs) (match-end 0))))
+	    (push ccs follow-to)))))
+    follow-to))
+
+
 ;;;###autoload
 (defun message-reply (&optional to-address wide)
   "Start editing a reply to the article in the current buffer."
   (interactive)
+  (require 'gnus-sum)			; for gnus-list-identifiers
   (let ((cur (current-buffer))
 	from subject date reply-to to cc
 	references message-id follow-to
 	(inhibit-point-motion-hooks t)
-	mct never-mct gnus-warning)
+	(message-this-is-mail t)
+	gnus-warning)
     (save-restriction
       (message-narrow-to-head)
       ;; Allow customizations to have their say.
@@ -3283,79 +3735,26 @@
 	    (save-excursion
 	      (setq follow-to
 		    (funcall message-wide-reply-to-function)))))
-      ;; Find all relevant headers we need.
-      (setq from (message-fetch-field "from")
-	    date (message-fetch-field "date")
-	    subject (or (message-fetch-field "subject") "none")
-	    to (message-fetch-field "to")
-	    cc (message-fetch-field "cc")
-	    mct (message-fetch-field "mail-copies-to")
-	    reply-to (message-fetch-field "reply-to")
+      (setq message-id (message-fetch-field "message-id" t)
 	    references (message-fetch-field "references")
-	    message-id (message-fetch-field "message-id" t))
-      ;; Remove any (buggy) Re:'s that are present and make a
-      ;; proper one.
-      (when (string-match message-subject-re-regexp subject)
-	(setq subject (substring subject (match-end 0))))
-      (setq subject (concat "Re: " subject))
-
-      (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
-		 (string-match "<[^>]+>" gnus-warning))
-	(setq message-id (match-string 0 gnus-warning)))
-
-      ;; Handle special values of Mail-Copies-To.
-      (when mct
-	(cond ((equal (downcase mct) "never")
-	       (setq never-mct t)
-	       (setq mct nil))
-	      ((equal (downcase mct) "always")
-	       (setq mct (or reply-to from)))))
-
-      (unless follow-to
-	(if (or (not wide)
-		to-address)
-	    (progn
-	      (setq follow-to (list (cons 'To (or to-address reply-to from))))
-	      (when (and wide mct)
-		(push (cons 'Cc mct) follow-to)))
-	  (let (ccalist)
-	    (save-excursion
-	      (message-set-work-buffer)
-	      (unless never-mct
-		(insert (or reply-to from "")))
-	      (insert (if to (concat (if (bolp) "" ", ") to "") ""))
-	      (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
-	      (insert (if cc (concat (if (bolp) "" ", ") cc) ""))
-	      (goto-char (point-min))
-	      (while (re-search-forward "[ \t]+" nil t)
-		(replace-match " " t t))
-	      ;; Remove addresses that match `rmail-dont-reply-to-names'.
-	      (insert (prog1 (rmail-dont-reply-to (buffer-string))
-			(erase-buffer)))
-	      (goto-char (point-min))
-	      ;; Perhaps Mail-Copies-To: never removed the only address?
-	      (when (eobp)
-		(insert (or reply-to from "")))
-	      (setq ccalist
-		    (mapcar
-		     (lambda (addr)
-		       (cons (mail-strip-quoted-names addr) addr))
-		     (message-tokenize-header (buffer-string))))
-	      (let ((s ccalist))
-		(while s
-		  (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
-	    (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
-	    (when ccalist
-	      (let ((ccs (cons 'Cc (mapconcat
-				    (lambda (addr) (cdr addr)) ccalist ", "))))
-		(when (string-match "^ +" (cdr ccs))
-		  (setcdr ccs (substring (cdr ccs) (match-end 0))))
-		(push ccs follow-to))))))
-      (widen))
-
-    (message-pop-to-buffer (message-buffer-name
-			    (if wide "wide reply" "reply") from
-			    (if wide to-address nil)))
+	    date (message-fetch-field "date")
+	    from (message-fetch-field "from")
+	    subject (or (message-fetch-field "subject") "none"))
+    (if gnus-list-identifiers
+	(setq subject (message-strip-list-identifiers subject)))
+    (setq subject (concat "Re: " (message-strip-subject-re subject)))
+
+    (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
+	       (string-match "<[^>]+>" gnus-warning))
+      (setq message-id (match-string 0 gnus-warning)))
+
+    (unless follow-to
+      (setq follow-to (message-get-reply-headers wide to-address))))
+
+    (message-pop-to-buffer
+     (message-buffer-name
+      (if wide "wide reply" "reply") from
+      (if wide to-address nil)))
 
     (setq message-reply-headers
 	  (vector 0 subject from date message-id references 0 0 ""))
@@ -3380,6 +3779,7 @@
   "Follow up to the message in the current buffer.
 If TO-NEWSGROUPS, use that as the new Newsgroups line."
   (interactive)
+  (require 'gnus-sum)			; for gnus-list-identifiers
   (let ((cur (current-buffer))
 	from subject date reply-to mct
 	references message-id follow-to
@@ -3414,11 +3814,9 @@
 		 (let ((case-fold-search t))
 		   (string-match "world" distribution)))
 	(setq distribution nil))
-      ;; Remove any (buggy) Re:'s that are present and make a
-      ;; proper one.
-      (when (string-match message-subject-re-regexp subject)
-	(setq subject (substring subject (match-end 0))))
-      (setq subject (concat "Re: " subject))
+      (if gnus-list-identifiers
+	  (setq subject (message-strip-list-identifiers subject)))
+      (setq subject (concat "Re: " (message-strip-subject-re subject)))
       (widen))
 
     (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
@@ -3475,8 +3873,10 @@
 	     `((References . ,(concat (or references "") (and references " ")
 				      (or message-id "")))))
        ,@(when (and mct
-		    (not (equal (downcase mct) "never")))
-	   (list (cons 'Cc (if (equal (downcase mct) "always")
+		    (not (or (equal (downcase mct) "never")
+			     (equal (downcase mct) "nobody"))))
+	   (list (cons 'Cc (if (or (equal (downcase mct) "always")
+				   (equal (downcase mct) "poster"))
 			       (or reply-to from "")
 			     mct)))))
 
@@ -3487,15 +3887,16 @@
 
 
 ;;;###autoload
-(defun message-cancel-news ()
-  "Cancel an article you posted."
-  (interactive)
+(defun message-cancel-news (&optional arg)
+  "Cancel an article you posted.
+If ARG, allow editing of the cancellation message."
+  (interactive "P")
   (unless (message-news-p)
     (error "This is not a news article; canceling is impossible"))
   (when (yes-or-no-p "Do you really want to cancel this article? ")
     (let (from newsgroups message-id distribution buf sender)
       (save-excursion
-	;; Get header info. from original article.
+	;; Get header info from original article.
 	(save-restriction
 	  (message-narrow-to-head)
 	  (setq from (message-fetch-field "from")
@@ -3514,11 +3915,12 @@
 				      (message-make-from))))))
 	  (error "This article is not yours"))
 	;; Make control message.
-	(setq buf (set-buffer (get-buffer-create " *message cancel*")))
-	(buffer-disable-undo (current-buffer))
+	(if arg
+	    (message-news)
+	  (setq buf (set-buffer (get-buffer-create " *message cancel*"))))
 	(erase-buffer)
 	(insert "Newsgroups: " newsgroups "\n"
-		"From: " (message-make-from) "\n"
+               "From: " from "\n"
 		"Subject: cmsg cancel " message-id "\n"
 		"Control: cancel " message-id "\n"
 		(if distribution
@@ -3526,12 +3928,14 @@
 		  "")
 		mail-header-separator "\n"
 		message-cancel-message)
-	(message "Canceling your article...")
-	(if (let ((message-syntax-checks
-		   'dont-check-for-anything-just-trust-me))
-	      (funcall message-send-news-function))
-	    (message "Canceling your article...done"))
-	(kill-buffer buf)))))
+	(run-hooks 'message-cancel-hook)
+	(unless arg
+	  (message "Canceling your article...")
+	  (if (let ((message-syntax-checks
+		     'dont-check-for-anything-just-trust-me))
+		(funcall message-send-news-function))
+	      (message "Canceling your article...done"))
+	  (kill-buffer buf))))))
 
 ;;;###autoload
 (defun message-supersede ()
@@ -3555,6 +3959,7 @@
     ;; Get a normal message buffer.
     (message-pop-to-buffer (message-buffer-name "supersede"))
     (insert-buffer-substring cur)
+    (mime-to-mml)
     (message-narrow-to-head)
     ;; Remove unwanted headers.
     (when message-ignored-supersedes-headers
@@ -3576,6 +3981,8 @@
     (cond ((save-window-excursion
 	     (if (not (eq system-type 'vax-vms))
 		 (with-output-to-temp-buffer "*Directory*"
+		   (with-current-buffer standard-output
+		     (fundamental-mode)) ; for Emacs 20.4+
 		   (buffer-disable-undo standard-output)
 		   (let ((default-directory "/"))
 		     (call-process
@@ -3590,7 +3997,7 @@
 
 (defun message-wash-subject (subject)
   "Remove junk like \"Re:\", \"(fwd)\", etc. that was added to the subject by previous forwarders, replyers, etc."
-  (nnheader-temp-write nil
+  (with-temp-buffer
     (insert-string subject)
     (goto-char (point-min))
     ;; strip Re/Fwd stuff off the beginning
@@ -3661,52 +4068,77 @@
 	subject))))
 
 ;;;###autoload
-(defun message-forward (&optional news)
+(defun message-forward (&optional news digest)
   "Forward the current message via mail.
-Optional NEWS will use news to forward instead of mail."
+Optional NEWS will use news to forward instead of mail.
+Optional DIGEST will use digest to forward."
   (interactive "P")
-  (let ((cur (current-buffer))
-	(subject (message-make-forward-subject))
-	art-beg)
-    (if news (message-news nil subject) (message-mail nil subject))
+  (let* ((cur (current-buffer))
+	 (subject (if message-forward-show-mml
+		      (message-make-forward-subject)
+		    (mail-decode-encoded-word-string
+		     (message-make-forward-subject))))
+	 art-beg)
+    (if news
+	(message-news nil subject)
+      (message-mail nil subject))
     ;; Put point where we want it before inserting the forwarded
     ;; message.
-    (if message-signature-before-forwarded-message
-	(goto-char (point-max))
-      (message-goto-body))
-    ;; Make sure we're at the start of the line.
-    (unless (eolp)
-      (insert "\n"))
-    ;; Narrow to the area we are to insert.
-    (narrow-to-region (point) (point))
-    ;; Insert the separators and the forwarded buffer.
-    (insert message-forward-start-separator)
-    (setq art-beg (point))
-    (insert-buffer-substring cur)
-    (goto-char (point-max))
-    (insert message-forward-end-separator)
-    (set-text-properties (point-min) (point-max) nil)
-    ;; Remove all unwanted headers.
-    (goto-char art-beg)
-    (narrow-to-region (point) (if (search-forward "\n\n" nil t)
-				  (1- (point))
-				(point)))
-    (goto-char (point-min))
-    (message-remove-header message-included-forward-headers t nil t)
-    (widen)
+    (if message-forward-before-signature
+        (message-goto-body)
+      (goto-char (point-max)))
+    (if message-forward-as-mime
+	(if digest
+	    (insert "\n<#multipart type=digest>\n")
+	  (if message-forward-show-mml
+	      (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
+	    (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
+      (insert "\n-------------------- Start of forwarded message --------------------\n"))
+    (let ((b (point)) e)
+      (if digest
+	  (if message-forward-as-mime
+	      (insert-buffer-substring cur)
+	    (mml-insert-buffer cur))
+	(if message-forward-show-mml
+	    (insert-buffer-substring cur)
+	  (mm-with-unibyte-current-buffer
+	    (mml-insert-buffer cur))))
+      (setq e (point))
+      (if message-forward-as-mime
+	  (if digest
+	      (insert "<#/multipart>\n")
+	    (if message-forward-show-mml
+		(insert "<#/mml>\n")
+	      (insert "<#/part>\n")))
+	(insert "\n-------------------- End of forwarded message --------------------\n"))
+      (if (and digest message-forward-as-mime)
+	  (save-restriction
+	    (narrow-to-region b e)
+	    (goto-char b)
+	    (narrow-to-region (point) 
+			      (or (search-forward "\n\n" nil t) (point)))
+	    (delete-region (point-min) (point-max)))
+	(when (and (not current-prefix-arg)
+		   message-forward-ignored-headers)
+	  (save-restriction
+	    (narrow-to-region b e)
+	    (goto-char b)
+	    (narrow-to-region (point) 
+			      (or (search-forward "\n\n" nil t) (point)))
+	    (message-remove-header message-forward-ignored-headers t)))))
     (message-position-point)))
 
 ;;;###autoload
 (defun message-resend (address)
   "Resend the current article to ADDRESS."
-  (interactive "sResend message to: ")
+  (interactive
+   (list (message-read-from-minibuffer "Resend message to: ")))
   (message "Resending message to %s..." address)
   (save-excursion
     (let ((cur (current-buffer))
 	  beg)
       ;; We first set up a normal mail buffer.
       (set-buffer (get-buffer-create " *message resend*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
       (message-setup `((To . ,address)))
       ;; Insert our usual headers.
@@ -3739,44 +4171,42 @@
       (when (looking-at "From ")
 	(replace-match "X-From-Line: "))
       ;; Send it.
-      (message-send-mail)
+      (let ((message-inhibit-body-encoding t)
+	    message-required-mail-headers)
+	(message-send-mail))
       (kill-buffer (current-buffer)))
     (message "Resending message to %s...done" address)))
 
 ;;;###autoload
 (defun message-bounce ()
   "Re-mail the current message.
-This only makes sense if the current message is a bounce message than
+This only makes sense if the current message is a bounce message that
 contains some mail you have written which has been bounced back to
 you."
   (interactive)
-  (let ((cur (current-buffer))
+  (let ((handles (mm-dissect-buffer t))
 	boundary)
     (message-pop-to-buffer (message-buffer-name "bounce"))
-    (insert-buffer-substring cur)
-    (undo-boundary)
-    (message-narrow-to-head)
-    (if (and (message-fetch-field "Mime-Version")
-	     (setq boundary (message-fetch-field "Content-Type")))
-	(if (string-match "boundary=\"\\([^\"]+\\)\"" boundary)
-	    (setq boundary (concat (match-string 1 boundary) " *\n"
-				   "Content-Type: message/rfc822"))
-	  (setq boundary nil)))
-    (widen)
-    (goto-char (point-min))
-    (search-forward "\n\n" nil t)
-    (or (and boundary
-	     (re-search-forward boundary nil t)
-	     (forward-line 2))
-	(and (re-search-forward message-unsent-separator nil t)
-	     (forward-line 1))
-	(re-search-forward "^Return-Path:.*\n" nil t))
-    ;; We remove everything before the bounced mail.
-    (delete-region
-     (point-min)
-     (if (re-search-forward "^[^ \n\t]+:" nil t)
-	 (match-beginning 0)
-       (point)))
+    (if (stringp (car handles))
+	;; This is a MIME bounce.
+	(mm-insert-part (car (last handles)))
+      ;; This is a non-MIME bounce, so we try to remove things
+      ;; manually.
+      (mm-insert-part handles)
+      (undo-boundary)
+      (goto-char (point-min))
+      (search-forward "\n\n" nil t)
+      (or (and (re-search-forward message-unsent-separator nil t)
+	       (forward-line 1))
+	  (re-search-forward "^Return-Path:.*\n" nil t))
+      ;; We remove everything before the bounced mail.
+      (delete-region
+       (point-min)
+       (if (re-search-forward "^[^ \n\t]+:" nil t)
+	   (match-beginning 0)
+	 (point))))
+    (mm-enable-multibyte)
+    (mime-to-mml)
     (save-restriction
       (message-narrow-to-head)
       (message-remove-header message-ignored-bounced-headers t)
@@ -3859,7 +4289,7 @@
       (goto-char (min start end))
       (while (< (point) end1)
 	(or (looking-at "[_\^@- ]")
-	    (insert (following-char) "\b"))
+	    (insert (char-after) "\b"))
 	(forward-char 1)))))
 
 ;;;###autoload
@@ -3873,7 +4303,7 @@
       (move-marker end1 (max start end))
       (goto-char (min start end))
       (while (re-search-forward "\b" end1 t)
-	(if (eq (following-char) (char-after (- (point) 2)))
+	(if (eq (char-after) (char-after (- (point) 2)))
 	    (delete-char -2))))))
 
 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
@@ -3932,7 +4362,7 @@
 	  (message "No matching groups")
 	(save-selected-window
 	  (pop-to-buffer "*Completions*")
-	  (buffer-disable-undo (current-buffer))
+	  (buffer-disable-undo)
 	  (let ((buffer-read-only nil))
 	    (erase-buffer)
 	    (let ((standard-output (current-buffer)))
@@ -3952,6 +4382,7 @@
 	(save-excursion
 	  (with-output-to-temp-buffer " *MESSAGE information message*"
 	    (set-buffer " *MESSAGE information message*")
+	    (fundamental-mode)		; for Emacs 20.4+
 	    (mapcar 'princ text)
 	    (goto-char (point-min))))
 	(funcall ask question))
@@ -3975,20 +4406,22 @@
   (let ((oldbuf (current-buffer)))
     (save-excursion
       (set-buffer (generate-new-buffer name))
-      (message-clone-locals oldbuf)
+      (message-clone-locals oldbuf varstr)
       (current-buffer))))
 
-(defun message-clone-locals (buffer)
+(defun message-clone-locals (buffer &optional varstr)
   "Clone the local variables from BUFFER to the current buffer."
   (let ((locals (save-excursion
 		  (set-buffer buffer)
 		  (buffer-local-variables)))
-	(regexp "^gnus\\|^nn\\|^message"))
+	(regexp "^gnus\\|^nn\\|^message\\|^user-mail-address"))
     (mapcar
      (lambda (local)
        (when (and (consp local)
 		  (car local)
-		  (string-match regexp (symbol-name (car local))))
+		  (string-match regexp (symbol-name (car local)))
+		  (or (null varstr)
+		      (string-match varstr (symbol-name (car local)))))
 	 (ignore-errors
 	   (set (make-local-variable (car local))
 		(cdr local)))))
@@ -3997,20 +4430,85 @@
 ;;; Miscellaneous functions
 
 ;; stolen (and renamed) from nnheader.el
-(defun message-replace-chars-in-string (string from to)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))	;Copy string.
-	(len (length string))
-	(idx 0))
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (when (= (aref string idx) from)
-	(aset string idx to))
-      (setq idx (1+ idx)))
-    string))
+(if (fboundp 'subst-char-in-string)
+    (defsubst message-replace-chars-in-string (string from to)
+      (subst-char-in-string from to string))
+  (defun message-replace-chars-in-string (string from to)
+    "Replace characters in STRING from FROM to TO."
+    (let ((string (substring string 0))	;Copy string.
+	  (len (length string))
+	  (idx 0))
+      ;; Replace all occurrences of FROM with TO.
+      (while (< idx len)
+	(when (= (aref string idx) from)
+	  (aset string idx to))
+	(setq idx (1+ idx)))
+      string)))
+
+;;;
+;;; MIME functions
+;;;
+
+(defvar message-inhibit-body-encoding nil)
+
+(defun message-encode-message-body ()
+  (unless message-inhibit-body-encoding 
+    (let ((mail-parse-charset (or mail-parse-charset
+				  message-default-charset))
+	  (case-fold-search t)
+	  lines content-type-p)
+      (message-goto-body)
+      (save-restriction
+	(narrow-to-region (point) (point-max))
+	(let ((new (mml-generate-mime)))
+	  (when new
+	    (delete-region (point-min) (point-max))
+	    (insert new)
+	    (goto-char (point-min))
+	    (if (eq (aref new 0) ?\n)
+		(delete-char 1)
+	      (search-forward "\n\n")
+	      (setq lines (buffer-substring (point-min) (1- (point))))
+	      (delete-region (point-min) (point))))))
+      (save-restriction
+	(message-narrow-to-headers-or-head)
+	(message-remove-header "Mime-Version")
+	(goto-char (point-max))
+	(insert "MIME-Version: 1.0\n")
+	(when lines
+	  (insert lines))
+	(setq content-type-p
+	      (re-search-backward "^Content-Type:" nil t)))
+      (save-restriction
+	(message-narrow-to-headers-or-head)
+	(message-remove-first-header "Content-Type")
+	(message-remove-first-header "Content-Transfer-Encoding"))
+      ;; We always make sure that the message has a Content-Type header.
+      ;; This is because some broken MTAs and MUAs get awfully confused
+      ;; when confronted with a message with a MIME-Version header and
+      ;; without a Content-Type header.  For instance, Solaris'
+      ;; /usr/bin/mail.
+      (unless content-type-p
+	(goto-char (point-min))
+	(re-search-forward "^MIME-Version:")
+	(forward-line 1)
+	(insert "Content-Type: text/plain; charset=us-ascii\n")))))
+
+(defun message-read-from-minibuffer (prompt)
+  "Read from the minibuffer while providing abbrev expansion."
+  (if (fboundp 'mail-abbrevs-setup)
+      (let ((mail-abbrev-mode-regexp "")
+	    (minibuffer-setup-hook 'mail-abbrevs-setup))
+	(read-from-minibuffer prompt))
+    (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook))
+      (read-string prompt))))
+
+(provide 'message)
 
 (run-hooks 'message-load-hook)
 
-(provide 'message)
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
 
 ;;; message.el ends here
--- a/lisp/gnus/messcompat.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/messcompat.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; messcompat.el --- making message mode compatible with mail mode
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: mail, news
@@ -70,6 +72,7 @@
 If a function, the result from the function will be used instead.
 If a form, the result from the form will be used instead.")
 
+;; Deleted the autoload cookie because this crashes in loaddefs.el.
 (defvar message-signature-file mail-signature-file
   "*File containing the text inserted at end of the message buffer.")
 
--- a/lisp/gnus/nnagent.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnagent.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,5 @@
 ;;; nnagent.el --- offline backend for Gnus
-;; Copyright (C) 1997,98 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news, mail
@@ -58,13 +58,18 @@
 
 (nnoo-define-basics nnagent)
 
+(defun nnagent-server (server)
+  (and server (format "%s+%s" (car gnus-command-method) server)))
+
 (deffoo nnagent-open-server (server &optional defs)
   (setq defs
 	`((nnagent-directory ,(gnus-agent-directory))
 	  (nnagent-active-file ,(gnus-agent-lib-file "active"))
 	  (nnagent-newsgroups-file ,(gnus-agent-lib-file "newsgroups"))
 	  (nnagent-get-new-mail nil)))
-  (nnoo-change-server 'nnagent server defs)
+  (nnoo-change-server 'nnagent 
+		      (nnagent-server server)
+		      defs)
   (let ((dir (gnus-agent-directory))
 	err)
     (cond
@@ -111,7 +116,81 @@
 
 (deffoo nnagent-request-post (&optional server)
   (gnus-agent-insert-meta-information 'news gnus-command-method)
-  (gnus-request-accept-article "nndraft:queue"))
+  (gnus-request-accept-article "nndraft:queue" nil t t))
+
+(deffoo nnagent-request-set-mark (group action server)
+  (with-temp-buffer
+    (insert (format "(%s-request-set-mark \"%s\" '%s \"%s\")\n"
+                    (nth 0 gnus-command-method) group action
+                    (or server (nth 1 gnus-command-method))))
+    (append-to-file (point-min) (point-max) (gnus-agent-lib-file "flags")))
+  nil)
+
+(deffoo nnagent-request-group (group &optional server dont-check)
+  (nnoo-parent-function 'nnagent 'nnml-request-group
+		    (list group (nnagent-server server) dont-check)))
+
+(deffoo nnagent-close-group (group &optional server)
+  (nnoo-parent-function 'nnagent 'nnml-close-group
+		    (list group (nnagent-server server))))
+
+(deffoo nnagent-request-accept-article (group &optional server last)
+  (nnoo-parent-function 'nnagent 'nnml-request-accept-article
+		    (list group (nnagent-server server) last)))
+
+(deffoo nnagent-request-article (id &optional group server buffer)
+  (nnoo-parent-function 'nnagent 'nnml-request-article
+		    (list id group (nnagent-server server) buffer)))
+
+(deffoo nnagent-request-create-group (group &optional server args)
+  (nnoo-parent-function 'nnagent 'nnml-request-create-group
+		    (list group (nnagent-server server) args)))
+
+(deffoo nnagent-request-delete-group (group &optional force server)
+  (nnoo-parent-function 'nnagent 'nnml-request-delete-group
+		    (list group force (nnagent-server server))))
+
+(deffoo nnagent-request-expire-articles (articles group &optional server force)
+  (nnoo-parent-function 'nnagent 'nnml-request-expire-articles
+		    (list articles group (nnagent-server server) force)))
+
+(deffoo nnagent-request-list (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-request-list 
+		    (list (nnagent-server server))))
+
+(deffoo nnagent-request-list-newsgroups (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-request-list-newsgroups 
+		    (list (nnagent-server server))))
+
+(deffoo nnagent-request-move-article 
+    (article group server accept-form &optional last)
+  (nnoo-parent-function 'nnagent 'nnml-request-move-article 
+		    (list article group (nnagent-server server) 
+			  accept-form last)))
+
+(deffoo nnagent-request-rename-group (group new-name &optional server)
+  (nnoo-parent-function 'nnagent 'nnml-request-rename-group 
+		    (list group new-name (nnagent-server server))))
+
+(deffoo nnagent-request-scan (&optional group server)
+  (nnoo-parent-function 'nnagent 'nnml-request-scan 
+		    (list group (nnagent-server server))))
+
+(deffoo nnagent-retrieve-headers (sequence &optional group server fetch-old)
+  (nnoo-parent-function 'nnagent 'nnml-retrieve-headers 
+		    (list sequence group (nnagent-server server) fetch-old)))
+
+(deffoo nnagent-set-status (article name value &optional group server)
+  (nnoo-parent-function 'nnagent 'nnml-set-status 
+		    (list article name value group (nnagent-server server))))
+
+(deffoo nnagent-server-opened (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-server-opened
+			(list (nnagent-server server))))
+
+(deffoo nnagent-status-message (&optional server)
+  (nnoo-parent-function 'nnagent 'nnml-status-message
+			(list (nnagent-server server))))
 
 ;; Use nnml functions for just about everything.
 (nnoo-import nnagent
--- a/lisp/gnus/nnbabyl.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnbabyl.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnbabyl.el --- rmail mbox access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1099, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -32,7 +34,8 @@
 (require 'nnheader)
 (condition-case nil
     (require 'rmail)
-  (t (nnheader-message 5 "Ignore rmail errors from this file, you don't have rmail")))
+  (t (nnheader-message
+      5 "Ignore rmail errors from this file, you don't have rmail")))
 (require 'nnmail)
 (require 'nnoo)
 (eval-when-compile (require 'cl))
@@ -259,7 +262,7 @@
   (nnheader-report 'nnbabyl "nnbabyl: LIST NEWSGROUPS is not implemented."))
 
 (deffoo nnbabyl-request-expire-articles
-  (articles newsgroup &optional server force)
+    (articles newsgroup &optional server force)
   (nnbabyl-possibly-change-newsgroup newsgroup server)
   (let* ((is-old t)
 	 rest)
@@ -295,7 +298,7 @@
       (nconc rest articles))))
 
 (deffoo nnbabyl-request-move-article
-  (article group server accept-form &optional last)
+    (article group server accept-form &optional last)
   (let ((buf (get-buffer-create " *nnbabyl move*"))
 	result)
     (and
@@ -431,9 +434,9 @@
       (widen)
       (narrow-to-region
        (save-excursion
-	(unless (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
-	  (goto-char (point-min))
-	  (end-of-line))
+	 (unless (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
+	   (goto-char (point-min))
+	   (end-of-line))
 	 (if leave-delim (progn (forward-line 1) (point))
 	   (match-beginning 0)))
        (progn
@@ -557,10 +560,10 @@
   (nnbabyl-create-mbox)
 
   (unless (and nnbabyl-mbox-buffer
-	   (buffer-name nnbabyl-mbox-buffer)
-	   (save-excursion
-	     (set-buffer nnbabyl-mbox-buffer)
-	     (= (buffer-size) (nnheader-file-size nnbabyl-mbox-file))))
+	       (buffer-name nnbabyl-mbox-buffer)
+	       (save-excursion
+		 (set-buffer nnbabyl-mbox-buffer)
+		 (= (buffer-size) (nnheader-file-size nnbabyl-mbox-file))))
     ;; This buffer has changed since we read it last.  Possibly.
     (save-excursion
       (let ((delim (concat "^" nnbabyl-mail-delimiter))
@@ -568,13 +571,13 @@
 	    start end number)
 	(set-buffer (setq nnbabyl-mbox-buffer
 			  (nnheader-find-file-noselect
-			   nnbabyl-mbox-file nil 'raw)))
+			   nnbabyl-mbox-file nil t)))
 	;; Save previous buffer mode.
 	(setq nnbabyl-previous-buffer-mode
 	      (cons (cons (point-min) (point-max))
 		    major-mode))
 
-	(buffer-disable-undo (current-buffer))
+	(buffer-disable-undo)
 	(widen)
 	(setq buffer-read-only nil)
 	(fundamental-mode)
--- a/lisp/gnus/nndir.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nndir.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nndir.el --- single directory newsgroup access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
--- a/lisp/gnus/nndoc.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nndoc.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nndoc.el --- single file access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -31,6 +32,7 @@
 (require 'nnmail)
 (require 'nnoo)
 (require 'gnus-util)
+(require 'mm-util)
 (eval-when-compile (require 'cl))
 
 (nnoo-declare nndoc)
@@ -38,8 +40,8 @@
 (defvoo nndoc-article-type 'guess
   "*Type of the file.
 One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
-`rfc934', `rfc822-forward', `mime-digest', `mime-parts', `standard-digest',
-`slack-digest', `clari-briefs' or `guess'.")
+`rfc934', `rfc822-forward', `mime-parts', `standard-digest',
+`slack-digest', `clari-briefs', `nsmail' or `guess'.")
 
 (defvoo nndoc-post-type 'mail
   "*Whether the nndoc group is `mail' or `post'.")
@@ -47,12 +49,14 @@
 (defvoo nndoc-open-document-hook 'nnheader-ms-strip-cr
   "Hook run after opening a document.
 The default function removes all trailing carriage returns
-from the document.")  
+from the document.")
 
 (defvar nndoc-type-alist
   `((mmdf
      (article-begin .  "^\^A\^A\^A\^A\n")
      (body-end .  "^\^A\^A\^A\^A\n"))
+    (nsmail
+     (article-begin .  "^From - "))
     (news
      (article-begin . "^Path:"))
     (rnews
@@ -67,8 +71,8 @@
      (body-begin-function . nndoc-babyl-body-begin)
      (head-begin-function . nndoc-babyl-head-begin))
     (forward
-     (article-begin . "^-+ Start of forwarded message -+\n+")
-     (body-end . "^-+ End of forwarded message -+$")
+     (article-begin . "^-+ \\(Start of \\)?forwarded message.*\n+")
+     (body-end . "^-+ End \\(of \\)?forwarded message.*$")
      (prepare-body-function . nndoc-unquote-dashes))
     (rfc934
      (article-begin . "^--.*\n+")
@@ -83,6 +87,7 @@
      (article-transform-function . nndoc-transform-clari-briefs))
     (mime-digest
      (article-begin . "")
+     (head-begin . "^ ?\n")
      (head-end . "^ ?$")
      (body-end . "")
      (file-end . "")
@@ -120,6 +125,9 @@
     (rfc822-forward
      (article-begin . "^\n")
      (body-end-function . nndoc-rfc822-forward-body-end-function))
+    (outlook
+     (article-begin-function . nndoc-outlook-article-begin)
+     (body-end .  "\0"))
     (guess
      (guess . t)
      (subtype nil))
@@ -143,10 +151,13 @@
 (defvoo nndoc-head-begin-function nil)
 (defvoo nndoc-body-end nil)
 ;; nndoc-dissection-alist is a list of sublists.  Each sublist holds the
-;; following items.  ARTICLE is an ordinal starting at 1.  HEAD-BEGIN,
-;; HEAD-END, BODY-BEGIN and BODY-END are positions in the `nndoc' buffer.
-;; LINE-COUNT is a count of lines in the body.  SUBJECT, MESSAGE-ID and
-;; REFERENCES, only present for MIME dissections, are field values.
+;; following items.  ARTICLE acts as the association key and is an ordinal
+;; starting at 1.  HEAD-BEGIN [0], HEAD-END [1], BODY-BEGIN [2] and BODY-END
+;; [3] are positions in the `nndoc' buffer.  LINE-COUNT [4] is a count of
+;; lines in the body.  For MIME dissections only, ARTICLE-INSERT [5] and
+;; SUMMARY-INSERT [6] give headers to insert for full article or summary line
+;; generation, respectively.  Other headers usually follow directly from the
+;; buffer.  Value `nil' means no insert.
 (defvoo nndoc-dissection-alist nil)
 (defvoo nndoc-prepare-body-function nil)
 (defvoo nndoc-generate-head-function nil)
@@ -158,8 +169,6 @@
 (defvoo nndoc-current-buffer nil
   "Current nndoc news buffer.")
 (defvoo nndoc-address nil)
-(defvoo nndoc-mime-header nil)
-(defvoo nndoc-mime-subject nil)
 
 (defconst nndoc-version "nndoc 1.0"
   "nndoc version.")
@@ -187,7 +196,7 @@
 		(insert-buffer-substring
 		 nndoc-current-buffer (car entry) (nth 1 entry)))
 	      (goto-char (point-max))
-	      (unless (= (char-after (1- (point))) ?\n)
+	      (unless (eq (char-after (1- (point))) ?\n)
 		(insert "\n"))
 	      (insert (format "Lines: %d\n" (nth 4 entry)))
 	      (insert ".\n")))
@@ -289,7 +298,6 @@
       (setq nndoc-dissection-alist nil)
       (save-excursion
 	(set-buffer nndoc-current-buffer)
-	(buffer-disable-undo (current-buffer))
 	(erase-buffer)
 	(if (stringp nndoc-address)
 	    (nnheader-insert-file-contents nndoc-address)
@@ -343,6 +351,9 @@
 		(setq entry (pop alist)))
       (when (memq subtype (or (cdr (assq 'subtype entry)) '(guess)))
 	(goto-char (point-min))
+	;; Remove blank lines.
+	(while (eq (following-char) ?\n)
+	  (delete-char 1))
 	(when (numberp (setq result (funcall (intern
 					      (format "nndoc-%s-type-p"
 						      (car entry))))))
@@ -425,7 +436,8 @@
     t))
 
 (defun nndoc-forward-type-p ()
-  (when (and (re-search-forward "^-+ Start of forwarded message -+\n+" nil t)
+  (when (and (re-search-forward "^-+ \\(Start of \\)?forwarded message.*\n+" 
+				nil t)
 	     (not (re-search-forward "^Subject:.*digest" nil t))
 	     (not (re-search-backward "^From:" nil t 2))
 	     (not (re-search-forward "^From:" nil t 2)))
@@ -452,38 +464,30 @@
 	(limit (search-forward "\n\n" nil t)))
     (goto-char (point-min))
     (when (and limit
-		(re-search-forward
-		 (concat "\
-^Content-Type:[ \t]*multipart/[a-z]+;\\(.*;\\)*"
-			 "[ \t\n]*[ \t]boundary=\"?[^\"\n]*[^\" \t\n]")
-	   limit t))
+	       (re-search-forward
+		(concat "\
+^Content-Type:[ \t]*multipart/[a-z]+ *; *\\(\\(\n[ \t]\\)?.*;\\)*"
+			"\\(\n[ \t]\\)?[ \t]*boundary=\"?[^\"\n]*[^\" \t\n]")
+		limit t))
       t)))
 
 (defun nndoc-transform-mime-parts (article)
-  (unless (= article 1)
-    ;; Ensure some MIME-Version.
-    (goto-char (point-min))
-    (search-forward "\n\n")
-    (let ((case-fold-search nil)
-	  (limit (point)))
+  (let* ((entry (cdr (assq article nndoc-dissection-alist)))
+	 (headers (nth 5 entry)))
+    (when headers
       (goto-char (point-min))
-      (or (save-excursion (re-search-forward "^MIME-Version:" limit t))
-	  (insert "Mime-Version: 1.0\n")))
-    ;; Generate default header before entity fields.
-    (goto-char (point-min))
-    (nndoc-generate-mime-parts-head article t)))
+      (insert headers))))
 
-(defun nndoc-generate-mime-parts-head (article &optional body-present)
-  (let ((entry (cdr (assq (if body-present 1 article) nndoc-dissection-alist))))
-    (let ((subject (if body-present
-		       nndoc-mime-subject
-		     (concat "<" (nth 5 entry) ">")))
-	  (message-id (nth 6 entry))
-	  (references (nth 7 entry)))
-      (insert nndoc-mime-header)
-      (and subject (insert "Subject: " subject "\n"))
-      (and message-id (insert "Message-ID: " message-id "\n"))
-      (and references (insert "References: " references "\n")))))
+(defun nndoc-generate-mime-parts-head (article)
+  (let* ((entry (cdr (assq article nndoc-dissection-alist)))
+	 (headers (nth 6 entry)))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (insert-buffer-substring
+       nndoc-current-buffer (car entry) (nth 1 entry))
+      (goto-char (point-max)))
+    (when headers
+      (insert headers))))
 
 (defun nndoc-clari-briefs-type-p ()
   (when (let ((case-fold-search nil))
@@ -516,6 +520,7 @@
     (insert "From: " "clari@clari.net (" (or from "unknown") ")"
 	    "\nSubject: " (or subject "(no subject)") "\n")))
 
+
 (defun nndoc-mime-digest-type-p ()
   (let ((case-fold-search t)
 	boundary-id b-delimiter entry)
@@ -526,10 +531,11 @@
 	    nil t)
 	   (match-beginning 1))
       (setq boundary-id (match-string 1)
-	    b-delimiter (concat "\n--" boundary-id "[\n \t]+"))
+	    b-delimiter (concat "\n--" boundary-id "[ \t]*$"))
       (setq entry (assq 'mime-digest nndoc-type-alist))
       (setcdr entry
 	      (list
+	       (cons 'head-begin "^ ?\n")
 	       (cons 'head-end "^ ?$")
 	       (cons 'body-begin "^ ?\n")
 	       (cons 'article-begin b-delimiter)
@@ -558,10 +564,7 @@
 (defun nndoc-transform-lanl-gov-announce (article)
   (goto-char (point-max))
   (when (re-search-backward "^\\\\\\\\ +(\\([^ ]*\\) , *\\([^ ]*\\))" nil t)
-    (replace-match "\n\nGet it at \\1 (\\2)" t nil))
-  ;;  (when (re-search-backward "^\\\\\\\\$" nil t)
-  ;;    (replace-match "" t t))
-  )
+    (replace-match "\n\nGet it at \\1 (\\2)" t nil)))
 
 (defun nndoc-generate-lanl-gov-head (article)
   (let ((entry (cdr (assq article nndoc-dissection-alist)))
@@ -579,18 +582,28 @@
  	  (when (re-search-forward "^Title: \\([^\f]*\\)\nAuthors?: \\(.*\\)"
  				   nil t)
  	    (setq subject (concat (match-string 1) subject))
- 	    (setq from (concat (match-string 2) " <" e-mail ">"))))
- 	))
+ 	    (setq from (concat (match-string 2) " <" e-mail ">"))))))
     (while (and from (string-match "(\[^)\]*)" from))
       (setq from (replace-match "" t t from)))
     (insert "From: "  (or from "unknown")
  	    "\nSubject: " (or subject "(no subject)") "\n")))
 
+(defun nndoc-nsmail-type-p ()
+  (when (looking-at "From - ")
+    t))
+
+(defun nndoc-outlook-article-begin ()
+  (prog1 (re-search-forward "From:\\|Received:" nil t)
+    (goto-char (match-beginning 0))))
+
+(defun nndoc-outlook-type-p ()
+  ;; FIXME: Is JMF the magic of outlook mailbox? -- ShengHuo.
+  (looking-at "JMF"))
+
 (deffoo nndoc-request-accept-article (group &optional server last)
   nil)
 
 
-
 ;;;
 ;;; Functions for dissecting the documents
 ;;;
@@ -609,6 +622,9 @@
     (save-excursion
       (set-buffer nndoc-current-buffer)
       (goto-char (point-min))
+      ;; Remove blank lines.
+      (while (eq (following-char) ?\n)
+	(delete-char 1))
       ;; Find the beginning of the file.
       (when nndoc-file-begin
 	(nndoc-search nndoc-file-begin))
@@ -669,92 +685,128 @@
 	nndoc-mime-split-ordinal 0)
   (save-excursion
     (set-buffer nndoc-current-buffer)
-    (message-narrow-to-head)
-    (let ((case-fold-search t)
-	  (message-id (message-fetch-field "Message-ID"))
-	  (references (message-fetch-field "References")))
-      (setq nndoc-mime-header (buffer-substring (point-min) (point-max))
-	    nndoc-mime-subject (message-fetch-field "Subject"))
-      (while (string-match "\
-^\\(Subject\\|Message-ID\\|References\\|Lines\\|\
-MIME-Version\\|Content-Type\\|Content-Transfer-Encoding\\|\
-\\):.*\n\\([ \t].*\n\\)*"
-			   nndoc-mime-header)
-	(setq nndoc-mime-header (replace-match "" t t nndoc-mime-header)))
-      (widen)
-      (nndoc-dissect-mime-parts-sub (point-min) (point-max)
-				    nil message-id references))))
+    (nndoc-dissect-mime-parts-sub (point-min) (point-max) nil nil nil)))
 
-(defun nndoc-dissect-mime-parts-sub (begin end position message-id references)
-  "Dissect an entity within a composite MIME message.
-The article, which corresponds to a MIME entity, extends from BEGIN to END.
+(defun nndoc-dissect-mime-parts-sub (head-begin body-end article-insert
+						position parent)
+  "Dissect an entity, within a composite MIME message.
+The complete message or MIME entity extends from HEAD-BEGIN to BODY-END.
+ARTICLE-INSERT should be added at beginning for generating a full article.
 The string POSITION holds a dotted decimal representation of the article
 position in the hierarchical structure, it is nil for the outer entity.
-The generated article should use MESSAGE-ID and REFERENCES field values."
-  ;; Note: `case-fold-search' is already `t' from the calling function.
-  (let ((head-begin begin)
-	(body-end end)
-	head-end body-begin type subtype composite comment)
-    (save-excursion
-      ;; Gracefully handle a missing body.
-      (goto-char head-begin)
-      (if (search-forward "\n\n" body-end t)
-	  (setq head-end (1- (point))
-		body-begin (point))
-	(setq head-end end
-	      body-begin end))
-      ;; Save MIME attributes.
-      (goto-char head-begin)
-      (if (re-search-forward "\
-^Content-Type: *\\([^ \t\n/;]+\\)/\\([^ \t\n/;]+\\)"
-			     head-end t)
-	  (setq type (downcase (match-string 1))
-		subtype (downcase (match-string 2)))
-	(setq type "text"
-	      subtype "plain"))
-      (setq composite (string= type "multipart")
-	    comment (concat position
-			    (when (and position composite) ".")
-			    (when composite "*")
-			    (when (or position composite) " ")
-			    (cond ((string= subtype "plain") type)
-				  ((string= subtype "basic") type)
-				  (t subtype))))
-      ;; Generate dissection information for this entity.
-      (push (list (incf nndoc-mime-split-ordinal)
-		  head-begin head-end body-begin body-end
-		  (count-lines body-begin body-end)
-		  comment message-id references)
-	    nndoc-dissection-alist)
-      ;; Recurse for all sub-entities, if any.
-      (goto-char head-begin)
-      (when (re-search-forward
-	     (concat "\
-^Content-Type: *multipart/\\([a-z]+\\);\\(.*;\\)*"
-		     "[ \t\n]*[ \t]boundary=\"?\\([^\"\n]*[^\" \t\n]\\)")
-	   head-end t)
-	(let ((boundary (concat "\n--" (match-string 3) "\\(--\\)?[ \t]*\n"))
-	      (part-counter 0)
-	      begin end eof-flag)
-	  (goto-char head-end)
-	  (setq eof-flag (not (re-search-forward boundary body-end t)))
+PARENT is the message-ID of the parent summary line, or nil for none."
+  (let ((case-fold-search t)
+	(message-id (nnmail-message-id))
+	head-end body-begin summary-insert message-rfc822 multipart-any
+	subject content-type type subtype boundary-regexp)
+    ;; Gracefully handle a missing body.
+    (goto-char head-begin)
+    (if (search-forward "\n\n" body-end t)
+	(setq head-end (1- (point))
+	      body-begin (point))
+      (setq head-end body-end
+	    body-begin body-end))
+    (narrow-to-region head-begin head-end)
+    ;; Save MIME attributes.
+    (goto-char head-begin)
+    (setq content-type (message-fetch-field "Content-Type"))
+    (when content-type
+      (when (string-match
+	     "^ *\\([^ \t\n/;]+\\)/\\([^ \t\n/;]+\\)" content-type)
+	(setq type (downcase (match-string 1 content-type))
+	      subtype (downcase (match-string 2 content-type))
+	      message-rfc822 (and (string= type "message")
+				  (string= subtype "rfc822"))
+	      multipart-any (string= type "multipart")))
+      (when (string-match ";[ \t\n]*name=\\([^ \t\n;]+\\)" content-type)
+	(setq subject (match-string 1 content-type)))
+      (when (string-match "boundary=\"?\\([^\"\n]*[^\" \t\n]\\)" content-type)
+	(setq boundary-regexp (concat "^--"
+				      (regexp-quote
+				       (match-string 1 content-type))
+				      "\\(--\\)?[ \t]*\n"))))
+    (unless subject
+      (when (or multipart-any (not article-insert))
+	(setq subject (message-fetch-field "Subject"))))
+    (unless type
+      (setq type "text"
+	    subtype "plain"))
+    ;; Prepare the article and summary inserts.
+    (unless article-insert
+      (setq article-insert (buffer-substring (point-min) (point-max))
+	    head-end head-begin))
+    (setq summary-insert article-insert)
+    ;; - summary Subject.
+    (setq summary-insert
+	  (let ((line (concat "Subject: <" position
+			      (and position multipart-any ".")
+			      (and multipart-any "*")
+			      (and (or position multipart-any) " ")
+			      (cond ((string= subtype "plain") type)
+				    ((string= subtype "basic") type)
+				    (t subtype))
+			      ">"
+			      (and subject " ")
+			      subject
+			      "\n")))
+	    (if (string-match "Subject:.*\n\\([ \t].*\n\\)*" summary-insert)
+		(replace-match line t t summary-insert)
+	      (concat summary-insert line))))
+    ;; - summary Message-ID.
+    (setq summary-insert
+	  (let ((line (concat "Message-ID: " message-id "\n")))
+	    (if (string-match "Message-ID:.*\n\\([ \t].*\n\\)*" summary-insert)
+		(replace-match line t t summary-insert)
+	      (concat summary-insert line))))
+    ;; - summary References.
+    (when parent
+      (setq summary-insert
+	    (let ((line (concat "References: " parent "\n")))
+	      (if (string-match "References:.*\n\\([ \t].*\n\\)*"
+				summary-insert)
+		  (replace-match line t t summary-insert)
+		(concat summary-insert line)))))
+    ;; Generate dissection information for this entity.
+    (push (list (incf nndoc-mime-split-ordinal)
+		head-begin head-end body-begin body-end
+		(count-lines body-begin body-end)
+		article-insert summary-insert)
+	  nndoc-dissection-alist)
+    ;; Recurse for all sub-entities, if any.
+    (widen)
+    (cond
+     (message-rfc822
+      (save-excursion
+	(nndoc-dissect-mime-parts-sub body-begin body-end nil
+				      position message-id)))
+     ((and multipart-any boundary-regexp)
+      (let ((part-counter 0)
+	    part-begin part-end eof-flag)
+	(while (string-match "\
+^\\(Lines\\|Content-\\(Type\\|Transfer-Encoding\\|Disposition\\)\\):.*\n\\([ \t].*\n\\)*"
+			     article-insert)
+	  (setq article-insert (replace-match "" t t article-insert)))
+	(let ((case-fold-search nil))
+	  (goto-char body-begin)
+	  (setq eof-flag (not (re-search-forward boundary-regexp body-end t)))
 	  (while (not eof-flag)
-	    (setq begin (point))
-	    (cond ((re-search-forward boundary body-end t)
+	    (setq part-begin (point))
+	    (cond ((re-search-forward boundary-regexp body-end t)
 		   (or (not (match-string 1))
 		       (string= (match-string 1) "")
 		       (setq eof-flag t))
 		   (forward-line -1)
-		   (setq end (point))
+		   (setq part-end (point))
 		   (forward-line 1))
-		  (t (setq end body-end
+		  (t (setq part-end body-end
 			   eof-flag t)))
-	    (nndoc-dissect-mime-parts-sub begin end
-					  (concat position (when position ".")
-						  (format "%d"
-							  (incf part-counter)))
-					  (nnmail-message-id)
-					  message-id)))))))
+	    (save-excursion
+	      (nndoc-dissect-mime-parts-sub
+	       part-begin part-end article-insert
+	       (concat position
+		       (and position ".")
+		       (format "%d" (incf part-counter)))
+	       message-id)))))))))
 
 ;;;###autoload
 (defun nndoc-add-type (definition &optional position)
--- a/lisp/gnus/nndraft.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nndraft.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nndraft.el --- draft article access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -30,6 +31,7 @@
 (require 'gnus-start)
 (require 'nnmh)
 (require 'nnoo)
+(require 'mm-util)
 (eval-when-compile
   (require 'cl)
   ;; This is just to shut up the byte-compiler.
@@ -77,16 +79,12 @@
   (save-excursion
     (set-buffer nntp-server-buffer)
     (erase-buffer)
-    (let* ((buf (get-buffer-create " *draft headers*"))
-	   article)
-      (set-buffer buf)
-      (buffer-disable-undo (current-buffer))
-      (erase-buffer)
+    (let* (article)
       ;; We don't support fetching by Message-ID.
       (if (stringp (car articles))
 	  'headers
 	(while articles
-	  (set-buffer buf)
+	  (narrow-to-region (point) (point))
 	  (when (nndraft-request-article
 		 (setq article (pop articles)) group server (current-buffer))
 	    (goto-char (point-min))
@@ -94,10 +92,10 @@
 		(forward-line -1)
 	      (goto-char (point-max)))
 	    (delete-region (point) (point-max))
-	    (set-buffer nntp-server-buffer)
+	    (goto-char (point-min))
+	    (insert (format "221 %d Article retrieved.\n" article))
+	    (widen)
 	    (goto-char (point-max))
-	    (insert (format "221 %d Article retrieved.\n" article))
-	    (insert-buffer-substring buf)
 	    (insert ".\n")))
 
 	(nnheader-fold-continuation-lines)
@@ -113,7 +111,13 @@
 	   (newest (if (file-newer-than-file-p file auto) file auto))
 	   (nntp-server-buffer (or buffer nntp-server-buffer)))
       (when (and (file-exists-p newest)
-		 (nnmail-find-file newest))
+		 (let ((nnmail-file-coding-system
+			(if (file-newer-than-file-p file auto)
+			    (if (equal group "drafts")
+				message-draft-coding-system
+			      mm-text-coding-system)
+			  mm-auto-save-coding-system)))
+		   (nnmail-find-file newest)))
 	(save-excursion
 	  (set-buffer nntp-server-buffer)
 	  (goto-char (point-min))
@@ -138,8 +142,9 @@
    info
    (gnus-update-read-articles (gnus-group-prefixed-name group '(nndraft ""))
 			      (nndraft-articles) t))
-  (let (marks)
-    (when (setq marks (nth 3 info))
+  (let ((marks (nth 3 info)))
+    (when marks
+      ;; Nix out all marks except the `unsend'-able article marks.
       (setcar (nthcdr 3 info)
 	      (if (assq 'unsend marks)
 		  (list (assq 'unsend marks))
@@ -153,14 +158,14 @@
   (nndraft-possibly-change-group group)
   (let ((gnus-verbose-backends nil)
 	(buf (current-buffer))
-	 article file)
-    (nnheader-temp-write nil
-      (insert-buffer buf)
+	article file)
+    (with-temp-buffer
+      (insert-buffer-substring buf)
       (setq article (nndraft-request-accept-article
-		     group (nnoo-current-server 'nndraft) t 'noinsert))
-      (setq file (nndraft-article-filename article)))
-    (setq buffer-file-name (expand-file-name file))
-    (setq buffer-auto-save-file-name (make-auto-save-file-name))
+		     group (nnoo-current-server 'nndraft) t 'noinsert)
+	    file (nndraft-article-filename article)))
+    (setq buffer-file-name (expand-file-name file)
+	  buffer-auto-save-file-name (make-auto-save-file-name))
     (clear-visited-file-modtime)
     article))
 
@@ -177,7 +182,14 @@
 	(let ((auto (nndraft-auto-save-file-name
 		     (nndraft-article-filename article))))
 	  (when (file-exists-p auto)
-	    (funcall nnmail-delete-file-function auto)))))
+	    (funcall nnmail-delete-file-function auto)))
+	(dolist (backup
+		 (let ((kept-new-versions 1)
+		       (kept-old-versions 0))
+		   (find-backup-file-name
+		    (nndraft-article-filename article))))
+	  (when (file-exists-p backup)
+	    (funcall nnmail-delete-file-function backup)))))
     res))
 
 (deffoo nndraft-request-accept-article (group &optional server last noinsert)
@@ -186,6 +198,15 @@
     (nnoo-parent-function 'nndraft 'nnmh-request-accept-article
 			  (list group server last noinsert))))
 
+(deffoo nndraft-request-replace-article (article group buffer)
+  (nndraft-possibly-change-group group)
+  (let ((nnmail-file-coding-system
+	 (if (equal group "drafts")
+	     mm-auto-save-coding-system
+	   mm-text-coding-system)))
+    (nnoo-parent-function 'nndraft 'nnmh-request-replace-article
+			  (list article group buffer))))
+
 (deffoo nndraft-request-create-group (group &optional server args)
   (nndraft-possibly-change-group group)
   (if (file-exists-p nndraft-current-directory)
@@ -237,10 +258,9 @@
    nnmh-retrieve-headers
    nnmh-request-group
    nnmh-close-group
-   nnmh-request-list 
+   nnmh-request-list
    nnmh-request-newsgroups
-   nnmh-request-move-article
-   nnmh-request-replace-article))
+   nnmh-request-move-article))
 
 (provide 'nndraft)
 
--- a/lisp/gnus/nneething.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nneething.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nneething.el --- arbitrary file access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -45,6 +47,11 @@
   "Regexp saying what files to exclude from the group.
 If this variable is nil, no files will be excluded.")
 
+(defvoo nneething-include-files nil
+  "Regexp saying what files to include in the group.
+If this variable is non-nil, only files matching this regexp will be
+included.")
+
 
 
 ;;; Internal variables.
@@ -68,8 +75,6 @@
 
 
 
-(autoload 'gnus-encode-coding-string "gnus-ems")
-
 ;;; Interface functions.
 
 (nnoo-define-basics nneething)
@@ -104,7 +109,7 @@
 	  (and large
 	       (zerop (% count 20))
 	       (nnheader-message 5 "nneething: Receiving headers... %d%%"
-			(/ (* count 100) number))))
+				 (/ (* count 100) number))))
 
 	(when large
 	  (nnheader-message 5 "nneething: Receiving headers...done"))
@@ -124,7 +129,8 @@
 	   (nnmail-find-file file)	; Insert the file in the nntp buf.
 	   (unless (nnheader-article-p)	; Either it's a real article...
 	     (goto-char (point-min))
-	     (nneething-make-head file (current-buffer)) ; ... or we fake some headers.
+	     (nneething-make-head
+	      file (current-buffer))	; ... or we fake some headers.
 	     (insert "\n"))
 	   t))))
 
@@ -213,17 +219,27 @@
 		  (setq files (cdr files)))
 	      (setq prev f))
 	    (setq f (cdr f)))))
+      ;; Remove files not matching the inclusion regexp.
+      (when nneething-include-files
+	(let ((f files)
+	      prev)
+	  (while f
+	    (if (not (string-match nneething-include-files (car f)))
+		(if prev (setcdr prev (cdr f))
+		  (setq files (cdr files)))
+	      (setq prev f))
+	    (setq f (cdr f)))))
       ;; Remove deleted files from the map.
       (let ((map nneething-map)
 	    prev)
 	(while map
-	  (if (and (member (cadar map) files)
+	  (if (and (member (cadr (car map)) files)
 		   ;; We also remove files that have changed mod times.
 		   (equal (nth 5 (file-attributes
-				  (nneething-file-name (cadar map))))
-			  (caddar map)))
+				  (nneething-file-name (cadr (car map)))))
+			  (cadr (cdar map))))
 	      (progn
-		(push (cadar map) map-files)
+		(push (cadr (car map)) map-files)
 		(setq prev map))
 	    (setq touched t)
 	    (if prev
@@ -243,7 +259,7 @@
 	(setq files (cdr files)))
       (when (and touched
 		 (not nneething-read-only))
-	(nnheader-temp-write map-file
+	(with-temp-file map-file
 	  (insert "(setq nneething-map '")
 	  (gnus-prin1 nneething-map)
 	  (insert ")\n(setq nneething-active '")
@@ -281,8 +297,7 @@
 	   (concat "Lines: " (int-to-string
 			      (count-lines (point-min) (point-max)))
 		   "\n"))
-       "")
-     )))
+       ""))))
 
 (defun nneething-from-line (uid &optional file)
   "Return a From header based of UID."
@@ -302,7 +317,8 @@
 		       (substring file
 				  (match-beginning 1)
 				  (match-end 1))
-		     (when (string-match "/\\(users\\|home\\)/\\([^/]+\\)/" file)
+		     (when (string-match
+			    "/\\(users\\|home\\)/\\([^/]+\\)/" file)
 		       (setq login (substring file
 					      (match-beginning 2)
 					      (match-end 2))
@@ -316,7 +332,7 @@
   (save-excursion
     (set-buffer (get-buffer-create nneething-work-buffer))
     (setq case-fold-search nil)
-    (buffer-disable-undo (current-buffer))
+    (buffer-disable-undo)
     (erase-buffer)
     (cond
      ((not (file-exists-p file))
@@ -344,10 +360,13 @@
 
 (defun nneething-file-name (article)
   "Return the file name of ARTICLE."
-  (concat (file-name-as-directory nneething-address)
-	  (if (numberp article)
-	      (cadr (assq article nneething-map))
-	    article)))
+  (let ((dir (file-name-as-directory nneething-address))
+        fname)
+    (if (numberp article)
+	(if (setq fname (cadr (assq article nneething-map)))
+	    (expand-file-name fname dir)
+	  (make-temp-name (expand-file-name "nneething" dir)))
+      (expand-file-name article dir))))
 
 (provide 'nneething)
 
--- a/lisp/gnus/nnfolder.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnfolder.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnfolder.el --- mail folder access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Scott Byer <byer@mv.us.adobe.com>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -40,27 +41,29 @@
   "The name of the nnfolder directory.")
 
 (defvoo nnfolder-active-file
-  (nnheader-concat nnfolder-directory "active")
+    (nnheader-concat nnfolder-directory "active")
   "The name of the active file.")
 
 ;; I renamed this variable to something more in keeping with the general GNU
 ;; style. -SLB
 
 (defvoo nnfolder-ignore-active-file nil
-  "If non-nil, causes nnfolder to do some extra work in order to determine
-the true active ranges of an mbox file.  Note that the active file is still
-saved, but it's values are not used.  This costs some extra time when
-scanning an mbox when opening it.")
+  "If non-nil, the active file is ignores.
+This causes nnfolder to do some extra work in order to determine the
+true active ranges of an mbox file.  Note that the active file is
+still saved, but it's values are not used.  This costs some extra time
+when scanning an mbox when opening it.")
 
 (defvoo nnfolder-distrust-mbox nil
-  "If non-nil, causes nnfolder to not trust the user with respect to
-inserting unaccounted for mail in the middle of an mbox file.  This can greatly
-slow down scans, which now must scan the entire file for unmarked messages.
-When nil, scans occur forward from the last marked message, a huge
-time saver for large mailboxes.")
+  "If non-nil, the folder will be distrusted.
+This means that nnfolder will not trust the user with respect to
+inserting unaccounted for mail in the middle of an mbox file.  This
+can greatly slow down scans, which now must scan the entire file for
+unmarked messages.  When nil, scans occur forward from the last marked
+message, a huge time saver for large mailboxes.")
 
 (defvoo nnfolder-newsgroups-file
-  (concat (file-name-as-directory nnfolder-directory) "newsgroups")
+    (concat (file-name-as-directory nnfolder-directory) "newsgroups")
   "Mail newsgroups description file.")
 
 (defvoo nnfolder-get-new-mail t
@@ -90,6 +93,13 @@
 (defvoo nnfolder-buffer-alist nil)
 (defvoo nnfolder-scantime-alist nil)
 (defvoo nnfolder-active-timestamp nil)
+(defvoo nnfolder-active-file-coding-system mm-text-coding-system)
+(defvoo nnfolder-active-file-coding-system-for-write 
+    nnmail-active-file-coding-system)
+(defvoo nnfolder-file-coding-system mm-text-coding-system)
+(defvoo nnfolder-file-coding-system-for-write nnheader-file-coding-system
+  "Coding system for save nnfolder file.
+If NIL, NNFOLDER-FILE-CODING-SYSTEM is used.")
 
 
 
@@ -112,8 +122,9 @@
 	    (set-buffer nnfolder-current-buffer)
 	    (when (nnfolder-goto-article article)
 	      (setq start (point))
-	      (search-forward "\n\n" nil t)
-	      (setq stop (1- (point)))
+	      (setq stop (if (search-forward "\n\n" nil t)
+			     (1- (point))
+			   (point-max)))
 	      (set-buffer nntp-server-buffer)
 	      (insert (format "221 %d Article retrieved.\n" article))
 	      (insert-buffer-substring nnfolder-current-buffer start stop)
@@ -176,11 +187,13 @@
 	  (if (numberp article)
 	      (cons nnfolder-current-group article)
 	    (goto-char (point-min))
-	    (search-forward (concat "\n" nnfolder-article-marker))
 	    (cons nnfolder-current-group
-		  (string-to-int
-		   (buffer-substring
-		    (point) (progn (end-of-line) (point)))))))))))
+		  (if (search-forward (concat "\n" nnfolder-article-marker) 
+				      nil t)
+		      (string-to-int
+		       (buffer-substring
+			(point) (progn (end-of-line) (point))))
+		    -1))))))))
 
 (deffoo nnfolder-request-group (group &optional server dont-check)
   (nnfolder-possibly-change-group group server t)
@@ -266,15 +279,14 @@
   (when group
     (unless (assoc group nnfolder-group-alist)
       (push (list group (cons 1 0)) nnfolder-group-alist)
-      (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
+      (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
       (nnfolder-read-folder group)))
   t)
 
 (deffoo nnfolder-request-list (&optional server)
   (nnfolder-possibly-change-group nil server)
   (save-excursion
-    (let ((nnmail-file-coding-system nnmail-active-file-coding-system)
-	  (pathname-coding-system 'binary))
+    (let ((nnmail-file-coding-system nnfolder-active-file-coding-system))
       (nnmail-find-file nnfolder-active-file)
       (setq nnfolder-group-alist (nnmail-get-active)))
     t))
@@ -286,38 +298,69 @@
 (deffoo nnfolder-request-list-newsgroups (&optional server)
   (nnfolder-possibly-change-group nil server)
   (save-excursion
-    (nnmail-find-file nnfolder-newsgroups-file)))
+    (let ((nnmail-file-coding-system nnfolder-file-coding-system))
+      (nnmail-find-file nnfolder-newsgroups-file))))
+
+;; Return a list consisting of all article numbers existing in the
+;; current folder.
+
+(defun nnfolder-existing-articles ()
+  (save-excursion
+    (when nnfolder-current-buffer
+      (set-buffer nnfolder-current-buffer)
+      (goto-char (point-min))
+      (let ((marker (concat "\n" nnfolder-article-marker))
+	    (number "[0-9]+")
+	    numbers)
+      
+	(while (and (search-forward marker nil t)
+		    (re-search-forward number nil t))
+	  (let ((newnum (string-to-number (match-string 0))))
+	    (if (nnmail-within-headers-p)
+		(push newnum numbers))))
+	numbers))))
 
 (deffoo nnfolder-request-expire-articles
-  (articles newsgroup &optional server force)
+    (articles newsgroup &optional server force)
   (nnfolder-possibly-change-group newsgroup server)
   (let* ((is-old t)
-	 rest)
+	 ;; The articles we have deleted so far.
+	 (deleted-articles nil)
+	 ;; The articles that really exist and will
+	 ;; be expired if they are old enough.
+	 (maybe-expirable
+	  (gnus-intersection articles (nnfolder-existing-articles))))
     (nnmail-activate 'nnfolder)
 
     (save-excursion
       (set-buffer nnfolder-current-buffer)
-      (while (and articles is-old)
+      ;; Since messages are sorted in arrival order and expired in the
+      ;; same order, we can stop as soon as we find a message that is
+      ;; too old.
+      (while (and maybe-expirable is-old)
 	(goto-char (point-min))
-	(when (nnfolder-goto-article (car articles))
-	  (if (setq is-old
-		    (nnmail-expired-article-p
-		     newsgroup
-		     (buffer-substring
-		      (point) (progn (end-of-line) (point)))
-		     force nnfolder-inhibit-expiry))
-	      (progn
-		(nnheader-message 5 "Deleting article %d..."
-				  (car articles) newsgroup)
-		(nnfolder-delete-mail))
-	    (push (car articles) rest)))
-	(setq articles (cdr articles)))
+	(when (and (nnfolder-goto-article (car maybe-expirable))
+		   (search-forward (concat "\n" nnfolder-article-marker)
+				   nil t))
+	  (forward-sexp)
+	  (when (setq is-old
+		      (nnmail-expired-article-p
+		       newsgroup
+		       (buffer-substring
+			(point) (progn (end-of-line) (point)))
+		       force nnfolder-inhibit-expiry))
+	    (nnheader-message 5 "Deleting article %d..."
+			      (car maybe-expirable) newsgroup)
+	    (nnfolder-delete-mail)
+	    ;; Must remember which articles were actually deleted
+	    (push (car maybe-expirable) deleted-articles)))
+	(setq maybe-expirable (cdr maybe-expirable)))
       (unless nnfolder-inhibit-expiry
 	(nnheader-message 5 "Deleting articles...done"))
       (nnfolder-save-buffer)
       (nnfolder-adjust-min-active newsgroup)
-      (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
-      (nconc rest articles))))
+      (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
+      (gnus-sorted-complement articles (nreverse deleted-articles)))))
 
 (deffoo nnfolder-request-move-article (article group server
 					       accept-form &optional last)
@@ -328,13 +371,13 @@
        (nnfolder-request-article article group server)
        (save-excursion
 	 (set-buffer buf)
-	 (buffer-disable-undo (current-buffer))
 	 (erase-buffer)
 	 (insert-buffer-substring nntp-server-buffer)
 	 (goto-char (point-min))
 	 (while (re-search-forward
 		 (concat "^" nnfolder-article-marker)
-		 (save-excursion (search-forward "\n\n" nil t) (point)) t)
+		 (save-excursion (and (search-forward "\n\n" nil t) (point))) 
+		 t)
 	   (delete-region (progn (beginning-of-line) (point))
 			  (progn (forward-line 1) (point))))
 	 (setq result (eval accept-form))
@@ -349,7 +392,7 @@
 	 (when last
 	   (nnfolder-save-buffer)
 	   (nnfolder-adjust-min-active group)
-	   (nnmail-save-active nnfolder-group-alist nnfolder-active-file))))
+	   (nnfolder-save-active nnfolder-group-alist nnfolder-active-file))))
       result)))
 
 (deffoo nnfolder-request-accept-article (group &optional server last)
@@ -366,8 +409,9 @@
        (save-excursion
 	 (set-buffer buf)
 	 (goto-char (point-min))
-	 (search-forward "\n\n" nil t)
-	 (forward-line -1)
+	 (if (search-forward "\n\n" nil t)
+	     (forward-line -1)
+	   (goto-char (point-max)))
 	 (while (re-search-backward (concat "^" nnfolder-article-marker) nil t)
 	   (delete-region (point) (progn (forward-line 1) (point))))
 	 (when nnmail-cache-accepted-message-ids
@@ -387,7 +431,7 @@
 	   (nnfolder-save-buffer)
 	   (when nnmail-cache-accepted-message-ids
 	     (nnmail-cache-close)))))
-      (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
+      (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
       (unless result
 	(nnheader-report 'nnfolder "Couldn't store article"))
       result)))
@@ -404,7 +448,7 @@
       (goto-char (point-min))
       (if xfrom
 	  (insert "From " xfrom "\n")
-	(unless (looking-at message-unix-mail-delimiter)
+	(unless (looking-at "From ")
 	  (insert "From nobody " (current-time-string) "\n"))))
     (nnfolder-normalize-buffer)
     (set-buffer nnfolder-current-buffer)
@@ -430,7 +474,7 @@
 	nnfolder-current-group nil
 	nnfolder-current-buffer nil)
   ;; Save the active file.
-  (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
+  (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
   t)
 
 (deffoo nnfolder-request-rename-group (group new-name &optional server)
@@ -441,7 +485,9 @@
 	 (ignore-errors
 	   (rename-file
 	    buffer-file-name
-	    (nnfolder-group-pathname new-name))
+	    (let ((new-file (nnfolder-group-pathname new-name)))
+	      (gnus-make-directory (file-name-directory new-file))
+	      new-file))
 	   t)
 	 ;; That went ok, so we change the internal structures.
 	 (let ((entry (assoc group nnfolder-group-alist)))
@@ -449,7 +495,7 @@
 	   (setq nnfolder-current-buffer nil
 		 nnfolder-current-group nil)
 	   ;; Save the new group alist.
-	   (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
+	   (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
 	   ;; We kill the buffer instead of renaming it and stuff.
 	   (kill-buffer (current-buffer))
 	   t))))
@@ -511,17 +557,21 @@
   "Delete the message that point is in.
 If optional argument LEAVE-DELIM is t, then mailbox delimiter is not
 deleted.  Point is left where the deleted region was."
-  (delete-region
-   (save-excursion
-     (forward-line 1) ; in case point is at beginning of message already
-     (nnmail-search-unix-mail-delim-backward)
-     (if leave-delim (progn (forward-line 1) (point))
-       (point)))
-   (progn
-     (forward-line 1)
-     (if (nnmail-search-unix-mail-delim)
-	 (point)
-       (point-max)))))
+  (save-restriction
+    (narrow-to-region
+     (save-excursion
+       ;; In case point is at the beginning of the message already.
+       (forward-line 1)
+       (nnmail-search-unix-mail-delim-backward)
+       (if leave-delim (progn (forward-line 1) (point))
+	 (point)))
+     (progn
+       (forward-line 1)
+       (if (nnmail-search-unix-mail-delim)
+	   (point)
+	 (point-max))))
+    (run-hooks 'nnfolder-delete-mail-hook)
+    (delete-region (point-min) (point-max))))
 
 (defun nnfolder-possibly-change-group (group &optional server dont-check)
   ;; Change servers.
@@ -534,15 +584,14 @@
   ;; Change group.
   (when (and group
 	     (not (equal group nnfolder-current-group)))
-    (let ((file-name-coding-system 'binary)
-	  (pathname-coding-system 'binary))
+    (let ((file-name-coding-system nnmail-pathname-coding-system))
       (nnmail-activate 'nnfolder)
       (when (and (not (assoc group nnfolder-group-alist))
 		 (not (file-exists-p
 		       (nnfolder-group-pathname group))))
 	;; The group doesn't exist, so we create a new entry for it.
 	(push (list group (cons 1 0)) nnfolder-group-alist)
-	(nnmail-save-active nnfolder-group-alist nnfolder-active-file))
+	(nnfolder-save-active nnfolder-group-alist nnfolder-active-file))
 
       (if dont-check
 	  (setq nnfolder-current-group group
@@ -572,7 +621,10 @@
 	      ;; See whether we need to create the new file.
 	      (unless (file-exists-p file)
 		(gnus-make-directory (file-name-directory file))
-		(nnmail-write-region 1 1 file t 'nomesg))
+		(let ((nnmail-file-coding-system 
+		       (or nnfolder-file-coding-system-for-write
+			   nnfolder-file-coding-system-for-write)))
+		  (nnmail-write-region 1 1 file t 'nomesg)))
 	      (when (setq nnfolder-current-buffer (nnfolder-read-folder group))
 		(set-buffer nnfolder-current-buffer)
 		(push (list group nnfolder-current-buffer)
@@ -583,19 +635,14 @@
   (let* (save-list group-art)
     (goto-char (point-min))
     ;; The From line may have been quoted by movemail.
-    (when (looking-at (concat ">" message-unix-mail-delimiter))
+    (when (looking-at ">From")
       (delete-char 1))
     ;; This might come from somewhere else.
-    (unless (looking-at message-unix-mail-delimiter)
+    (unless (looking-at "From ")
       (insert "From nobody " (current-time-string) "\n")
       (goto-char (point-min)))
+    ;; Quote all "From " lines in the article.
     (forward-line 1)
-    ;; Quote subsequent "From " lines in the header.
-    (while (looking-at message-unix-mail-delimiter)
-      (delete-region (point) (+ (point) 4))
-      (insert "X-From-Line:")
-      (forward-line 1))
-    ;; Quote all "From " lines in the article.
     (let (case-fold-search)
       (while (re-search-forward "^From " nil t)
 	(beginning-of-line)
@@ -610,8 +657,9 @@
     (while (setq group-art (pop group-art-list))
       ;; Kill any previous newsgroup markers.
       (goto-char (point-min))
-      (search-forward "\n\n" nil t)
-      (forward-line -1)
+      (if (search-forward "\n\n" nil t)
+	  (forward-line -1)
+	(goto-char (point-max)))
       (while (search-backward (concat "\n" nnfolder-article-marker) nil t)
 	(delete-region (1+ (point)) (progn (forward-line 2) (point))))
 
@@ -640,10 +688,12 @@
 (defun nnfolder-insert-newsgroup-line (group-art)
   (save-excursion
     (goto-char (point-min))
-    (when (search-forward "\n\n" nil t)
-      (forward-char -1)
-      (insert (format (concat nnfolder-article-marker "%d   %s\n")
-		      (cdr group-art) (current-time-string))))))
+    (unless (search-forward "\n\n" nil t)
+      (goto-char (point-max))
+      (insert "\n"))
+    (forward-char -1)
+    (insert (format (concat nnfolder-article-marker "%d   %s\n")
+		    (cdr group-art) (current-time-string)))))
 
 (defun nnfolder-active-number (group)
   ;; Find the next article number in GROUP.
@@ -665,7 +715,7 @@
       (when inf
 	(setq nnfolder-buffer-alist (delq inf nnfolder-buffer-alist)))
       (when nnfolder-group-alist
-	(nnmail-save-active nnfolder-group-alist nnfolder-active-file))
+	(nnfolder-save-active nnfolder-group-alist nnfolder-active-file))
       (push (list group (nnfolder-read-folder group))
 	    nnfolder-buffer-alist))))
 
@@ -686,7 +736,10 @@
 
 (defun nnfolder-read-folder (group)
   (let* ((file (nnfolder-group-pathname group))
-	 (buffer (set-buffer (nnheader-find-file-noselect file))))
+	 (buffer (set-buffer
+		  (let ((nnheader-file-coding-system 
+			 nnfolder-file-coding-system))
+		    (nnheader-find-file-noselect file)))))
     (if (equal (cadr (assoc group nnfolder-scantime-alist))
 	       (nth 5 (file-attributes file)))
 	;; This looks up-to-date, so we don't do any scanning.
@@ -694,12 +747,16 @@
 	    buffer
 	  (push (list group buffer) nnfolder-buffer-alist)
 	  (set-buffer-modified-p t)
-	  (save-buffer))
+	  (nnfolder-save-buffer))
       ;; Parse the damn thing.
       (save-excursion
+	(goto-char (point-min))
+	;; Remove any blank lines at the start.
+	(while (eq (following-char) ?\n)
+	  (delete-char 1))
 	(nnmail-activate 'nnfolder)
 	;; Read in the file.
-	(let ((delim (concat "^" message-unix-mail-delimiter))
+	(let ((delim "^From ")
 	      (marker (concat "\n" nnfolder-article-marker))
 	      (number "[0-9]+")
 	      (active (or (cadr (assoc group nnfolder-group-alist))
@@ -708,7 +765,7 @@
 	      (minid (lsh -1 -1))
 	      maxid start end newscantime
 	      buffer-read-only)
-	  (buffer-disable-undo (current-buffer))
+	  (buffer-disable-undo)
 	  (setq maxid (cdr active))
 	  (goto-char (point-min))
 
@@ -768,7 +825,7 @@
 
 	  (set-marker end nil)
 	  ;; Make absolutely sure that the active list reflects reality!
-	  (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
+	  (nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
 	  ;; Set the scantime for this group.
 	  (setq newscantime (visited-file-modtime))
 	  (if scantime
@@ -779,7 +836,8 @@
 
 ;;;###autoload
 (defun nnfolder-generate-active-file ()
-  "Look for mbox folders in the nnfolder directory and make them into groups."
+  "Look for mbox folders in the nnfolder directory and make them into groups.
+This command does not work if you use short group names."
   (interactive)
   (nnmail-activate 'nnfolder)
   (let ((files (directory-files nnfolder-directory))
@@ -803,7 +861,8 @@
 
 (defun nnfolder-group-pathname (group)
   "Make pathname for GROUP."
-  (setq group (gnus-encode-coding-string group nnmail-pathname-coding-system))
+  (setq group
+	(mm-encode-coding-string group nnmail-pathname-coding-system))
   (let ((dir (file-name-as-directory (expand-file-name nnfolder-directory))))
     ;; If this file exists, we use it directly.
     (if (or nnmail-use-long-file-names
@@ -817,7 +876,16 @@
   (when (buffer-modified-p)
     (run-hooks 'nnfolder-save-buffer-hook)
     (gnus-make-directory (file-name-directory (buffer-file-name)))
-    (save-buffer)))
+    (let ((coding-system-for-write 
+	   (or nnfolder-file-coding-system-for-write
+	       nnfolder-file-coding-system)))
+      (save-buffer))))
+
+(defun nnfolder-save-active (group-alist active-file)
+  (let ((nnmail-active-file-coding-system
+	 (or nnfolder-active-file-coding-system-for-write
+	     nnfolder-active-file-coding-system)))
+    (nnmail-save-active group-alist active-file)))
 
 (provide 'nnfolder)
 
--- a/lisp/gnus/nngateway.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nngateway.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nngateway.el --- posting news via mail gateways
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news, mail
@@ -55,7 +57,7 @@
 	    (nngateway-open-server server))
     ;; Rewrite the header.
     (let ((buf (current-buffer)))
-      (nnheader-temp-write nil
+      (with-temp-buffer
 	(insert-buffer-substring buf)
 	(message-narrow-to-head)
 	(funcall nngateway-header-transformation nngateway-address)
--- a/lisp/gnus/nnheader.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnheader.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,8 @@
 ;;; nnheader.el --- header access macros for Gnus and its backends
-;; Copyright (C) 1987,88,89,90,93,94,95,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
+;;        1997, 1998, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;; 	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -24,24 +27,12 @@
 
 ;;; Commentary:
 
-;; These macros may look very much like the ones in GNUS 4.1.  They
-;; are, in a way, but you should note that the indices they use have
-;; been changed from the internal GNUS format to the NOV format.  The
-;; makes it possible to read headers from XOVER much faster.
-;;
-;; The format of a header is now:
-;; [number subject from date id references chars lines xref]
-;;
-;; (That last entry is defined as "misc" in the NOV format, but Gnus
-;; uses it for xrefs.)
-
 ;;; Code:
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'mail-utils)
+(require 'mm-util)
 
 (defvar nnheader-max-head-length 4096
   "*Max length of the head of articles.")
@@ -51,23 +42,32 @@
 
 (defvar nnheader-file-name-translation-alist nil
   "*Alist that says how to translate characters in file names.
-For instance, if \":\" is illegal as a file character in file names
+For instance, if \":\" is invalid as a file character in file names
 on your system, you could say something like:
 
 \(setq nnheader-file-name-translation-alist '((?: . ?_)))")
 
 (eval-and-compile
- (autoload 'nnmail-message-id "nnmail")
- (autoload 'mail-position-on-field "sendmail")
- (autoload 'message-remove-header "message")
- (autoload 'cancel-function-timers "timers")
- (autoload 'gnus-point-at-eol "gnus-util")
- (autoload 'gnus-delete-line "gnus-util")
- (autoload 'gnus-buffer-live-p "gnus-util")
- (autoload 'gnus-encode-coding-string "gnus-ems"))
+  (autoload 'nnmail-message-id "nnmail")
+  (autoload 'mail-position-on-field "sendmail")
+  (autoload 'message-remove-header "message")
+  (autoload 'gnus-point-at-eol "gnus-util")
+  (autoload 'gnus-delete-line "gnus-util")
+  (autoload 'gnus-buffer-live-p "gnus-util"))
 
 ;;; Header access macros.
 
+;; These macros may look very much like the ones in GNUS 4.1.  They
+;; are, in a way, but you should note that the indices they use have
+;; been changed from the internal GNUS format to the NOV format.  The
+;; makes it possible to read headers from XOVER much faster.
+;;
+;; The format of a header is now:
+;; [number subject from date id references chars lines xref extra]
+;;
+;; (That next-to-last entry is defined as "misc" in the NOV format,
+;; but Gnus uses it for xrefs.)
+
 (defmacro mail-header-number (header)
   "Return article number in HEADER."
   `(aref ,header 0))
@@ -139,17 +139,26 @@
   `(aref ,header 8))
 
 (defmacro mail-header-set-xref (header xref)
-  "Set article xref of HEADER to xref."
+  "Set article XREF of HEADER to xref."
   `(aset ,header 8 ,xref))
 
-(defun make-mail-header (&optional init)
-  "Create a new mail header structure initialized with INIT."
-  (make-vector 9 init))
+(defmacro mail-header-extra (header)
+  "Return the extra headers in HEADER."
+  `(aref ,header 9))
+
+(defmacro mail-header-set-extra (header extra)
+  "Set the extra headers in HEADER to EXTRA."
+  `(aset ,header 9 ',extra))
 
-(defun make-full-mail-header (&optional number subject from date id
-					references chars lines xref)
+(defsubst make-mail-header (&optional init)
+  "Create a new mail header structure initialized with INIT."
+  (make-vector 10 init))
+
+(defsubst make-full-mail-header (&optional number subject from date id
+					   references chars lines xref
+					   extra)
   "Create a new mail header structure initialized with the parameters given."
-  (vector number subject from date id references chars lines xref))
+  (vector number subject from date id references chars lines xref extra))
 
 ;; fake message-ids: generation and detection
 
@@ -235,11 +244,12 @@
 	       ;; promising.
 	       (if (and (search-forward "\nin-reply-to: " nil t)
 			(setq in-reply-to (nnheader-header-value))
-			(string-match "<[^>]+>" in-reply-to))
+			(string-match "<[^\n>]+>" in-reply-to))
 		   (let (ref2)
 		     (setq ref (substring in-reply-to (match-beginning 0)
 					  (match-end 0)))
-		     (while (string-match "<[^>]+>" in-reply-to (match-end 0))
+		     (while (string-match "<[^\n>]+>"
+					  in-reply-to (match-end 0))
 		       (setq ref2 (substring in-reply-to (match-beginning 0)
 					     (match-end 0)))
 		       (when (> (length ref2) (length ref))
@@ -259,7 +269,20 @@
 	   (progn
 	     (goto-char p)
 	     (and (search-forward "\nxref: " nil t)
-		  (nnheader-header-value)))))
+		  (nnheader-header-value)))
+
+	   ;; Extra.
+	   (when nnmail-extra-headers
+	     (let ((extra nnmail-extra-headers)
+		   out)
+	       (while extra
+		 (goto-char p)
+		 (when (search-forward
+			(concat "\n" (symbol-name (car extra)) ": ") nil t)
+		   (push (cons (car extra) (nnheader-header-value))
+			 out))
+		 (pop extra))
+	       out))))
       (when naked
 	(goto-char (point-min))
 	(delete-char 1)))))
@@ -272,13 +295,29 @@
 
 (defmacro nnheader-nov-read-integer ()
   '(prog1
-       (if (= (following-char) ?\t)
+       (if (eq (char-after) ?\t)
 	   0
-	 (let ((num (ignore-errors (read (current-buffer)))))
+	 (let ((num (condition-case nil
+			(read (current-buffer))
+		      (error nil))))
 	   (if (numberp num) num 0)))
      (or (eobp) (forward-char 1))))
 
-;; (defvar nnheader-none-counter 0)
+(defmacro nnheader-nov-parse-extra ()
+  '(let (out string)
+     (while (not (memq (char-after) '(?\n nil)))
+       (setq string (nnheader-nov-field))
+       (when (string-match "^\\([^ :]+\\): " string)
+	 (push (cons (intern (match-string 1 string))
+		     (substring string (match-end 0)))
+	       out)))
+     out))
+
+(defmacro nnheader-nov-read-message-id ()
+  '(let ((id (nnheader-nov-field)))
+     (if (string-match "^<[^>]+>$" id)
+	 id
+       (nnheader-generate-fake-message-id))))
 
 (defun nnheader-parse-nov ()
   (let ((eol (gnus-point-at-eol)))
@@ -287,34 +326,58 @@
      (nnheader-nov-field)		; subject
      (nnheader-nov-field)		; from
      (nnheader-nov-field)		; date
-     (or (nnheader-nov-field)
-	 (nnheader-generate-fake-message-id)) ; id
+     (nnheader-nov-read-message-id)	; id
      (nnheader-nov-field)		; refs
      (nnheader-nov-read-integer)	; chars
      (nnheader-nov-read-integer)	; lines
-     (if (= (following-char) ?\n)
+     (if (eq (char-after) ?\n)
 	 nil
        (nnheader-nov-field))		; misc
-     )))
+     (nnheader-nov-parse-extra))))	; extra
 
 (defun nnheader-insert-nov (header)
   (princ (mail-header-number header) (current-buffer))
+  (let ((p (point)))
+    (insert
+     "\t"
+     (or (mail-header-subject header) "(none)") "\t"
+     (or (mail-header-from header) "(nobody)") "\t"
+     (or (mail-header-date header) "") "\t"
+     (or (mail-header-id header)
+	 (nnmail-message-id))
+     "\t"
+     (or (mail-header-references header) "") "\t")
+    (princ (or (mail-header-chars header) 0) (current-buffer))
+    (insert "\t")
+    (princ (or (mail-header-lines header) 0) (current-buffer))
+    (insert "\t")
+    (when (mail-header-xref header)
+      (insert "Xref: " (mail-header-xref header)))
+    (when (or (mail-header-xref header)
+	      (mail-header-extra header))
+      (insert "\t"))
+    (when (mail-header-extra header)
+      (let ((extra (mail-header-extra header)))
+	(while extra
+	  (insert (symbol-name (caar extra))
+		  ": " (cdar extra) "\t")
+	  (pop extra))))
+    (insert "\n")
+    (backward-char 1)
+    (while (search-backward "\n" p t)
+      (delete-char 1))
+    (forward-line 1)))
+
+(defun nnheader-insert-header (header)
   (insert
-   "\t"
-   (or (mail-header-subject header) "(none)") "\t"
-   (or (mail-header-from header) "(nobody)") "\t"
-   (or (mail-header-date header) "") "\t"
-   (or (mail-header-id header)
-       (nnmail-message-id))
-   "\t"
-   (or (mail-header-references header) "") "\t")
-  (princ (or (mail-header-chars header) 0) (current-buffer))
-  (insert "\t")
+   "Subject: " (or (mail-header-subject header) "(none)") "\n"
+   "From: " (or (mail-header-from header) "(nobody)") "\n"
+   "Date: " (or (mail-header-date header) "") "\n"
+   "Message-ID: " (or (mail-header-id header) (nnmail-message-id)) "\n"
+   "References: " (or (mail-header-references header) "") "\n"
+   "Lines: ")
   (princ (or (mail-header-lines header) 0) (current-buffer))
-  (insert "\t")
-  (when (mail-header-xref header)
-    (insert "Xref: " (mail-header-xref header) "\t"))
-  (insert "\n"))
+  (insert "\n\n"))
 
 (defun nnheader-insert-article-line (article)
   (goto-char (point-min))
@@ -401,6 +464,7 @@
   (save-excursion
     (unless (gnus-buffer-live-p nntp-server-buffer)
       (setq nntp-server-buffer (get-buffer-create " *nntpd*")))
+    (mm-enable-multibyte)
     (set-buffer nntp-server-buffer)
     (erase-buffer)
     (kill-all-local-variables)
@@ -447,7 +511,7 @@
       nil
     (narrow-to-region (point-min) (1- (point)))
     (goto-char (point-min))
-    (while (looking-at "[A-Z][^ \t]+:.*\n\\([ \t].*\n\\)*\\|From .*\n")
+    (while (looking-at "[a-zA-Z][^ \t]+:.*\n\\([ \t].*\n\\)*\\|From .*\n")
       (goto-char (match-end 0)))
     (prog1
 	(eobp)
@@ -456,7 +520,8 @@
 (defun nnheader-insert-references (references message-id)
   "Insert a References header based on REFERENCES and MESSAGE-ID."
   (if (and (not references) (not message-id))
-      ()				; This is illegal, but not all articles have Message-IDs.
+      ;; This is invalid, but not all articles have Message-IDs.
+      ()
     (mail-position-on-field "References")
     (let ((begin (save-excursion (beginning-of-line) (point)))
 	  (fill-column 78)
@@ -495,58 +560,12 @@
 (defun nnheader-set-temp-buffer (name &optional noerase)
   "Set-buffer to an empty (possibly new) buffer called NAME with undo disabled."
   (set-buffer (get-buffer-create name))
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (unless noerase
     (erase-buffer))
   (current-buffer))
 
-(defmacro nnheader-temp-write (file &rest forms)
-  "Create a new buffer, evaluate FORMS there, and write the buffer to FILE.
-Return the value of FORMS.
-If FILE is nil, just evaluate FORMS and don't save anything.
-If FILE is t, return the buffer contents as a string."
-  (let ((temp-file (make-symbol "temp-file"))
-	(temp-buffer (make-symbol "temp-buffer"))
-	(temp-results (make-symbol "temp-results")))
-    `(save-excursion
-       (let* ((,temp-file ,file)
-	      (default-major-mode 'fundamental-mode)
-	      (,temp-buffer
-	       (set-buffer
-		(get-buffer-create
-		 (generate-new-buffer-name " *nnheader temp*"))))
-	      ,temp-results)
-	 (unwind-protect
-	     (progn
-	       (setq ,temp-results (progn ,@forms))
-	       (cond
-		;; Don't save anything.
-		((null ,temp-file)
-		 ,temp-results)
-		;; Return the buffer contents.
-		((eq ,temp-file t)
-		 (set-buffer ,temp-buffer)
-		 (buffer-string))
-		;; Save a file.
-		(t
-		 (set-buffer ,temp-buffer)
-		 ;; Make sure the directory where this file is
-		 ;; to be saved exists.
-		 (when (not (file-directory-p
-			     (file-name-directory ,temp-file)))
-		   (make-directory (file-name-directory ,temp-file) t))
-		 ;; Save the file.
-		 (write-region (point-min) (point-max)
-			       ,temp-file nil 'nomesg)
-		 ,temp-results)))
-	   ;; Kill the buffer.
-	   (when (buffer-name ,temp-buffer)
-	     (kill-buffer ,temp-buffer)))))))
-
-(put 'nnheader-temp-write 'lisp-indent-function 1)
-(put 'nnheader-temp-write 'edebug-form-spec '(form body))
-
-(defvar jka-compr-compression-info-list)
+(eval-when-compile (defvar jka-compr-compression-info-list))
 (defvar nnheader-numerical-files
   (if (boundp 'jka-compr-compression-info-list)
       (concat "\\([0-9]+\\)\\("
@@ -563,7 +582,7 @@
   "Regexp that matches numerical full file paths.")
 
 (defsubst nnheader-file-to-number (file)
-  "Take a file name and return the article number."
+  "Take a FILE name and return the article number."
   (if (string= nnheader-numerical-short-files "^[0-9]+$")
       (string-to-int file)
     (string-match nnheader-numerical-short-files file)
@@ -581,7 +600,7 @@
       second)))
 
 (defun nnheader-directory-articles (dir)
-  "Return a list of all article files in a directory."
+  "Return a list of all article files in directory DIR."
   (mapcar 'nnheader-file-to-number
 	  (nnheader-directory-files-safe
 	   dir nil nnheader-numerical-short-files t)))
@@ -607,7 +626,9 @@
       (if full
 	  ;; Do complete translation.
 	  (setq leaf (copy-sequence file)
-		path "")
+		path ""
+		i (if (and (< 1 (length leaf)) (eq ?: (aref leaf 1)))
+		      2 0))
 	;; We translate -- but only the file name.  We leave the directory
 	;; alone.
 	(if (string-match "/[^/]+\\'" file)
@@ -638,7 +659,7 @@
   "Get the most recent report from BACKEND."
   (condition-case ()
       (nnheader-message 5 "%s" (symbol-value (intern (format "%s-status-string"
-						  backend))))
+							     backend))))
     (error (nnheader-message 5 ""))))
 
 (defun nnheader-insert (format &rest args)
@@ -653,15 +674,33 @@
       (apply 'insert format args))
     t))
 
-(defun nnheader-replace-chars-in-string (string from to)
+(if (fboundp 'subst-char-in-string)
+    (defsubst nnheader-replace-chars-in-string (string from to)
+      (subst-char-in-string from to string))
+  (defun nnheader-replace-chars-in-string (string from to)
+    "Replace characters in STRING from FROM to TO."
+    (let ((string (substring string 0))	;Copy string.
+	  (len (length string))
+	  (idx 0))
+      ;; Replace all occurrences of FROM with TO.
+      (while (< idx len)
+	(when (= (aref string idx) from)
+	  (aset string idx to))
+	(setq idx (1+ idx)))
+      string)))
+
+(defun nnheader-replace-duplicate-chars-in-string (string from to)
   "Replace characters in STRING from FROM to TO."
   (let ((string (substring string 0))	;Copy string.
 	(len (length string))
-	(idx 0))
+	(idx 0) prev i)
     ;; Replace all occurrences of FROM with TO.
     (while (< idx len)
-      (when (= (aref string idx) from)
+      (setq i (aref string idx))
+      (when (and (eq prev from) (= i from))
+	(aset string (1- idx) to)
 	(aset string idx to))
+      (setq prev i)
       (setq idx (1+ idx)))
     string))
 
@@ -690,12 +729,7 @@
   (or (not (numberp gnus-verbose-backends))
       (<= level gnus-verbose-backends)))
 
-(defvar nnheader-pathname-coding-system 'iso-8859-1
-  "*Coding system for pathname.")
-
-;; 1997/8/10 by MORIOKA Tomohiko
-(defvar nnheader-pathname-coding-system
-  'iso-8859-1
+(defvar nnheader-pathname-coding-system 'binary
   "*Coding system for pathname.")
 
 (defun nnheader-group-pathname (group dir &optional file)
@@ -703,14 +737,14 @@
   (concat
    (let ((dir (file-name-as-directory (expand-file-name dir))))
      ;; If this directory exists, we use it directly.
-     (if (file-directory-p (concat dir group))
-	 (concat dir group "/")
-       ;; If not, we translate dots into slashes.
-       (concat dir
-	       (gnus-encode-coding-string
-		(nnheader-replace-chars-in-string group ?. ?/)
-		nnheader-pathname-coding-system)
-	       "/")))
+     (file-name-as-directory
+      (if (file-directory-p (concat dir group))
+	  (expand-file-name group dir)
+	;; If not, we translate dots into slashes.
+	(expand-file-name (mm-encode-coding-string
+			   (nnheader-replace-chars-in-string group ?. ?/)
+			  nnheader-pathname-coding-system)
+			  dir))))
    (cond ((null file) "")
 	 ((numberp file) (int-to-string file))
 	 (t file))))
@@ -721,7 +755,7 @@
       (and (listp form) (eq (car form) 'lambda))))
 
 (defun nnheader-concat (dir &rest files)
-  "Concat DIR as directory to FILE."
+  "Concat DIR as directory to FILES."
   (apply 'concat (file-name-as-directory dir) files))
 
 (defun nnheader-ms-strip-cr ()
@@ -770,45 +804,26 @@
 (defvar nnheader-file-coding-system 'raw-text
   "Coding system used in file backends of Gnus.")
 
-;; 1997/5/4 by MORIOKA Tomohiko <morioka@jaist.ac.jp>
-(defvar nnheader-file-coding-system nil
-  "Coding system used in file backends of Gnus.")
-
 (defun nnheader-insert-file-contents (filename &optional visit beg end replace)
   "Like `insert-file-contents', q.v., but only reads in the file.
 A buffer may be modified in several ways after reading into the buffer due
 to advanced Emacs features, such as file-name-handlers, format decoding,
 find-file-hooks, etc.
   This function ensures that none of these modifications will take place."
-  (let ((format-alist nil)
-	(auto-mode-alist (nnheader-auto-mode-alist))
-	(default-major-mode 'fundamental-mode)
-	(enable-local-variables nil)
-        (after-insert-file-functions nil)
-	(find-file-hooks nil)
-	(coding-system-for-read nnheader-file-coding-system))
-    (insert-file-contents filename visit beg end replace)))
+  (let ((coding-system-for-read nnheader-file-coding-system))
+    (mm-insert-file-contents filename visit beg end replace)))
 
 (defun nnheader-find-file-noselect (&rest args)
   (let ((format-alist nil)
-	(auto-mode-alist (nnheader-auto-mode-alist))
+	(auto-mode-alist (mm-auto-mode-alist))
 	(default-major-mode 'fundamental-mode)
 	(enable-local-variables nil)
         (after-insert-file-functions nil)
+	(enable-local-eval nil)
 	(find-file-hooks nil)
 	(coding-system-for-read nnheader-file-coding-system))
     (apply 'find-file-noselect args)))
 
-(defun nnheader-auto-mode-alist ()
-  "Return an `auto-mode-alist' with only the .gz (etc) thingies."
-  (let ((alist auto-mode-alist)
-	out)
-    (while alist
-      (when (listp (cdar alist))
-	(push (car alist) out))
-      (pop alist))
-    (nreverse out)))
-
 (defun nnheader-directory-regular-files (dir)
   "Return a list of all regular files in DIR."
   (let ((files (directory-files dir t))
@@ -833,8 +848,6 @@
   `(let ((new (generate-new-buffer " *nnheader replace*"))
 	 (cur (current-buffer))
 	 (start (point-min)))
-     (set-buffer new)
-     (buffer-disable-undo (current-buffer))
      (set-buffer cur)
      (goto-char (point-min))
      (while (,(if regexp 're-search-forward 'search-forward)
@@ -852,22 +865,22 @@
      (set-buffer cur)))
 
 (defun nnheader-replace-string (from to)
-  "Do a fast replacement of FROM to TO from point to point-max."
+  "Do a fast replacement of FROM to TO from point to `point-max'."
   (nnheader-skeleton-replace from to))
 
 (defun nnheader-replace-regexp (from to)
-  "Do a fast regexp replacement of FROM to TO from point to point-max."
+  "Do a fast regexp replacement of FROM to TO from point to `point-max'."
   (nnheader-skeleton-replace from to t))
 
 (defun nnheader-strip-cr ()
   "Strip all \r's from the current buffer."
   (nnheader-skeleton-replace "\r"))
 
-(fset 'nnheader-run-at-time 'run-at-time)
-(fset 'nnheader-cancel-timer 'cancel-timer)
-(fset 'nnheader-cancel-function-timers 'cancel-function-timers)
+(defalias 'nnheader-run-at-time 'run-at-time)
+(defalias 'nnheader-cancel-timer 'cancel-timer)
+(defalias 'nnheader-cancel-function-timers 'cancel-function-timers)
 
-(when (string-match "XEmacs\\|Lucid" emacs-version)
+(when (string-match "XEmacs" emacs-version)
   (require 'nnheaderxm))
 
 (run-hooks 'nnheader-load-hook)
--- a/lisp/gnus/nnkiboze.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnkiboze.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnkiboze.el --- select virtual news access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999,.2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -136,7 +138,7 @@
   ;; Remove NOV lines of articles that are marked as read.
   (when (and (file-exists-p (nnkiboze-nov-file-name))
 	     nnkiboze-remove-read-articles)
-    (nnheader-temp-write (nnkiboze-nov-file-name)
+    (with-temp-file (nnkiboze-nov-file-name)
       (let ((cur (current-buffer)))
 	(nnheader-insert-file-contents (nnkiboze-nov-file-name))
 	(goto-char (point-min))
@@ -155,15 +157,15 @@
 (deffoo nnkiboze-request-delete-group (group &optional force server)
   (nnkiboze-possibly-change-group group)
   (when force
-     (let ((files (nconc
-		   (nnkiboze-score-file group)
-		   (list (nnkiboze-nov-file-name)
-			 (nnkiboze-nov-file-name ".newsrc")))))
-       (while files
-	 (and (file-exists-p (car files))
-	      (file-writable-p (car files))
-	      (delete-file (car files)))
-	 (setq files (cdr files)))))
+    (let ((files (nconc
+		  (nnkiboze-score-file group)
+		  (list (nnkiboze-nov-file-name)
+			(nnkiboze-nov-file-name ".newsrc")))))
+      (while files
+	(and (file-exists-p (car files))
+	     (file-writable-p (car files))
+	     (delete-file (car files)))
+	(setq files (cdr files)))))
   (setq nnkiboze-current-group nil)
   t)
 
@@ -184,6 +186,7 @@
 Finds out what articles are to be part of the nnkiboze groups."
   (interactive)
   (let ((nnmail-spool-file nil)
+	(mail-sources nil)
 	(gnus-use-dribble-file nil)
 	(gnus-read-active-file t)
 	(gnus-expert-user t))
@@ -209,7 +212,7 @@
 
 (defun nnkiboze-generate-group (group)
   (let* ((info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
-	 (newsrc-file (concat nnkiboze-directory 
+	 (newsrc-file (concat nnkiboze-directory
                               (nnheader-translate-file-chars
                                (concat group ".newsrc"))))
 	 (nov-file (concat nnkiboze-directory
@@ -230,7 +233,7 @@
     ;; Load the kiboze newsrc file for this group.
     (when (file-exists-p newsrc-file)
       (load newsrc-file))
-    (nnheader-temp-write nov-file
+    (with-temp-file nov-file
       (when (file-exists-p nov-file)
 	(insert-file-contents nov-file))
       (setq nov-buffer (current-buffer))
@@ -287,7 +290,7 @@
 					   (car ginfo)))
 				  0))
 			   (progn
-			     (ignore-errors 
+			     (ignore-errors
 			       (gnus-group-select-group nil))
 			     (eq major-mode 'gnus-summary-mode)))
 		  ;; We are now in the group where we want to be.
@@ -318,7 +321,7 @@
 	(gnus-message 3 "nnkiboze: Checking %s...done" (caar newsrc))
 	(setq newsrc (cdr newsrc))))
     ;; We save the kiboze newsrc for this group.
-    (nnheader-temp-write newsrc-file
+    (with-temp-file newsrc-file
       (insert "(setq nnkiboze-newsrc '")
       (gnus-prin1 nnkiboze-newsrc)
       (insert ")\n")))
--- a/lisp/gnus/nnlistserv.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnlistserv.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnlistserv.el --- retrieving articles via web mailing list archives
-;; Copyright (C) 1997,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news, mail
@@ -31,8 +32,7 @@
 (eval-when-compile (require 'cl))
 
 (require 'nnoo)
-(eval-when-compile (ignore-errors (require 'nnweb)))
-(eval '(require 'nnweb))
+(require 'nnweb)
 
 (nnoo-declare nnlistserv
   nnweb)
@@ -46,15 +46,15 @@
   nnweb-type)
 
 (defvoo nnlistserv-type-definition
-  '((kk
-     (article . nnlistserv-kk-wash-article)
-     (map . nnlistserv-kk-create-mapping)
-     (search . nnlistserv-kk-search)
-     (address . "http://www.itk.ntnu.no/ansatte/Andresen_Trond/kk-f/%s/")
-     (pages "fra160396" "fra160796" "fra061196" "fra160197"
-	    "fra090997" "fra040797" "fra130397" "nye")
-     (index . "date.html")
-     (identifier . nnlistserv-kk-identity)))
+    '((kk
+       (article . nnlistserv-kk-wash-article)
+       (map . nnlistserv-kk-create-mapping)
+       (search . nnlistserv-kk-search)
+       (address . "http://www.itk.ntnu.no/ansatte/Andresen_Trond/kk-f/%s/")
+       (pages "fra160396" "fra160796" "fra061196" "fra160197"
+	      "fra090997" "fra040797" "fra130397" "nye")
+       (index . "date.html")
+       (identifier . nnlistserv-kk-identity)))
   "Type-definition alist."
   nnweb-type-definition)
 
@@ -112,8 +112,7 @@
 		 nil 0 0 url))
 	       map)
 	      (nnweb-set-hashtb (cadar map) (car map))
-	      (nnheader-message 5 "%s %s %s" (cdr active) (point) pages)
-	      ))))
+	      (nnheader-message 5 "%s %s %s" (cdr active) (point) pages)))))
       ;; Return the articles in the right order.
       (setq nnweb-articles
 	    (sort (nconc nnweb-articles map) 'car-less-than-car)))))
@@ -142,7 +141,7 @@
 
 (defun nnlistserv-kk-search (search)
   (url-insert-file-contents
-   (concat (format (nnweb-definition 'address) search) 
+   (concat (format (nnweb-definition 'address) search)
 	   (nnweb-definition 'index)))
   t)
 
--- a/lisp/gnus/nnmail.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnmail.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news, mail
@@ -28,15 +29,15 @@
 (eval-when-compile (require 'cl))
 
 (require 'nnheader)
-(require 'timezone)
 (require 'message)
 (require 'custom)
 (require 'gnus-util)
+(require 'mail-source)
+(require 'mm-util)
 
 (eval-and-compile
   (autoload 'gnus-error "gnus-util")
-  (autoload 'gnus-buffer-live-p "gnus-util")
-  (autoload 'gnus-encode-coding-string "gnus-ems"))
+  (autoload 'gnus-buffer-live-p "gnus-util"))
 
 (defgroup nnmail nil
   "Reading mail with Gnus."
@@ -166,51 +167,39 @@
   :type '(choice (const :tag "nnmail-expiry-wait" nil)
 		 (function :format "%v" nnmail-)))
 
+(defcustom nnmail-expiry-target 'delete
+  "*Variable that says where expired messages should end up.
+The default value is `delete' (which says to delete the messages),
+but it can also be a string or a function.  If it is a string, expired
+messages end up in that group.  If it is a function, the function is
+called in a buffer narrowed to the message in question.  The function
+receives one argument, the name of the group the message comes from.
+The return value should be `delete' or a group name (a string)."
+    :group 'nnmail-expire
+    :type '(choice (const delete)
+		   (function :format "%v" nnmail-)
+		   string))
+
 (defcustom nnmail-cache-accepted-message-ids nil
   "If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache."
   :group 'nnmail
   :type 'boolean)
 
-(defcustom nnmail-spool-file
-  (or (getenv "MAIL")
-      (concat "/usr/spool/mail/" (user-login-name)))
+(defcustom nnmail-spool-file '((file))
   "*Where the mail backends will look for incoming mail.
-This variable is \"/usr/spool/mail/$user\" by default.
-If this variable is nil, no mail backends will read incoming mail.
-If this variable is a list, all files mentioned in this list will be
-used as incoming mailboxes.
-If this variable is a directory (i. e., it's name ends with a \"/\"),
-treat all files in that directory as incoming spool files."
+This variable is a list of mail source specifiers.
+This variable is obsolete; `mail-sources' should be used instead."
   :group 'nnmail-files
-  :type '(choice (file :tag "File")
-		 (repeat :tag "Files" file)))
+  :type 'sexp)
 
-(defcustom nnmail-crash-box "~/.gnus-crash-box"
-  "File where Gnus will store mail while processing it."
-  :group 'nnmail-files
-  :type 'file)
-
-(defcustom nnmail-use-procmail nil
-  "*If non-nil, the mail backends will look in `nnmail-procmail-directory' for spool files.
-The file(s) in `nnmail-spool-file' will also be read."
+(defcustom nnmail-resplit-incoming nil
+  "*If non-nil, re-split incoming procmail sorted mail."
   :group 'nnmail-procmail
   :type 'boolean)
 
-(defcustom nnmail-procmail-directory "~/incoming/"
-  "*When using procmail (and the like), incoming mail is put in this directory.
-The Gnus mail backends will read the mail from this directory."
-  :group 'nnmail-procmail
-  :type 'directory)
-
-(defcustom nnmail-procmail-suffix "\\.spool"
-  "*Suffix of files created by procmail (and the like).
-This variable might be a suffix-regexp to match the suffixes of
-several files - eg. \".spool[0-9]*\"."
-  :group 'nnmail-procmail
-  :type 'regexp)
-
-(defcustom nnmail-resplit-incoming nil
-  "*If non-nil, re-split incoming procmail sorted mail."
+(defcustom nnmail-scan-directory-mail-source-once nil
+  "*If non-nil, scan all incoming procmail sorted mails once.
+It scans low-level sorted spools even when not required."
   :group 'nnmail-procmail
   :type 'boolean)
 
@@ -232,22 +221,6 @@
 		(function-item copy-file)
 		(function :tag "Other")))
 
-(defcustom nnmail-movemail-program "movemail"
-  "*A command to be executed to move mail from the inbox.
-The default is \"movemail\".
-
-This can also be a function.  In that case, the function will be
-called with two parameters -- the name of the INBOX file, and the file
-to be moved to."
-  :group 'nnmail-files
-  :group 'nnmail-retrieve
-  :type 'string)
-
-(defcustom nnmail-pop-password-required nil
-  "*Non-nil if a password is required when reading mail using POP."
-  :group 'nnmail-retrieve
-  :type 'boolean)
-
 (defcustom nnmail-read-incoming-hook
   (if (eq system-type 'windows-nt)
       '(nnheader-ms-strip-cr)
@@ -262,9 +235,9 @@
 Eg.
 
 \(add-hook 'nnmail-read-incoming-hook
-	   (lambda ()
-	     (start-process \"mailsend\" nil
-			    \"/local/bin/mailsend\" \"read\" \"mbox\")))
+          (lambda ()
+            (call-process \"/local/bin/mailsend\" nil nil nil
+                          \"read\" nnmail-spool-file)))
 
 If you have xwatch running, this will alert it that mail has been
 read.
@@ -280,7 +253,6 @@
   :group 'nnmail-prepare
   :type 'hook)
 
-;; Suggested by Erik Selberg <speed@cs.washington.edu>.
 (defcustom nnmail-prepare-incoming-hook nil
   "Hook called before treating incoming mail.
 The hook is run in a buffer with all the new, incoming mail."
@@ -325,15 +297,6 @@
   :group 'nnmail-split
   :type 'hook)
 
-;; Suggested by Mejia Pablo J <pjm9806@usl.edu>.
-(defcustom nnmail-tmp-directory nil
-  "*If non-nil, use this directory for temporary storage.
-Used when reading incoming mail."
-  :group 'nnmail-files
-  :group 'nnmail-retrieve
-  :type '(choice (const :tag "default" nil)
-		 (directory :format "%v")))
-
 (defcustom nnmail-large-newsgroup 50
   "*The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
@@ -350,8 +313,12 @@
 
 GROUP: Mail will be stored in GROUP (a string).
 
-\(FIELD VALUE SPLIT): If the message field FIELD (a regexp) contains
-  VALUE (a regexp), store the messages as specified by SPLIT.
+\(FIELD VALUE [- RESTRICT [- RESTRICT [...]]] SPLIT): If the message
+  field FIELD (a regexp) contains VALUE (a regexp), store the messages 
+  as specified by SPLIT.  If RESTRICT (a regexp) matches some string
+  after FIELD and before the end of the matched VALUE, return NIL,
+  otherwise process SPLIT.  Multiple RESTRICTs add up, further
+  restricting the possibility of processing SPLIT.
 
 \(| SPLIT...): Process each SPLIT expression until one of them matches.
   A SPLIT expression is said to match if it will cause the mail
@@ -363,6 +330,10 @@
   the buffer containing the message headers.  The return value FUNCTION
   should be a split, which is then recursively processed.
 
+\(! FUNCTION SPLIT): Call FUNCTION with the result of SPLIT.  The
+  return value FUNCTION should be a split, which is then recursively
+  processed.
+
 FIELD must match a complete field name.  VALUE must match a complete
 word according to the `nnmail-split-fancy-syntax-table' syntax table.
 You can use \".*\" in the regexps to match partial field names or words.
@@ -390,6 +361,13 @@
 	     ;; Other mailing lists...
 	     (any \"procmail@informatik\\\\.rwth-aachen\\\\.de\" \"procmail.list\")
 	     (any \"SmartList@informatik\\\\.rwth-aachen\\\\.de\" \"SmartList.list\")
+             ;; Both lists below have the same suffix, so prevent
+             ;; cross-posting to mkpkg.list of messages posted only to 
+             ;; the bugs- list, but allow cross-posting when the
+             ;; message was really cross-posted.
+             (any \"bugs-mypackage@somewhere\" \"mypkg.bugs\")
+             (any \"mypackage@somewhere\" - \"bugs-mypackage\" \"mypkg.list\")
+             ;; 
 	     ;; People...
 	     (any \"larsi@ifi\\\\.uio\\\\.no\" \"people.Lars Magne Ingebrigtsen\"))
 	  ;; Unmatched mail goes to the catch all group.
@@ -409,12 +387,6 @@
   :group 'nnmail-split
   :type '(repeat (cons :format "%v" symbol regexp)))
 
-(defcustom nnmail-delete-incoming t
-  "*If non-nil, the mail backends will delete incoming files after
-splitting."
-  :group 'nnmail-retrieve
-  :type 'boolean)
-
 (defcustom nnmail-message-id-cache-length 1000
   "*The approximate number of Message-IDs nnmail will keep in its cache.
 If this variable is nil, no checking on duplicate messages will be
@@ -431,7 +403,7 @@
 
 (defcustom nnmail-treat-duplicates 'warn
   "*If non-nil, nnmail keep a cache of Message-IDs to discover mail duplicates.
-Three values are legal: nil, which means that nnmail is not to keep a
+Three values are valid: nil, which means that nnmail is not to keep a
 Message-ID cache; `warn', which means that nnmail should insert extra
 headers to warn the user about the duplication (this is the default);
 and `delete', which means that nnmail will delete duplicated mails.
@@ -444,16 +416,21 @@
 		 (const warn)
 		 (const delete)))
 
+(defcustom nnmail-extra-headers nil
+  "*Extra headers to parse."
+  :group 'nnmail
+  :type '(repeat symbol))
+
+(defcustom nnmail-split-header-length-limit 512
+  "Header lines longer than this limit are excluded from the split function."
+  :group 'nnmail
+  :type 'integer)
+
 ;;; Internal variables.
 
 (defvar nnmail-split-history nil
   "List of group/article elements that say where the previous split put messages.")
 
-(defvar nnmail-current-spool nil)
-
-(defvar nnmail-pop-password nil
-  "*Password to use when reading mail from a POP server, if required.")
-
 (defvar nnmail-split-fancy-syntax-table nil
   "Syntax table used by `nnmail-split-fancy'.")
 (unless (syntax-table-p nnmail-split-fancy-syntax-table)
@@ -465,11 +442,6 @@
 (defvar nnmail-prepare-save-mail-hook nil
   "Hook called before saving mail.")
 
-(defvar nnmail-moved-inboxes nil
-  "List of inboxes that have been moved.")
-
-(defvar nnmail-internal-password nil)
-
 (defvar nnmail-split-tracing nil)
 (defvar nnmail-split-trace nil)
 
@@ -486,231 +458,90 @@
 (defvar nnmail-file-coding-system 'raw-text
   "Coding system used in nnmail.")
 
-(defvar nnmail-file-coding-system nil
-  "Coding system used in nnmail.")
+(defvar nnmail-incoming-coding-system
+  mm-text-coding-system
+  "Coding system used in reading inbox")
+
+(defvar nnmail-pathname-coding-system 'binary
+  "*Coding system for pathname.")
 
 (defun nnmail-find-file (file)
   "Insert FILE in server buffer safely."
   (set-buffer nntp-server-buffer)
-  (erase-buffer)
+  (delete-region (point-min) (point-max))
   (let ((format-alist nil)
         (after-insert-file-functions nil))
     (condition-case ()
 	(let ((coding-system-for-read nnmail-file-coding-system)
-	      (file-name-coding-system 'binary)
-	      (pathname-coding-system 'binary))
+	      (auto-mode-alist (mm-auto-mode-alist))
+	      (file-name-coding-system nnmail-pathname-coding-system))
 	  (insert-file-contents file)
 	  t)
       (file-error nil))))
 
-(defvar nnmail-pathname-coding-system
-  'iso-8859-1
-  "*Coding system for pathname.")
-
 (defun nnmail-group-pathname (group dir &optional file)
   "Make pathname for GROUP."
   (concat
    (let ((dir (file-name-as-directory (expand-file-name dir))))
+     (setq group (nnheader-replace-duplicate-chars-in-string
+		  (nnheader-replace-chars-in-string group ?/ ?_)
+		  ?. ?_))
      (setq group (nnheader-translate-file-chars group))
      ;; If this directory exists, we use it directly.
-     (if (or nnmail-use-long-file-names
-	     (file-directory-p (concat dir group)))
-	 (concat dir group "/")
-       ;; If not, we translate dots into slashes.
-       (concat dir
-	       (gnus-encode-coding-string
-		(nnheader-replace-chars-in-string group ?. ?/)
-		nnmail-pathname-coding-system)
-	       "/")))
+     (file-name-as-directory
+      (if (or nnmail-use-long-file-names
+	      (file-directory-p (concat dir group)))
+	  (expand-file-name group dir)
+	;; If not, we translate dots into slashes.
+	(expand-file-name
+	 (mm-encode-coding-string
+	  (nnheader-replace-chars-in-string group ?. ?/)
+	  nnmail-pathname-coding-system)
+	 dir))))
    (or file "")))
 
-(defun nnmail-date-to-time (date)
-  "Convert DATE into time."
-  (condition-case ()
-      (let* ((d1 (timezone-parse-date date))
-	     (t1 (timezone-parse-time (aref d1 3))))
-	(apply 'encode-time
-	       (mapcar (lambda (el)
-			 (and el (string-to-number el)))
-		       (list
-			(aref t1 2) (aref t1 1) (aref t1 0)
-			(aref d1 2) (aref d1 1) (aref d1 0)
-			(number-to-string
-			 (* 60 (timezone-zone-to-minute
-                                (or (aref d1 4) (current-time-zone)))))))))
-    ;; If we get an error, then we just return a 0 time.
-    (error (list 0 0))))
-
-(defun nnmail-time-less (t1 t2)
-  "Say whether time T1 is less than time T2."
-  (or (< (car t1) (car t2))
-      (and (= (car t1) (car t2))
-	   (< (nth 1 t1) (nth 1 t2)))))
-
-(defun nnmail-days-to-time (days)
-  "Convert DAYS into time."
-  (let* ((seconds (* 1.0 days 60 60 24))
-	 (rest (expt 2 16))
-	 (ms (condition-case nil (floor (/ seconds rest))
-	       (range-error (expt 2 16)))))
-    (list ms (condition-case nil (round (- seconds (* ms rest)))
-	       (range-error (expt 2 16))))))
-
-(defun nnmail-time-since (time)
-  "Return the time since TIME, which is either an internal time or a date."
-  (when (stringp time)
-    ;; Convert date strings to internal time.
-    (setq time (nnmail-date-to-time time)))
-  (let* ((current (current-time))
-	 (rest (when (< (nth 1 current) (nth 1 time))
-		 (expt 2 16))))
-    (list (- (+ (car current) (if rest -1 0)) (car time))
-	  (- (+ (or rest 0) (nth 1 current)) (nth 1 time)))))
-
-;; Function rewritten from rmail.el.
-(defun nnmail-move-inbox (inbox)
-  "Move INBOX to `nnmail-crash-box'."
-  (if (not (file-writable-p nnmail-crash-box))
-      (gnus-error 1 "Can't write to crash box %s.  Not moving mail"
-		  nnmail-crash-box)
-    ;; If the crash box exists and is empty, we delete it.
-    (when (and (file-exists-p nnmail-crash-box)
-	       (zerop (nnheader-file-size (file-truename nnmail-crash-box))))
-      (delete-file nnmail-crash-box))
-    (let ((tofile (file-truename (expand-file-name nnmail-crash-box)))
-	  (popmail (string-match "^po:" inbox))
-	  movemail errors result)
-      (unless popmail
-	(setq inbox (file-truename (expand-file-name inbox)))
-	(setq movemail t)
-	;; On some systems, /usr/spool/mail/foo is a directory
-	;; and the actual inbox is /usr/spool/mail/foo/foo.
-	(when (file-directory-p inbox)
-	  (setq inbox (expand-file-name (user-login-name) inbox))))
-      (if (member inbox nnmail-moved-inboxes)
-	  ;; We don't try to move an already moved inbox.
-	  nil
-	(if popmail
-	    (progn
-	      (when (and nnmail-pop-password
-			 (not nnmail-internal-password))
-		(setq nnmail-internal-password nnmail-pop-password))
-	      (when (and nnmail-pop-password-required
-			 (not nnmail-internal-password))
-		(setq nnmail-internal-password
-		      (nnmail-read-passwd
-		       (format "Password for %s: "
-			       (substring inbox (+ popmail 3))))))
-	      (nnheader-message 5 "Getting mail from the post office..."))
-	  (when (or (and (file-exists-p tofile)
-			 (/= 0 (nnheader-file-size tofile)))
-		    (and (file-exists-p inbox)
-			 (/= 0 (nnheader-file-size inbox))))
-	    (nnheader-message 5 "Getting mail from %s..." inbox)))
-	;; Set TOFILE if have not already done so, and
-	;; rename or copy the file INBOX to TOFILE if and as appropriate.
-	(cond
-	 ((file-exists-p tofile)
-	  ;; The crash box exists already.
-	  t)
-	 ((and (not popmail)
-	       (not (file-exists-p inbox)))
-	  ;; There is no inbox.
-	  (setq tofile nil))
-	 (t
-	  ;; If getting from mail spool directory, use movemail to move
-	  ;; rather than just renaming, so as to interlock with the
-	  ;; mailer.
-	  (unwind-protect
-	      (save-excursion
-		(setq errors (generate-new-buffer " *nnmail loss*"))
-		(buffer-disable-undo errors)
-		(if (nnheader-functionp nnmail-movemail-program)
-		    (condition-case err
-			(progn
-			  (funcall nnmail-movemail-program inbox tofile)
-			  (setq result 0))
-		      (error
-		       (save-excursion
-			 (set-buffer errors)
-			 (insert (prin1-to-string err))
-			 (setq result 255))))
-		  (let ((default-directory "/"))
-		    (setq result
-			  (apply
-			   'call-process
-			   (append
-			    (list
-			     (expand-file-name
-			      nnmail-movemail-program exec-directory)
-			     nil errors nil inbox tofile)
-			    (when nnmail-internal-password
-			      (list nnmail-internal-password)))))))
-		(push inbox nnmail-moved-inboxes)
-		(if (and (not (buffer-modified-p errors))
-			 (zerop result))
-		    ;; No output => movemail won
-		    (progn
-		      (unless popmail
-			(when (file-exists-p tofile)
-			  (set-file-modes tofile nnmail-default-file-modes))))
-		  (set-buffer errors)
-		  ;; There may be a warning about older revisions.  We
-		  ;; ignore those.
-		  (goto-char (point-min))
-		  (if (search-forward "older revision" nil t)
-		      (progn
-			(unless popmail
-			  (when (file-exists-p tofile)
-			    (set-file-modes
-			     tofile nnmail-default-file-modes))))
-		    ;; Probably a real error.
-		    ;; We nix out the password in case the error
-		    ;; was because of a wrong password being given.
-		    (setq nnmail-internal-password nil)
-		    (subst-char-in-region (point-min) (point-max) ?\n ?\  )
-		    (goto-char (point-max))
-		    (skip-chars-backward " \t")
-		    (delete-region (point) (point-max))
-		    (goto-char (point-min))
-		    (when (looking-at "movemail: ")
-		      (delete-region (point-min) (match-end 0)))
-		    (unless (yes-or-no-p
-			     (format "movemail: %s (%d return).  Continue? "
-				     (buffer-string) result))
-		      (error "%s" (buffer-string)))
-		    (setq tofile nil)))))))
-	(nnheader-message 5 "Getting mail from %s...done" inbox)
-	(and errors
-	     (buffer-name errors)
-	     (kill-buffer errors))
-	tofile))))
-
 (defun nnmail-get-active ()
   "Returns an assoc of group names and active ranges.
 nn*-request-list should have been called before calling this function."
-  (let (group-assoc)
-    ;; Go through all groups from the active list.
-    (save-excursion
-      (set-buffer nntp-server-buffer)
-      (goto-char (point-min))
-      (while (re-search-forward
-	      "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
-	;; We create an alist with `(GROUP (LOW . HIGH))' elements.
-	(push (list (match-string 1)
-		    (cons (string-to-int (match-string 3))
-			  (string-to-int (match-string 2))))
-	      group-assoc)))
+  ;; Go through all groups from the active list.
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    (nnmail-parse-active)))
+
+(defun nnmail-parse-active ()
+  "Parse the active file in the current buffer and return an alist."
+  (goto-char (point-min))
+  (unless (re-search-forward "[\\\"]" nil t)
+    (goto-char (point-max))
+    (while (re-search-backward "[][';?()#]" nil t)
+      (insert ?\\)))
+  (goto-char (point-min))
+  (let ((buffer (current-buffer))
+	group-assoc group max min)
+    (while (not (eobp))
+      (condition-case err
+	  (progn
+	    (narrow-to-region (point) (gnus-point-at-eol))
+	    (setq group (read buffer))
+	    (unless (stringp group)
+	      (setq group (symbol-name group)))
+	    (if (and (numberp (setq max (read nntp-server-buffer)))
+		     (numberp (setq min (read nntp-server-buffer))))
+		(push (list group (cons min max))
+		      group-assoc)))
+	(error nil))
+      (widen)
+      (forward-line 1))
     group-assoc))
 
-(defvar nnmail-active-file-coding-system 'binary
+(defvar nnmail-active-file-coding-system 'raw-text
   "*Coding system for active file.")
 
 (defun nnmail-save-active (group-assoc file-name)
   "Save GROUP-ASSOC in ACTIVE-FILE."
   (let ((coding-system-for-write nnmail-active-file-coding-system))
     (when file-name
-      (nnheader-temp-write file-name
+      (with-temp-file file-name
 	(nnmail-generate-active group-assoc)))))
 
 (defun nnmail-generate-active (alist)
@@ -718,37 +549,26 @@
   (erase-buffer)
   (let (group)
     (while (setq group (pop alist))
-      (insert (format "%s %d %d y\n" (car group) (cdadr group)
-		      (caadr group))))))
+      (insert (format "%S %d %d y\n" (intern (car group)) (cdadr group)
+		      (caadr group))))
+    (goto-char (point-max))
+    (while (search-backward "\\." nil t)
+      (delete-char 1))))
 
-(defun nnmail-get-split-group (file group)
+(defun nnmail-get-split-group (file source)
   "Find out whether this FILE is to be split into GROUP only.
-If GROUP is non-nil and we are using procmail, return the group name
-only when the file is the correct procmail file.  When GROUP is nil,
-return nil if FILE is a spool file or the procmail group for which it
-is a spool.  If not using procmail, return GROUP."
-  (if (or (eq nnmail-spool-file 'procmail)
-	  nnmail-use-procmail)
-      (if (string-match (concat "^" (regexp-quote
-				     (expand-file-name
-				      (file-name-as-directory
-				       nnmail-procmail-directory)))
-				"\\([^/]*\\)"
-				nnmail-procmail-suffix "$")
-			(expand-file-name file))
-	  (let ((procmail-group (substring (expand-file-name file)
-					   (match-beginning 1)
-					   (match-end 1))))
-	    (if group
-		(if (string-equal group procmail-group)
-		    group
-		  nil)
-	      procmail-group))
-	nil)
-    group))
+If SOURCE is a directory spec, try to return the group name component."
+  (if (eq (car source) 'directory)
+      (let ((file (file-name-nondirectory file)))
+	(mail-source-bind (directory source)
+	  (if (string-match (concat (regexp-quote suffix) "$") file)
+	      (substring file 0 (match-beginning 0))
+	    nil)))
+    nil))
 
 (defun nnmail-process-babyl-mail-format (func artnum-func)
   (let ((case-fold-search t)
+	(count 0)
 	start message-id content-length do-search end)
     (while (not (eobp))
       (goto-char (point-min))
@@ -820,8 +640,10 @@
 	  (narrow-to-region start (point))
 	  (goto-char (point-min))
 	  (nnmail-check-duplication message-id func artnum-func)
+	  (incf count)
 	  (setq end (point-max))))
-      (goto-char end))))
+      (goto-char end))
+    count))
 
 (defsubst nnmail-search-unix-mail-delim ()
   "Put point at the beginning of the next Unix mbox message."
@@ -842,7 +664,7 @@
 	  (when (and (or (bobp)
 			 (save-excursion
 			   (forward-line -1)
-			   (= (following-char) ?\n)))
+			   (eq (char-after) ?\n)))
 		     (save-excursion
 		       (forward-line 1)
 		       (while (looking-at ">From \\|From ")
@@ -871,7 +693,7 @@
 	  (when (and (or (bobp)
 			 (save-excursion
 			   (forward-line -1)
-			   (= (following-char) ?\n)))
+			   (eq (char-after) ?\n)))
 		     (save-excursion
 		       (forward-line 1)
 		       (while (looking-at ">From \\|From ")
@@ -883,14 +705,13 @@
 
 (defun nnmail-process-unix-mail-format (func artnum-func)
   (let ((case-fold-search t)
+	(count 0)
 	start message-id content-length end skip head-end)
     (goto-char (point-min))
     (if (not (and (re-search-forward "^From " nil t)
 		  (goto-char (match-beginning 0))))
 	;; Possibly wrong format?
-	(progn
-	  (pop-to-buffer (nnheader-find-file-noselect nnmail-current-spool))
-	  (error "Error, unknown mail format! (Possibly corrupted.)"))
+	(error "Error, unknown mail format! (Possibly corrupted.)")
       ;; Carry on until the bitter end.
       (while (not (eobp))
 	(setq start (point)
@@ -963,21 +784,22 @@
 	  (save-restriction
 	    (narrow-to-region start (point))
 	    (goto-char (point-min))
+	    (incf count)
 	    (nnmail-check-duplication message-id func artnum-func)
 	    (setq end (point-max))))
-	(goto-char end)))))
+	(goto-char end)))
+    count))
 
 (defun nnmail-process-mmdf-mail-format (func artnum-func)
   (let ((delim "^\^A\^A\^A\^A$")
 	(case-fold-search t)
+	(count 0)
 	start message-id end)
     (goto-char (point-min))
     (if (not (and (re-search-forward delim nil t)
 		  (forward-line 1)))
 	;; Possibly wrong format?
-	(progn
-	  (pop-to-buffer (nnheader-find-file-noselect nnmail-current-spool))
-	  (error "Error, unknown mail format! (Possibly corrupted.)"))
+	(error "Error, unknown mail format! (Possibly corrupted.)")
       ;; Carry on until the bitter end.
       (while (not (eobp))
 	(setq start (point))
@@ -1015,10 +837,47 @@
 	  (save-restriction
 	    (narrow-to-region start (point))
 	    (goto-char (point-min))
+	    (incf count)
 	    (nnmail-check-duplication message-id func artnum-func)
 	    (setq end (point-max))))
 	(goto-char end)
-	(forward-line 2)))))
+	(forward-line 2)))
+    count))
+
+(defun nnmail-process-maildir-mail-format (func artnum-func)
+  ;; In a maildir, every file contains exactly one mail.
+  (let ((case-fold-search t)
+	message-id)
+    (goto-char (point-min))
+    ;; Find the end of the head.
+    (narrow-to-region
+     (point-min)
+     (if (search-forward "\n\n" nil t)
+	 (1- (point))
+       ;; This will never happen, but just to be on the safe side --
+       ;; if there is no head-body delimiter, we search a bit manually.
+       (while (and (looking-at "From \\|[^ \t]+:")
+		   (not (eobp)))
+	 (forward-line 1))
+       (point)))
+    ;; Find the Message-ID header.
+    (goto-char (point-min))
+    (if (re-search-forward "^Message-ID:[ \t]*\\(<[^>]+>\\)" nil t)
+	(setq message-id (match-string 1))
+      ;; There is no Message-ID here, so we create one.
+      (save-excursion
+	(when (re-search-backward "^Message-ID[ \t]*:" nil t)
+	  (beginning-of-line)
+	  (insert "Original-")))
+      (forward-line 1)
+      (insert "Message-ID: " (setq message-id (nnmail-message-id)) "\n"))
+    (run-hooks 'nnmail-prepare-incoming-header-hook)
+    ;; Allow the backend to save the article.
+    (widen)
+    (save-excursion
+      (goto-char (point-min))
+      (nnmail-check-duplication message-id func artnum-func))
+    1))
 
 (defun nnmail-split-incoming (incoming func &optional exit-func
 				       group artnum-func)
@@ -1027,33 +886,35 @@
   (let (;; If this is a group-specific split, we bind the split
 	;; methods to just this group.
 	(nnmail-split-methods (if (and group
-				       (or (eq nnmail-spool-file 'procmail)
-					   nnmail-use-procmail)
 				       (not nnmail-resplit-incoming))
 				  (list (list group ""))
 				nnmail-split-methods)))
     (save-excursion
       ;; Insert the incoming file.
       (set-buffer (get-buffer-create " *nnmail incoming*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (nnheader-insert-file-contents incoming)
-      (unless (zerop (buffer-size))
-	(goto-char (point-min))
-	(save-excursion (run-hooks 'nnmail-prepare-incoming-hook))
-	;; Handle both babyl, MMDF and unix mail formats, since movemail will
-	;; use the former when fetching from a mailbox, the latter when
-	;; fetching from a file.
-	(cond ((or (looking-at "\^L")
-		   (looking-at "BABYL OPTIONS:"))
-	       (nnmail-process-babyl-mail-format func artnum-func))
-	      ((looking-at "\^A\^A\^A\^A")
-	       (nnmail-process-mmdf-mail-format func artnum-func))
-	      (t
-	       (nnmail-process-unix-mail-format func artnum-func))))
-      (when exit-func
-	(funcall exit-func))
-      (kill-buffer (current-buffer)))))
+      (let ((coding-system-for-read nnmail-incoming-coding-system))
+	(mm-insert-file-contents incoming))
+      (prog1
+	  (if (zerop (buffer-size))
+	      0
+	    (goto-char (point-min))
+	    (save-excursion (run-hooks 'nnmail-prepare-incoming-hook))
+	    ;; Handle both babyl, MMDF and unix mail formats, since
+	    ;; movemail will use the former when fetching from a
+	    ;; mailbox, the latter when fetching from a file.
+	    (cond ((or (looking-at "\^L")
+		       (looking-at "BABYL OPTIONS:"))
+		   (nnmail-process-babyl-mail-format func artnum-func))
+		  ((looking-at "\^A\^A\^A\^A")
+		   (nnmail-process-mmdf-mail-format func artnum-func))
+		  ((looking-at "Return-Path:")
+		   (nnmail-process-maildir-mail-format func artnum-func))
+		  (t
+		   (nnmail-process-unix-mail-format func artnum-func))))
+	(when exit-func
+	  (funcall exit-func))
+	(kill-buffer (current-buffer))))))
 
 (defun nnmail-article-group (func &optional trace)
   "Look at the headers and return an alist of groups that match.
@@ -1061,7 +922,7 @@
   (let ((methods nnmail-split-methods)
 	(obuf (current-buffer))
 	(beg (point-min))
-	end group-art method regrepp)
+	end group-art method grp)
     (if (and (sequencep methods)
 	     (= (length methods) 1))
 	;; If there is only just one group to put everything in, we
@@ -1087,10 +948,10 @@
 	;; existence to process.
 	(goto-char (point-min))
 	(while (not (eobp))
-	  (end-of-line)
-	  (if (> (current-column) 1024)
-	      (gnus-delete-line)
-	    (forward-line 1)))
+	  (unless (< (move-to-column nnmail-split-header-length-limit)
+		     nnmail-split-header-length-limit)
+	    (delete-region (point) (progn (end-of-line) (point))))
+	  (forward-line 1))
 	;; Allow washing.
 	(goto-char (point-min))
 	(run-hooks 'nnmail-split-hook)
@@ -1107,7 +968,7 @@
 			   '("bogus"))
 		     (error
 		      (nnheader-message 5
-		       "Error in `nnmail-split-methods'; using `bogus' mail group")
+					"Error in `nnmail-split-methods'; using `bogus' mail group")
 		      (sit-for 1)
 		      '("bogus")))))
 	      (setq split (gnus-remove-duplicates split))
@@ -1128,25 +989,24 @@
 			  (not group-art)))
 	    (goto-char (point-max))
 	    (setq method (pop methods)
-		  regrepp nil)
+		  grp (car method))
 	    (if (or methods
 		    (not (equal "" (nth 1 method))))
 		(when (and
 		       (ignore-errors
 			 (if (stringp (nth 1 method))
-			     (progn
-			       (setq regrepp
-				     (string-match "\\\\[0-9&]" (car method)))
-			       (re-search-backward (cadr method) nil t))
+			     (let ((expand (string-match "\\\\[0-9&]" grp))
+				   (pos (re-search-backward (cadr method)
+							    nil t)))
+			       (and expand
+				    (setq grp (nnmail-expand-newtext grp)))
+			       pos)
 			   ;; Function to say whether this is a match.
-			   (funcall (nth 1 method) (car method))))
+			   (funcall (nth 1 method) grp)))
 		       ;; Don't enter the article into the same
 		       ;; group twice.
-		       (not (assoc (car method) group-art)))
-		  (push (cons (if regrepp
-				  (nnmail-expand-newtext (car method))
-				(car method))
-			      (funcall func (car method)))
+		       (not (assoc grp group-art)))
+		  (push (cons grp (funcall func grp))
 			group-art))
 	      ;; This is the final group, which is used as a
 	      ;; catch-all.
@@ -1183,35 +1043,39 @@
   (let (lines chars)
     (save-excursion
       (goto-char (point-min))
-      (when (search-forward "\n\n" nil t)
-	(setq chars (- (point-max) (point)))
-	(setq lines (count-lines (point) (point-max)))
-	(forward-char -1)
-	(save-excursion
-	  (when (re-search-backward "^Lines: " nil t)
-	    (delete-region (point) (progn (forward-line 1) (point)))))
-	(beginning-of-line)
-	(insert (format "Lines: %d\n" (max lines 0)))
-	chars))))
+      (unless (search-forward "\n\n" nil t) 
+	(goto-char (point-max))
+	(insert "\n"))
+      (setq chars (- (point-max) (point)))
+      (setq lines (count-lines (point) (point-max)))
+      (forward-char -1)
+      (save-excursion
+	(when (re-search-backward "^Lines: " nil t)
+	  (delete-region (point) (progn (forward-line 1) (point)))))
+      (beginning-of-line)
+      (insert (format "Lines: %d\n" (max lines 0)))
+      chars)))
 
 (defun nnmail-insert-xref (group-alist)
   "Insert an Xref line based on the (group . article) alist."
   (save-excursion
     (goto-char (point-min))
-    (when (search-forward "\n\n" nil t)
-      (forward-char -1)
-      (when (re-search-backward "^Xref: " nil t)
-	(delete-region (match-beginning 0)
-		       (progn (forward-line 1) (point))))
-      (insert (format "Xref: %s" (system-name)))
-      (while group-alist
-	(insert (format " %s:%d"
-			(gnus-encode-coding-string
-			 (caar group-alist)
-			 nnmail-pathname-coding-system)
-			(cdar group-alist)))
-	(setq group-alist (cdr group-alist)))
-      (insert "\n"))))
+    (unless (search-forward "\n\n" nil t)
+      (goto-char (point-max))
+      (insert "\n"))
+    (forward-char -1)
+    (when (re-search-backward "^Xref: " nil t)
+      (delete-region (match-beginning 0)
+		     (progn (forward-line 1) (point))))
+    (insert (format "Xref: %s" (system-name)))
+    (while group-alist
+      (insert (format " %s:%d"
+		      (mm-encode-coding-string
+		       (caar group-alist)
+		       nnmail-pathname-coding-system)
+		      (cdar group-alist)))
+      (setq group-alist (cdr group-alist)))
+    (insert "\n")))
 
 ;;; Message washing functions
 
@@ -1224,11 +1088,11 @@
 (defun nnmail-remove-list-identifiers ()
   "Remove list identifiers from Subject headers."
   (let ((regexp (if (stringp nnmail-list-identifiers) nnmail-list-identifiers
-		  (mapconcat 'identity nnmail-list-identifiers "\\|"))))
+		  (mapconcat 'identity nnmail-list-identifiers " *\\|"))))
     (when regexp
       (goto-char (point-min))
       (when (re-search-forward
-	     (concat "^Subject: +\\(Re: +\\)?\\(" regexp "\\) *")
+	     (concat "^Subject: +\\(Re: +\\)?\\(" regexp " *\\)")
 	     nil t)
 	(delete-region (match-beginning 2) (match-end 0))))))
 
@@ -1236,10 +1100,22 @@
   "Translate TAB characters into SPACE characters."
   (subst-char-in-region (point-min) (point-max) ?\t ?  t))
 
-;;; Utility functions
+(defun nnmail-fix-eudora-headers ()
+  "Eudora has a broken References line, but an OK In-Reply-To."
+  (goto-char (point-min))
+  (when (re-search-forward "^X-Mailer:.*Eudora" nil t)
+    (goto-char (point-min))
+    (when (re-search-forward "^References:" nil t)
+      (beginning-of-line)
+      (insert "X-Gnus-Broken-Eudora-"))
+    (goto-char (point-min))
+    (when (re-search-forward "^In-Reply-To:[^\n]+\\(\n[ \t]+\\)" nil t)
+      (replace-match "" t t nil 1))))
 
+(custom-add-option 'nnmail-prepare-incoming-header-hook
+		   'nnmail-fix-eudora-headers)
 
-;; Written by Per Abrahamsen <amanda@iesd.auc.dk>.
+;;; Utility functions
 
 (defun nnmail-split-fancy ()
   "Fancy splitting method.
@@ -1290,49 +1166,78 @@
      ((eq (car split) ':)
       (nnmail-split-it (save-excursion (eval (cdr split)))))
 
+     ;; Builtin ! operation.
+     ((eq (car split) '!)
+      (funcall (cadr split) (nnmail-split-it (caddr split))))
+
      ;; Check the cache for the regexp for this split.
      ((setq cached-pair (assq split nnmail-split-cache))
-      (goto-char (point-max))
-      ;; FIX FIX FIX problem with re-search-backward is that if you have
-      ;; a split: (from "foo-\\(bar\\|baz\\)@gnus.org "mail.foo.\\1")
-      ;; and someone mails a message with 'To: foo-bar@gnus.org' and
-      ;; 'CC: foo-baz@gnus.org', we'll pick 'mail.foo.baz' as the group
-      ;; if the cc line is a later header, even though the other choice
-      ;; is probably better.  Also, this routine won't do a crosspost
-      ;; when there are two different matches.
-      ;; I guess you could just make this more determined, and it could
-      ;; look for still more matches prior to this one, and recurse
-      ;; on each of the multiple matches hit.  Of course, then you'd
-      ;; want to make sure that nnmail-article-group or nnmail-split-fancy
-      ;; removed duplicates, since there might be more of those.
-      ;; I guess we could also remove duplicates in the & split case, since
-      ;; that's the only thing that can introduce them.
-      (when (re-search-backward (cdr cached-pair) nil t)
-	(when nnmail-split-tracing
-	  (push (cdr cached-pair) nnmail-split-trace))
-	;; Someone might want to do a \N sub on this match, so get the
-	;; correct match positions.
-	(goto-char (match-end 0))
-	(let ((value (nth 1 split)))
-	  (re-search-backward (if (symbolp value)
-				  (cdr (assq value nnmail-split-abbrev-alist))
-				value)
-			      (match-end 1)))
-	(nnmail-split-it (nth 2 split))))
+      (let (split-result
+	    (end-point (point-max))
+	    (value (nth 1 split)))
+	(if (symbolp value)
+	    (setq value (cdr (assq value nnmail-split-abbrev-alist))))
+	(while (and (goto-char end-point)
+		    (re-search-backward (cdr cached-pair) nil t))
+	  (when nnmail-split-tracing
+	    (push (cdr cached-pair) nnmail-split-trace))
+	  (let ((split-rest (cddr split))
+		(end (match-end 0))
+		;; The searched regexp is \(\(FIELD\).*\)\(VALUE\).  So,
+		;; start-of-value is the the point just before the
+		;; beginning of the value, whereas after-header-name is
+		;; the point just after the field name.
+		(start-of-value (match-end 1))
+		(after-header-name (match-end 2)))
+	    ;; Start the next search just before the beginning of the
+	    ;; VALUE match.
+	    (setq end-point (1- start-of-value))
+	    ;; Handle - RESTRICTs
+	    (while (eq (car split-rest) '-)
+	      ;; RESTRICT must start after-header-name and
+	      ;; end after start-of-value, so that, for
+	      ;; (any "foo" - "x-foo" "foo.list")
+	      ;; we do not exclude foo.list just because
+	      ;; the header is: ``To: x-foo, foo''
+	      (goto-char end)
+	      (if (and (re-search-backward (cadr split-rest)
+					   after-header-name t)
+		       (> (match-end 0) start-of-value))
+		  (setq split-rest nil)
+		(setq split-rest (cddr split-rest))))
+	    (when split-rest
+	      (goto-char end)
+	      (let ((value (nth 1 split)))
+		(if (symbolp value)
+		    (setq value (cdr (assq value nnmail-split-abbrev-alist))))
+		;; Someone might want to do a \N sub on this match, so get the
+		;; correct match positions.
+		(re-search-backward value start-of-value))
+	      (dolist (sp (nnmail-split-it (car split-rest)))
+		(unless (memq sp split-result)
+		  (push sp split-result))))))
+	split-result))
 
      ;; Not in cache, compute a regexp for the field/value pair.
      (t
       (let* ((field (nth 0 split))
 	     (value (nth 1 split))
-	     (regexp (concat "^\\(\\("
+	     partial regexp)
+	(if (symbolp value)
+	    (setq value (cdr (assq value nnmail-split-abbrev-alist))))
+	(if (and (>= (length value) 2)
+		 (string= ".*" (substring value 0 2)))
+	    (setq value (substring value 2)
+		  partial ""))
+	(setq regexp (concat "^\\(\\("
 			     (if (symbolp field)
 				 (cdr (assq field nnmail-split-abbrev-alist))
 			       field)
-			     "\\):.*\\)\\<\\("
-			     (if (symbolp value)
-				 (cdr (assq value nnmail-split-abbrev-alist))
-			       value)
-			     "\\)\\>")))
+			     "\\):.*\\)"
+			     (or partial "\\<")
+			     "\\("
+			     value
+			     "\\)\\>"))
 	(push (cons split regexp) nnmail-split-cache)
 	;; Now that it's in the cache, just call nnmail-split-it again
 	;; on the same split, which will find it immediately in the cache.
@@ -1371,68 +1276,6 @@
 	(apply 'concat (nreverse expanded))
       newtext)))
 
-;; Get a list of spool files to read.
-(defun nnmail-get-spool-files (&optional group)
-  (if (null nnmail-spool-file)
-      ;; No spool file whatsoever.
-      nil
-    (let* ((procmails
-	    ;; If procmail is used to get incoming mail, the files
-	    ;; are stored in this directory.
-	    (and (file-exists-p nnmail-procmail-directory)
-		 (or (eq nnmail-spool-file 'procmail)
-		     nnmail-use-procmail)
-		 (directory-files
-		  nnmail-procmail-directory
-		  t (concat (if group (concat "^" (regexp-quote group)) "")
-			    nnmail-procmail-suffix "$"))))
-	   (p procmails)
-	   (crash (when (and (file-exists-p nnmail-crash-box)
-			     (> (nnheader-file-size
-				 (file-truename nnmail-crash-box))
-				0))
-		    (list nnmail-crash-box))))
-      ;; Remove any directories that inadvertently match the procmail
-      ;; suffix, which might happen if the suffix is "".
-      (while p
-	(when (file-directory-p (car p))
-	  (setq procmails (delete (car p) procmails)))
-	(setq p (cdr p)))
-      ;; Return the list of spools.
-      (append
-       crash
-       (cond ((and group
-		   (or (eq nnmail-spool-file 'procmail)
-		       nnmail-use-procmail)
-		   procmails)
-	      procmails)
-	     ((and group
-		   (eq nnmail-spool-file 'procmail))
-	      nil)
-	     ((listp nnmail-spool-file)
-	      (nconc
-	       (apply
-		'nconc
-		(mapcar
-		 (lambda (file)
-		   (if (and (not (string-match "^po:" file))
-			    (file-directory-p file))
-		       (nnheader-directory-regular-files file)
-		     (list file)))
-		 nnmail-spool-file))
-	       procmails))
-	     ((stringp nnmail-spool-file)
-	      (if (and (not (string-match "^po:" nnmail-spool-file))
-		       (file-directory-p nnmail-spool-file))
-		  (nconc
-		   (nnheader-directory-regular-files nnmail-spool-file)
-		   procmails)
-		(cons nnmail-spool-file procmails)))
-	     ((eq nnmail-spool-file 'pop)
-	      (cons (format "po:%s" (user-login-name)) procmails))
-	     (t
-	      procmails))))))
-
 ;; Activate a backend only if it isn't already activated.
 ;; If FORCE, re-read the active file even if the backend is
 ;; already activated.
@@ -1482,7 +1325,6 @@
       (set-buffer
        (setq nnmail-cache-buffer
 	     (get-buffer-create " *nnmail message-id cache*")))
-      (buffer-disable-undo (current-buffer))
       (when (file-exists-p nnmail-message-id-cache-file)
 	(nnheader-insert-file-contents nnmail-message-id-cache-file))
       (set-buffer-modified-p nil)
@@ -1511,14 +1353,84 @@
       (setq nnmail-cache-buffer nil)
       (kill-buffer (current-buffer)))))
 
+;; Compiler directives.
+(defvar group)
+(defvar group-art-list)
+(defvar group-art)
 (defun nnmail-cache-insert (id)
   (when nnmail-treat-duplicates
-    (unless (gnus-buffer-live-p nnmail-cache-buffer)
-      (nnmail-cache-open))
+    ;; Store some information about the group this message is written
+    ;; to.  This function might have been called from various places.
+    ;; Sometimes, a function up in the calling sequence has an
+    ;; argument GROUP which is bound to a string, the group name.  At
+    ;; other times, there is a function up in the calling sequence
+    ;; which has an argument GROUP-ART which is a list of pairs, and
+    ;; the car of a pair is a group name.  Should we check that the
+    ;; length of the list is equal to 1? -- kai
+    (let ((g nil))
+      (cond ((and (boundp 'group) group)
+             (setq g group))
+            ((and (boundp 'group-art-list) group-art-list
+                  (listp group-art-list))
+             (setq g (caar group-art-list)))
+            ((and (boundp 'group-art) group-art (listp group-art))
+             (setq g (caar group-art)))
+            (t (setq g "")))
+      (unless (gnus-buffer-live-p nnmail-cache-buffer)
+        (nnmail-cache-open))
+      (save-excursion
+        (set-buffer nnmail-cache-buffer)
+        (goto-char (point-max))
+        (if (and g (not (string= "" g))
+                 (gnus-methods-equal-p gnus-command-method
+                                       (nnmail-cache-primary-mail-backend)))
+            (insert id "\t" g "\n")
+          (insert id "\n"))))))
+
+(defun nnmail-cache-primary-mail-backend ()
+  (let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
+        (be nil)
+        (res nil))
+    (while (and (null res) be-list)
+      (setq be (car be-list))
+      (setq be-list (cdr be-list))
+      (when (and (gnus-method-option-p be 'respool)
+                 (eval (intern (format "%s-get-new-mail" (car be)))))
+        (setq res be)))
+    res))
+
+;; Fetch the group name corresponding to the message id stored in the
+;; cache.
+(defun nnmail-cache-fetch-group (id)
+  (when (and nnmail-treat-duplicates nnmail-cache-buffer)
     (save-excursion
       (set-buffer nnmail-cache-buffer)
       (goto-char (point-max))
-      (insert id "\n"))))
+      (when (search-backward id nil t)
+        (beginning-of-line)
+        (skip-chars-forward "^\n\r\t")
+        (unless (eolp)
+          (forward-char 1)
+          (buffer-substring (point)
+                            (progn (end-of-line) (point))))))))
+
+;; Function for nnmail-split-fancy: look up all references in the
+;; cache and if a match is found, return that group.
+(defun nnmail-split-fancy-with-parent ()
+  (let* ((refstr (or (message-fetch-field "references")
+                     (message-fetch-field "in-reply-to")))
+         (references nil)
+         (res nil))
+    (when refstr
+      (setq references (nreverse (gnus-split-references refstr)))
+      (unless (gnus-buffer-live-p nnmail-cache-buffer)
+        (nnmail-cache-open))
+      (mapcar (lambda (x)
+                (setq res (or (nnmail-cache-fetch-group x) res))
+                (when (string= "drafts" res)
+                  (setq res nil)))
+              references)
+      res)))
 
 (defun nnmail-cache-id-exists-p (id)
   (when nnmail-treat-duplicates
@@ -1547,12 +1459,19 @@
 		    (t
 		     nnmail-treat-duplicates))))
 	 group-art)
+    ;; We insert a line that says what the mail source is.
+    (let ((case-fold-search t))
+      (goto-char (point-min))
+      (re-search-forward "^message-id[ \t]*:" nil t)
+      (beginning-of-line)
+      (insert (format "X-Gnus-Mail-Source: %s\n" mail-source-string)))
+
     ;; Let the backend save the article (or not).
     (cond
      ((not duplication)
-      (nnmail-cache-insert message-id)
       (funcall func (setq group-art
-			  (nreverse (nnmail-article-group artnum-func)))))
+			  (nreverse (nnmail-article-group artnum-func))))
+      (nnmail-cache-insert message-id))
      ((eq action 'delete)
       (setq group-art nil))
      ((eq action 'warn)
@@ -1575,6 +1494,8 @@
 
 ;;; Get new mail.
 
+(defvar nnmail-fetched-sources nil)
+
 (defun nnmail-get-value (&rest args)
   (let ((sym (intern (apply 'format args))))
     (when (boundp sym)
@@ -1583,72 +1504,89 @@
 (defun nnmail-get-new-mail (method exit-func temp
 				   &optional group spool-func)
   "Read new incoming mail."
-  (let* ((spools (nnmail-get-spool-files group))
+  (let* ((sources (or mail-sources
+		      (if (listp nnmail-spool-file) nnmail-spool-file
+			(list nnmail-spool-file))))
+	 fetching-sources
 	 (group-in group)
-	 nnmail-current-spool incoming incomings spool)
-    (when (and (nnmail-get-value "%s-get-new-mail" method)
-	       nnmail-spool-file)
+	 (i 0)
+	 (new 0)
+	 (total 0)
+	 incoming incomings source)
+    (when (nnmail-get-value "%s-get-new-mail" method)
+      (while (setq source (pop sources))
+	;; Be compatible with old values.
+	(cond
+	 ((stringp source)
+	  (setq source
+		(cond
+		 ((string-match "^po:" source)
+		  (list 'pop :user (substring source (match-end 0))))
+		 ((file-directory-p source)
+		  (list 'directory :path source))
+		 (t
+		  (list 'file :path source)))))
+	 ((eq source 'procmail)
+	  (message "Invalid value for nnmail-spool-file: `procmail'")
+	  nil))
+	;; Hack to only fetch the contents of a single group's spool file.
+	(when (and (eq (car source) 'directory)
+		   (null nnmail-scan-directory-mail-source-once)
+		   group)
+	  (mail-source-bind (directory source)
+	    (setq source (append source
+				 (list
+				  :predicate
+				  `(lambda (file)
+				     (string-match
+				      ,(concat
+					(regexp-quote (concat group suffix))
+					"$")
+				      file)))))))
+	(when nnmail-fetched-sources
+	  (if (member source nnmail-fetched-sources)
+	      (setq source nil)
+	    (push source nnmail-fetched-sources)
+	    (push source fetching-sources)))))
+    (when fetching-sources
       ;; We first activate all the groups.
       (nnmail-activate method)
       ;; Allow the user to hook.
       (run-hooks 'nnmail-pre-get-new-mail-hook)
       ;; Open the message-id cache.
       (nnmail-cache-open)
-      ;; The we go through all the existing spool files and split the
-      ;; mail from each.
-      (while spools
-	(setq spool (pop spools))
-	;; We read each spool file if either the spool is a POP-mail
-	;; spool, or the file exists.  We can't check for the
-	;; existence of POPped mail.
-	(when (or (string-match "^po:" spool)
-		  (and (file-exists-p (file-truename spool))
-		       (> (nnheader-file-size (file-truename spool)) 0)))
-	  (nnheader-message 3 "%s: Reading incoming mail..." method)
-	  (when (and (nnmail-move-inbox spool)
-		     (file-exists-p nnmail-crash-box))
-	    (setq nnmail-current-spool spool)
-	    ;; There is new mail.  We first find out if all this mail
-	    ;; is supposed to go to some specific group.
-	    (setq group (nnmail-get-split-group spool group-in))
-	    ;; We split the mail
-	    (nnmail-split-incoming
-	     nnmail-crash-box (intern (format "%s-save-mail" method))
-	     spool-func group (intern (format "%s-active-number" method)))
-	    ;; Check whether the inbox is to be moved to the special tmp dir.
-	    (let ((prefix
-		   (expand-file-name
-		    (if nnmail-tmp-directory
-			(concat
-			 (file-name-as-directory nnmail-tmp-directory)
-			 (file-name-nondirectory
-			  (concat (file-name-as-directory temp) "Incoming")))
-		      (concat (file-name-as-directory temp) "Incoming")))))
-	      (unless (file-exists-p (file-name-directory prefix))
-		(make-directory (file-name-directory prefix) t))
-	      (setq incoming (make-temp-file prefix)))
-	    (rename-file nnmail-crash-box incoming t)
-	    (push incoming incomings))))
+      ;; The we go through all the existing mail source specification
+      ;; and fetch the mail from each.
+      (while (setq source (pop fetching-sources))
+	(nnheader-message 4 "%s: Reading incoming mail from %s..."
+			  method (car source))
+	(when (setq new
+		    (mail-source-fetch
+		     source
+		     `(lambda (file orig-file)
+			(nnmail-split-incoming
+			 file ',(intern (format "%s-save-mail" method))
+			 ',spool-func
+			 (nnmail-get-split-group orig-file source)
+			 ',(intern (format "%s-active-number" method))))))
+	  (incf total new)
+	  (incf i)))
       ;; If we did indeed read any incoming spools, we save all info.
-      (when incomings
+      (if (zerop total)
+	  (nnheader-message 4 "%s: Reading incoming mail (no new mail)...done"
+			    method (car source))
 	(nnmail-save-active
 	 (nnmail-get-value "%s-group-alist" method)
 	 (nnmail-get-value "%s-active-file" method))
 	(when exit-func
 	  (funcall exit-func))
 	(run-hooks 'nnmail-read-incoming-hook)
-	(nnheader-message 3 "%s: Reading incoming mail...done" method))
+	(nnheader-message 4 "%s: Reading incoming mail (%d new)...done" method
+			  total))
       ;; Close the message-id cache.
       (nnmail-cache-close)
       ;; Allow the user to hook.
-      (run-hooks 'nnmail-post-get-new-mail-hook)
-      ;; Delete all the temporary files.
-      (while incomings
-	(setq incoming (pop incomings))
-	(and nnmail-delete-incoming
-	     (file-exists-p incoming)
-	     (file-writable-p incoming)
-	     (delete-file incoming))))))
+      (run-hooks 'nnmail-post-get-new-mail-hook))))
 
 (defun nnmail-expired-article-p (group time force &optional inhibit)
   "Say whether an article that is TIME old in GROUP should be expired."
@@ -1669,27 +1607,15 @@
 	     ;; This is an ange-ftp group, and we don't have any dates.
 	     nil)
 	    ((numberp days)
-	     (setq days (nnmail-days-to-time days))
+	     (setq days (days-to-time days))
 	     ;; Compare the time with the current time.
-	     (nnmail-time-less days (nnmail-time-since time)))))))
+	     (ignore-errors (time-less-p days (time-since time))))))))
 
-(defvar nnmail-read-passwd nil)
-(defun nnmail-read-passwd (prompt &rest args)
-  "Read a password using PROMPT.
-If ARGS, PROMPT is used as an argument to `format'."
-  (let ((prompt
-	 (if args
-	     (apply 'format prompt args)
-	   prompt)))
-    (unless nnmail-read-passwd
-      (if (fboundp 'read-passwd)
-	  (setq nnmail-read-passwd 'read-passwd)
-	(if (load "passwd" t)
-	    (setq nnmail-read-passwd 'read-passwd)
-	  (unless (fboundp 'ange-ftp-read-passwd)
-	    (autoload 'ange-ftp-read-passwd "ange-ftp"))
-	  (setq nnmail-read-passwd 'ange-ftp-read-passwd))))
-    (funcall nnmail-read-passwd prompt)))
+(defun nnmail-expiry-target-group (target group)
+  (when (nnheader-functionp target)
+    (setq target (funcall target group)))
+  (unless (eq target 'delete)
+    (gnus-request-accept-article target nil nil t)))
 
 (defun nnmail-check-syntax ()
   "Check (and modify) the syntax of the message in the current buffer."
@@ -1702,7 +1628,7 @@
 (defun nnmail-write-region (start end filename &optional append visit lockname)
   "Do a `write-region', and then set the file modes."
   (let ((coding-system-for-write nnmail-file-coding-system)
-	(pathname-coding-system 'binary))
+	(file-name-coding-system nnmail-pathname-coding-system))
     (write-region start end filename append visit lockname)
     (set-file-modes filename nnmail-default-file-modes)))
 
@@ -1738,11 +1664,11 @@
 	(goto-char (point-min))
 	(while (re-search-forward "[^ \t=]+" nil t)
 	  (setq name (match-string 0))
-	  (if (not (= (following-char) ?=))
+	  (if (not (eq (char-after) ?=))
 	      ;; Implied "yes".
 	      (setq value "yes")
 	    (forward-char 1)
-	    (if (not (= (following-char) ?\"))
+	    (if (not (eq (char-after) ?\"))
 		(if (not (looking-at "[^ \t]"))
 		    ;; Implied "no".
 		    (setq value "no")
@@ -1771,6 +1697,8 @@
   (unless nnmail-split-history
     (error "No current split history"))
   (with-output-to-temp-buffer "*nnmail split history*"
+    (with-current-buffer standard-output
+      (fundamental-mode))		; for Emacs 20.4+
     (let ((history nnmail-split-history)
 	  elem)
       (while (setq elem (pop history))
@@ -1799,15 +1727,6 @@
 	      his nil)))
     found))
 
-(eval-and-compile
-  (autoload 'pop3-movemail "pop3"))
-
-(defun nnmail-pop3-movemail (inbox crashbox)
-  "Function to move mail from INBOX on a pop3 server to file CRASHBOX."
-  (let ((pop3-maildrop
-         (substring inbox (match-end (string-match "^po:" inbox)))))
-    (pop3-movemail crashbox)))
-
 (defun nnmail-within-headers-p ()
   "Check to see if point is within the headers of a unix mail message.
 Doesn't change point."
--- a/lisp/gnus/nnmbox.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnmbox.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnmbox.el --- mail mbox access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -59,6 +61,11 @@
 (defvoo nnmbox-group-alist nil)
 (defvoo nnmbox-active-timestamp nil)
 
+(defvoo nnmbox-file-coding-system mm-text-coding-system)
+(defvoo nnmbox-file-coding-system-for-write nil)
+(defvoo nnmbox-active-file-coding-system mm-text-coding-system)
+(defvoo nnmbox-active-file-coding-system-for-write nil)
+
 
 
 ;;; Interface functions
@@ -166,6 +173,7 @@
 	    (nnmbox-article-group-number)))))))
 
 (deffoo nnmbox-request-group (group &optional server dont-check)
+  (nnmbox-possibly-change-newsgroup nil server)
   (let ((active (cadr (assoc group nnmbox-group-alist))))
     (cond
      ((or (null active)
@@ -180,6 +188,18 @@
 		       (1+ (- (cdr active) (car active)))
 		       (car active) (cdr active) group)))))
 
+(defun nnmbox-save-buffer ()
+  (let ((coding-system-for-write 
+	 (or nnmbox-file-coding-system-for-write
+	     nnmbox-file-coding-system)))
+    (save-buffer)))
+
+(defun nnmbox-save-active (group-alist active-file)
+  (let ((nnmail-active-file-coding-system
+	 (or nnmbox-active-file-coding-system-for-write
+	     nnmbox-active-file-coding-system)))
+    (nnmail-save-active group-alist active-file)))
+
 (deffoo nnmbox-request-scan (&optional group server)
   (nnmbox-possibly-change-newsgroup group server)
   (nnmbox-read-mbox)
@@ -188,7 +208,7 @@
    (lambda ()
      (save-excursion
        (set-buffer nnmbox-mbox-buffer)
-       (save-buffer)))
+       (nnmbox-save-buffer)))
    (file-name-directory nnmbox-mbox-file)
    group
    (lambda ()
@@ -197,7 +217,7 @@
 	 (set-buffer nnmbox-mbox-buffer)
 	 (goto-char (point-max))
 	 (insert-buffer-substring in-buf)))
-     (nnmail-save-active nnmbox-group-alist nnmbox-active-file))))
+     (nnmbox-save-active nnmbox-group-alist nnmbox-active-file))))
 
 (deffoo nnmbox-close-group (group &optional server)
   t)
@@ -207,12 +227,14 @@
   (unless (assoc group nnmbox-group-alist)
     (push (list group (cons 1 0))
 	  nnmbox-group-alist)
-    (nnmail-save-active nnmbox-group-alist nnmbox-active-file))
+    (nnmbox-save-active nnmbox-group-alist nnmbox-active-file))
   t)
 
 (deffoo nnmbox-request-list (&optional server)
   (save-excursion
-    (nnmail-find-file nnmbox-active-file)
+    (let ((nnmail-file-coding-system
+	   nnmbox-active-file-coding-system))
+      (nnmail-find-file nnmbox-active-file))
     (setq nnmbox-group-alist (nnmail-get-active))
     t))
 
@@ -223,7 +245,7 @@
   (nnheader-report 'nnmbox "LIST NEWSGROUPS is not implemented."))
 
 (deffoo nnmbox-request-expire-articles
-  (articles newsgroup &optional server force)
+    (articles newsgroup &optional server force)
   (nnmbox-possibly-change-newsgroup newsgroup server)
   (let* ((is-old t)
 	 rest)
@@ -245,7 +267,7 @@
 		(nnmbox-delete-mail))
 	    (push (car articles) rest)))
 	(setq articles (cdr articles)))
-      (save-buffer)
+      (nnmbox-save-buffer)
       ;; Find the lowest active article in this group.
       (let ((active (nth 1 (assoc newsgroup nnmbox-group-alist))))
 	(goto-char (point-min))
@@ -254,18 +276,17 @@
 		    (<= (car active) (cdr active)))
 	  (setcar active (1+ (car active)))
 	  (goto-char (point-min))))
-      (nnmail-save-active nnmbox-group-alist nnmbox-active-file)
+      (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
       (nconc rest articles))))
 
 (deffoo nnmbox-request-move-article
-  (article group server accept-form &optional last)
+    (article group server accept-form &optional last)
   (let ((buf (get-buffer-create " *nnmbox move*"))
 	result)
     (and
      (nnmbox-request-article article group server)
      (save-excursion
        (set-buffer buf)
-       (buffer-disable-undo (current-buffer))
        (erase-buffer)
        (insert-buffer-substring nntp-server-buffer)
        (goto-char (point-min))
@@ -283,7 +304,7 @@
        (goto-char (point-min))
        (when (search-forward (nnmbox-article-string article) nil t)
 	 (nnmbox-delete-mail))
-       (and last (save-buffer))))
+       (and last (nnmbox-save-buffer))))
     result))
 
 (deffoo nnmbox-request-accept-article (group &optional server last)
@@ -323,8 +344,8 @@
        (when last
 	 (when nnmail-cache-accepted-message-ids
 	   (nnmail-cache-close))
-	 (nnmail-save-active nnmbox-group-alist nnmbox-active-file)
-	 (save-buffer))))
+	 (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
+	 (nnmbox-save-buffer))))
     result))
 
 (deffoo nnmbox-request-replace-article (article group buffer)
@@ -336,7 +357,7 @@
 	nil
       (nnmbox-delete-mail t t)
       (insert-buffer-substring buffer)
-      (save-buffer)
+      (nnmbox-save-buffer)
       t)))
 
 (deffoo nnmbox-request-delete-group (group &optional force server)
@@ -354,13 +375,13 @@
 	  (setq found t)
 	  (nnmbox-delete-mail))
 	(when found
-	  (save-buffer)))))
+	  (nnmbox-save-buffer)))))
   ;; Remove the group from all structures.
   (setq nnmbox-group-alist
 	(delq (assoc group nnmbox-group-alist) nnmbox-group-alist)
 	nnmbox-current-group nil)
   ;; Save the active file.
-  (nnmail-save-active nnmbox-group-alist nnmbox-active-file)
+  (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
   t)
 
 (deffoo nnmbox-request-rename-group (group new-name &optional server)
@@ -375,13 +396,13 @@
 	(replace-match new-ident t t)
 	(setq found t))
       (when found
-	(save-buffer))))
+	(nnmbox-save-buffer))))
   (let ((entry (assoc group nnmbox-group-alist)))
     (when entry
       (setcar entry new-name))
     (setq nnmbox-current-group nil)
     ;; Save the new group alist.
-    (nnmail-save-active nnmbox-group-alist nnmbox-active-file)
+    (nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
     t))
 
 
@@ -425,9 +446,12 @@
 	    (not (buffer-name nnmbox-mbox-buffer)))
     (save-excursion
       (set-buffer (setq nnmbox-mbox-buffer
-			(nnheader-find-file-noselect
-			 nnmbox-mbox-file nil 'raw)))
-      (buffer-disable-undo (current-buffer))))
+			(let ((nnheader-file-coding-system
+			       nnmbox-file-coding-system))
+			  (nnheader-find-file-noselect
+			   nnmbox-mbox-file nil t))))
+      (mm-enable-multibyte)
+      (buffer-disable-undo)))
   (when (not nnmbox-group-alist)
     (nnmail-activate 'nnmbox))
   (if newsgroup
@@ -496,7 +520,10 @@
 
 (defun nnmbox-create-mbox ()
   (when (not (file-exists-p nnmbox-mbox-file))
-    (nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg)))
+    (let ((nnmail-file-coding-system
+	   (or nnmbox-file-coding-system-for-write
+	       nnmbox-file-coding-system)))
+      (nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg))))
 
 (defun nnmbox-read-mbox ()
   (nnmail-activate 'nnmbox)
@@ -512,9 +539,12 @@
 	    (alist nnmbox-group-alist)
 	    start end number)
 	(set-buffer (setq nnmbox-mbox-buffer
-			  (nnheader-find-file-noselect
-			   nnmbox-mbox-file nil 'raw)))
-	(buffer-disable-undo (current-buffer))
+			  (let ((nnheader-file-coding-system
+				 nnmbox-file-coding-system))
+			    (nnheader-find-file-noselect
+			     nnmbox-mbox-file nil t))))
+	(mm-enable-multibyte)
+	(buffer-disable-undo)
 
 	;; Go through the group alist and compare against
 	;; the mbox file.
@@ -523,26 +553,31 @@
 	  (when (and (re-search-backward
 		      (format "^X-Gnus-Newsgroup: %s:\\([0-9]+\\) "
 			      (caar alist)) nil t)
-		     (>= (setq number
-			       (string-to-number
-				(buffer-substring
-				 (match-beginning 1) (match-end 1))))
-			 (cdadar alist)))
-	    (setcdr (cadar alist) (1+ number)))
+		     (> (setq number
+			      (string-to-number
+			       (buffer-substring
+				(match-beginning 1) (match-end 1))))
+			(cdadar alist)))
+	    (setcdr (cadar alist) number))
 	  (setq alist (cdr alist)))
 
 	(goto-char (point-min))
 	(while (re-search-forward delim nil t)
 	  (setq start (match-beginning 0))
-	  (when (not (search-forward "\nX-Gnus-Newsgroup: "
-				     (save-excursion
-				       (setq end
-					     (or
-					      (and
-					       (re-search-forward delim nil t)
-					       (match-beginning 0))
-					      (point-max))))
-				     t))
+	  (unless (search-forward
+		   "\nX-Gnus-Newsgroup: "
+		   (save-excursion
+		     (setq end
+			   (or
+			    (and
+			     ;; skip to end of headers first, since mail
+			     ;; which has been respooled has additional
+			     ;; "From nobody" lines.
+			     (search-forward "\n\n" nil t)
+			     (re-search-forward delim nil t)
+			     (match-beginning 0))
+			    (point-max))))
+		   t)
 	    (save-excursion
 	      (save-restriction
 		(narrow-to-region start end)
--- a/lisp/gnus/nnmh.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnmh.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnmh.el --- mhspool access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -48,7 +50,10 @@
   "*Hook run narrowed to an article before saving.")
 
 (defvoo nnmh-be-safe nil
-  "*If non-nil, nnmh will check all articles to make sure whether they are new or not.")
+  "*If non-nil, nnmh will check all articles to make sure whether they are new or not.
+Go through the .nnmh-articles file and compare with the actual
+articles in this folder.  The articles that are \"new\" will be marked
+as unread by Gnus.")
 
 
 
@@ -60,7 +65,10 @@
 
 (defvoo nnmh-status-string "")
 (defvoo nnmh-group-alist nil)
-(defvoo nnmh-allow-delete-final nil)
+;; Don't even think about setting this variable.  It does not exist.
+;; Forget about it.  Uh-huh.  Nope.  Nobody here.  It's only bound
+;; dynamically by certain functions in nndraft.
+(defvar nnmh-allow-delete-final nil)
 
 
 
@@ -77,8 +85,7 @@
 	   (large (and (numberp nnmail-large-newsgroup)
 		       (> number nnmail-large-newsgroup)))
 	   (count 0)
-	   (file-name-coding-system 'binary)
-	   (pathname-coding-system 'binary)
+	   (file-name-coding-system nnmail-pathname-coding-system)
 	   beg article)
       (nnmh-possibly-change-directory newsgroup server)
       ;; We don't support fetching by Message-ID.
@@ -106,7 +113,7 @@
 	  (and large
 	       (zerop (% count 20))
 	       (nnheader-message 5 "nnmh: Receiving headers... %d%%"
-			(/ (* count 100) number))))
+				 (/ (* count 100) number))))
 
 	(when large
 	  (nnheader-message 5 "nnmh: Receiving headers...done"))
@@ -137,8 +144,7 @@
   (let ((file (if (stringp id)
 		  nil
 		(concat nnmh-current-directory (int-to-string id))))
-	(pathname-coding-system 'binary)
-	(file-name-coding-system 'binary)
+	(file-name-coding-system nnmail-pathname-coding-system)
 	(nntp-server-buffer (or buffer nntp-server-buffer)))
     (and (stringp file)
 	 (file-exists-p file)
@@ -150,8 +156,7 @@
   (nnheader-init-server-buffer)
   (nnmh-possibly-change-directory group server)
   (let ((pathname (nnmail-group-pathname group nnmh-directory))
-	(pathname-coding-system 'binary)
-	(file-name-coding-system 'binary)
+	(file-name-coding-system nnmail-pathname-coding-system)
 	dir)
     (cond
      ((not (file-directory-p pathname))
@@ -174,16 +179,19 @@
 	       (mapcar (lambda (name) (string-to-int name))
 		       (directory-files pathname nil "^[0-9]+$" t))
 	       '<))
-	  (cond
-	   (dir
-	    (nnheader-report 'nnmh "Selected group %s" group)
-	    (nnheader-insert
-	     "211 %d %d %d %s\n" (length dir) (car dir)
-	     (progn (while (cdr dir) (setq dir (cdr dir))) (car dir))
-	     group))
-	   (t
-	    (nnheader-report 'nnmh "Empty group %s" group)
-	    (nnheader-insert (format "211 0 1 0 %s\n" group))))))))))
+	(cond
+	 (dir
+	  (setq nnmh-group-alist
+		(delq (assoc group nnmh-group-alist) nnmh-group-alist))
+	  (push (list group (cons (car dir) (car (last dir))))
+		nnmh-group-alist)
+	  (nnheader-report 'nnmh "Selected group %s" group)
+	  (nnheader-insert
+	   "211 %d %d %d %s\n" (length dir) (car dir)
+	   (car (last dir)) group))
+	 (t
+	  (nnheader-report 'nnmh "Empty group %s" group)
+	  (nnheader-insert (format "211 0 1 0 %s\n" group))))))))))
 
 (deffoo nnmh-request-scan (&optional group server)
   (nnmail-get-new-mail 'nnmh nil nnmh-directory group))
@@ -191,10 +199,9 @@
 (deffoo nnmh-request-list (&optional server dir)
   (nnheader-insert "")
   (nnmh-possibly-change-directory nil server)
-  (let* ((pathname-coding-system 'binary)
-	 (file-name-coding-system 'binary)
-	 (nnmh-toplev
-	  (file-truename (or dir (file-name-as-directory nnmh-directory)))))
+  (let ((file-name-coding-system nnmail-pathname-coding-system)
+	(nnmh-toplev
+	 (file-truename (or dir (file-name-as-directory nnmh-directory)))))
     (nnmh-request-list-1 nnmh-toplev))
   (setq nnmh-group-alist (nnmail-get-active))
   t)
@@ -233,8 +240,8 @@
 				(expand-file-name nnmh-toplev))))
 	       dir)
 	      (nnheader-replace-chars-in-string
-	       (gnus-decode-coding-string (substring dir (match-end 0))
-					  nnmail-pathname-coding-system)
+	       (mm-decode-coding-string (substring dir (match-end 0))
+					nnmail-pathname-coding-system)
 	       ?/ ?.))
 	    (apply 'max files)
 	    (apply 'min files)))))))
@@ -275,7 +282,7 @@
   t)
 
 (deffoo nnmh-request-move-article
-  (article group server accept-form &optional last)
+    (article group server accept-form &optional last)
   (let ((buf (get-buffer-create " *nnmh move*"))
 	result)
     (and
@@ -405,8 +412,7 @@
     (nnmh-open-server server))
   (when newsgroup
     (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory))
-	  (file-name-coding-system 'binary)
-	  (pathname-coding-system 'binary))
+	  (file-name-coding-system nnmail-pathname-coding-system))
       (if (file-directory-p pathname)
 	  (setq nnmh-current-directory pathname)
 	(error "No such newsgroup: %s" newsgroup)))))
@@ -455,8 +461,8 @@
   "Compute the next article number in GROUP."
   (let ((active (cadr (assoc group nnmh-group-alist)))
 	(dir (nnmail-group-pathname group nnmh-directory))
-	(file-name-coding-system 'binary)
-	(pathname-coding-system 'binary))
+	(file-name-coding-system nnmail-pathname-coding-system)
+	file)
     (unless active
       ;; The group wasn't known to nnmh, so we just create an active
       ;; entry for it.
@@ -474,9 +480,15 @@
 	(when files
 	  (setcdr active (car files)))))
     (setcdr active (1+ (cdr active)))
-    (while (file-exists-p
-	    (concat (nnmail-group-pathname group nnmh-directory)
-		    (int-to-string (cdr active))))
+    (while (or
+	    ;; See whether the file exists...
+	    (file-exists-p
+	     (setq file (concat (nnmail-group-pathname group nnmh-directory)
+				(int-to-string (cdr active)))))
+	    ;; ... or there is a buffer that will make that file exist
+	    ;; in the future.
+	    (get-file-buffer file))
+      ;; Skip past that file.
       (setcdr active (1+ (cdr active))))
     (cdr active)))
 
@@ -539,7 +551,7 @@
     (setq articles (sort articles (lambda (art1 art2)
 				    (> (car art1) (car art2)))))
     ;; Finally write this list back to the .nnmh-articles file.
-    (nnheader-temp-write nnmh-file
+    (with-temp-file nnmh-file
       (insert ";; Gnus article active file for " group "\n\n")
       (insert "(setq nnmh-newsgroup-articles '")
       (gnus-prin1 articles)
--- a/lisp/gnus/nnml.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnml.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnml.el --- mail spool access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -41,11 +42,11 @@
   "Spool directory for the nnml mail backend.")
 
 (defvoo nnml-active-file
-  (concat (file-name-as-directory nnml-directory) "active")
+    (expand-file-name "active" nnml-directory)
   "Mail active file.")
 
 (defvoo nnml-newsgroups-file
-  (concat (file-name-as-directory nnml-directory) "newsgroups")
+    (expand-file-name "newsgroups" nnml-directory)
   "Mail newsgroups description file.")
 
 (defvoo nnml-get-new-mail t
@@ -86,6 +87,8 @@
 
 (defvar nnml-nov-buffer-file-name nil)
 
+(defvoo nnml-file-coding-system nnmail-file-coding-system)
+
 
 
 ;;; Interface functions.
@@ -100,8 +103,7 @@
       (let ((file nil)
 	    (number (length sequence))
 	    (count 0)
-	    (file-name-coding-system 'binary)
-	    (pathname-coding-system 'binary)
+	    (file-name-coding-system nnmail-pathname-coding-system)
 	    beg article)
 	(if (stringp (car sequence))
 	    'headers
@@ -141,9 +143,7 @@
 (deffoo nnml-open-server (server &optional defs)
   (nnoo-change-server 'nnml server defs)
   (when (not (file-exists-p nnml-directory))
-    (condition-case ()
-	(make-directory nnml-directory t)
-      (error)))
+    (ignore-errors (make-directory nnml-directory t)))
   (cond
    ((not (file-exists-p nnml-directory))
     (nnml-close-server)
@@ -164,8 +164,7 @@
 (deffoo nnml-request-article (id &optional group server buffer)
   (nnml-possibly-change-directory group server)
   (let* ((nntp-server-buffer (or buffer nntp-server-buffer))
-	 (file-name-coding-system 'binary)
-	 (pathname-coding-system 'binary)
+	 (file-name-coding-system nnmail-pathname-coding-system)
 	 path gpath group-num)
     (if (stringp id)
 	(when (and (setq group-num (nnml-find-group-number id))
@@ -185,7 +184,9 @@
       (nnheader-report 'nnml "No such file: %s" path))
      ((file-directory-p path)
       (nnheader-report 'nnml "File is a directory: %s" path))
-     ((not (save-excursion (nnmail-find-file path)))
+     ((not (save-excursion (let ((nnmail-file-coding-system
+				  nnml-file-coding-system))
+			     (nnmail-find-file path))))
       (nnheader-report 'nnml "Couldn't read file: %s" path))
      (t
       (nnheader-report 'nnml "Article %s retrieved" id)
@@ -194,8 +195,7 @@
 	    (string-to-int (file-name-nondirectory path)))))))
 
 (deffoo nnml-request-group (group &optional server dont-check)
-  (let ((pathname-coding-system 'binary)
-	(file-name-coding-system 'binary))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
     (cond
      ((not (nnml-possibly-change-directory group server))
       (nnheader-report 'nnml "Invalid group (no such directory)"))
@@ -228,6 +228,7 @@
   t)
 
 (deffoo nnml-request-create-group (group &optional server args)
+  (nnml-possibly-change-directory nil server)
   (nnmail-activate 'nnml)
   (cond
    ((assoc group nnml-group-alist)
@@ -252,10 +253,8 @@
 (deffoo nnml-request-list (&optional server)
   (save-excursion
     (let ((nnmail-file-coding-system nnmail-active-file-coding-system)
-	  (file-name-coding-system 'binary)
-	  (pathname-coding-system 'binary))
-      (nnmail-find-file nnml-active-file)
-      )
+	  (file-name-coding-system nnmail-pathname-coding-system))
+      (nnmail-find-file nnml-active-file))
     (setq nnml-group-alist (nnmail-get-active))
     t))
 
@@ -266,8 +265,7 @@
   (save-excursion
     (nnmail-find-file nnml-newsgroups-file)))
 
-(deffoo nnml-request-expire-articles (articles group
-					       &optional server force)
+(deffoo nnml-request-expire-articles (articles group &optional server force)
   (nnml-possibly-change-directory group server)
   (let ((active-articles
 	 (nnheader-directory-articles nnml-current-directory))
@@ -288,8 +286,16 @@
 			 (nnmail-expired-article-p group mod-time force
 						   nnml-inhibit-expiry)))
 	      (progn
+		;; Allow a special target group.
+		(unless (eq nnmail-expiry-target 'delete)
+		  (with-temp-buffer
+		    (nnml-request-article number group server
+					  (current-buffer))
+		    (let ((nnml-current-directory nil))
+		      (nnmail-expiry-target-group
+		       nnmail-expiry-target group))))
 		(nnheader-message 5 "Deleting article %s in %s"
-				  article group)
+				  number group)
 		(condition-case ()
 		    (funcall nnmail-delete-file-function article)
 		  (file-error
@@ -307,7 +313,7 @@
     (nconc rest articles)))
 
 (deffoo nnml-request-move-article
-  (article group server accept-form &optional last)
+    (article group server accept-form &optional last)
   (let ((buf (get-buffer-create " *nnml move*"))
 	result)
     (nnml-possibly-change-directory group server)
@@ -315,12 +321,15 @@
     (and
      (nnml-deletable-article-p group article)
      (nnml-request-article article group server)
-     (save-excursion
-       (set-buffer buf)
-       (insert-buffer-substring nntp-server-buffer)
-       (setq result (eval accept-form))
-       (kill-buffer (current-buffer))
-       result)
+     (let (nnml-current-directory 
+	   nnml-current-group 
+	   nnml-article-file-alist)
+       (save-excursion
+	 (set-buffer buf)
+	 (insert-buffer-substring nntp-server-buffer)
+	 (setq result (eval accept-form))
+	 (kill-buffer (current-buffer))
+	 result))
      (progn
        (nnml-possibly-change-directory group server)
        (condition-case ()
@@ -368,16 +377,14 @@
     (let ((chars (nnmail-insert-lines))
 	  (art (concat (int-to-string article) "\t"))
 	  headers)
-      (when (condition-case ()
-		(progn
-		  (nnmail-write-region
-		   (point-min) (point-max)
-		   (or (nnml-article-to-file article)
-		       (concat nnml-current-directory
-			       (int-to-string article)))
-		   nil (if (nnheader-be-verbose 5) nil 'nomesg))
-		  t)
-	      (error nil))
+      (when (ignore-errors
+	      (nnmail-write-region
+	       (point-min) (point-max)
+	       (or (nnml-article-to-file article)
+		   (expand-file-name (int-to-string article)
+				     nnml-current-directory))
+	       nil (if (nnheader-be-verbose 5) nil 'nomesg))
+	      t)
 	(setq headers (nnml-parse-head chars article))
 	;; Replace the NOV line in the NOV file.
 	(save-excursion
@@ -418,9 +425,7 @@
 	  (nnheader-message 5 "Deleting article %s in %s..." article group)
 	  (funcall nnmail-delete-file-function article))))
     ;; Try to delete the directory itself.
-    (condition-case ()
-	(delete-directory nnml-current-directory)
-      (error nil)))
+    (ignore-errors (delete-directory nnml-current-directory)))
   ;; Remove the group from all structures.
   (setq nnml-group-alist
 	(delq (assoc group nnml-group-alist) nnml-group-alist)
@@ -434,11 +439,9 @@
   (nnml-possibly-change-directory group server)
   (let ((new-dir (nnmail-group-pathname new-name nnml-directory))
 	(old-dir (nnmail-group-pathname group nnml-directory)))
-    (when (condition-case ()
-	      (progn
-		(make-directory new-dir t)
-		t)
-	    (error nil))
+    (when (ignore-errors
+	    (make-directory new-dir t)
+	    t)
       ;; We move the articles file by file instead of renaming
       ;; the directory -- there may be subgroups in this group.
       ;; One might be more clever, I guess.
@@ -453,9 +456,7 @@
 	(when (file-exists-p overview)
 	  (rename-file overview (concat new-dir nnml-nov-file-name))))
       (when (<= (length (directory-files old-dir)) 2)
-	(condition-case ()
-	    (delete-directory old-dir)
-	  (error nil)))
+	(ignore-errors (delete-directory old-dir)))
       ;; That went ok, so we change the internal structures.
       (let ((entry (assoc group nnml-group-alist)))
 	(when entry
@@ -473,7 +474,7 @@
      ((not (file-exists-p file))
       (nnheader-report 'nnml "File %s does not exist" file))
      (t
-      (nnheader-temp-write file
+      (with-temp-file file
 	(nnheader-insert-file-contents file)
 	(nnmail-replace-status name value))
       t))))
@@ -485,7 +486,7 @@
   (nnml-update-file-alist)
   (let (file)
     (if (setq file (cdr (assq article nnml-article-file-alist)))
-	(concat nnml-current-directory file)
+	(expand-file-name file nnml-current-directory)
       ;; Just to make sure nothing went wrong when reading over NFS --
       ;; check once more.
       (when (file-exists-p
@@ -507,7 +508,6 @@
 (defun nnml-find-group-number (id)
   (save-excursion
     (set-buffer (get-buffer-create " *nnml id*"))
-    (buffer-disable-undo (current-buffer))
     (let ((alist nnml-group-alist)
 	  number)
       ;; We want to look through all .overview files, but we want to
@@ -527,8 +527,8 @@
 
 (defun nnml-find-id (group id)
   (erase-buffer)
-  (let ((nov (concat (nnmail-group-pathname group nnml-directory)
-		     nnml-nov-file-name))
+  (let ((nov (expand-file-name nnml-nov-file-name
+			       (nnmail-group-pathname group nnml-directory)))
 	number found)
     (when (file-exists-p nov)
       (nnheader-insert-file-contents nov)
@@ -542,15 +542,13 @@
 	  (setq found t)
 	  ;; We return the article number.
 	  (setq number
-		(condition-case ()
-		    (read (current-buffer))
-		  (error nil)))))
+		(ignore-errors (read (current-buffer))))))
       number)))
 
 (defun nnml-retrieve-headers-with-nov (articles &optional fetch-old)
   (if (or gnus-nov-is-evil nnml-nov-is-evil)
       nil
-    (let ((nov (concat nnml-current-directory nnml-nov-file-name)))
+    (let ((nov (expand-file-name nnml-nov-file-name nnml-current-directory)))
       (when (file-exists-p nov)
 	(save-excursion
 	  (set-buffer nntp-server-buffer)
@@ -572,8 +570,7 @@
   (if (not group)
       t
     (let ((pathname (nnmail-group-pathname group nnml-directory))
-	  (file-name-coding-system 'binary)
-	  (pathname-coding-system 'binary))
+	  (file-name-coding-system nnmail-pathname-coding-system))
       (when (not (equal pathname nnml-current-directory))
 	(setq nnml-current-directory pathname
 	      nnml-current-group group
@@ -581,15 +578,10 @@
       (file-exists-p nnml-current-directory))))
 
 (defun nnml-possibly-create-directory (group)
-  (let (dir dirs)
-    (setq dir (nnmail-group-pathname group nnml-directory))
-    (while (not (file-directory-p dir))
-      (push dir dirs)
-      (setq dir (file-name-directory (directory-file-name dir))))
-    (while dirs
-      (make-directory (directory-file-name (car dirs)))
-      (nnheader-message 5 "Creating mail directory %s" (car dirs))
-      (setq dirs (cdr dirs)))))
+  (let ((dir (nnmail-group-pathname group nnml-directory)))
+    (unless (file-exists-p dir)
+      (make-directory (directory-file-name dir) t)
+      (nnheader-message 5 "Creating mail directory %s" dir))))
 
 (defun nnml-save-mail (group-art)
   "Called narrowed to an article."
@@ -652,8 +644,8 @@
       (push (list group active) nnml-group-alist))
     (setcdr active (1+ (cdr active)))
     (while (file-exists-p
-	    (concat (nnmail-group-pathname group nnml-directory)
-		    (int-to-string (cdr active))))
+	    (expand-file-name (int-to-string (cdr active))
+			      (nnmail-group-pathname group nnml-directory)))
       (setcdr active (1+ (cdr active))))
     (cdr active)))
 
@@ -693,8 +685,9 @@
 	(save-excursion
 	  (set-buffer buffer)
 	  (set (make-local-variable 'nnml-nov-buffer-file-name)
-	       (concat (nnmail-group-pathname group nnml-directory)
-		       nnml-nov-file-name))
+	       (expand-file-name
+		nnml-nov-file-name
+		(nnmail-group-pathname group nnml-directory)))
 	  (erase-buffer)
 	  (when (file-exists-p nnml-nov-buffer-file-name)
 	    (nnheader-insert-file-contents nnml-nov-buffer-file-name)))
@@ -738,7 +731,7 @@
     (let ((dirs (directory-files dir t nil t))
 	  dir)
       (while (setq dir (pop dirs))
-	(when (and (not (member (file-name-nondirectory dir) '("." "..")))
+	(when (and (not (string-match "^\\." (file-name-nondirectory dir)))
 		   (file-directory-p dir))
 	  (nnml-generate-nov-databases-1 dir seen))))
     ;; Do this directory.
@@ -778,7 +771,7 @@
     (save-excursion
       ;; Init the nov buffer.
       (set-buffer nov-buffer)
-      (buffer-disable-undo (current-buffer))
+      (buffer-disable-undo)
       (erase-buffer)
       (set-buffer nntp-server-buffer)
       ;; Delete the old NOV file.
--- a/lisp/gnus/nnoo.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnoo.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnoo.el --- OO Gnus Backends
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -105,11 +107,11 @@
 			(cdr (assq pbackend (nnoo-parents backend))))
     (prog1
 	(apply function args)
-    ;; Copy the changed variables back into the child.
-    (let ((vars (cdr (assq pbackend (nnoo-parents backend)))))
-      (while vars
-	(set (cadar vars) (symbol-value (caar vars)))
-	(setq vars (cdr vars)))))))
+      ;; Copy the changed variables back into the child.
+      (let ((vars (cdr (assq pbackend (nnoo-parents backend)))))
+	(while vars
+	  (set (cadar vars) (symbol-value (caar vars)))
+	  (setq vars (cdr vars)))))))
 
 (defun nnoo-execute (backend function &rest args)
   "Execute FUNCTION on behalf of BACKEND."
--- a/lisp/gnus/nnsoup.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnsoup.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnsoup.el --- SOUP access for Gnus
-;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;;	Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -38,19 +40,22 @@
 (defvoo nnsoup-directory "~/SOUP/"
   "*SOUP packet directory.")
 
-(defvoo nnsoup-tmp-directory temporary-file-directory
+(defvoo nnsoup-tmp-directory
+    (cond ((fboundp 'temp-directory) (temp-directory))
+	  ((boundp 'temporary-file-directory) temporary-file-directory)
+	  ("/tmp/"))
   "*Where nnsoup will store temporary files.")
 
-(defvoo nnsoup-replies-directory (concat nnsoup-directory "replies/")
+(defvoo nnsoup-replies-directory (expand-file-name "replies/" nnsoup-directory)
   "*Directory where outgoing packets will be composed.")
 
-(defvoo nnsoup-replies-format-type ?n
+(defvoo nnsoup-replies-format-type ?u  ;; u is USENET news format.
   "*Format of the replies packages.")
 
 (defvoo nnsoup-replies-index-type ?n
   "*Index type of the replies packages.")
 
-(defvoo nnsoup-active-file (concat nnsoup-directory "active")
+(defvoo nnsoup-active-file (expand-file-name "active" nnsoup-directory)
   "Active file.")
 
 (defvoo nnsoup-packer "tar cf - %s | gzip > $HOME/Soupin%d.tgz"
@@ -70,8 +75,8 @@
   "*Regular expression matching SOUP packets in `nnsoup-packet-directory'.")
 
 (defvoo nnsoup-always-save t
-  "If non nil commit the reply buffer on each message send. 
-This is necessary if using message mode outside Gnus with nnsoup as a 
+  "If non nil commit the reply buffer on each message send.
+This is necessary if using message mode outside Gnus with nnsoup as a
 backend for the messages.")
 
 
@@ -252,7 +257,7 @@
 		  (nth 1 (nnsoup-article-to-area
 			  article nnsoup-current-group))))))
       (cond ((= kind ?m) 'mail)
-	    ((= kind ?n) 'news)
+	    ((= kind ?n) 'news) 
 	    (t 'unknown)))))
 
 (deffoo nnsoup-close-group (group &optional server)
@@ -310,7 +315,7 @@
       (setq info (pop infolist)
 	    range-list (gnus-uncompress-range (car info))
 	    prefix (gnus-soup-area-prefix (nth 1 info)))
-      (when ;; All the articles in this file are marked for expiry.
+      (when;; All the articles in this file are marked for expiry.
 	  (and (or (setq mod-time (nth 5 (file-attributes
 					  (nnsoup-file prefix))))
 		   (setq mod-time (nth 5 (file-attributes
@@ -376,7 +381,7 @@
 	     (or force
 		 nnsoup-group-alist-touched))
     (setq nnsoup-group-alist-touched nil)
-    (nnheader-temp-write nnsoup-active-file
+    (with-temp-file nnsoup-active-file
       (gnus-prin1 `(setq nnsoup-group-alist ',nnsoup-group-alist))
       (insert "\n")
       (gnus-prin1 `(setq nnsoup-current-prefix ,nnsoup-current-prefix))
@@ -419,12 +424,15 @@
 	    (setq cur-prefix (nnsoup-next-prefix))
 	    (nnheader-message 5 "Incorporating file %s..." cur-prefix)
 	    (when (file-exists-p
-		   (setq file (concat nnsoup-tmp-directory
-				      (gnus-soup-area-prefix area) ".IDX")))
+		   (setq file
+			 (expand-file-name
+			  (concat (gnus-soup-area-prefix area) ".IDX")
+			  nnsoup-tmp-directory)))
 	      (rename-file file (nnsoup-file cur-prefix)))
 	    (when (file-exists-p
-		   (setq file (concat nnsoup-tmp-directory
-				      (gnus-soup-area-prefix area) ".MSG")))
+		   (setq file (expand-file-name
+			       (concat (gnus-soup-area-prefix area) ".MSG")
+			       nnsoup-tmp-directory)))
 	      (rename-file file (nnsoup-file cur-prefix t))
 	      (gnus-soup-set-area-prefix area cur-prefix)
 	      ;; Find the number of new articles in this area.
@@ -473,7 +481,8 @@
     (goto-char (point-min))
     (cond
      ;; rnews batch format
-     ((= format ?n)
+     ((or (= format ?u)
+	  (= format ?n)) ;; Gnus back compatibility.
       (while (looking-at "^#! *rnews \\(+[0-9]+\\) *$")
 	(forward-line 1)
 	(push (list
@@ -527,17 +536,19 @@
   (let* ((file (concat prefix (if message ".MSG" ".IDX")))
 	 (buffer-name (concat " *nnsoup " file "*")))
     (or (get-buffer buffer-name)	; File already loaded.
-	(when (file-exists-p (concat nnsoup-directory file))
+	(when (file-exists-p (expand-file-name file nnsoup-directory))
 	  (save-excursion		; Load the file.
 	    (set-buffer (get-buffer-create buffer-name))
-	    (buffer-disable-undo (current-buffer))
+	    (buffer-disable-undo)
 	    (push (cons nnsoup-current-group (current-buffer)) nnsoup-buffers)
-	    (nnheader-insert-file-contents (concat nnsoup-directory file))
+	    (nnheader-insert-file-contents
+	     (expand-file-name file nnsoup-directory))
 	    (current-buffer))))))
 
 (defun nnsoup-file (prefix &optional message)
   (expand-file-name
-   (concat nnsoup-directory prefix (if message ".MSG" ".IDX"))))
+   (concat prefix (if message ".MSG" ".IDX"))
+   nnsoup-directory))
 
 (defun nnsoup-message-buffer (prefix)
   (nnsoup-index-buffer prefix 'msg))
@@ -587,7 +598,7 @@
 		(let ((format (gnus-soup-encoding-format
 			       (gnus-soup-area-encoding (nth 1 area)))))
 		  (goto-char end)
-		  (when (or (= format ?n) (= format ?m))
+		  (when (or (= format ?u) (= format ?n) (= format ?m))
 		    (setq end (progn (forward-line -1) (point))))))
 	    (set-buffer msg-buf))
 	  (widen)
@@ -666,8 +677,6 @@
   (require 'mail-utils)
   (let ((tembuf (generate-new-buffer " message temp"))
 	(case-fold-search nil)
-	(real-header-separator mail-header-separator)
-	(mail-header-separator "")
 	delimline
 	(mailbuf (current-buffer)))
     (unwind-protect
@@ -693,15 +702,11 @@
 	    ;; Change header-delimiter to be what sendmail expects.
 	    (goto-char (point-min))
 	    (re-search-forward
-	     (concat "^" (regexp-quote real-header-separator) "\n"))
+	     (concat "^" (regexp-quote mail-header-separator) "\n"))
 	    (replace-match "\n")
 	    (backward-char 1)
 	    (setq delimline (point-marker))
-	    ;; Insert an extra newline if we need it to work around
-	    ;; Sun's bug that swallows newlines.
 	    (goto-char (1+ delimline))
-	    (when (eval message-mailer-swallows-blank-line)
-	      (newline))
 	    (let ((msg-buf
 		   (gnus-soup-store
 		    nnsoup-replies-directory
@@ -724,7 +729,7 @@
   (unless nnsoup-replies-list
     (setq nnsoup-replies-list
 	  (gnus-soup-parse-replies
-	   (concat nnsoup-replies-directory "REPLIES"))))
+	   (expand-file-name "REPLIES" nnsoup-replies-directory))))
   (let ((replies nnsoup-replies-list))
     (while (and replies
 		(not (string= kind (gnus-soup-reply-kind (car replies)))))
@@ -752,7 +757,6 @@
 				 (string-to-int (match-string 1 f2)))))))
 	active group lines ident elem min)
     (set-buffer (get-buffer-create " *nnsoup work*"))
-    (buffer-disable-undo (current-buffer))
     (while files
       (nnheader-message 5 "Doing %s..." (car files))
       (erase-buffer)
@@ -770,13 +774,13 @@
       (if (not (setq elem (assoc group active)))
 	  (push (list group (cons 1 lines)
 		      (list (cons 1 lines)
-			    (vector ident group "ncm" "" lines)))
+			    (vector ident group "ucm" "" lines)))
 		active)
 	(nconc elem
 	       (list
 		(list (cons (1+ (setq min (cdadr elem)))
 			    (+ min lines))
-		      (vector ident group "ncm" "" lines))))
+		      (vector ident group "ucm" "" lines))))
 	(setcdr (cadr elem) (+ min lines)))
       (setq files (cdr files)))
     (nnheader-message 5 "")
@@ -804,7 +808,8 @@
     ;; Sort and delete the files.
     (setq non-files (sort non-files 'string<))
     (map-y-or-n-p "Delete file %s? "
-		  (lambda (file) (delete-file (concat nnsoup-directory file)))
+		  (lambda (file) (delete-file
+				  (expand-file-name file nnsoup-directory)))
 		  non-files)))
 
 (provide 'nnsoup)
--- a/lisp/gnus/nnspool.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnspool.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
 ;;; nnspool.el --- spool access for GNU Emacs
-;; Copyright (C) 1988,89,90,93,94,95,96,97,98 Free Software Foundation, Inc.
+
+;; Copyright (C) 1988, 1989, 1990, 1993, 1994, 1995, 1996, 1997, 1998,
+;;	2000 Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;; 	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,7 +30,6 @@
 
 (require 'nnheader)
 (require 'nntp)
-(require 'timezone)
 (require 'nnoo)
 (eval-when-compile (require 'cl))
 
@@ -85,10 +86,6 @@
 (defvoo nnspool-file-coding-system nnheader-file-coding-system
   "Coding system for nnspool.")
 
-;; 1997/8/14 by MORIOKA Tomohiko
-(defvoo nnspool-file-coding-system nnheader-file-coding-system
-  "Coding system for nnspool.")
-
 
 
 (defconst nnspool-version "nnspool 2.0"
@@ -141,15 +138,20 @@
 	      (setq beg (point))
 	      (inline (nnheader-insert-head file))
 	      (goto-char beg)
-	      (search-forward "\n\n" nil t)
-	      (forward-char -1)
-	      (insert ".\n")
+	      (if (search-forward "\n\n" nil t)
+		  (progn
+		    (forward-char -1)
+		    (insert ".\n"))
+		(goto-char (point-max))
+		(if (bolp)
+		    (insert ".\n")
+		  (insert "\n.\n")))
 	      (delete-region (point) (point-max)))
 
 	    (and do-message
 		 (zerop (% (incf count) 20))
 		 (nnheader-message 5 "nnspool: Receiving headers... %d%%"
-			  (/ (* count 100) number))))
+				   (/ (* count 100) number))))
 
 	  (when do-message
 	    (nnheader-message 5 "nnspool: Receiving headers...done"))
@@ -284,7 +286,7 @@
 	(while (and (not (looking-at
 			  "\\([^ ]+\\) +\\([0-9]+\\)[0-9][0-9][0-9] "))
 		    (zerop (forward-line -1))))
-	(let ((seconds (nnspool-seconds-since-epoch date))
+	(let ((seconds (time-to-seconds (date-to-time date)))
 	      groups)
 	  ;; Go through lines and add the latest groups to a list.
 	  (while (and (looking-at "\\([^ ]+\\) +[0-9]+ ")
@@ -299,8 +301,8 @@
 			     (read (current-buffer)))
 			   seconds))
 		      (push (buffer-substring
-					  (match-beginning 1) (match-end 1))
-					 groups)
+			     (match-beginning 1) (match-end 1))
+			    groups)
 		      (zerop (forward-line -1))))
 	  (erase-buffer)
 	  (while groups
@@ -424,7 +426,6 @@
 (defun nnspool-find-id (id)
   (save-excursion
     (set-buffer (get-buffer-create " *nnspool work*"))
-    (buffer-disable-undo (current-buffer))
     (erase-buffer)
     (ignore-errors
       (call-process "grep" nil t nil (regexp-quote id) nnspool-history-file))
@@ -439,8 +440,8 @@
   (set-buffer nntp-server-buffer)
   (erase-buffer)
   (condition-case ()
-      (let ((nnheader-file-coding-system nnspool-file-coding-system))
-	(nnheader-insert-file-contents file)
+      (let ((coding-system-for-read nnspool-file-coding-system))
+	(mm-insert-file-contents file)
 	t)
     (file-error nil)))
 
@@ -457,18 +458,6 @@
   "Find the path for GROUP."
   (nnheader-group-pathname group nnspool-spool-directory article))
 
-(defun nnspool-seconds-since-epoch (date)
-  (let* ((tdate (mapcar (lambda (ti) (and ti (string-to-int ti)))
-			(timezone-parse-date date)))
-	 (ttime (mapcar (lambda (ti) (and ti (string-to-int ti)))
-			(timezone-parse-time
-			 (aref (timezone-parse-date date) 3))))
-	 (unix (encode-time (nth 2 ttime) (nth 1 ttime) (nth 0 ttime)
-			    (nth 2 tdate) (nth 1 tdate) (nth 0 tdate)
-			    (nth 4 tdate))))
-    (+ (* (car unix) 65536.0)
-       (cadr unix))))
-
 (provide 'nnspool)
 
 ;;; nnspool.el ends here
--- a/lisp/gnus/nntp.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nntp.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,7 @@
-;;; nntp.el --- nntp access for Gnus Copyright (C) 1987-90,92-97 Free
-;;; Software Foundation, Inc.
+;;; nntp.el --- nntp access for Gnus
+;; Copyright (C) 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996,
+;;        1997, 1998, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -28,13 +30,9 @@
 (require 'nnoo)
 (require 'gnus-util)
 
-(eval-when-compile (require 'cl))
-
 (nnoo-declare nntp)
 
-(eval-and-compile
-  (unless (fboundp 'open-network-stream)
-    (require 'tcp)))
+(eval-when-compile (require 'cl))
 
 (defvoo nntp-address nil
   "Address of the physical nntp server.")
@@ -52,10 +50,10 @@
 It is called with no parameters.")
 
 (defvoo nntp-server-action-alist
-  '(("nntpd 1\\.5\\.11t"
-     (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader))
-    ("NNRP server Netscape"
-     (setq nntp-server-list-active-group nil)))
+    '(("nntpd 1\\.5\\.11t"
+       (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader))
+      ("NNRP server Netscape"
+       (setq nntp-server-list-active-group nil)))
   "Alist of regexps to match on server types and actions to be taken.
 For instance, if you want Gnus to beep every time you connect
 to innd, you could say something like:
@@ -89,7 +87,8 @@
 (defvoo nntp-rlogin-user-name nil
   "*User name on remote system when using the rlogin connect method.")
 
-(defvoo nntp-telnet-parameters '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp")
+(defvoo nntp-telnet-parameters
+    '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp")
   "*Parameters to `nntp-open-telnet'.
 That function may be used as `nntp-open-connection-function'.  In that
 case, this list will be executed as a command after logging in
@@ -177,13 +176,6 @@
 					  (const :format "" "password")
 					  (string :format "Password: %v")))))))
 
-;; 1997/5/4 by MORIOKA Tomohiko <morioka@jaist.ac.jp>
-(defvoo nntp-coding-system-for-read 'binary
-  "*Coding system to read from NNTP.")
-
-(defvoo nntp-coding-system-for-write 'binary
-  "*Coding system to write to NNTP.")
-
 
 
 (defvoo nntp-connection-timeout nil
@@ -220,8 +212,18 @@
 (defvoo nntp-server-xover 'try)
 (defvoo nntp-server-list-active-group 'try)
 
+(defvar nntp-async-needs-kluge
+  (string-match "^GNU Emacs 20\\.3\\." (emacs-version))
+  "*When non-nil, nntp will poll asynchronous connections
+once a second.  By default, this is turned on only for Emacs
+20.3, which has a bug that breaks nntp's normal method of
+noticing asynchronous data.")
+
+(defvar nntp-async-timer nil)
+(defvar nntp-async-process-list nil)
+
 (eval-and-compile
-  (autoload 'nnmail-read-passwd "nnmail")
+  (autoload 'mail-source-read-passwd "mail-source")
   (autoload 'open-ssl-stream "ssl"))
 
 
@@ -281,9 +283,9 @@
 	  (nntp-decode-text (not decode))
 	  (unless discard
 	    (save-excursion
-	      (set-buffer buffer)
-	      (goto-char (point-max))
-	      (insert-buffer-substring (process-buffer process))
+ 	      (set-buffer buffer)
+ 	      (goto-char (point-max))
+ 	      (insert-buffer-substring (process-buffer process))
 	      ;; Nix out "nntp reading...." message.
 	      (when nntp-have-messaged
 		(setq nntp-have-messaged nil)
@@ -292,6 +294,11 @@
       (unless discard
 	(erase-buffer)))))
 
+(defun nntp-kill-buffer (buffer)
+  (when (buffer-name buffer)
+    (kill-buffer buffer)
+    (nnheader-init-server-buffer)))
+
 (defsubst nntp-find-connection (buffer)
   "Find the connection delivering to BUFFER."
   (let ((alist nntp-connection-alist)
@@ -304,8 +311,7 @@
     (when process
       (if (memq (process-status process) '(open run))
 	  process
-	(when (buffer-name (process-buffer process))
-	  (kill-buffer (process-buffer process)))
+	(nntp-kill-buffer (process-buffer process))
 	(setq nntp-connection-alist (delq entry nntp-connection-alist))
 	nil))))
 
@@ -330,27 +336,23 @@
 	(save-excursion
 	  (set-buffer (process-buffer process))
 	  (erase-buffer)))
-      (when command
-	(nntp-send-string process command))
-      (cond
-       ((eq callback 'ignore)
-	t)
-       ((and callback wait-for)
-	(save-excursion
-	  (set-buffer (process-buffer process))
-	  (unless nntp-inside-change-function
-	    (erase-buffer))
-	  (setq nntp-process-decode decode
-		nntp-process-to-buffer buffer
-		nntp-process-wait-for wait-for
-		nntp-process-callback callback
-		nntp-process-start-point (point-max)
-		after-change-functions
-		(list 'nntp-after-change-function-callback)))
-	t)
-       (wait-for
-	(nntp-wait-for process wait-for buffer decode))
-       (t t)))))
+      (condition-case err
+	  (progn
+	    (when command
+	      (nntp-send-string process command))
+	    (cond
+	     ((eq callback 'ignore)
+	      t)
+	     ((and callback wait-for)
+	      (nntp-async-wait process wait-for buffer decode callback)
+	      t)
+	     (wait-for
+	      (nntp-wait-for process wait-for buffer decode))
+	     (t t)))
+	(error 
+	 (nnheader-report 'nntp "Couldn't open connection to %s: %s" 
+			  address err))
+	(quit nil)))))
 
 (defsubst nntp-send-command (wait-for &rest strings)
   "Send STRINGS to server and wait until WAIT-FOR returns."
@@ -407,7 +409,7 @@
   (cond
    ;; A result that starts with a 2xx code is terminated by
    ;; a line with only a "." on it.
-   ((eq (following-char) ?2)
+   ((eq (char-after) ?2)
     (if (re-search-forward "\n\\.\r?\n" nil t)
 	t
       nil))
@@ -442,36 +444,36 @@
 	    (nntp-inhibit-erase t)
 	    article)
 	;; Send HEAD commands.
-      (while (setq article (pop articles))
-	(nntp-send-command
-	 nil
-	 "HEAD" (if (numberp article)
-		    (int-to-string article)
-		  ;; `articles' is either a list of article numbers
-		  ;; or a list of article IDs.
-		  article))
-	(incf count)
-	;; Every 400 requests we have to read the stream in
-	;; order to avoid deadlocks.
-	(when (or (null articles)	;All requests have been sent.
-		  (zerop (% count nntp-maximum-request)))
-	  (nntp-accept-response)
-	  (while (progn
-		   (set-buffer buf)
-		   (goto-char last-point)
-		   ;; Count replies.
-		   (while (nntp-next-result-arrived-p)
-		     (setq last-point (point))
-		     (incf received))
-		   (< received count))
-	    ;; If number of headers is greater than 100, give
-	    ;;  informative messages.
-	    (and (numberp nntp-large-newsgroup)
-		 (> number nntp-large-newsgroup)
-		 (zerop (% received 20))
-		 (nnheader-message 6 "NNTP: Receiving headers... %d%%"
-				   (/ (* received 100) number)))
-	    (nntp-accept-response))))
+	(while (setq article (pop articles))
+	  (nntp-send-command
+	   nil
+	   "HEAD" (if (numberp article)
+		      (int-to-string article)
+		    ;; `articles' is either a list of article numbers
+		    ;; or a list of article IDs.
+		    article))
+	  (incf count)
+	  ;; Every 400 requests we have to read the stream in
+	  ;; order to avoid deadlocks.
+	  (when (or (null articles)	;All requests have been sent.
+		    (zerop (% count nntp-maximum-request)))
+	    (nntp-accept-response)
+	    (while (progn
+		     (set-buffer buf)
+		     (goto-char last-point)
+		     ;; Count replies.
+		     (while (nntp-next-result-arrived-p)
+		       (setq last-point (point))
+		       (incf received))
+		     (< received count))
+	      ;; If number of headers is greater than 100, give
+	      ;;  informative messages.
+	      (and (numberp nntp-large-newsgroup)
+		   (> number nntp-large-newsgroup)
+		   (zerop (% received 20))
+		   (nnheader-message 6 "NNTP: Receiving headers... %d%%"
+				     (/ (* received 100) number)))
+	      (nntp-accept-response))))
 	(and (numberp nntp-large-newsgroup)
 	     (> number nntp-large-newsgroup)
 	     (nnheader-message 6 "NNTP: Receiving headers...done"))
@@ -486,64 +488,75 @@
 (deffoo nntp-retrieve-groups (groups &optional server)
   "Retrieve group info on GROUPS."
   (nntp-possibly-change-group nil server)
-  (save-excursion
-    (set-buffer (nntp-find-connection-buffer nntp-server-buffer))
-    ;; The first time this is run, this variable is `try'.  So we
-    ;; try.
-    (when (eq nntp-server-list-active-group 'try)
-      (nntp-try-list-active (car groups)))
-    (erase-buffer)
-    (let ((count 0)
-	  (received 0)
-	  (last-point (point-min))
-	  (nntp-inhibit-erase t)
-	  (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP")))
-      (while groups
-	;; Send the command to the server.
-	(nntp-send-command nil command (pop groups))
-	(incf count)
-	;; Every 400 requests we have to read the stream in
-	;; order to avoid deadlocks.
-	(when (or (null groups)		;All requests have been sent.
-		  (zerop (% count nntp-maximum-request)))
-	  (nntp-accept-response)
+  (when (nntp-find-connection-buffer nntp-server-buffer)
+    (save-excursion
+      ;; Erase nntp-server-buffer before nntp-inhibit-erase.
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (set-buffer (nntp-find-connection-buffer nntp-server-buffer))
+      ;; The first time this is run, this variable is `try'.  So we
+      ;; try.
+      (when (eq nntp-server-list-active-group 'try)
+	(nntp-try-list-active (car groups)))
+      (erase-buffer)
+      (let ((count 0)
+	    (received 0)
+	    (last-point (point-min))
+	    (nntp-inhibit-erase t)
+	    (buf (nntp-find-connection-buffer nntp-server-buffer))
+	    (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP")))
+	(while groups
+	  ;; Send the command to the server.
+	  (nntp-send-command nil command (pop groups))
+	  (incf count)
+	  ;; Every 400 requests we have to read the stream in
+	  ;; order to avoid deadlocks.
+	  (when (or (null groups)	;All requests have been sent.
+		    (zerop (% count nntp-maximum-request)))
+	    (nntp-accept-response)
+	    (while (progn
+		     ;; Search `blue moon' in this file for the
+		     ;; reason why set-buffer here.
+		     (set-buffer buf)
+		     (goto-char last-point)
+		     ;; Count replies.
+		     (while (re-search-forward "^[0-9]" nil t)
+		       (incf received))
+		     (setq last-point (point))
+		     (< received count))
+	      (nntp-accept-response))))
+
+	;; Wait for the reply from the final command.
+	(set-buffer buf)
+	(goto-char (point-max))
+	(re-search-backward "^[0-9]" nil t)
+	(when (looking-at "^[23]")
 	  (while (progn
-		   (goto-char last-point)
-		   ;; Count replies.
-		   (while (re-search-forward "^[0-9]" nil t)
-		     (incf received))
-		   (setq last-point (point))
-		   (< received count))
-	    (nntp-accept-response))))
+		   (set-buffer buf)
+		   (goto-char (point-max))
+		   (if (not nntp-server-list-active-group)
+		       (not (re-search-backward "\r?\n" (- (point) 3) t))
+		     (not (re-search-backward "^\\.\r?\n" (- (point) 4) t))))
+	    (nntp-accept-response)))
+
+	;; Now all replies are received.  We remove CRs.
+	(set-buffer buf)
+	(goto-char (point-min))
+	(while (search-forward "\r" nil t)
+	  (replace-match "" t t))
 
-      ;; Wait for the reply from the final command.
-      (goto-char (point-max))
-      (re-search-backward "^[0-9]" nil t)
-      (when (looking-at "^[23]")
-	(while (progn
-		 (goto-char (point-max))
-		 (if (not nntp-server-list-active-group)
-		     (not (re-search-backward "\r?\n" (- (point) 3) t))
-		   (not (re-search-backward "^\\.\r?\n" (- (point) 4) t))))
-	  (nntp-accept-response)))
-
-      ;; Now all replies are received.  We remove CRs.
-      (goto-char (point-min))
-      (while (search-forward "\r" nil t)
-	(replace-match "" t t))
-
-      (if (not nntp-server-list-active-group)
-	  (progn
-	    (copy-to-buffer nntp-server-buffer (point-min) (point-max))
-	    'group)
-	;; We have read active entries, so we just delete the
-	;; superfluous gunk.
-	(goto-char (point-min))
-	(while (re-search-forward "^[.2-5]" nil t)
-	  (delete-region (match-beginning 0)
-			 (progn (forward-line 1) (point))))
-	(copy-to-buffer nntp-server-buffer (point-min) (point-max))
-	'active))))
+	(if (not nntp-server-list-active-group)
+	    (progn
+	      (copy-to-buffer nntp-server-buffer (point-min) (point-max))
+	      'group)
+	  ;; We have read active entries, so we just delete the
+	  ;; superfluous gunk.
+	  (goto-char (point-min))
+	  (while (re-search-forward "^[.2-5]" nil t)
+	    (delete-region (match-beginning 0)
+			   (progn (forward-line 1) (point))))
+	  (copy-to-buffer nntp-server-buffer (point-min) (point-max))
+	  'active)))))
 
 (deffoo nntp-retrieve-articles (articles &optional group server)
   (nntp-possibly-change-group group server)
@@ -625,9 +638,14 @@
 	   (setq nntp-server-list-active-group t)))))
 
 (deffoo nntp-list-active-group (group &optional server)
-  "Return the active info on GROUP (which can be a regexp."
+  "Return the active info on GROUP (which can be a regexp)."
   (nntp-possibly-change-group nil server)
-  (nntp-send-command "^.*\r?\n" "LIST ACTIVE" group))
+  (nntp-send-command "^\\.*\r?\n" "LIST ACTIVE" group))
+
+(deffoo nntp-request-group-articles (group &optional server)
+  "Return the list of existing articles in GROUP."
+  (nntp-possibly-change-group nil server)
+  (nntp-send-command "^\\.*\r?\n" "LISTGROUP" group))
 
 (deffoo nntp-request-article (article &optional group server buffer command)
   (nntp-possibly-change-group group server)
@@ -700,8 +718,7 @@
 	    ;; QUIT command actually is sent out before we kill
 	    ;; the process.
 	    (sleep-for 1))))
-      (when (buffer-name (process-buffer process))
-	(kill-buffer (process-buffer process)))
+      (nntp-kill-buffer (process-buffer process))
       (setq process (car (pop nntp-connection-alist))))
     (nnoo-close-server 'nntp)))
 
@@ -717,8 +734,7 @@
 	    ;; QUIT command actually is sent out before we kill
 	    ;; the process.
 	    (sleep-for 1))))
-      (when (buffer-name (process-buffer process))
-	(kill-buffer (process-buffer process))))))
+      (nntp-kill-buffer (process-buffer process)))))
 
 (deffoo nntp-request-list (&optional server)
   (nntp-possibly-change-group nil server)
@@ -735,7 +751,7 @@
     (prog1
 	(nntp-send-command
 	 "^\\.\r?\n" "NEWGROUPS"
-	 (format-time-string "%y%m%d %H%M%S" (nnmail-date-to-time date)))
+	 (format-time-string "%y%m%d %H%M%S" (date-to-time date)))
       (nntp-decode-text))))
 
 (deffoo nntp-request-post (&optional server)
@@ -756,7 +772,7 @@
 This function is supposed to be called from `nntp-server-opened-hook'.
 It will make innd servers spawn an nnrpd process to allow actual article
 reading."
-  (nntp-send-command "^.*\r?\n" "MODE READER"))
+  (nntp-send-command "^.*\n" "MODE READER"))
 
 (defun nntp-send-authinfo (&optional send-if-force)
   "Send the AUTHINFO to the nntp server.
@@ -767,7 +783,7 @@
 If SEND-IF-FORCE, only send authinfo to the server if the
 .authinfo file has the FORCE token."
   (let* ((list (gnus-parse-netrc nntp-authinfo-file))
-	 (alist (gnus-netrc-machine list nntp-address))
+	 (alist (gnus-netrc-machine list nntp-address "nntp"))
 	 (force (gnus-netrc-get alist "force"))
 	 (user (or (gnus-netrc-get alist "login") nntp-authinfo-user))
 	 (passwd (gnus-netrc-get alist "password")))
@@ -779,13 +795,13 @@
       (unless (member user '(nil ""))
 	(nntp-send-command "^3.*\r?\n" "AUTHINFO USER" user)
 	(when t				;???Should check if AUTHINFO succeeded
-      (nntp-send-command
-       "^2.*\r?\n" "AUTHINFO PASS"
-       (or passwd
-	   nntp-authinfo-password
-	   (setq nntp-authinfo-password
-		     (nnmail-read-passwd (format "NNTP (%s@%s) password: "
-						 user nntp-address))))))))))
+	  (nntp-send-command
+	   "^2.*\r?\n" "AUTHINFO PASS"
+	   (or passwd
+	       nntp-authinfo-password
+	       (setq nntp-authinfo-password
+		     (mail-source-read-passwd (format "NNTP (%s@%s) password: "
+						      user nntp-address))))))))))
 
 (defun nntp-send-nosy-authinfo ()
   "Send the AUTHINFO to the nntp server."
@@ -794,8 +810,8 @@
       (nntp-send-command "^3.*\r?\n" "AUTHINFO USER" user)
       (when t				;???Should check if AUTHINFO succeeded
 	(nntp-send-command "^2.*\r?\n" "AUTHINFO PASS"
-			   (nnmail-read-passwd "NNTP (%s@%s) password: "
-					       user nntp-address))))))
+			   (mail-source-read-passwd "NNTP (%s@%s) password: "
+						    user nntp-address))))))
 
 (defun nntp-send-authinfo-from-file ()
   "Send the AUTHINFO to the nntp server.
@@ -803,7 +819,7 @@
 The authinfo login name is taken from the user's login name and the
 password contained in '~/.nntp-authinfo'."
   (when (file-exists-p "~/.nntp-authinfo")
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (insert-file-contents "~/.nntp-authinfo")
       (goto-char (point-min))
       (nntp-send-command "^3.*\r?\n" "AUTHINFO USER" (user-login-name))
@@ -832,7 +848,7 @@
       (format " *server %s %s %s*"
 	      nntp-address nntp-port-number
 	      (gnus-buffer-exists-p buffer))))
-    (buffer-disable-undo (current-buffer))
+    (mm-enable-multibyte)
     (set (make-local-variable 'after-change-functions) nil)
     (set (make-local-variable 'nntp-process-wait-for) nil)
     (set (make-local-variable 'nntp-process-callback) nil)
@@ -850,8 +866,7 @@
 	       (nnheader-run-at-time
 		nntp-connection-timeout nil
 		`(lambda ()
-		   (when (buffer-name ,pbuffer)
-		     (kill-buffer ,pbuffer))))))
+		   (nntp-kill-buffer ,pbuffer)))))
 	 (process
 	  (condition-case ()
 	      (let ((coding-system-for-read nntp-coding-system-for-read)
@@ -877,8 +892,7 @@
 	      (let ((nnheader-callback-function nil))
 		(run-hooks 'nntp-server-opened-hook)
 		(nntp-send-authinfo t))))
-	(when (buffer-name (process-buffer process))
-	  (kill-buffer (process-buffer process)))
+	(nntp-kill-buffer (process-buffer process))
 	nil))))
 
 (defun nntp-open-network-stream (buffer)
@@ -910,40 +924,97 @@
 	    (eval (cadr entry))
 	  (funcall (cadr entry)))))))
 
-(defun nntp-after-change-function-callback (beg end len)
-  (when nntp-process-callback
-    (save-match-data
-      (if (and (= beg (point-min))
-	       (memq (char-after beg) '(?4 ?5)))
-	  ;; Report back error messages.
-	  (save-excursion
-	    (goto-char beg)
-	    (if (looking-at "480")
-		(nntp-handle-authinfo nntp-process-to-buffer)
-	      (nntp-snarf-error-message)
-	      (funcall nntp-process-callback nil)))
-	(goto-char end)
-	(when (and (> (point) nntp-process-start-point)
-		   (re-search-backward nntp-process-wait-for
-				       nntp-process-start-point t))
+(defun nntp-async-wait (process wait-for buffer decode callback)
+  (save-excursion
+    (set-buffer (process-buffer process))
+    (unless nntp-inside-change-function
+      (erase-buffer))
+    (setq nntp-process-wait-for wait-for
+	  nntp-process-to-buffer buffer
+	  nntp-process-decode decode
+	  nntp-process-callback callback
+	  nntp-process-start-point (point-max))
+    (setq after-change-functions '(nntp-after-change-function))
+    (if nntp-async-needs-kluge
+	(nntp-async-kluge process))))
+
+(defun nntp-async-kluge (process)
+  ;; emacs 20.3 bug: process output with encoding 'binary
+  ;; doesn't trigger after-change-functions.
+  (unless nntp-async-timer
+    (setq nntp-async-timer
+	  (nnheader-run-at-time 1 1 'nntp-async-timer-handler)))
+  (add-to-list 'nntp-async-process-list process))
+
+(defun nntp-async-timer-handler ()
+  (mapcar
+   (lambda (proc)
+     (if (memq (process-status proc) '(open run))
+	 (nntp-async-trigger proc)
+       (nntp-async-stop proc)))
+   nntp-async-process-list))
+
+(defun nntp-async-stop (proc)
+  (setq nntp-async-process-list (delq proc nntp-async-process-list))
+  (when (and nntp-async-timer (not nntp-async-process-list))
+    (nnheader-cancel-timer nntp-async-timer)
+    (setq nntp-async-timer nil)))
+
+(defun nntp-after-change-function (beg end len)
+  (unwind-protect
+      ;; we only care about insertions at eob
+      (when (and (eq 0 len) (eq (point-max) end))
+	(save-match-data
+	  (let ((proc (get-buffer-process (current-buffer))))
+	    (when proc
+	      (nntp-async-trigger proc)))))
+    ;; any throw from after-change-functions will leave it
+    ;; set to nil.  so we reset it here, if necessary.
+    (when quit-flag
+      (setq after-change-functions '(nntp-after-change-function)))))
+
+(defun nntp-async-trigger (process)
+  (save-excursion
+    (set-buffer (process-buffer process))
+    (when nntp-process-callback
+      ;; do we have an error message?
+      (goto-char nntp-process-start-point)
+      (if (memq (following-char) '(?4 ?5))
+	  ;; wants credentials?
+	  (if (looking-at "480")
+	      (nntp-handle-authinfo nntp-process-to-buffer)
+	    ;; report error message.
+	    (nntp-snarf-error-message)
+	    (nntp-do-callback nil))
+
+	;; got what we expect?
+	(goto-char (point-max))
+	(when (re-search-backward
+	       nntp-process-wait-for nntp-process-start-point t)
+	  (nntp-async-stop process)
+	  ;; convert it.
 	  (when (gnus-buffer-exists-p nntp-process-to-buffer)
-	    (let ((cur (current-buffer))
-		  (start nntp-process-start-point))
+	    (let ((buf (current-buffer))
+		  (start nntp-process-start-point)
+		  (decode nntp-process-decode))
 	      (save-excursion
 		(set-buffer nntp-process-to-buffer)
 		(goto-char (point-max))
-		(let ((b (point)))
-		  (insert-buffer-substring cur start)
-		  (narrow-to-region b (point-max))
-		  (nntp-decode-text)
-		  (widen)))))
-	  (goto-char end)
-	  (let ((callback nntp-process-callback)
-		(nntp-inside-change-function t))
-	    (setq nntp-process-callback nil)
-	    (save-excursion
-	      (funcall callback (buffer-name
-				 (get-buffer nntp-process-to-buffer))))))))))
+		(save-restriction
+		  (narrow-to-region (point) (point))
+		  (insert-buffer-substring buf start)
+		  (when decode
+		    (nntp-decode-text))))))
+	  ;; report it.
+	  (goto-char (point-max))
+	  (nntp-do-callback
+	   (buffer-name (get-buffer nntp-process-to-buffer))))))))
+
+(defun nntp-do-callback (arg)
+  (let ((callback nntp-process-callback)
+	(nntp-inside-change-function t))
+    (setq nntp-process-callback nil)
+    (funcall callback arg)))
 
 (defun nntp-snarf-error-message ()
   "Save the error message in the current buffer."
@@ -953,7 +1024,7 @@
     (nnheader-report 'nntp message)
     message))
 
-(defun nntp-accept-process-output (process)
+(defun nntp-accept-process-output (process &optional timeout)
   "Wait for output from PROCESS and message some dots."
   (save-excursion
     (set-buffer (or (nntp-find-connection-buffer nntp-server-buffer)
@@ -963,7 +1034,7 @@
       (unless (< len 10)
 	(setq nntp-have-messaged t)
 	(nnheader-message 7 "nntp read: %dk" len)))
-    (accept-process-output process 1)))
+    (accept-process-output process (or timeout 1))))
 
 (defun nntp-accept-response ()
   "Wait for output from the process that outputs to BUFFER."
@@ -985,10 +1056,7 @@
 	(save-excursion
 	  (set-buffer (process-buffer (car entry)))
 	  (erase-buffer)
-	  (nntp-send-string (car entry) (concat "GROUP " group))
-	  ;; allow for unexpected responses, since this can be called
-	  ;; from a timer with quit inhibited
-	  (nntp-wait-for-string "^[245].*\n")
+	  (nntp-send-command "^[245].*\n" "GROUP" group)
 	  (setcar (cddr entry) group)
 	  (erase-buffer))))))
 
@@ -1051,7 +1119,7 @@
      (car (last articles)) 'wait)
 
     (goto-char (point-min))
-    (when (looking-at "[1-5][0-9][0-9] ")
+    (when (looking-at "[1-5][0-9][0-9] .*\n")
       (delete-region (point) (progn (forward-line 1) (point))))
     (while (search-forward "\r" nil t)
       (replace-match "" t t))
@@ -1068,9 +1136,10 @@
    ((numberp nntp-nov-gap)
     (let ((count 0)
 	  (received 0)
-	  (last-point (point-min))
+	  last-point
+	  in-process-buffer-p
 	  (buf nntp-server-buffer)
-	  ;;(process-buffer (nntp-find-connection (current-buffer))))
+	  (process-buffer (nntp-find-connection-buffer nntp-server-buffer))
 	  first)
       ;; We have to check `nntp-server-xover'.  If it gets set to nil,
       ;; that means that the server does not understand XOVER, but we
@@ -1083,40 +1152,58 @@
 		    (< (- (nth 1 articles) (car articles)) nntp-nov-gap))
 	  (setq articles (cdr articles)))
 
-	(when (nntp-send-xover-command first (car articles))
-	  (setq articles (cdr articles)
-		count (1+ count))
-
+	(setq in-process-buffer-p (stringp nntp-server-xover))
+	(nntp-send-xover-command first (car articles))
+	(setq articles (cdr articles))
+	
+	(when (and nntp-server-xover in-process-buffer-p)
+	  ;; Don't count tried request.
+	  (setq count (1+ count))
+	  
 	  ;; Every 400 requests we have to read the stream in
 	  ;; order to avoid deadlocks.
 	  (when (or (null articles)	;All requests have been sent.
 		    (zerop (% count nntp-maximum-request)))
-	    (accept-process-output)
-	    ;; On some Emacs versions the preceding function has
-	    ;; a tendency to change the buffer.  Perhaps.  It's
-	    ;; quite difficult to reproduce, because it only
-	    ;; seems to happen once in a blue moon.
-	    (set-buffer buf)
+
+	    (nntp-accept-response)
+	    ;; On some Emacs versions the preceding function has a
+	    ;; tendency to change the buffer.  Perhaps.  It's quite
+	    ;; difficult to reproduce, because it only seems to happen
+	    ;; once in a blue moon.
+	    (set-buffer process-buffer)
 	    (while (progn
-		     (goto-char last-point)
+		     (goto-char (or last-point (point-min)))
 		     ;; Count replies.
-		     (while (re-search-forward "^[0-9][0-9][0-9] " nil t)
-		       (setq received (1+ received)))
+		     (while (re-search-forward "^[0-9][0-9][0-9] .*\n" nil t)
+		       (incf received))
 		     (setq last-point (point))
 		     (< received count))
-	      (accept-process-output)
-	      (set-buffer buf)))))
+	      (nntp-accept-response)
+	      (set-buffer process-buffer))
+	    (set-buffer buf))))
 
       (when nntp-server-xover
-	;; Wait for the reply from the final command.
-	(goto-char (point-max))
-	(re-search-backward "^[0-9][0-9][0-9] " nil t)
-	(when (looking-at "^[23]")
-	  (while (progn
-		   (goto-char (point-max))
-		   (forward-line -1)
-		   (not (looking-at "^\\.\r?\n")))
-	    (nntp-accept-response)))
+	(when in-process-buffer-p
+	  (set-buffer process-buffer)
+	  ;; Wait for the reply from the final command.
+	  (goto-char (point-max))
+	  (while (not (re-search-backward "^[0-9][0-9][0-9] " nil t))
+	    (nntp-accept-response)
+	    (set-buffer process-buffer)
+	    (goto-char (point-max)))
+	  (when (looking-at "^[23]")
+	    (while (progn
+		     (goto-char (point-max))
+		     (forward-line -1)
+		     (not (looking-at "^\\.\r?\n")))
+	      (nntp-accept-response)
+	      (set-buffer process-buffer)))
+	  (set-buffer buf)
+	  (goto-char (point-max))
+	  (insert-buffer-substring process-buffer)
+	  (set-buffer process-buffer)
+	  (erase-buffer)
+	  (set-buffer buf))
 
 	;; We remove any "." lines and status lines.
 	(goto-char (point-min))
@@ -1124,7 +1211,6 @@
 	  (delete-char -1))
 	(goto-char (point-min))
 	(delete-matching-lines "^\\.$\\|^[1-5][0-9][0-9] ")
-	;;(copy-to-buffer nntp-server-buffer (point-min) (point-max))
 	t))))
 
   nntp-server-xover)
@@ -1140,7 +1226,7 @@
 	    (nntp-send-command-nodelete
 	     "\r?\n\\.\r?\n" nntp-server-xover range)
 	  ;; We do not wait for the reply.
-	  (nntp-send-command-nodelete "\r?\n\\.\r?\n" nntp-server-xover range))
+	  (nntp-send-command-nodelete nil nntp-server-xover range))
       (let ((commands nntp-xover-commands))
 	;; `nntp-xover-commands' is a list of possible XOVER commands.
 	;; We try them all until we get at positive response.
@@ -1206,9 +1292,8 @@
 	 proc (concat
 	       (or nntp-telnet-passwd
 		   (setq nntp-telnet-passwd
-			 (nnmail-read-passwd "Password: ")))
+			 (mail-source-read-passwd "Password: ")))
 	       "\n"))
-	(erase-buffer)
 	(nntp-wait-for-string nntp-telnet-shell-prompt)
 	(process-send-string
 	 proc (concat (mapconcat 'identity nntp-telnet-parameters " ") "\n"))
--- a/lisp/gnus/nnvirtual.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnvirtual.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnvirtual.el --- virtual newsgroups access for Gnus
-;; Copyright (C) 1994,95,96,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: David Moore <dmoore@ucsd.edu>
 ;;	Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -45,10 +46,9 @@
 
 (defvoo nnvirtual-always-rescan t
   "*If non-nil, always scan groups for unread articles when entering a group.
-If this variable is nil (which is the default) and you read articles
-in a component group after the virtual group has been activated, the
-read articles from the component group will show up when you enter the
-virtual group.")
+If this variable is nil and you read articles in a component group
+after the virtual group has been activated, the read articles from the
+component group will show up when you enter the virtual group.")
 
 (defvoo nnvirtual-component-regexp nil
   "*Regexp to match component groups.")
@@ -63,8 +63,7 @@
 (defvoo nnvirtual-current-group nil)
 
 (defvoo nnvirtual-mapping-table nil
-  "Table of rules on how to map between component group and article number
-to virtual article number.")
+  "Table of rules on how to map between component group and article number to virtual article number.")
 
 (defvoo nnvirtual-mapping-offsets nil
   "Table indexed by component group to an offset to be applied to article numbers in that group.")
@@ -122,47 +121,47 @@
 		       (let ((gnus-use-cache t))
 			 (setq result (gnus-retrieve-headers
 				       articles cgroup nil))))
-	    (set-buffer nntp-server-buffer)
-	    ;; If we got HEAD headers, we convert them into NOV
-	    ;; headers.  This is slow, inefficient and, come to think
-	    ;; of it, downright evil.  So sue me.  I couldn't be
-	    ;; bothered to write a header parse routine that could
-	    ;; parse a mixed HEAD/NOV buffer.
-	    (when (eq result 'headers)
-	      (nnvirtual-convert-headers))
-	    (goto-char (point-min))
-	    (while (not (eobp))
-	      (delete-region (point)
-			     (progn
-			       (setq carticle (read nntp-server-buffer))
-			       (point)))
+	      (set-buffer nntp-server-buffer)
+	      ;; If we got HEAD headers, we convert them into NOV
+	      ;; headers.  This is slow, inefficient and, come to think
+	      ;; of it, downright evil.  So sue me.  I couldn't be
+	      ;; bothered to write a header parse routine that could
+	      ;; parse a mixed HEAD/NOV buffer.
+	      (when (eq result 'headers)
+		(nnvirtual-convert-headers))
+	      (goto-char (point-min))
+	      (while (not (eobp))
+		(delete-region (point)
+			       (progn
+				 (setq carticle (read nntp-server-buffer))
+				 (point)))
 
-	      ;; We remove this article from the articles list, if
-	      ;; anything is left in the articles list after going through
-	      ;; the entire buffer, then those articles have been
-	      ;; expired or canceled, so we appropriately update the
-	      ;; component group below.  They should be coming up
-	      ;; generally in order, so this shouldn't be slow.
-	      (setq articles (delq carticle articles))
+		;; We remove this article from the articles list, if
+		;; anything is left in the articles list after going through
+		;; the entire buffer, then those articles have been
+		;; expired or canceled, so we appropriately update the
+		;; component group below.  They should be coming up
+		;; generally in order, so this shouldn't be slow.
+		(setq articles (delq carticle articles))
 
-	      (setq article (nnvirtual-reverse-map-article cgroup carticle))
-	      (if (null article)
-		  ;; This line has no reverse mapping, that means it
-		  ;; was an extra article reference returned by nntp.
-		  (progn
-		    (beginning-of-line)
-		    (delete-region (point) (progn (forward-line 1) (point))))
-		;; Otherwise insert the virtual article number,
-		;; and clean up the xrefs.
-		(princ article nntp-server-buffer)
-		(nnvirtual-update-xref-header cgroup carticle
-					      prefix system-name)
-		(forward-line 1))
-	      )
+		(setq article (nnvirtual-reverse-map-article cgroup carticle))
+		(if (null article)
+		    ;; This line has no reverse mapping, that means it
+		    ;; was an extra article reference returned by nntp.
+		    (progn
+		      (beginning-of-line)
+		      (delete-region (point) (progn (forward-line 1) (point))))
+		  ;; Otherwise insert the virtual article number,
+		  ;; and clean up the xrefs.
+		  (princ article nntp-server-buffer)
+		  (nnvirtual-update-xref-header cgroup carticle
+						prefix system-name)
+		  (forward-line 1))
+		)
 
-	    (set-buffer vbuf)
-	    (goto-char (point-max))
-	    (insert-buffer-substring nntp-server-buffer))
+	      (set-buffer vbuf)
+	      (goto-char (point-max))
+	      (insert-buffer-substring nntp-server-buffer))
 	    ;; Anything left in articles is expired or canceled.
 	    ;; Could be smart and not tell it about articles already known?
 	    (when articles
@@ -199,8 +198,9 @@
 	  (save-excursion
 	    (when buffer
 	      (set-buffer buffer))
-	    (let ((method (gnus-find-method-for-group
-			   nnvirtual-last-accessed-component-group)))
+	    (let* ((gnus-override-method nil)
+		   (method (gnus-find-method-for-group
+			    nnvirtual-last-accessed-component-group)))
 	      (funcall (gnus-get-function method 'request-article)
 		       article nil (nth 1 method) buffer)))))
       ;; This is a fetch by number.
@@ -219,7 +219,9 @@
 	  (if buffer
 	      (save-excursion
 		(set-buffer buffer)
-		(gnus-request-article-this-buffer (cdr amap) cgroup))
+		;; We bind this here to avoid double decoding.
+		(let ((gnus-article-decode-hook nil))
+		  (gnus-request-article-this-buffer (cdr amap) cgroup)))
 	    (gnus-request-article (cdr amap) cgroup))))))))
 
 
@@ -283,11 +285,11 @@
 
 (deffoo nnvirtual-request-update-mark (group article mark)
   (let* ((nart (nnvirtual-map-article article))
-	 (cgroup (car nart))
-	 ;; The component group might be a virtual group.
-	 (nmark (gnus-request-update-mark cgroup (cdr nart) mark)))
+	 (cgroup (car nart)))
     (when (and nart
-	       (= mark nmark)
+	       (memq mark gnus-auto-expirable-marks)
+	       ;; The component group might be a virtual group.
+	       (= mark (gnus-request-update-mark cgroup (cdr nart) mark))
 	       (gnus-group-auto-expirable-p cgroup))
       (setq mark gnus-expirable-mark)))
   mark)
@@ -359,6 +361,22 @@
 		       (cdr gnus-message-group-art)))))
       (gnus-request-post (gnus-find-method-for-group group)))))
 
+
+(deffoo nnvirtual-request-expire-articles (articles group 
+						    &optional server force)
+  (nnvirtual-possibly-change-server server)
+  (setq nnvirtual-component-groups
+	(delete (nnvirtual-current-group) nnvirtual-component-groups))
+  (let (unexpired)
+    (dolist (group nnvirtual-component-groups)
+      (setq unexpired (nconc unexpired
+			     (mapcar
+			      #'(lambda (article)
+				  (nnvirtual-reverse-map-article
+				   group article))
+			      (gnus-group-expire-articles-1 group)))))
+    (sort unexpired '<)))
+
 
 ;;; Internal functions.
 
@@ -385,7 +403,7 @@
     (insert "\t"))
 
   ;; Remove any spaces at the beginning of the Xref field.
-  (while (= (char-after (1- (point))) ? )
+  (while (eq (char-after (1- (point))) ? )
     (forward-char -1)
     (delete-char 1))
 
@@ -417,7 +435,7 @@
 
   ;; Ensure a trailing \t.
   (end-of-line)
-  (or (= (char-after (1- (point))) ?\t)
+  (or (eq (char-after (1- (point))) ?\t)
       (insert ?\t)))
 
 
@@ -436,19 +454,24 @@
 			(nnvirtual-partition-sequence
 			 (gnus-list-of-unread-articles
 			  (nnvirtual-current-group)))))
-	  (type-marks (mapcar (lambda (ml)
-				(cons (car ml)
-				      (nnvirtual-partition-sequence (cdr ml))))
-			      (gnus-info-marks (gnus-get-info
-						(nnvirtual-current-group)))))
+	  (type-marks
+	   (delq nil
+		 (mapcar (lambda (ml)
+			   (if (eq (car ml) 'score)
+			       nil
+			     (cons (car ml)
+				   (nnvirtual-partition-sequence (cdr ml)))))
+			 (gnus-info-marks (gnus-get-info
+					   (nnvirtual-current-group))))))
 	  mark type groups carticles info entry)
 
       ;; Ok, atomically move all of the (un)read info, clear any old
       ;; marks, and move all of the current marks.  This way if someone
       ;; hits C-g, you won't leave the component groups in a half-way state.
-      (gnus-atomic-progn
+      (progn
 	;; move (un)read
-	(let ((gnus-newsgroup-active nil)) ;workaround guns-update-read-articles
+	;; bind for workaround guns-update-read-articles
+	(let ((gnus-newsgroup-active nil))
 	  (while (setq entry (pop unreads))
 	    (gnus-update-read-articles (car entry) (cdr entry))))
 
@@ -457,7 +480,11 @@
 	(while groups
 	  (when (and (setq info (gnus-get-info (pop groups)))
 		     (gnus-info-marks info))
-	    (gnus-info-set-marks info nil)))
+	    (gnus-info-set-marks
+	     info
+	     (if (assq 'score (gnus-info-marks info))
+		 (list (assq 'score (gnus-info-marks info)))
+	       nil))))
 
 	;; Ok, currently type-marks is an assq list with keys of a mark type,
 	;; with data of an assq list with keys of component group names
@@ -571,7 +598,7 @@
 	       (aref entry 1)
 	       (cdr (aref nnvirtual-mapping-offsets group-pos)))
 	    ))
-      ))
+    ))
 
 
 
@@ -629,7 +656,7 @@
   "Return an association list of component article numbers.
 These are indexed by elements of nnvirtual-component-groups, based on
 the sequence ARTICLES of virtual article numbers.  ARTICLES should be
-sorted, and can be a compressed sequence. If any of the article
+sorted, and can be a compressed sequence.  If any of the article
 numbers has no corresponding component article, then it is left out of
 the result."
   (when (numberp (cdr-safe articles))
@@ -692,7 +719,7 @@
 		(setq cnt (1+ cnt)
 		      tot (+ tot size)
 		      M (max M size))))
-	  nnvirtual-component-groups)
+	    nnvirtual-component-groups)
 
     ;; Number of articles in the virtual group.
     (setq nnvirtual-mapping-len tot)
--- a/lisp/gnus/nnweb.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/nnweb.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,5 +1,6 @@
 ;;; nnweb.el --- retrieving articles via web search engines
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -30,23 +31,24 @@
 
 (eval-when-compile (require 'cl))
 
-(eval-when-compile (require 'cl))
-
 (require 'nnoo)
 (require 'message)
 (require 'gnus-util)
 (require 'gnus)
 (require 'nnmail)
+(require 'mm-util)
 (eval-when-compile
   (ignore-errors
-   (require 'w3)
-   (require 'url)
-   (require 'w3-forms)))
+    (require 'w3)
+    (require 'url)
+    (require 'w3-forms)))
+
 ;; Report failure to find w3 at load time if appropriate.
-(eval '(progn
-	 (require 'w3)
-	 (require 'url)
-	 (require 'w3-forms)))
+(unless noninteractive
+  (eval '(progn
+	   (require 'w3)
+	   (require 'url)
+	   (require 'w3-forms))))
 
 (nnoo-declare nnweb)
 
@@ -58,18 +60,19 @@
 Valid types include `dejanews', `dejanewsold', `reference',
 and `altavista'.")
 
-(defvoo nnweb-type-definition
+(defvar nnweb-type-definition
   '((dejanews
-     (article . nnweb-dejanews-wash-article)
+     (article . ignore)
+     (id . "http://search.dejanews.com/msgid.xp?MID=%s&fmt=text")
      (map . nnweb-dejanews-create-mapping)
      (search . nnweb-dejanews-search)
-     (address . "http://x8.dejanews.com/dnquery.xp")
+     (address . "http://www.deja.com/=dnc/qs.xp")
      (identifier . nnweb-dejanews-identity))
     (dejanewsold
-     (article . nnweb-dejanews-wash-article)
+     (article . ignore)
      (map . nnweb-dejanews-create-mapping)
      (search . nnweb-dejanewsold-search)
-     (address . "http://x8.dejanews.com/dnquery.xp")
+     (address . "http://www.deja.com/dnquery.xp")
      (identifier . nnweb-dejanews-identity))
     (reference
      (article . nnweb-reference-wash-article)
@@ -113,14 +116,14 @@
     (set-buffer nntp-server-buffer)
     (erase-buffer)
     (let (article header)
-      (while (setq article (pop articles))
-	(when (setq header (cadr (assq article nnweb-articles)))
-	  (nnheader-insert-nov header)))
+      (mm-with-unibyte-current-buffer
+	(while (setq article (pop articles))
+	  (when (setq header (cadr (assq article nnweb-articles)))
+	    (nnheader-insert-nov header))))
       'nov)))
 
 (deffoo nnweb-request-scan (&optional group server)
   (nnweb-possibly-change-server group server)
-  (setq nnweb-hashtb (gnus-make-hashtable 4095))
   (funcall (nnweb-definition 'map))
   (unless nnweb-ephemeral-p
     (nnweb-write-active)
@@ -132,11 +135,12 @@
 	     (not (equal group nnweb-group))
 	     (not nnweb-ephemeral-p))
     (let ((info (assoc group nnweb-group-alist)))
-      (setq nnweb-group group)
-      (setq nnweb-type (nth 2 info))
-      (setq nnweb-search (nth 3 info))
-      (unless dont-check
-	(nnweb-read-overview group))))
+      (when info
+	(setq nnweb-group group)
+	(setq nnweb-type (nth 2 info))
+	(setq nnweb-search (nth 3 info))
+	(unless dont-check
+	  (nnweb-read-overview group)))))
   (cond
    ((not nnweb-articles)
     (nnheader-report 'nnweb "No matching articles"))
@@ -166,7 +170,8 @@
     (let* ((header (cadr (assq article nnweb-articles)))
 	   (url (and header (mail-header-xref header))))
       (when (or (and url
-		     (nnweb-fetch-url url))
+		     (mm-with-unibyte-current-buffer
+		       (nnweb-fetch-url url)))
 		(and (stringp article)
 		     (nnweb-definition 'id t)
 		     (let ((fetch (nnweb-definition 'id))
@@ -175,13 +180,14 @@
 			 (setq art (match-string 1 article)))
 		       (and fetch
 			    art
-			    (nnweb-fetch-url
-			     (format fetch article))))))
+			    (mm-with-unibyte-current-buffer
+			      (nnweb-fetch-url
+			       (format fetch article)))))))
 	(unless nnheader-callback-function
 	  (funcall (nnweb-definition 'article))
 	  (nnweb-decode-entities))
 	(nnheader-report 'nnweb "Fetched article %s" article)
-	t))))
+	(cons group (and (numberp article) article))))))
 
 (deffoo nnweb-close-server (&optional server)
   (when (and (nnweb-server-opened server)
@@ -200,9 +206,7 @@
     t))
 
 (deffoo nnweb-request-update-info (group info &optional server)
-  (nnweb-possibly-change-server group server)
-  ;;(setcar (cddr info) nil)
-  )
+  (nnweb-possibly-change-server group server))
 
 (deffoo nnweb-asynchronous-p ()
   t)
@@ -216,7 +220,8 @@
 
 (deffoo nnweb-request-delete-group (group &optional force server)
   (nnweb-possibly-change-server group server)
-  (gnus-pull group nnweb-group-alist)
+  (gnus-pull group nnweb-group-alist t)
+  (nnweb-write-active)
   (gnus-delete-file (nnweb-overview-file group))
   t)
 
@@ -227,7 +232,7 @@
 (defun nnweb-read-overview (group)
   "Read the overview of GROUP and build the map."
   (when (file-exists-p (nnweb-overview-file group))
-    (nnheader-temp-write nil
+    (mm-with-unibyte-buffer
       (nnheader-insert-file-contents (nnweb-overview-file group))
       (goto-char (point-min))
       (let (header)
@@ -241,7 +246,7 @@
 
 (defun nnweb-write-overview (group)
   "Write the overview file for GROUP."
-  (nnheader-temp-write (nnweb-overview-file group)
+  (with-temp-file (nnweb-overview-file group)
     (let ((articles nnweb-articles))
       (while articles
 	(nnheader-insert-nov (cadr (pop articles)))))))
@@ -262,7 +267,8 @@
 
 (defun nnweb-write-active ()
   "Save the active file."
-  (nnheader-temp-write (nnheader-concat nnweb-directory "active")
+  (gnus-make-directory nnweb-directory)
+  (with-temp-file (nnheader-concat nnweb-directory "active")
     (prin1 `(setq nnweb-group-alist ',nnweb-group-alist) (current-buffer))))
 
 (defun nnweb-read-active ()
@@ -287,6 +293,7 @@
   (when group
     (when (and (not nnweb-ephemeral-p)
 	       (not (equal group nnweb-group)))
+      (setq nnweb-hashtb (gnus-make-hashtable 4095))
       (nnweb-request-group group nil t))))
 
 (defun nnweb-init (server)
@@ -294,22 +301,30 @@
   (unless (gnus-buffer-live-p nnweb-buffer)
     (setq nnweb-buffer
 	  (save-excursion
-	    (nnheader-set-temp-buffer
-	     (format " *nnweb %s %s %s*" nnweb-type nnweb-search server))))))
+	    (mm-with-unibyte
+	      (nnheader-set-temp-buffer
+	       (format " *nnweb %s %s %s*"
+		       nnweb-type nnweb-search server))
+	      (current-buffer))))))
 
 (defun nnweb-fetch-url (url)
-  (save-excursion
-    (if (not nnheader-callback-function)
-	(let ((buf (current-buffer)))
-	  (save-excursion
-	    (set-buffer nnweb-buffer)
+  (let (buf)
+    (save-excursion
+      (if (not nnheader-callback-function)
+	  (progn
+	    (with-temp-buffer
+	      (mm-enable-multibyte)
+	      (let ((coding-system-for-read 'binary)
+		    (coding-system-for-write 'binary)
+		    (default-process-coding-system 'binary))
+		(nnweb-insert url))
+	      (setq buf (buffer-string)))
 	    (erase-buffer)
-	    (url-insert-file-contents url)
-	    (copy-to-buffer buf (point-min) (point-max))
-	    t))
-      (nnweb-url-retrieve-asynch
-       url 'nnweb-callback (current-buffer) nnheader-callback-function)
-      t)))
+	    (insert buf)
+	    t)
+	(nnweb-url-retrieve-asynch
+	 url 'nnweb-callback (current-buffer) nnheader-callback-function)
+	t))))
 
 (defun nnweb-callback (buffer callback)
   (when (gnus-buffer-live-p url-working-buffer)
@@ -338,42 +353,6 @@
       (url-retrieve url))
     (setq-default url-be-asynchronous old-asynch)))
 
-(defun nnweb-encode-www-form-urlencoded (pairs)
-  "Return PAIRS encoded for forms."
-  (mapconcat
-   (function
-    (lambda (data)
-      (concat (w3-form-encode-xwfu (car data)) "="
-	      (w3-form-encode-xwfu (cdr data)))))
-   pairs "&"))
-
-(defun nnweb-fetch-form (url pairs)
-  (let ((url-request-data (nnweb-encode-www-form-urlencoded pairs))
-	(url-request-method "POST")
-	(url-request-extra-headers
-	 '(("Content-type" . "application/x-www-form-urlencoded"))))
-    (url-insert-file-contents url)
-    (setq buffer-file-name nil))
-  t)
-
-(defun nnweb-decode-entities ()
-  (goto-char (point-min))
-  (while (re-search-forward "&\\([a-z]+\\);" nil t)
-    (replace-match (char-to-string (or (cdr (assq (intern (match-string 1))
-						  w3-html-entities))
-				       ?#))
-		   t t)))
-
-(defun nnweb-remove-markup ()
-  (goto-char (point-min))
-  (while (search-forward "<!--" nil t)
-    (delete-region (match-beginning 0)
-		   (or (search-forward "-->" nil t)
-		       (point-max))))
-  (goto-char (point-min))
-  (while (re-search-forward "<[^>]+>" nil t)
-    (replace-match "" t t)))
-
 ;;;
 ;;; DejaNews functions.
 ;;;
@@ -389,51 +368,46 @@
 	    (case-fold-search t)
 	    (active (or (cadr (assoc nnweb-group nnweb-group-alist))
 			(cons 1 0)))
-	    Subject (Score "0") Date Newsgroup Author
-	    map url)
+	    subject date from
+	    map url parse a table group text)
 	(while more
 	  ;; Go through all the article hits on this page.
 	  (goto-char (point-min))
-	  (nnweb-decode-entities)
+	  (setq parse (w3-parse-buffer (current-buffer))
+		table (nth 1 (nnweb-parse-find-all 'table parse)))
+	  (dolist (row (nth 2 (car (nth 2 table))))
+	    (setq a (nnweb-parse-find 'a row)
+		  url (cdr (assq 'href (nth 1 a)))
+		  text (nreverse (nnweb-text row)))
+	    (when a
+	      (setq subject (nth 4 text)
+		    group (nth 2 text)
+		    date (nth 1 text)
+		    from (nth 0 text))
+	      (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
+		  (setq date (format "%s %s 00:00:00 %s"
+				     (car (rassq (string-to-number
+						  (match-string 2 date))
+						 parse-time-months))
+				     (match-string 3 date) 
+				     (match-string 1 date)))
+		(setq date "Jan 1 00:00:00 0000"))
+	      (incf i)
+	      (setq url (concat url "&fmt=text"))
+	      (when (string-match "&context=[^&]+" url)
+		(setq url (replace-match "" t t url)))
+	      (unless (nnweb-get-hashtb url)
+		(push
+		 (list
+		  (incf (cdr active))
+		  (make-full-mail-header
+		   (cdr active) (concat subject " (" group ")") from date
+		   (concat "<" (nnweb-identifier url) "@dejanews>")
+		   nil 0 0 url))
+		 map)
+		(nnweb-set-hashtb (cadar map) (car map)))))
+	  ;; See whether there is a "Get next 20 hits" button here.
 	  (goto-char (point-min))
-	  (while (re-search-forward "^ <P>\n" nil t)
-	    (narrow-to-region
-	     (point)
-	     (cond ((re-search-forward "^ <P>\n" nil t)
-		    (match-beginning 0))
-		   ((search-forward "\n\n" nil t)
-		    (point))
-		   (t
-		    (point-max))))
-	    (goto-char (point-min))
-	    (looking-at ".*HREF=\"\\([^\"]+\\)\"\\(.*\\)")
-	    (setq url (match-string 1))
- 	    (let ((begin (point)))
- 	      (nnweb-remove-markup)
- 	      (goto-char begin)
- 	      (while (search-forward "\t" nil t)
- 		(replace-match " "))
- 	      (goto-char begin)
- 	      (end-of-line)
- 	      (setq Subject (buffer-substring begin (point)))
- 	      (if (re-search-forward
- 		   "^ Newsgroup: \\(.*\\)\n Posted on \\([0-9/]+\\) by \\(.*\\)$" nil t)
- 		  (setq Newsgroup (match-string 1)
- 			Date (match-string 2)
- 			Author (match-string 3))))
-	    (widen)
-	    (incf i)
-	    (unless (nnweb-get-hashtb url)
-	      (push
-	       (list
-		(incf (cdr active))
-		(make-full-mail-header
-		 (cdr active) Subject Author Date
-		 (concat "<" (nnweb-identifier url) "@dejanews>")
-		 nil 0 (string-to-int Score) url))
-	       map)
-	      (nnweb-set-hashtb (cadar map) (car map))))
-	  ;; See whether there is a "Get next 20 hits" button here.
 	  (if (or (not (re-search-forward
 			"HREF=\"\\([^\"]+\\)\"[<>b]+Next result" nil t))
 		  (>= i nnweb-max-hits))
@@ -446,39 +420,25 @@
 	(setq nnweb-articles
 	      (sort (nconc nnweb-articles map) 'car-less-than-car))))))
 
-(defun nnweb-dejanews-wash-article ()
-  (let ((case-fold-search t))
-    (goto-char (point-min))
-    (re-search-forward "<PRE>" nil t)
-    (delete-region (point-min) (point))
-    (re-search-forward "</PRE>" nil t)
-    (delete-region (point) (point-max))
-    (nnweb-remove-markup)
-    (goto-char (point-min))
-    (while (and (looking-at " *$")
-		(not (eobp)))
-      (gnus-delete-line))
-    (while (looking-at "\\(^[^ ]+:\\) *")
-      (replace-match "\\1 " t)
-      (forward-line 1))
-    (when (re-search-forward "\n\n+" nil t)
-      (replace-match "\n" t t))
-    (goto-char (point-min))
-    (when (search-forward "[More Headers]" nil t)
-      (replace-match "" t t))))
-
 (defun nnweb-dejanews-search (search)
-  (nnweb-fetch-form
-   (nnweb-definition 'address)
-   `(("query" . ,search)
-     ("defaultOp" . "AND")
-     ("svcclass" . "dncurrent")
-     ("maxhits" . "100")
-     ("format" . "verbose2")
-     ("threaded" . "0")
-     ("showsort" . "date")
-     ("agesign" . "1")
-     ("ageweight" . "1")))
+  (nnweb-insert
+   (concat
+    (nnweb-definition 'address)
+    "?"
+    (nnweb-encode-www-form-urlencoded
+     `(("ST" . "PS")
+       ("svcclass" . "dnyr")
+       ("QRY" . ,search)
+       ("defaultOp" . "AND")
+       ("DBS" . "1")
+       ("OP" . "dnquery.xp")
+       ("LNG" . "ALL")
+       ("maxhits" . "100")
+       ("threaded" . "0")
+       ("format" . "verbose2")
+       ("showsort" . "date")
+       ("agesign" . "1")
+       ("ageweight" . "1")))))
   t)
 
 (defun nnweb-dejanewsold-search (search)
@@ -497,7 +457,7 @@
 
 (defun nnweb-dejanews-identity (url)
   "Return an unique identifier based on URL."
-  (if (string-match "recnum=\\([0-9]+\\)" url)
+  (if (string-match "AN=\\([0-9]+\\)" url)
       (match-string 1 url)
     url))
 
@@ -523,7 +483,6 @@
 	  (goto-char (point-min))
 	  (search-forward "</pre><hr>" nil t)
 	  (delete-region (point-min) (point))
-					;(nnweb-decode-entities)
 	  (goto-char (point-min))
 	  (while (re-search-forward "^ +[0-9]+\\." nil t)
 	    (narrow-to-region
@@ -719,6 +678,145 @@
   (setq buffer-file-name nil)
   t)
 
+;;;
+;;; General web/w3 interface utility functions
+;;;
+
+(defun nnweb-insert-html (parse)
+  "Insert HTML based on a w3 parse tree."
+  (if (stringp parse)
+      (insert parse)
+    (insert "<" (symbol-name (car parse)) " ")
+    (insert (mapconcat
+	     (lambda (param)
+	       (concat (symbol-name (car param)) "="
+		       (prin1-to-string
+			(if (consp (cdr param))
+			    (cadr param)
+			  (cdr param)))))
+	     (nth 1 parse)
+	     " "))
+    (insert ">\n")
+    (mapcar 'nnweb-insert-html (nth 2 parse))
+    (insert "</" (symbol-name (car parse)) ">\n")))
+
+(defun nnweb-encode-www-form-urlencoded (pairs)
+  "Return PAIRS encoded for forms."
+  (mapconcat
+   (function
+    (lambda (data)
+      (concat (w3-form-encode-xwfu (car data)) "="
+	      (w3-form-encode-xwfu (cdr data)))))
+   pairs "&"))
+
+(defun nnweb-fetch-form (url pairs)
+  "Fetch a form from URL with PAIRS as the data using the POST method."
+  (let ((url-request-data (nnweb-encode-www-form-urlencoded pairs))
+	(url-request-method "POST")
+	(url-request-extra-headers
+	 '(("Content-type" . "application/x-www-form-urlencoded"))))
+    (url-insert-file-contents url)
+    (setq buffer-file-name nil))
+  t)
+
+(defun nnweb-decode-entities ()
+  "Decode all HTML entities."
+  (goto-char (point-min))
+  (while (re-search-forward "&\\(#[0-9]+\\|[a-z]+\\);" nil t)
+    (replace-match (char-to-string 
+		    (if (eq (aref (match-string 1) 0) ?\#)
+			(let ((c
+			       (string-to-number (substring 
+						  (match-string 1) 1))))
+			  (if (mm-char-or-char-int-p c) c 32))
+		      (or (cdr (assq (intern (match-string 1))
+				     w3-html-entities))
+			  ?#)))
+		   t t)))
+
+(defun nnweb-decode-entities-string (str)
+  (with-temp-buffer
+    (insert str)
+    (nnweb-decode-entities)
+    (buffer-substring (point-min) (point-max))))
+
+(defun nnweb-remove-markup ()
+  "Remove all HTML markup, leaving just plain text."
+  (goto-char (point-min))
+  (while (search-forward "<!--" nil t)
+    (delete-region (match-beginning 0)
+		   (or (search-forward "-->" nil t)
+		       (point-max))))
+  (goto-char (point-min))
+  (while (re-search-forward "<[^>]+>" nil t)
+    (replace-match "" t t)))
+
+(defun nnweb-insert (url &optional follow-refresh)
+  "Insert the contents from an URL in the current buffer.
+If FOLLOW-REFRESH is non-nil, redirect refresh url in META."
+  (let ((name buffer-file-name))
+    (if follow-refresh
+	(save-restriction
+	  (narrow-to-region (point) (point))
+	  (url-insert-file-contents url)
+	  (goto-char (point-min))
+	  (when (re-search-forward 
+		 "<meta[ \t\r\n]*http-equiv=\"Refresh\"[^>]*URL=\\([^\"]+\\)\"" nil t)
+	    (let ((url (match-string 1)))
+	      (delete-region (point-min) (point-max))
+	      (nnweb-insert url t))))
+      (url-insert-file-contents url))
+    (setq buffer-file-name name)))
+
+(defun nnweb-parse-find (type parse &optional maxdepth)
+  "Find the element of TYPE in PARSE."
+  (catch 'found
+    (nnweb-parse-find-1 type parse maxdepth)))
+
+(defun nnweb-parse-find-1 (type contents maxdepth)
+  (when (or (null maxdepth)
+	    (not (zerop maxdepth)))
+    (when (consp contents)
+      (when (eq (car contents) type)
+	(throw 'found contents))
+      (when (listp (cdr contents))
+	(dolist (element contents)
+	  (when (consp element)
+	    (nnweb-parse-find-1 type element
+				(and maxdepth (1- maxdepth)))))))))
+
+(defun nnweb-parse-find-all (type parse)
+  "Find all elements of TYPE in PARSE."
+  (catch 'found
+    (nnweb-parse-find-all-1 type parse)))
+
+(defun nnweb-parse-find-all-1 (type contents)
+  (let (result)
+    (when (consp contents)
+      (if (eq (car contents) type)
+	  (push contents result)
+	(when (listp (cdr contents))
+	  (dolist (element contents)
+	    (when (consp element)
+	      (setq result
+		    (nconc result (nnweb-parse-find-all-1 type element))))))))
+    result))
+
+(defvar nnweb-text)
+(defun nnweb-text (parse)
+  "Return a list of text contents in PARSE."
+  (let ((nnweb-text nil))
+    (nnweb-text-1 parse)
+    (nreverse nnweb-text)))
+
+(defun nnweb-text-1 (contents)
+  (dolist (element contents)
+    (if (stringp element)
+	(push element nnweb-text)
+      (when (and (consp element)
+		 (listp (cdr element)))
+	(nnweb-text-1 element)))))
+
 (provide 'nnweb)
 
 ;;; nnweb.el ends here
--- a/lisp/gnus/parse-time.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/parse-time.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,6 +1,6 @@
 ;;; parse-time.el --- Parsing time strings
 
-;; Copyright (C) 1996 by Free Software Foundation, Inc.
+;; Copyright (C) 1996, 2000 by Free Software Foundation, Inc.
 
 ;; Author: Erik Naggum <erik@naggum.no>
 ;; Keywords: util
@@ -36,12 +36,10 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))		;and ah ain't kiddin' 'bout it
+(eval-when-compile (require 'cl))	;and ah ain't kiddin' 'bout it
 
-(put 'parse-time-syntax 'char-table-extra-slots 0)
-
-(defvar parse-time-syntax (make-char-table 'parse-time-syntax))
-(defvar parse-time-digits (make-char-table 'parse-time-syntax))
+(defvar parse-time-syntax (make-vector 256 nil))
+(defvar parse-time-digits (make-vector 256 nil))
 
 ;; Byte-compiler warnings
 (defvar elt)
@@ -49,18 +47,18 @@
 
 (unless (aref parse-time-digits ?0)
   (loop for i from ?0 to ?9
-	do (set-char-table-range parse-time-digits i (- i ?0))))
+    do (aset parse-time-digits i (- i ?0))))
 
 (unless (aref parse-time-syntax ?0)
   (loop for i from ?0 to ?9
-	do (set-char-table-range parse-time-syntax i ?0))
+    do (aset parse-time-syntax i ?0))
   (loop for i from ?A to ?Z
-	do (set-char-table-range parse-time-syntax i ?A))
+    do (aset parse-time-syntax i ?A))
   (loop for i from ?a to ?z
-	do (set-char-table-range parse-time-syntax i ?a))
-  (set-char-table-range parse-time-syntax ?+ 1)
-  (set-char-table-range parse-time-syntax ?- -1)
-  (set-char-table-range parse-time-syntax ?: ?d)
+    do (aset parse-time-syntax i ?a))
+  (aset parse-time-syntax ?+ 1)
+  (aset parse-time-syntax ?- -1)
+  (aset parse-time-syntax ?: ?d)
   )
 
 (defsubst digit-char-p (char)
@@ -89,7 +87,8 @@
 	  (setq integer (+ (* integer 10) digit)
 		index (1+ index)))
 	(if (/= index end)
-	    (signal 'parse-error `("not an integer" ,(substring string (or start 0) end)))
+	    (signal 'parse-error `("not an integer"
+				   ,(substring string (or start 0) end)))
 	  (* sign integer))))))
 
 (defun parse-time-tokenize (string)
@@ -114,24 +113,24 @@
 		list)))
     (nreverse list)))
 
-(defvar parse-time-months '(("Jan" . 1) ("Feb" . 2) ("Mar" . 3)
-			    ("Apr" . 4) ("May" . 5) ("Jun" . 6)
-			    ("Jul" . 7) ("Aug" . 8) ("Sep" . 9)
-			    ("Oct" . 10) ("Nov" . 11) ("Dec" . 12)))
-(defvar parse-time-weekdays '(("Sun" . 0) ("Mon" . 1) ("Tue" . 2)
-			      ("Wed" . 3) ("Thu" . 4) ("Fri" . 5) ("Sat" . 6)))
-(defvar parse-time-zoneinfo `(("Z" 0) ("UT" 0) ("GMT" 0)
-			      ("PST" ,(* -8 3600)) ("PDT" ,(* -7 3600) t)
-			      ("MST" ,(* -7 3600)) ("MDT" ,(* -6 3600) t)
-			      ("CST" ,(* -6 3600)) ("CDT" ,(* -5 3600) t)
-			      ("EST" ,(* -5 3600)) ("EDT" ,(* -4 3600) t))
+(defvar parse-time-months '(("jan" . 1) ("feb" . 2) ("mar" . 3)
+			    ("apr" . 4) ("may" . 5) ("jun" . 6)
+			    ("jul" . 7) ("aug" . 8) ("sep" . 9)
+			    ("oct" . 10) ("nov" . 11) ("dec" . 12)))
+(defvar parse-time-weekdays '(("sun" . 0) ("mon" . 1) ("tue" . 2)
+			      ("wed" . 3) ("thu" . 4) ("fri" . 5) ("sat" . 6)))
+(defvar parse-time-zoneinfo `(("z" 0) ("ut" 0) ("gmt" 0)
+			      ("pst" ,(* -8 3600)) ("pdt" ,(* -7 3600) t)
+			      ("mst" ,(* -7 3600)) ("mdt" ,(* -6 3600) t)
+			      ("cst" ,(* -6 3600)) ("cdt" ,(* -5 3600) t)
+			      ("est" ,(* -5 3600)) ("edt" ,(* -4 3600) t))
   "(zoneinfo seconds-off daylight-savings-time-p)")
 
 (defvar parse-time-rules
   `(((6) parse-time-weekdays)
     ((3) (1 31))
     ((4) parse-time-months)
-    ((5) (1970 2038))
+    ((5) (100 4038))
     ((2 1 0)
      ,#'(lambda () (and (stringp elt)
 			(= (length elt) 8)
@@ -150,20 +149,34 @@
 			    (* 60 (parse-integer elt 1 3)))
 		      (if (= (aref elt 0) ?-) -1 1))))
     ((5 4 3)
-     ,#'(lambda () (and (stringp elt) (= (length elt) 10) (= (aref elt 4) ?-) (= (aref elt 7) ?-)))
+     ,#'(lambda () (and (stringp elt)
+			(= (length elt) 10)
+			(= (aref elt 4) ?-)
+			(= (aref elt 7) ?-)))
      [0 4] [5 7] [8 10])
-    ((2 1)
+    ((2 1 0)
      ,#'(lambda () (and (stringp elt) (= (length elt) 5) (= (aref elt 2) ?:)))
-     [0 2] [3 5])
-    ((5) (70 99) ,#'(lambda () (+ 1900 elt))))
+     [0 2] [3 5] ,#'(lambda () 0))
+    ((2 1 0)
+     ,#'(lambda () (and (stringp elt)
+			(= (length elt) 4)
+			(= (aref elt 1) ?:)))
+     [0 1] [2 4] ,#'(lambda () 0))
+    ((2 1 0)
+     ,#'(lambda () (and (stringp elt)
+			(= (length elt) 7)
+			(= (aref elt 1) ?:)))
+     [0 1] [2 4] [5 7])
+    ((5) (50 110) ,#'(lambda () (+ 1900 elt)))
+    ((5) (0 49) ,#'(lambda () (+ 2000 elt))))
   "(slots predicate extractor...)")
 
 (defun parse-time-string (string)
   "Parse the time-string STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ).
 The values are identical to those of `decode-time', but any values that are
 unknown are returned as nil."
-  (let ((time (list nil nil nil nil nil nil nil nil nil nil))
-	(temp (parse-time-tokenize string)))
+  (let ((time (list nil nil nil nil nil nil nil nil nil))
+	(temp (parse-time-tokenize (downcase string))))
     (while temp
       (let ((elt (pop temp))
 	    (rules parse-time-rules)
@@ -173,25 +186,27 @@
 		 (slots (pop rule))
 		 (predicate (pop rule))
 		 (val))
-	    (if (and (not (nth (car slots) time)) ;not already set
-		     (setq val (cond ((and (consp predicate)
-					   (not (eq (car predicate) 'lambda)))
-				      (and (numberp elt)
-					   (<= (car predicate) elt)
-					   (<= elt (cadr predicate))
-					   elt))
-				     ((symbolp predicate)
-				      (cdr (assoc elt (symbol-value predicate))))
-				     ((funcall predicate)))))
-		(progn
-		  (setq exit t)
-		  (while slots
-		    (let ((new-val (and rule
-					(let ((this (pop rule)))
-					  (if (vectorp this)
-					      (parse-integer elt (aref this 0) (aref this 1))
-					    (funcall this))))))
-		      (rplaca (nthcdr (pop slots) time) (or new-val val))))))))))
+	    (when (and (not (nth (car slots) time)) ;not already set
+		       (setq val (cond ((and (consp predicate)
+					     (not (eq (car predicate)
+						      'lambda)))
+					(and (numberp elt)
+					     (<= (car predicate) elt)
+					     (<= elt (cadr predicate))
+					     elt))
+				       ((symbolp predicate)
+					(cdr (assoc elt
+						    (symbol-value predicate))))
+				       ((funcall predicate)))))
+	      (setq exit t)
+	      (while slots
+		(let ((new-val (and rule
+				    (let ((this (pop rule)))
+				      (if (vectorp this)
+					  (parse-integer
+					   elt (aref this 0) (aref this 1))
+					(funcall this))))))
+		  (rplaca (nthcdr (pop slots) time) (or new-val val)))))))))
     time))
 
 (provide 'parse-time)
--- a/lisp/gnus/pop3.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/pop3.el	Tue Sep 19 13:37:09 2000 +0000
@@ -1,6 +1,7 @@
 ;;; pop3.el --- Post Office Protocol (RFC 1460) interface
 
-;; Copyright (C) 1996, 96, 97, 98, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;        Free Software Foundation, Inc.
 
 ;; Author: Richard L. Pieri <ratinox@peorth.gweep.net>
 ;; Maintainer: FSF
--- a/lisp/gnus/score-mode.el	Tue Sep 19 13:28:27 2000 +0000
+++ b/lisp/gnus/score-mode.el	Tue Sep 19 13:37:09 2000 +0000
@@ -25,9 +25,8 @@
 
 ;;; Code:
 
-(require 'easymenu)
-(require 'timezone)
 (eval-when-compile (require 'cl))
+(require 'mm-util)			; for mm-auto-save-coding-system
 
 (defvar gnus-score-mode-hook nil
   "*Hook run in score mode buffers.")
@@ -40,7 +39,8 @@
 
 (defvar gnus-score-mode-map nil)
 (unless gnus-score-mode-map
-  (setq gnus-score-mode-map (copy-keymap emacs-lisp-mode-map))
+  (setq gnus-score-mode-map (make-sparse-keymap))
+  (set-keymap-parent gnus-score-mode-map emacs-lisp-mode-map)
   (define-key gnus-score-mode-map "\C-c\C-c" 'gnus-score-edit-exit)
   (define-key gnus-score-mode-map "\C-c\C-d" 'gnus-score-edit-insert-date)
   (define-key gnus-score-mode-map "\C-c\C-p" 'gnus-score-pretty-print))
@@ -51,6 +51,9 @@
     table)
   "Syntax table used in score-mode buffers.")
 
+;; We need this to cope with non-ASCII scoring.
+(defvar score-mode-coding-system mm-auto-save-coding-system)
+
 ;;;###autoload
 (defun gnus-score-mode ()
   "Mode for editing Gnus score files.
@@ -81,7 +84,7 @@
 (defun gnus-score-edit-insert-date ()
   "Insert date in numerical format."
   (interactive)
-  (princ (gnus-score-day-number (current-time)) (current-buffer)))
+  (princ (time-to-days (current-time)) (current-buffer)))
 
 (defun gnus-score-pretty-print ()
   "Format the current score file."
@@ -98,7 +101,8 @@
   (interactive)
   (unless (file-exists-p (file-name-directory (buffer-file-name)))
     (make-directory (file-name-directory (buffer-file-name)) t))
-  (save-buffer)
+  (let ((coding-system-for-write score-mode-coding-system))
+    (save-buffer))
   (bury-buffer (current-buffer))
   (let ((buf (current-buffer)))
     (when gnus-score-edit-exit-function
@@ -106,11 +110,6 @@
     (when (eq buf (current-buffer))
       (switch-to-buffer (other-buffer (current-buffer))))))
 
-(defun gnus-score-day-number (time)
-  (let ((dat (decode-time time)))
-    (timezone-absolute-from-gregorian
-     (nth 4 dat) (nth 3 dat) (nth 5 dat))))
-
 (provide 'score-mode)
 
 ;;; score-mode.el ends here