Importing Oort Gnus v0.03.
[elisp/gnus.git-] / lisp / gnus-sum.el
index 146c5c0..7d8f6f5 100644 (file)
@@ -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, 2001
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 (require 'gnus-int)
 (require 'gnus-undo)
 (require 'gnus-util)
+(require 'mm-decode)
+;; Recursive :-(.
+;; (require 'gnus-art)
+(require 'nnoo)
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
+(autoload 'gnus-cache-write-active "gnus-cache")
+(autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
+(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
+(autoload 'mm-uu-dissect "mm-uu")
 
 (defcustom gnus-kill-summary-on-exit t
   "*If non-nil, kill the summary buffer when you exit from it.
@@ -167,10 +176,15 @@ This variable will only be used if the value of
   :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)
@@ -252,8 +266,12 @@ equal will be included."
 (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
@@ -261,7 +279,10 @@ in some newsgroups, set the variable to nil in
   :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.
@@ -302,6 +323,7 @@ and non-`vertical', do both horizontal and vertical recentering."
   :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
@@ -314,7 +336,7 @@ and non-`vertical', do both horizontal and vertical recentering."
   "*If non-nil, ignore articles with identical Message-ID headers."
   :group 'gnus-summary
   :type 'boolean)
-  
+
 (defcustom gnus-single-article-buffer t
   "*If non-nil, display all articles in the same buffer.
 If nil, each group will get its own article buffer."
@@ -330,13 +352,15 @@ variable."
 
 (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."
+It uses the same syntax as the `gnus-split-methods' variable.
+However, whereas `gnus-split-methods' specifies file names as targets,
+this variable specifies group names."
   :group 'gnus-summary-mail
   :type '(repeat (choice (list :value (fun) function)
                         (cons :value ("" "") regexp (repeat string))
                         (sexp :value nil))))
 
-(defcustom gnus-unread-mark ? 
+(defcustom gnus-unread-mark ?  ;Whitespace
   "*Mark used for unread articles."
   :group 'gnus-summary-marks
   :type 'character)
@@ -372,7 +396,7 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :type 'character)
 
 (defcustom gnus-souped-mark ?F
-  "*Mark used for killed articles."
+  "*Mark used for souped articles."
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -396,6 +420,11 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-summary-marks
   :type 'character)
 
+(defcustom gnus-forwarded-mark ?O
+  "*Mark used for articles that have been forwarded."
+  :group 'gnus-summary-marks
+  :type 'character)
+
 (defcustom gnus-cached-mark ?*
   "*Mark used for articles that are in the cache."
   :group 'gnus-summary-marks
@@ -406,6 +435,11 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-summary-marks
   :type 'character)
 
+(defcustom gnus-no-mark ?  ;Whitespace
+  "*Mark used for articles that have no other secondary mark."
+  :group 'gnus-summary-marks
+  :type 'character)
+
 (defcustom gnus-ancient-mark ?O
   "*Mark used for ancient articles."
   :group 'gnus-summary-marks
@@ -451,7 +485,7 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-summary-marks
   :type 'character)
 
-(defcustom gnus-empty-thread-mark ? 
+(defcustom gnus-empty-thread-mark ?  ;Whitespace
   "*There is no thread under the article."
   :group 'gnus-summary-marks
   :type 'character)
@@ -466,6 +500,21 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :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."
+  :version "21.1"
+  :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."
+  :version "21.1"
+  :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
@@ -520,6 +569,16 @@ with some simple extensions:
   :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."
+  :version "21.1"
+  :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
@@ -529,7 +588,22 @@ score file."
 
 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
   "*List of functions used for sorting articles in the summary buffer.
-This variable is only used when not using a threaded display."
+
+Each function takes two articles and returns non-nil if the first
+article should be sorted before the other.  If you use more than one
+function, the primary sort function should be the last.  You should
+probably always include `gnus-article-sort-by-number' in the list of
+sorting functions -- preferably first.  Also note that sorting by date
+is often much slower than sorting by number, and the sorting order is
+very similar.  (Sorting by date means sorting by the time the message
+was sent, sorting by number means sorting by arrival time.)
+
+Ready-made functions include `gnus-article-sort-by-number',
+`gnus-article-sort-by-author', `gnus-article-sort-by-subject',
+`gnus-article-sort-by-date' and `gnus-article-sort-by-score'.
+
+When threading is turned on, the variable `gnus-thread-sort-functions'
+controls how articles are sorted."
   :group 'gnus-summary-sort
   :type '(repeat (choice (function-item gnus-article-sort-by-number)
                         (function-item gnus-article-sort-by-author)
@@ -542,16 +616,22 @@ This variable is only used when not using a threaded display."
   "*List of functions used for sorting threads in the summary buffer.
 By default, threads are sorted by article number.
 
-Each function takes two threads and return non-nil if the first thread
-should be sorted before the other.  If you use more than one function,
-the primary sort function should be the last.  You should probably
-always include `gnus-thread-sort-by-number' in the list of sorting
-functions -- preferably first.
+Each function takes two threads and returns non-nil if the first
+thread should be sorted before the other.  If you use more than one
+function, the primary sort function should be the last.  You should
+probably always include `gnus-thread-sort-by-number' in the list of
+sorting functions -- preferably first.  Also note that sorting by date
+is often much slower than sorting by number, and the sorting order is
+very similar.  (Sorting by date means sorting by the time the message
+was sent, sorting by number means sorting by arrival time.)
 
 Ready-made functions include `gnus-thread-sort-by-number',
 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score' and
-`gnus-thread-sort-by-total-score' (see `gnus-thread-score-function')."
+`gnus-thread-sort-by-total-score' (see `gnus-thread-score-function').
+
+When threading is turned off, the variable
+`gnus-article-sort-functions' controls how articles are sorted."
   :group 'gnus-summary-sort
   :type '(repeat (choice (function-item gnus-thread-sort-by-number)
                         (function-item gnus-thread-sort-by-author)
@@ -584,7 +664,7 @@ See `gnus-thread-score-function' for en explanation of what a
 \"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))
@@ -592,9 +672,17 @@ This variable is local to the summary buffers."
 (defcustom gnus-summary-mode-hook nil
   "*A hook for Gnus summary mode.
 This hook is run before any variables are set in the summary buffer."
+  :options '(turn-on-gnus-mailing-list-mode)
   :group 'gnus-summary-various
   :type 'hook)
 
+;; Extracted from gnus-xmas-redefine in order to preserve user settings
+(when (featurep 'xemacs)
+  (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
+  (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
+  (add-hook 'gnus-summary-mode-hook
+           'gnus-xmas-switch-horizontal-scrollbar-off))
+
 (defcustom gnus-summary-menu-hook nil
   "*Hook run after the creation of the summary mode menu."
   :group 'gnus-summary-visual
@@ -662,7 +750,8 @@ is not run if `gnus-visual' is nil."
   :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)
 
@@ -731,8 +820,11 @@ automatically when it is selected."
     ((and (< score default) (memq mark (list gnus-downloadable-mark
                                             gnus-undownloaded-mark)))
      . gnus-summary-low-unread-face)
-    ((memq mark (list gnus-downloadable-mark gnus-undownloaded-mark))
+    ((and (memq mark (list gnus-downloadable-mark gnus-undownloaded-mark))
+         (memq article gnus-newsgroup-unreads))
      . gnus-summary-normal-unread-face)
+    ((memq mark (list gnus-downloadable-mark gnus-undownloaded-mark))
+     . gnus-summary-normal-read-face)
     ((> score default)
      . gnus-summary-high-read-face)
     ((< score default)
@@ -761,11 +853,126 @@ mark:    The articles mark."
 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."
+  :version "21.1"
+  :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."
+  :version "21.1"
+  :group 'gnus-summary
+  :type 'regexp)
+
+(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."
+  :version "21.1"
+  :type '(repeat symbol)
+  :group 'gnus-charset)
+
+(gnus-define-group-parameter
+ ignored-charsets
+ :type list
+ :function-document
+ "Return the ignored charsets of GROUP."
+ :variable gnus-group-ignored-charsets-alist
+ :variable-default 
+ '(("alt\\.chinese\\.text" iso-8859-1))
+ :variable-document
+ "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."
+ :variable-group gnus-charset
+ :variable-type '(repeat (cons (regexp :tag "Group")
+                              (repeat symbol)))
+ :parameter-type '(choice :tag "Ignored charsets" 
+                         :value nil
+                         (repeat (symbol)))
+ :parameter-document       "\
+List of charsets that should be ignored.
+
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead.")
+
+(defcustom gnus-group-highlight-words-alist nil
+  "Alist of group regexps and highlight regexps.
+This variable uses the same syntax as `gnus-emphasis-alist'."
+  :version "21.1"
+  :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))."
+  :version "21.1"
+  :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."
+  :version "21.1"
+  :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 '(choice (const nil) 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))
+
+(defcustom gnus-summary-save-parts-default-mime "image/.*"
+  "*A regexp to match MIME parts when saving multiple parts of a message
+with gnus-summary-save-parts (X m). This regexp will be used by default
+when prompting the user for which type of files to save."
+  :group 'gnus-summary
+  :type 'regexp)
+
+
+(defcustom gnus-summary-save-parts-default-mime "image/.*"
+  "*A regexp to match MIME parts when saving multiple parts of a message
+with gnus-summary-save-parts (X m). This regexp will be used by default
+when prompting the user for which type of files to save."
+  :group 'gnus-summary
+  :type 'regexp)
+
+(defcustom gnus-read-all-available-headers nil
+  "Whether Gnus should parse all headers made available to it.
+This is mostly relevant for slow backends where the user may
+wish to widen the summary buffer to include all headers
+that were fetched.  Say, for nnultimate groups."
+  :group 'gnus-summary
+  :type '(choice boolean regexp))
+
 ;;; Internal variables
 
 (defvar gnus-article-mime-handles nil)
+(defvar gnus-article-decoded-p nil)
+(defvar gnus-article-charset nil)
+(defvar gnus-article-ignored-charsets 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)
@@ -773,6 +980,14 @@ which it may alter in any way.")
 
 (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.")
+
+(defvar gnus-summary-save-parts-type-history nil)
+(defvar gnus-summary-save-parts-last-directory nil)
+
+(defvar gnus-summary-save-parts-type-history nil)
+(defvar gnus-summary-save-parts-last-directory nil)
 
 ;; Avoid highlighting in kill files.
 (defvar gnus-summary-inhibit-highlight nil)
@@ -807,7 +1022,7 @@ which it may alter in any way.")
     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
-    (?L gnus-tmp-lines ?d)
+    (?L gnus-tmp-lines ?s)
     (?I gnus-tmp-indentation ?s)
     (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
     (?R gnus-tmp-replied ?c)
@@ -820,6 +1035,7 @@ which it may alter in any way.")
     (?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)
@@ -828,9 +1044,9 @@ which it may alter in any way.")
        ?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)
@@ -903,6 +1119,9 @@ variable (string, integer, character, etc).")
 (defvar gnus-newsgroup-replied nil
   "List of articles that have been replied to in the current newsgroup.")
 
+(defvar gnus-newsgroup-forwarded nil
+  "List of articles that have been forwarded in the current newsgroup.")
+
 (defvar gnus-newsgroup-expirable nil
   "List of articles in the current newsgroup that can be expired.")
 
@@ -946,6 +1165,11 @@ variable (string, integer, character, etc).")
 (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)
+
+(defvar gnus-article-before-search nil)
 
 (defconst gnus-summary-local-variables
   '(gnus-newsgroup-name
@@ -955,7 +1179,8 @@ variable (string, integer, character, etc).")
     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
     gnus-newsgroup-unselected gnus-newsgroup-marked
     gnus-newsgroup-reads gnus-newsgroup-saved
-    gnus-newsgroup-replied gnus-newsgroup-expirable
+    gnus-newsgroup-replied gnus-newsgroup-forwarded
+    gnus-newsgroup-expirable
     gnus-newsgroup-processable gnus-newsgroup-killed
     gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
     gnus-newsgroup-unsendable
@@ -967,8 +1192,10 @@ variable (string, integer, character, etc).")
     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
@@ -977,16 +1204,58 @@ variable (string, integer, character, etc).")
     (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.")
 
+(defvar gnus-newsgroup-variables nil
+  "Variables that have separate values in the newsgroups.")
+
 ;; Byte-compiler warning.
-(defvar gnus-article-mode-map)
+(eval-when-compile (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)
@@ -1003,7 +1272,7 @@ variable (string, integer, character, etc).")
 
 (defsubst gnus-simplify-subject-re (subject)
   "Remove \"Re:\" from subject lines."
-  (if (string-match "^[Rr][Ee]: *" subject)
+  (if (string-match message-subject-re-regexp subject)
       (substring subject (match-end 0))
     subject))
 
@@ -1031,7 +1300,7 @@ If RE-ONLY is non-nil, strip leading `Re:'s only."
 (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.
@@ -1039,7 +1308,7 @@ The string in the accessible portion of the current buffer is simplified.
 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" " ")
@@ -1116,6 +1385,8 @@ increase the score of each group you read."
 
 (put 'gnus-summary-mode 'mode-class 'special)
 
+(defvar gnus-article-commands-menu)
+
 (when t
   ;; Non-orthogonal keys
 
@@ -1163,6 +1434,8 @@ increase the score of each group you read."
     "\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
@@ -1173,10 +1446,12 @@ increase the score of each group you read."
     "\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
     "\C-c\C-s\C-i" gnus-summary-sort-by-score
+    "\C-c\C-s\C-o" gnus-summary-sort-by-original
     "=" gnus-summary-expand-window
     "\C-x\C-s" gnus-summary-reselect-current-group
     "\M-g" gnus-summary-rescan-group
@@ -1203,13 +1478,14 @@ increase the score of each group you read."
     "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
@@ -1219,7 +1495,10 @@ increase the score of each group you read."
     "L" gnus-summary-lower-score
     "\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)
@@ -1261,15 +1540,19 @@ increase the score of each group you read."
     "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)
+    "C" gnus-summary-limit-mark-excluded-as-read
+    "o" gnus-summary-insert-old-articles
+    "N" gnus-summary-insert-new-articles)
 
   (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
     "n" gnus-summary-next-unread-article
@@ -1337,11 +1620,14 @@ increase the score of each group you read."
     "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
+    "M" gnus-mailing-list-insinuate
+    "t" gnus-article-babel)
 
   (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
     "b" gnus-article-add-buttons
@@ -1349,14 +1635,21 @@ increase the score of each group you read."
     "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
+    "s" gnus-summary-force-verify-and-decrypt
     "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
-    "h" gnus-article-treat-html
+    "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
+    "p" gnus-article-verify-x-pgp-sig
     "d" gnus-article-treat-dumbquotes)
 
   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
@@ -1366,7 +1659,9 @@ increase the score of each group you read."
     "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)
 
@@ -1378,12 +1673,15 @@ increase the score of each group you read."
 
   (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
     "w" gnus-article-decode-mime-words
-    "c" gnus-article-decode-charset)
+    "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
     "l" gnus-article-date-local
+    "p" gnus-article-date-english
     "e" gnus-article-date-lapsed
     "o" gnus-article-date-original
     "i" gnus-article-date-iso8601
@@ -1395,7 +1693,9 @@ increase the score of each group you read."
     "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
+    "w" gnus-article-remove-leading-whitespace)
 
   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
     "v" gnus-version
@@ -1409,6 +1709,7 @@ increase the score of each group you read."
     "\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
@@ -1417,6 +1718,7 @@ increase the score of each group you read."
     "q" gnus-summary-respool-query
     "t" gnus-summary-respool-trace
     "i" gnus-summary-import-article
+    "I" gnus-summary-create-article
     "p" gnus-summary-article-posted-p)
 
   (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
@@ -1429,7 +1731,21 @@ increase the score of each group you read."
     "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
+    "C" gnus-article-view-part-as-charset
+    "e" gnus-article-externalize-part
+    "E" gnus-article-encrypt-body
+    "i" gnus-article-inline-part
+    "|" gnus-article-pipe-part))
+
+(defvar gnus-article-post-menu nil)
 
 (defun gnus-summary-make-menu-bar ()
   (gnus-turn-off-edit-menu 'summary)
@@ -1442,7 +1758,6 @@ increase the score of each group you read."
       "Score"
       (nconc
        (list
-       ["Enter score..." gnus-summary-score-entry t]
        ["Customize" gnus-score-customize t])
        (gnus-make-score-map 'increase)
        (gnus-make-score-map 'lower)
@@ -1467,12 +1782,14 @@ increase the score of each group you read."
     ;; Define both the Article menu in the summary buffer and the equivalent
     ;; Commands menu in the article buffer here for consistency.
     (let ((innards
-           '(("Hide"
+           `(("Hide"
               ["All" gnus-article-hide t]
               ["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]
@@ -1482,7 +1799,11 @@ increase the score of each group you read."
             ("MIME"
              ["Words" gnus-article-decode-mime-words t]
              ["Charset" gnus-article-decode-charset t]
-             ["QP" gnus-article-de-quoted-unreadable t])
+             ["QP" gnus-article-de-quoted-unreadable t]
+             ["Base64" gnus-article-de-base64-unreadable t]
+             ["View all" gnus-mime-view-all-parts t]
+             ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
+             ["Encrypt body" gnus-article-encrypt-body t])
              ("Date"
               ["Local" gnus-article-date-local t]
               ["ISO8601" gnus-article-date-iso8601 t]
@@ -1497,25 +1818,39 @@ increase the score of each group you read."
                ["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]
+               ["Leading space in headers" 
+               gnus-article-remove-leading-whitespace 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]
-              ["Rot 13" gnus-summary-caesar-message t]
+              ["Base64" gnus-article-de-base64-unreadable t]
+              ["Rot 13" gnus-summary-caesar-message
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "\"Caesar rotate\" article by 13"))]
               ["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]
               ["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]
+             ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig 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]
+              ["Save in default format" gnus-summary-save-article
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "Save article using default method"))]
+              ["Save in file" gnus-summary-save-article-file
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "Save article in file"))]
               ["Save in Unix mail format" gnus-summary-save-article-mail t]
               ["Save in MH folder" gnus-summary-save-article-folder t]
               ["Save in VM folder" gnus-summary-save-article-vm t]
@@ -1534,6 +1869,7 @@ increase the score of each group you read."
                (gnus-check-backend-function
                 'request-replace-article gnus-newsgroup-name)]
               ["Import file..." gnus-summary-import-article t]
+              ["Create article..." gnus-summary-create-article t]
               ["Check if posted" gnus-summary-article-posted-p t]
               ["Edit article" gnus-summary-edit-article
                (not (gnus-group-read-only-p))]
@@ -1546,7 +1882,9 @@ increase the score of each group you read."
                (gnus-check-backend-function
                 'request-expire-articles gnus-newsgroup-name)])
              ("Extract"
-              ["Uudecode" gnus-uu-decode-uu t]
+              ["Uudecode" gnus-uu-decode-uu
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "Decode uuencoded article(s)"))]
               ["Uudecode and save" gnus-uu-decode-uu-and-save t]
               ["Unshar" gnus-uu-decode-unshar t]
               ["Unshar and save" gnus-uu-decode-unshar-and-save t]
@@ -1556,6 +1894,7 @@ increase the score of each group you read."
              ("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]
@@ -1565,14 +1904,21 @@ increase the score of each group you read."
              ["Fetch referenced articles" gnus-summary-refer-references t]
              ["Fetch current thread" gnus-summary-refer-thread t]
              ["Fetch article with id..." gnus-summary-refer-article t]
+             ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
              ["Redisplay" gnus-summary-show-article t])))
       (easy-menu-define
        gnus-summary-article-menu gnus-summary-mode-map ""
        (cons "Article" innards))
 
-      (easy-menu-define
-       gnus-article-commands-menu gnus-article-mode-map ""
-       (cons "Commands" innards)))
+      (if (not (keymapp gnus-summary-article-menu))
+         (easy-menu-define
+           gnus-article-commands-menu gnus-article-mode-map ""
+           (cons "Commands" innards))
+       ;; in Emacs, don't share menu.
+       (setq gnus-article-commands-menu 
+             (copy-keymap gnus-summary-article-menu))
+       (define-key gnus-article-mode-map [menu-bar commands]
+         (cons "Commands" gnus-article-commands-menu))))
 
     (easy-menu-define
      gnus-summary-thread-menu gnus-summary-mode-map ""
@@ -1590,21 +1936,30 @@ increase the score of each group you read."
        ["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 ""
-     '("Post"
-       ["Post an article" gnus-summary-post-news t]
-       ["Followup" gnus-summary-followup t]
-       ["Followup and yank" gnus-summary-followup-with-original t]
+     `("Post"
+       ["Post an article" gnus-summary-post-news
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Post an article"))]
+       ["Followup" gnus-summary-followup
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Post followup to this article"))]
+       ["Followup and yank" gnus-summary-followup-with-original
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Post followup to this article, quoting its contents"))]
        ["Supersede article" gnus-summary-supersede-article t]
-       ["Cancel article" gnus-summary-cancel-article t]
+       ["Cancel article" gnus-summary-cancel-article
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Cancel an article you posted"))]
        ["Reply" gnus-summary-reply t]
        ["Reply and yank" gnus-summary-reply-with-original t]
        ["Wide reply" gnus-summary-wide-reply t]
-       ["Wide reply and yank" gnus-summary-wide-reply-with-original t]
+       ["Wide reply and yank" gnus-summary-wide-reply-with-original
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Mail a reply, quoting this article"))]
        ["Mail forward" gnus-summary-mail-forward t]
        ["Post forward" gnus-summary-post-forward t]
        ["Digest and mail" gnus-uu-digest-mail-forward t]
@@ -1612,7 +1967,9 @@ increase the score of each group you read."
        ["Resend message" gnus-summary-resend-message t]
        ["Send bounced mail" gnus-summary-resend-bounced-mail t]
        ["Send a mail" gnus-summary-mail-other-window t]
-       ["Uuencode and post" gnus-uu-post-news t]
+       ["Uuencode and post" gnus-uu-post-news
+       ,@(if (featurep 'xemacs) '(t)
+           '(:help "Post a uuencoded article"))]
        ["Followup via news" gnus-summary-followup-to-mail t]
        ["Followup via news and yank"
        gnus-summary-followup-to-mail-with-original t]
@@ -1621,15 +1978,27 @@ increase the score of each group you read."
        ;;["Send bounced" gnus-resend-bounced-mail t])
        ))
 
+    (cond 
+     ((not (keymapp gnus-summary-post-menu))
+      (setq gnus-article-post-menu gnus-summary-post-menu))
+     ((not gnus-article-post-menu)
+      ;; Don't share post menu.
+      (setq gnus-article-post-menu
+           (copy-keymap gnus-summary-post-menu))))
+    (define-key gnus-article-mode-map [menu-bar post]
+      (cons "Post" gnus-article-post-menu))
+
     (easy-menu-define
      gnus-summary-misc-menu gnus-summary-mode-map ""
-     '("Misc"
+     `("Misc"
        ("Mark Read"
        ["Mark as read" gnus-summary-mark-as-read-forward t]
        ["Mark same subject and select"
         gnus-summary-kill-same-subject-and-select t]
        ["Mark same subject" gnus-summary-kill-same-subject t]
-       ["Catchup" gnus-summary-catchup t]
+       ["Catchup" gnus-summary-catchup
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Mark unread articles in this group as read"))]
        ["Catchup all" gnus-summary-catchup-all t]
        ["Catchup to here" gnus-summary-catchup-to-here t]
        ["Catchup region" gnus-summary-mark-region-as-read t]
@@ -1646,6 +2015,7 @@ increase the score of each group you read."
        ["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]
@@ -1655,7 +2025,8 @@ increase the score of each group you read."
        ["Hide childless dormant"
         gnus-summary-limit-exclude-childless-dormant t]
        ;;["Hide thread" gnus-summary-limit-exclude-thread t]
-       ["Show expunged" gnus-summary-show-all-expunged t])
+       ["Hide marked" gnus-summary-limit-exclude-marks t]
+       ["Show expunged" gnus-summary-limit-include-expunged t])
        ("Process Mark"
        ["Set mark" gnus-summary-mark-as-processable t]
        ["Remove mark" gnus-summary-unmark-as-processable t]
@@ -1677,8 +2048,12 @@ increase the score of each group you read."
          gnus-newsgroup-process-stack]
         ["Save" gnus-summary-save-process-mark t]))
        ("Scroll article"
-       ["Page forward" gnus-summary-next-page t]
-       ["Page backward" gnus-summary-prev-page t]
+       ["Page forward" gnus-summary-next-page
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Show next page of article"))]
+       ["Page backward" gnus-summary-prev-page
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Show previous page of article"))]
        ["Line forward" gnus-summary-scroll-up t])
        ("Move"
        ["Next unread article" gnus-summary-next-unread-article t]
@@ -1701,7 +2076,9 @@ increase the score of each group you read."
        ["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]
+       ["Original sort" gnus-summary-sort-by-original t])
        ("Help"
        ["Fetch group FAQ" gnus-summary-fetch-faq t]
        ["Describe group" gnus-summary-describe-group t]
@@ -1713,6 +2090,8 @@ increase the score of each group you read."
        ["Regenerate" gnus-summary-prepare t]
        ["Insert cached articles" gnus-summary-insert-cached-articles t]
        ["Toggle threading" gnus-summary-toggle-threads t])
+       ["See old articles" gnus-summary-insert-old-articles t]
+       ["See new articles" gnus-summary-insert-new-articles t]
        ["Filter articles..." gnus-summary-execute-command t]
        ["Run command on subjects..." gnus-summary-universal-argument t]
        ["Search articles forward..." gnus-summary-search-article-forward t]
@@ -1725,12 +2104,17 @@ increase the score of each group you read."
        ["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]
+       ["Catchup and exit" gnus-summary-catchup-and-exit
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Mark unread articles in this group as read, then exit"))]
        ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
        ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
-       ["Exit group" gnus-summary-exit t]
+       ["Exit group" gnus-summary-exit
+        ,@(if (featurep 'xemacs) '(t)
+            '(:help "Exit current group, return to group selection mode"))]
        ["Exit group without updating" gnus-summary-exit-no-update t]
        ["Exit and goto next group" gnus-summary-next-group t]
        ["Exit and goto prev group" gnus-summary-prev-group t]
@@ -1740,6 +2124,50 @@ increase the score of each group you read."
 
     (gnus-run-hooks 'gnus-summary-menu-hook)))
 
+(defvar gnus-summary-tool-bar-map nil)
+
+;; Emacs 21 tool bar.  Should be no-op otherwise.
+(defun gnus-summary-make-tool-bar ()
+  (if (and (fboundp 'tool-bar-add-item-from-menu)
+          (default-value 'tool-bar-mode)
+          (not gnus-summary-tool-bar-map))
+      (setq gnus-summary-tool-bar-map
+           (let ((tool-bar-map (make-sparse-keymap))
+                 (load-path (mm-image-load-path)))
+             (tool-bar-add-item-from-menu
+              'gnus-summary-prev-unread "prev-ur" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-next-unread "next-ur" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-post-news "post" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-followup-with-original "fuwo" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-followup "followup" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-reply-with-original "reply-wo" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-reply "reply" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-caesar-message "rot13" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-uu-decode-uu "uu-decode" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-save-article-file "save-aif" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-save-article "save-art" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-uu-post-news "uu-post" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-catchup "catchup" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-catchup-and-exit "cu-exit" gnus-summary-mode-map)
+             (tool-bar-add-item-from-menu
+              'gnus-summary-exit "exit-summ" gnus-summary-mode-map)
+             tool-bar-map)))
+  (if gnus-summary-tool-bar-map
+      (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
+
 (defun gnus-score-set-default (var value)
   "A version of set that updates the GNU Emacs menu-bar."
   (set var value)
@@ -1755,6 +2183,7 @@ increase the score of each group you read."
                     ("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" <)
@@ -1809,7 +2238,8 @@ increase the score of each group you read."
                                               (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)
@@ -1846,17 +2276,20 @@ The following commands are available:
 
 \\{gnus-summary-mode-map}"
   (interactive)
-  (when (gnus-visual-p 'summary-menu 'menu)
-    (gnus-summary-make-menu-bar))
   (kill-all-local-variables)
+  (when (gnus-visual-p 'summary-menu 'menu)
+    (gnus-summary-make-menu-bar)
+    (gnus-summary-make-tool-bar))
   (gnus-summary-make-local-variables)
+  (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+    (gnus-summary-make-local-variables))
   (gnus-make-thread-indent-array)
   (gnus-simplify-mode-line)
   (setq major-mode 'gnus-summary-mode)
   (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)
@@ -1869,20 +2302,18 @@ The following commands are available:
   (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)
+  (turn-on-gnus-mailing-list-mode)
+  (mm-enable-multibyte-mule4)
   (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)
@@ -1890,11 +2321,9 @@ The following commands are available:
                (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))
@@ -2214,12 +2643,13 @@ marks of articles."
 
 (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)))))
+  (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.
 
@@ -2229,9 +2659,10 @@ marks of articles."
   (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)
@@ -2254,9 +2685,13 @@ marks of articles."
          (aset table i [??]))))
     (setq buffer-display-table table)))
 
+(defun gnus-summary-buffer-name (group)
+  "Return the summary buffer name of GROUP."
+  (concat "*Summary " group "*"))
+
 (defun gnus-summary-setup-buffer (group)
   "Initialize summary buffer."
-  (let ((buffer (concat "*Summary " group "*")))
+  (let ((buffer (gnus-summary-buffer-name group)))
     (if (get-buffer buffer)
        (progn
          (set-buffer buffer)
@@ -2272,12 +2707,14 @@ marks of articles."
        (make-local-variable 'gnus-article-current)
        (make-local-variable 'gnus-original-article-buffer))
       (setq gnus-newsgroup-name group)
+      ;; Set any local variables in the group parameters.
+      (gnus-summary-set-local-parameters gnus-newsgroup-name)
       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)
@@ -2290,7 +2727,16 @@ marks of articles."
          (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)
+         vlist)
+      (let ((locals gnus-newsgroup-variables))
+       (while locals
+         (if (consp (car locals))
+             (push (eval (caar locals)) vlist)
+           (push (eval (car locals)) vlist))
+         (setq locals (cdr locals)))
+       (setq vlist (nreverse vlist)))
       (save-excursion
        (set-buffer gnus-group-buffer)
        (setq gnus-newsgroup-name name
@@ -2303,7 +2749,14 @@ marks of articles."
              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)
+       (let ((locals gnus-newsgroup-variables))
+         (while locals
+           (if (consp (car locals))
+               (set (caar locals) (pop vlist))
+             (set (car locals) (pop vlist)))
+           (setq locals (cdr locals))))
        ;; The article buffer also has local variables.
        (when (gnus-buffer-live-p gnus-article-buffer)
          (set-buffer gnus-article-buffer)
@@ -2322,7 +2775,8 @@ marks of articles."
 (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 ()
@@ -2352,7 +2806,8 @@ marks of articles."
        (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 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 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)))))
@@ -2376,6 +2831,33 @@ marks of articles."
    (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
@@ -2389,7 +2871,7 @@ marks of articles."
          (if (or (null gnus-summary-default-score)
                  (<= (abs (- gnus-tmp-score gnus-summary-default-score))
                      gnus-summary-zcore-fuzz))
-             ? 
+             ?  ;Whitespace
            (if (< gnus-tmp-score gnus-summary-default-score)
                gnus-score-below-mark gnus-score-over-mark)))
         (gnus-tmp-replied
@@ -2399,15 +2881,14 @@ marks of articles."
                (gnus-tmp-replied gnus-replied-mark)
                ((memq gnus-tmp-current gnus-newsgroup-saved)
                 gnus-saved-mark)
-               (t gnus-unread-mark)))
+               (t gnus-no-mark)))
         (gnus-tmp-from (mail-header-from gnus-tmp-header))
         (gnus-tmp-name
          (cond
           ((string-match "<[^>]+> *$" gnus-tmp-from)
            (let ((beg (match-beginning 0)))
-             (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
-                      (substring gnus-tmp-from (1+ (match-beginning 0))
-                                 (1- (match-end 0))))
+             (or (and (string-match "^\".+\"" gnus-tmp-from)
+                      (substring gnus-tmp-from 1 (1- (match-end 0))))
                  (substring gnus-tmp-from 0 beg))))
           ((string-match "(.+)" gnus-tmp-from)
            (substring gnus-tmp-from
@@ -2421,8 +2902,10 @@ marks of articles."
     (when (string= gnus-tmp-name "")
       (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
+      (setq gnus-tmp-lines -1))
+    (when (= gnus-tmp-lines -1)
+      (setq gnus-tmp-lines "?"))
+    (gnus-put-text-property
      (point)
      (progn (eval gnus-summary-line-format-spec) (point))
      'gnus-number gnus-tmp-number)
@@ -2432,7 +2915,7 @@ marks of articles."
       (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.
@@ -2454,7 +2937,7 @@ marks of articles."
         (if (or (null gnus-summary-default-score)
                 (<= (abs (- score gnus-summary-default-score))
                     gnus-summary-zcore-fuzz))
-            ? 
+            ?  ;Whitespace
           (if (< score gnus-summary-default-score)
               gnus-score-below-mark gnus-score-over-mark))
         'score))
@@ -2523,7 +3006,7 @@ If NO-DISPLAY, don't generate a summary buffer."
                                   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
@@ -2540,10 +3023,11 @@ If NO-DISPLAY, don't generate a summary buffer."
                                        kill-buffer no-display
                                        &optional select-articles)
   ;; Killed foreign groups can't be entered.
-  (when (and (not (gnus-group-native-p group))
-            (not (gnus-gethash group gnus-newsrc-hashtb)))
-    (error "Dead non-native groups can't be entered"))
-  (gnus-message 5 "Retrieving newsgroup: %s..." group)
+  ;;  (when (and (not (gnus-group-native-p group))
+  ;;        (not (gnus-gethash group gnus-newsrc-hashtb)))
+  ;;    (error "Dead non-native groups can't be entered"))
+  (gnus-message 5 "Retrieving newsgroup: %s..." 
+               (gnus-group-decoded-name group))
   (let* ((new-group (gnus-summary-setup-buffer group))
         (quit-config (gnus-group-quit-config group))
         (did-select (and new-group (gnus-select-newsgroup
@@ -2573,7 +3057,11 @@ If NO-DISPLAY, don't generate a summary buffer."
              (gnus-group-jump-to-group group)
              (gnus-group-next-unread-group 1))
          (gnus-handle-ephemeral-exit quit-config)))
-      (gnus-message 3 "Can't select group")
+      (let ((grpinfo (gnus-get-info group)))
+        (if (null (gnus-info-read grpinfo))
+            (gnus-message 3 "Group %s contains no messages" 
+                         (gnus-group-decoded-name group))
+          (gnus-message 3 "Can't select group")))
       nil)
      ;; The user did a `C-g' while prompting for number of articles,
      ;; so we exit this group.
@@ -2601,10 +3089,9 @@ If NO-DISPLAY, don't generate a summary buffer."
             (gnus-active gnus-newsgroup-name)))
       ;; You can change the summary buffer in some way with this hook.
       (gnus-run-hooks 'gnus-select-group-hook)
-      ;; Set any local variables in the group parameters.
-      (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))
@@ -2617,6 +3104,7 @@ If NO-DISPLAY, don't generate a summary buffer."
              (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))
@@ -2662,16 +3150,21 @@ If NO-DISPLAY, don't generate a summary buffer."
                 (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))
          (gnus-summary-position-point)
          (gnus-configure-windows 'summary 'force)
-         (gnus-set-mode-line 'summary))        
+         (gnus-set-mode-line 'summary))
        (when (get-buffer-window gnus-group-buffer t)
          ;; Gotta use windows, because recenter does weird stuff if
          ;; the current buffer ain't the displayed window.
@@ -2810,12 +3303,12 @@ If NO-DISPLAY, don't generate a summary buffer."
     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))
 
@@ -2950,6 +3443,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
 
 (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)
@@ -3002,7 +3496,8 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
   ;; 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)))
@@ -3017,24 +3512,6 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
             (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)
@@ -3052,16 +3529,20 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
          (setq header
                (make-full-mail-header
                 number                 ; number
-                (rfc2047-decode-string (gnus-nov-field)) ; subject
-                (rfc2047-decode-string (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)
+                  (if (looking-at "Xref: ")
+                      (goto-char (match-end 0)))
+                  (nnheader-nov-field)) ; Xref
+                (nnheader-nov-parse-extra)))) ; extra
 
       (widen))
 
@@ -3070,9 +3551,9 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
     (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
@@ -3107,6 +3588,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
 (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
@@ -3116,8 +3598,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
        (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)
@@ -3154,17 +3635,19 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
        (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))
@@ -3378,7 +3861,6 @@ If LINE, insert the rebuilt thread starting on line LINE."
                  (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)
@@ -3390,6 +3872,7 @@ If LINE, insert the rebuilt thread starting on line LINE."
       (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)
@@ -3397,13 +3880,22 @@ If LINE, insert the rebuilt thread starting on line LINE."
              (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)
@@ -3418,12 +3910,12 @@ If LINE, insert the rebuilt thread starting on line LINE."
 
 ;; 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)
@@ -3446,6 +3938,16 @@ If LINE, insert the rebuilt thread starting on line LINE."
   (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
@@ -3506,7 +4008,7 @@ Unscored articles will be counted as having a score of zero."
   (> (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)
@@ -3537,6 +4039,12 @@ Unscored articles will be counted as having a score of zero."
 (defvar gnus-tmp-root-expunged nil)
 (defvar gnus-tmp-dummy-line nil)
 
+(eval-when-compile (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 ...]...) ...])'
@@ -3734,7 +4242,7 @@ or a straight list of headers."
             (if (or (null gnus-summary-default-score)
                     (<= (abs (- gnus-tmp-score gnus-summary-default-score))
                         gnus-summary-zcore-fuzz))
-                ? 
+                ?  ;Whitespace
               (if (< gnus-tmp-score gnus-summary-default-score)
                   gnus-score-below-mark gnus-score-over-mark))
             gnus-tmp-replied
@@ -3744,17 +4252,18 @@ or a straight list of headers."
                    gnus-cached-mark)
                   ((memq number gnus-newsgroup-replied)
                    gnus-replied-mark)
+                  ((memq number gnus-newsgroup-forwarded)
+                   gnus-forwarded-mark)
                   ((memq number gnus-newsgroup-saved)
                    gnus-saved-mark)
-                  (t gnus-unread-mark))
+                  (t gnus-no-mark))
             gnus-tmp-from (mail-header-from gnus-tmp-header)
             gnus-tmp-name
             (cond
              ((string-match "<[^>]+> *$" gnus-tmp-from)
               (setq beg-match (match-beginning 0))
-              (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
-                       (substring gnus-tmp-from (1+ (match-beginning 0))
-                                  (1- (match-end 0))))
+              (or (and (string-match "^\".+\"" gnus-tmp-from)
+                       (substring gnus-tmp-from 1 (1- (match-end 0))))
                   (substring gnus-tmp-from 0 beg-match)))
              ((string-match "(.+)" gnus-tmp-from)
               (substring gnus-tmp-from
@@ -3763,8 +4272,10 @@ or a straight list of headers."
            (when (string= gnus-tmp-name "")
              (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
+             (setq gnus-tmp-lines -1))
+           (when (= gnus-tmp-lines -1)
+             (setq gnus-tmp-lines "?"))
+           (gnus-put-text-property
             (point)
             (progn (eval gnus-summary-line-format-spec) (point))
             'gnus-number number)
@@ -3818,6 +4329,53 @@ or a straight list of headers."
         (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 (consp gnus-list-identifiers)
+                   (mapconcat 'identity gnus-list-identifiers " *\\|")
+                 gnus-list-identifiers))
+       changed subject)
+    (when regexp
+      (dolist (header gnus-newsgroup-headers)
+       (setq subject (mail-header-subject header)
+             changed nil)
+       (while (string-match
+               (concat "^\\(R[Ee]: +\\)*\\(" regexp " *\\)")
+               subject)
+         (setq subject
+               (concat (substring subject 0 (match-beginning 2))
+                       (substring subject (match-end 0)))
+               changed t))
+       (when (and changed
+                  (string-match
+                   "^\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" subject))
+         (setq subject
+               (concat (substring subject 0 (match-beginning 1))
+                       (substring subject (match-end 1)))))
+       (when changed
+         (mail-header-set-subject header subject))))))
+
+(defun gnus-fetch-headers (articles)
+  "Fetch headers of ARTICLES."
+  (let ((name (gnus-group-decoded-name gnus-newsgroup-name)))
+    (gnus-message 5 "Fetching headers for %s..." name)
+    (prog1
+       (if (eq 'nov
+               (setq gnus-headers-retrieved-by
+                     (gnus-retrieve-headers
+                      articles gnus-newsgroup-name
+                      ;; We might want to fetch old headers, but
+                      ;; not if there is only 1 article.
+                      (and (or (and
+                                (not (eq gnus-fetch-old-headers 'some))
+                                (not (numberp gnus-fetch-old-headers)))
+                               (> (length articles) 1))
+                           gnus-fetch-old-headers))))
+           (gnus-get-newsgroup-headers-xover
+            articles nil nil gnus-newsgroup-name t)
+         (gnus-get-newsgroup-headers))
+      (gnus-message 5 "Fetching headers for %s...done" name))))
+
 (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.
@@ -3841,7 +4399,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
        (progn                          ; Or we bug out.
          (when (equal major-mode 'gnus-summary-mode)
            (kill-buffer (current-buffer)))
-         (error "Couldn't request group %s: %s"
+         (error "Couldn't activate group %s: %s"
                 group (gnus-status-message group))))
 
     (unless (gnus-request-group group t)
@@ -3853,6 +4411,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
     (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
@@ -3887,24 +4446,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       ;; 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
-           (if (eq 'nov
-                   (setq gnus-headers-retrieved-by
-                         (gnus-retrieve-headers
-                          articles gnus-newsgroup-name
-                          ;; We might want to fetch old headers, but
-                          ;; not if there is only 1 article.
-                          (and (or (and
-                                    (not (eq gnus-fetch-old-headers 'some))
-                                    (not (numberp gnus-fetch-old-headers)))
-                                   (> (length articles) 1))
-                               gnus-fetch-old-headers))))
-               (gnus-get-newsgroup-headers-xover
-                articles nil nil gnus-newsgroup-name t)
-             (gnus-get-newsgroup-headers)))
-      (gnus-message 5 "Fetching headers for %s...done" gnus-newsgroup-name)
+      (setq gnus-newsgroup-headers (gnus-fetch-headers articles))
 
       ;; Kludge to avoid having cached articles nixed out in virtual groups.
       (when cached
@@ -3935,6 +4479,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       ;; 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))
@@ -3952,7 +4499,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       (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.
@@ -3961,7 +4508,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                       (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))
                  '<)))
@@ -3997,7 +4546,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                    (if (string-match "^[ \t]*$" input)
                        number input)))
                 (t number))
-             (quit nil))))))
+             (quit
+              (message "Quit getting the articles to read")
+              nil))))))
     (setq select (if (stringp select) (string-to-number select) select))
     (if (or (null select) (zerop select))
        select
@@ -4017,6 +4568,12 @@ If SELECT-ARTICLES, only select those articles from GROUP."
            (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)
@@ -4039,7 +4596,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
     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))
@@ -4097,15 +4654,16 @@ If SELECT-ARTICLES, only select those articles from GROUP."
   (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)
@@ -4120,13 +4678,37 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                    (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)
@@ -4143,10 +4725,12 @@ If SELECT-ARTICLES, only select those articles from GROUP."
            (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
@@ -4157,7 +4741,8 @@ If WHERE is `summary', the summary mode line format will be used."
        (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-decoded-name 
+                                    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))
@@ -4196,7 +4781,7 @@ If WHERE is `summary', the summary mode line format will be used."
          ;; We might have to chop a bit of the string off...
          (when (> (length mode-string) max-len)
            (setq mode-string
-                 (concat (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))))
@@ -4274,7 +4859,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         (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)
@@ -4302,7 +4887,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
       ;; Then we add the read articles to the range.
       (gnus-add-to-range
        ninfo (setq articles (sort articles '<))))))
-  
+
 (defun gnus-group-make-articles-read (group articles)
   "Update the info of GROUP to say that ARTICLES are read."
   (let* ((num 0)
@@ -4343,15 +4928,6 @@ The resulting hash table is returned, or nil if no Xrefs were found."
        ;; 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)
@@ -4360,11 +4936,18 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         (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)
@@ -4396,13 +4979,16 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nsubject: " nil t)
-                 (rfc2047-decode-string (nnheader-header-value))
+                 (funcall gnus-decode-encoded-word-function
+                          (nnheader-header-value))
                "(none)"))
            ;; From.
            (progn
              (goto-char p)
-             (if (search-forward "\nfrom: " nil t)
-                 (rfc2047-decode-string (nnheader-header-value))
+             (if (or (search-forward "\nfrom: " nil t)
+                     (search-forward "\nfrom:" nil t))
+                 (funcall gnus-decode-encoded-word-function
+                          (nnheader-header-value))
                "(nobody)"))
            ;; Date.
            (progn
@@ -4459,20 +5045,32 @@ The resulting hash table is returned, or nil if no Xrefs were found."
              (goto-char p)
              (if (search-forward "\nchars: " nil t)
                  (if (numberp (setq chars (ignore-errors (read cur))))
-                     chars 0)
-               0))
+                     chars -1)
+               -1))
            ;; Lines.
            (progn
              (goto-char p)
              (if (search-forward "\nlines: " nil t)
                  (if (numberp (setq lines (ignore-errors (read cur))))
-                     lines 0)
-               0))
+                     lines -1)
+               -1))
            ;; Xref.
            (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))
 
@@ -4493,34 +5091,48 @@ The resulting hash table is returned, or nil if no Xrefs were found."
 (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))
+       (allp (cond
+              ((eq gnus-read-all-available-headers t)
+               t)
+              ((stringp gnus-read-all-available-headers)
+               (string-match gnus-read-all-available-headers group))
+              (t
+               nil)))
        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))
       (while (not (eobp))
        (condition-case ()
-           (while (and sequence (not (eobp)))
+           (while (and (or sequence allp)
+                       (not (eobp)))
              (setq number (read cur))
-             (while (and sequence
-                         (< (car sequence) number))
-               (setq sequence (cdr sequence)))
-             (and sequence
-                  (eq number (car sequence))
-                  (progn
-                    (setq sequence (cdr sequence))
-                    (setq header (inline
-                                   (gnus-nov-parse-line
-                                    number dependencies force-new))))
-                  (push header headers))
+             (when (not allp)
+               (while (and sequence
+                           (< (car sequence) number))
+                 (setq sequence (cdr sequence))))
+             (when (and (or allp
+                            (and sequence
+                                 (eq number (car sequence))))
+                        (progn
+                          (setq sequence (cdr sequence))
+                          (setq header (inline
+                                         (gnus-nov-parse-line
+                                          number dependencies force-new)))))
+               (push header headers))
              (forward-line 1))
          (error
           (gnus-error 4 "Strange nov line (%d)"
@@ -4556,7 +5168,8 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
          (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)))
@@ -4571,14 +5184,14 @@ the subject line on."
   (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.
@@ -4673,7 +5286,8 @@ executed with point over the summary line of the articles."
     `(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))
@@ -4818,9 +5432,12 @@ If `gnus-auto-center-summary' is nil, or the article buffer isn't
 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))
@@ -4833,9 +5450,22 @@ displayed, no centering will be performed."
        ;; Set the window start to either `bottom', which is the biggest
        ;; possible valid number, or the second line from the top,
        ;; whichever is the least.
-       (set-window-start
-        window (min bottom (save-excursion
-                             (forward-line (- top)) (point)))))
+       (let ((top-pos (save-excursion (forward-line (- top)) (point))))
+         (if (> bottom top-pos)
+             ;; Keep the second line from the top visible
+             (set-window-start window top-pos t)
+           ;; Try to keep the bottom line visible; if it's partially
+           ;; obscured, either scroll one more line to make it fully
+           ;; visible, or revert to using TOP-POS.
+           (save-excursion
+             (goto-char (point-max))
+             (forward-line -1)
+             (let ((last-line-start (point)))
+               (goto-char bottom)
+               (set-window-start window (point) t)
+               (when (not (pos-visible-in-window-p last-line-start window))
+                 (forward-line 1)
+                 (set-window-start window (min (point) top-pos) t)))))))
       ;; Do horizontal recentering while we're at it.
       (when (and (get-buffer-window (current-buffer) t)
                 (not (eq gnus-auto-center-summary 'vertical)))
@@ -4875,7 +5505,10 @@ displayed, no centering will be performed."
       ;; 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))
@@ -4932,8 +5565,7 @@ displayed, no centering will be performed."
          (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
@@ -5002,7 +5634,7 @@ The prefix argument ALL means to select all articles."
          (gnus-update-read-articles
           group (append gnus-newsgroup-unreads gnus-newsgroup-unselected))
          ;; Set the current article marks.
-         (let ((gnus-newsgroup-scored 
+         (let ((gnus-newsgroup-scored
                 (if (and (not gnus-save-score)
                          (not non-destructive))
                     nil
@@ -5029,9 +5661,16 @@ If FORCE (the prefix), also save the .newsrc file(s)."
 
 (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)
@@ -5039,6 +5678,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
         (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
@@ -5052,17 +5697,14 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
       (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)
@@ -5079,29 +5721,29 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
        nil                             ;Nothing to do.
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
-       (save-excursion
-         (set-buffer gnus-article-buffer)
-         (mapcar 'mm-destroy-part gnus-article-mime-handles))
        (gnus-kill-buffer gnus-article-buffer)
        (gnus-kill-buffer gnus-original-article-buffer)
        (setq gnus-article-current nil))
       (set-buffer buf)
       (if (not gnus-kill-summary-on-exit)
-         (gnus-deaden-summary)
+         (progn
+           (gnus-deaden-summary)
+           (setq mode nil))
        ;; We set all buffer-local variables to nil.  It is unclear why
        ;; this is needed, but if we don't, buffer-local variables are
        ;; not garbage-collected, it seems.  This would the lead to en
        ;; ever-growing Emacs.
        (gnus-summary-clear-local-variables)
+       (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+         (gnus-summary-clear-local-variables))
        (when (get-buffer gnus-article-buffer)
          (bury-buffer gnus-article-buffer))
        ;; We clear the global counterparts of the buffer-local
        ;; variables as well, just to be on the safe side.
        (set-buffer gnus-group-buffer)
        (gnus-summary-clear-local-variables)
-       ;; Return to group mode buffer.
-       (when (eq mode 'gnus-summary-mode)
-         (gnus-kill-buffer buf)))
+       (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+         (gnus-summary-clear-local-variables)))
       (setq gnus-current-select-method gnus-select-method)
       (pop-to-buffer gnus-group-buffer)
       (if (not quit-config)
@@ -5109,6 +5751,9 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
            (goto-char group-point)
            (gnus-configure-windows 'group 'force))
        (gnus-handle-ephemeral-exit quit-config))
+      ;; Return to group mode buffer.
+      (when (eq mode 'gnus-summary-mode)
+       (gnus-kill-buffer buf))
       ;; Clear the current group name.
       (unless quit-config
        (setq gnus-newsgroup-name nil)))))
@@ -5123,7 +5768,16 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
              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)
@@ -5133,8 +5787,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
          (gnus-deaden-summary)
        (gnus-close-group group)
        (gnus-summary-clear-local-variables)
+       (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+         (gnus-summary-clear-local-variables))
        (set-buffer gnus-group-buffer)
        (gnus-summary-clear-local-variables)
+       (let ((gnus-summary-local-variables gnus-newsgroup-variables))
+         (gnus-summary-clear-local-variables))
        (when (get-buffer gnus-summary-buffer)
          (kill-buffer gnus-summary-buffer)))
       (unless gnus-single-article-buffer
@@ -5231,7 +5889,8 @@ The state which existed when entering the ephemeral is reset."
       (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."
@@ -5292,8 +5951,7 @@ in."
 (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.
 
@@ -5399,8 +6057,8 @@ returned."
                (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" "")))
@@ -5461,7 +6119,15 @@ Given a prefix, will force an `article' buffer configuration."
 
 (defun gnus-summary-display-article (article &optional all-header)
   "Display ARTICLE in article buffer."
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (with-current-buffer gnus-article-buffer
+      (mm-enable-multibyte-mule4)))
   (gnus-set-global-variables)
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (with-current-buffer gnus-article-buffer
+      (setq gnus-article-charset gnus-newsgroup-charset)
+      (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
+      (mm-enable-multibyte-mule4)))
   (if (null article)
       nil
     (prog1
@@ -5491,35 +6157,44 @@ be displayed."
     (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
+           (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-mule4))))
            (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-force-verify-and-decrypt ()
+  (interactive)
+  (let ((mm-verify-option 'known)
+       (mm-decrypt-option 'known))
+    (gnus-summary-select-article nil 'force)))
 
 (defun gnus-summary-set-current-mark (&optional current-mark)
   "Obsolete function."
@@ -5791,15 +6466,25 @@ Return nil if there are no unread articles."
        (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 ()
@@ -5921,7 +6606,21 @@ If given a prefix, remove all limits."
   "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 older 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 (days-to-time age))
@@ -5930,7 +6629,9 @@ articles that are younger than AGE days."
          (when (and (vectorp (gnus-data-header d))
                     (setq date (mail-header-date (gnus-data-header d))))
            (setq is-younger (time-less-p
-                             (time-since (date-to-time date))
+                             (time-since (condition-case ()
+                                             (date-to-time date)
+                                           (error '(0 0))))
                              cutoff))
            (when (if younger-p
                      is-younger
@@ -5939,6 +6640,30 @@ articles that are younger than AGE days."
        (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)
@@ -6009,12 +6734,27 @@ Returns how many articles were removed."
       (gnus-summary-position-point))))
 
 (defun gnus-summary-limit-include-thread (id)
-  "Display all the hidden articles that in the current thread."
+  "Display all the hidden articles that is in the thread with ID in it.
+When called interactively, ID is the Message-ID of the current
+article."
   (interactive (list (mail-header-id (gnus-summary-article-header))))
   (let ((articles (gnus-articles-in-thread
                   (gnus-id-to-thread (gnus-root-id id)))))
     (prog1
        (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
+       (gnus-summary-limit-include-matching-articles
+        "subject"
+        (regexp-quote (gnus-simplify-subject-re
+                       (mail-header-subject (gnus-id-to-header id)))))
+      (gnus-summary-position-point))))
+
+(defun gnus-summary-limit-include-matching-articles (header regexp)
+  "Display all the hidden articles that have HEADERs that match REGEXP."
+  (interactive (list (read-string "Match on header: ")
+                    (read-string "Regexp: ")))
+  (let ((articles (gnus-find-matching-articles header regexp)))
+    (prog1
+       (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
       (gnus-summary-position-point))))
 
 (defun gnus-summary-limit-include-dormant ()
@@ -6135,7 +6875,8 @@ If ALL, mark even excluded ticked and dormants as read."
 (defsubst gnus-cut-thread (thread)
   "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)          
+           (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.
@@ -6165,6 +6906,7 @@ If ALL, mark even excluded ticked and dormants as read."
   "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))
@@ -6182,6 +6924,7 @@ fetch-old-headers verbiage, and so on."
   (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))
@@ -6235,7 +6978,8 @@ fetch-old-headers verbiage, and so on."
                 (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
@@ -6386,11 +7130,9 @@ of what's specified by the `gnus-refer-thread-limit' variable."
       (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.
@@ -6404,7 +7146,8 @@ or `gnus-select-method', no matter what backend the article comes from."
                        (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
@@ -6417,28 +7160,49 @@ or `gnus-select-method', no matter what backend the article comes from."
          (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 (and (symbolp (car gnus-refer-article-method))
+             (assq (car gnus-refer-article-method) nnoo-definition-alist)))
+    (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
@@ -6460,8 +7224,17 @@ to guess what the document format is."
                           (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
+                                   (funcall gnus-decode-encoded-word-function
+                                            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
@@ -6470,14 +7243,17 @@ to guess what the document format is."
         (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.
@@ -6561,10 +7337,14 @@ If BACKWARD, search backward instead."
         current-prefix-arg))
   (if (string-equal regexp "")
       (setq regexp (or gnus-last-search-regexp ""))
-    (setq gnus-last-search-regexp regexp))
-  (if (gnus-summary-search-article regexp backward)
-      (gnus-summary-show-thread)
-    (error "Search failed: \"%s\"" regexp)))
+    (setq gnus-last-search-regexp regexp)
+    (setq gnus-article-before-search gnus-current-article))
+  ;; Intentionally set gnus-last-article.
+  (setq gnus-last-article gnus-article-before-search)
+  (let ((gnus-last-article gnus-last-article))
+    (if (gnus-summary-search-article regexp backward)
+       (gnus-summary-show-thread)
+      (error "Search failed: \"%s\"" regexp))))
 
 (defun gnus-summary-search-article-backward (regexp)
   "Search for an article containing REGEXP backward."
@@ -6583,18 +7363,21 @@ Optional argument BACKWARD means do search for backward.
   ;; 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-display-mime-function)
+       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)
@@ -6610,6 +7393,9 @@ Optional argument BACKWARD means do search for backward.
               (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.
@@ -6637,6 +7423,18 @@ Optional argument BACKWARD means do search for backward.
       (gnus-summary-position-point)
       t)))
 
+(defun gnus-find-matching-articles (header regexp)
+  "Return a list of all articles that match REGEXP on HEADER.
+This search includes all articles in the current group that Gnus has
+fetched headers for, whether they are displayed or not."
+  (let ((articles nil)
+       (func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
+       (case-fold-search t))
+    (dolist (header gnus-newsgroup-headers)
+      (when (string-match regexp (funcall func header))
+       (push (mail-header-number header) articles)))
+    (nreverse articles)))
+
 (defun gnus-summary-find-matching (header regexp &optional backward unread
                                          not-case-fold)
   "Return a list of all articles that match REGEXP on HEADER.
@@ -6645,22 +7443,29 @@ BACKWARD is non-nil.  If BACKWARD is `all', do all articles.
 If UNREAD is non-nil, only unread articles will
 be taken into consideration.  If NOT-CASE-FOLD, case won't be folded
 in the comparisons."
-  (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))
-    (while data
-      (setq d (car data))
-      (and (or (not unread)            ; We want all articles...
-              (gnus-data-unread-p d))  ; Or just unreads.
-          (vectorp (gnus-data-header d)) ; It's not a pseudo.
-          (string-match regexp (funcall func (gnus-data-header d))) ; Match.
-          (push (gnus-data-number d) articles)) ; Success!
-      (setq data (cdr data)))
+  (let ((case-fold-search (not not-case-fold))
+       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))))
+    (dolist (d (if (eq backward 'all)
+                  gnus-newsgroup-data
+                (gnus-data-find-list
+                 (gnus-summary-article-number)
+                 (gnus-data-list backward))))
+      (when (and (or (not unread)      ; We want all articles...
+                    (gnus-data-unread-p d)) ; Or just unreads.
+                (vectorp (gnus-data-header d)) ; It's not a pseudo.
+                (string-match regexp
+                              (funcall func (gnus-data-header d)))) ; Match.
+       (push (gnus-data-number d) articles))) ; Success!
     (nreverse articles)))
 
 (defun gnus-summary-execute-command (header regexp command &optional backward)
@@ -6721,12 +7526,11 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
 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."
-  (interactive (list (ps-print-preprint current-prefix-arg)
-                    current-prefix-arg))
+  (interactive (list (ps-print-preprint current-prefix-arg)))
   (dolist (article (gnus-summary-work-articles n))
     (gnus-summary-select-article nil nil 'pseudo article)
     (gnus-eval-in-buffer-window gnus-article-buffer
@@ -6736,39 +7540,89 @@ to save in."
              (copy-to-buffer buffer (point-min) (point-max))
              (set-buffer buffer)
              (gnus-article-delete-invisible-text)
+             (when (gnus-visual-p 'article-highlight 'highlight)
+               ;; Copy-to-buffer doesn't copy overlay.  So redo
+               ;; highlight.
+               (let ((gnus-article-buffer buffer))
+                 (gnus-article-highlight-citation t)
+                 (gnus-article-highlight-signature)))
              (let ((ps-left-header
-                    (list 
+                    (list
                      (concat "("
                              (mail-header-subject gnus-current-headers) ")")
                      (concat "("
                              (mail-header-from gnus-current-headers) ")")))
-                   (ps-right-header 
-                    (list 
-                     "/pagenumberstring load" 
+                   (ps-right-header
+                    (list
+                     "/pagenumberstring load"
                      (concat "("
                              (mail-header-date gnus-current-headers) ")"))))
                (gnus-run-hooks 'gnus-ps-print-hook)
                (save-excursion
-                 (ps-print-buffer-with-faces filename))))
-         (kill-buffer buffer))))))
+                 (if window-system
+                     (ps-spool-buffer-with-faces)
+                   (ps-spool-buffer)))))
+         (kill-buffer buffer))))
+    (gnus-summary-remove-process-mark article))
+  (ps-despool filename))
 
 (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.
+  (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)
+      (let ((deps gnus-newsgroup-dependencies)
+           head header)
+       (save-excursion
+         (set-buffer gnus-original-article-buffer)
+         (save-restriction
+           (message-narrow-to-head)
+           (setq head (buffer-string)))
+         (with-temp-buffer
+           (insert (format "211 %d Article retrieved.\n"
+                           (cdr gnus-article-current)))
+           (insert head)
+           (insert ".\n")
+           (let ((nntp-server-buffer (current-buffer)))
+             (setq header (car (gnus-get-newsgroup-headers deps t))))))
+       (gnus-data-set-header
+        (gnus-data-find (cdr gnus-article-current))
+        header)
+       (gnus-summary-update-article-line
+        (cdr gnus-article-current) header))))
+   ((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-article-decode-hook
          gnus-display-mime-function
-         gnus-break-pages
-         gnus-visual)
-      (gnus-summary-select-article nil 'force)))
+         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))
 
@@ -6792,30 +7646,41 @@ If ARG is a negative number, hide the unwanted header lines."
   (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))
+  (gnus-summary-toggle-header 1))
 
 (defun gnus-summary-caesar-message (&optional arg)
   "Caesar rotate the current article by 13.
@@ -6857,7 +7722,9 @@ re-spool using this method.
 
 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))
@@ -6875,7 +7742,10 @@ and `request-accept' functions."
                    '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")))
@@ -6894,7 +7764,8 @@ and `request-accept' functions."
             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))
@@ -6920,7 +7791,7 @@ and `request-accept' functions."
                  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)
@@ -6928,7 +7799,7 @@ and `request-accept' functions."
           (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
@@ -6961,19 +7832,21 @@ and `request-accept' functions."
               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)))
@@ -6981,49 +7854,54 @@ and `request-accept' functions."
              (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 '"
@@ -7042,7 +7920,7 @@ and `request-accept' functions."
 
        ;;;!!!Why is this necessary?
        (set-buffer gnus-summary-buffer)
-       
+
        (gnus-summary-goto-subject article)
        (when (eq action 'move)
          (gnus-summary-mark-article article gnus-canceled-mark))))
@@ -7075,7 +7953,7 @@ re-spool using this method."
 (defcustom gnus-summary-respool-default-method nil
   "Default method for respooling an article.
 If nil, use to the current newsgroup method."
-  :type `(choice (gnus-select-method :value (nnml ""))
+  :type '(choice (gnus-select-method :value (nnml ""))
                 (const nil))
   :group 'gnus-summary-mail)
 
@@ -7123,12 +8001,12 @@ latter case, they will be copied into the relevant groups."
       (gnus-summary-move-article n nil method)
     (gnus-summary-copy-article n nil method)))
 
-(defun gnus-summary-import-article (file)
+(defun gnus-summary-import-article (file &optional edit)
   "Import an arbitrary file into a mail newsgroup."
-  (interactive "fImport file: ")
+  (interactive "fImport file: \nP")
   (let ((group gnus-newsgroup-name)
        (now (current-time))
-       atts lines)
+       atts lines group-art)
     (unless (gnus-check-backend-function 'request-accept-article group)
       (error "%s does not support article importing" group))
     (or (file-readable-p file)
@@ -7136,9 +8014,8 @@ latter case, they will be copied into the relevant groups."
        (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.
@@ -7146,21 +8023,48 @@ latter case, they will be copied into the relevant groups."
              lines (count-lines (point-min) (point-max)))
        (insert "From: " (read-string "From: ") "\n"
                "Subject: " (read-string "Subject: ") "\n"
-               "Date: " (message-make-date (nth 5 atts))
-               "\n"
+               "Date: " (message-make-date (nth 5 atts)) "\n"
                "Message-ID: " (message-make-message-id) "\n"
                "Lines: " (int-to-string lines) "\n"
                "Chars: " (int-to-string (nth 7 atts)) "\n\n"))
-      (gnus-request-accept-article group nil t)
-      (kill-buffer (current-buffer)))))
+      (setq group-art (gnus-request-accept-article group nil t))
+      (kill-buffer (current-buffer)))
+    (setq gnus-newsgroup-active (gnus-activate-group group))
+    (forward-line 1)
+    (gnus-summary-goto-article (cdr group-art) nil t)
+    (when edit
+      (gnus-summary-edit-article))))
+
+(defun gnus-summary-create-article ()
+  "Create an article in a mail newsgroup."
+  (interactive)
+  (let ((group gnus-newsgroup-name)
+       (now (current-time))
+       group-art)
+    (unless (gnus-check-backend-function 'request-accept-article group)
+      (error "%s does not support article importing" group))
+    (save-excursion
+      (set-buffer (gnus-get-buffer-create " *import file*"))
+      (erase-buffer)
+      (goto-char (point-min))
+      ;; This doesn't look like an article, so we fudge some headers.
+      (insert "From: " (read-string "From: ") "\n"
+             "Subject: " (read-string "Subject: ") "\n"
+             "Date: " (message-make-date now) "\n"
+             "Message-ID: " (message-make-message-id) "\n")
+      (setq group-art (gnus-request-accept-article group nil t))
+      (kill-buffer (current-buffer)))
+    (setq gnus-newsgroup-active (gnus-activate-group group))
+    (forward-line 1)
+    (gnus-summary-goto-article (cdr group-art) nil t)
+    (gnus-summary-edit-article)))
 
 (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)
@@ -7188,11 +8092,16 @@ This will be the case if the article has both been mailed and posted."
           (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
@@ -7201,19 +8110,19 @@ This will be the case if the article has both been mailed and posted."
                (setq es (gnus-request-expire-articles
                          expirable gnus-newsgroup-name)))
            (setq es (gnus-request-expire-articles
-                     expirable gnus-newsgroup-name))))
-       (unless total
-         (setq gnus-newsgroup-expirable es))
-       ;; We go through the old list of expirable, and mark all
-       ;; really expired articles as nonexistent.
-       (unless (eq es expirable)       ;If nothing was expired, we don't mark.
-         (let ((gnus-use-cache nil))
-           (while expirable
-             (unless (memq (car expirable) es)
-               (when (gnus-data-find (car expirable))
-                 (gnus-summary-mark-article
-                  (car expirable) gnus-canceled-mark)))
-             (setq expirable (cdr expirable)))))
+                     expirable gnus-newsgroup-name)))
+         (unless total
+           (setq gnus-newsgroup-expirable es))
+         ;; We go through the old list of expirable, and mark all
+         ;; really expired articles as nonexistent.
+         (unless (eq es expirable)     ;If nothing was expired, we don't mark.
+           (let ((gnus-use-cache nil))
+             (while expirable
+               (unless (memq (car expirable) es)
+                 (when (gnus-data-find (car expirable))
+                   (gnus-summary-mark-article
+                    (car expirable) gnus-canceled-mark)))
+               (setq expirable (cdr expirable))))))
        (gnus-message 6 "Expiring articles...done")))))
 
 (defun gnus-summary-expire-articles-now ()
@@ -7240,6 +8149,8 @@ delete these instead."
   (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)
@@ -7266,28 +8177,72 @@ delete these instead."
     (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.
+If ARG is 3, edit the articles with the current handles.
+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 current-handles)
+    (cond
+     ((null arg))
+     ((eq arg 1) (setq raw t))
+     ((eq arg 2) (setq raw t
+                      force t))
+     ((eq arg 3) (setq current-handles
+                      (and (gnus-buffer-live-p gnus-article-buffer)
+                           (with-current-buffer gnus-article-buffer
+                             (prog1
+                                 gnus-article-mime-handles
+                                 (setq gnus-article-mime-handles nil))))))
+     (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-mule4)))
+       (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 ,'current-handles)
+               (make-local-hook 'kill-buffer-hook)
+               (let ((mbl1 mml-buffer-list))
+                 (setq mml-buffer-list mbl)
+                 (set (make-local-variable 'mml-buffer-list) mbl1))
+               (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))))
+        `(lambda (no-highlight)
+           (let ((mail-parse-charset ',gnus-newsgroup-charset)
+                 (message-options message-options)
+                 (message-options-set-recipient)
+                 (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)
 
@@ -7295,14 +8250,35 @@ groups."
                                                 no-highlight)
   "Make edits to the current article permanent."
   (interactive)
+  (save-excursion
+    ;; The buffer restriction contains the entire article if it exists.
+    (when (article-goto-body)
+      (let ((lines (count-lines (point) (point-max)))
+           (length (- (point-max) (point)))
+           (case-fold-search t)
+           (body (copy-marker (point))))
+       (goto-char (point-min))
+       (when (re-search-forward "^content-length:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string length)))
+       (goto-char (point-min))
+       (when (re-search-forward
+              "^x-content-length:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string length)))
+       (goto-char (point-min))
+       (when (re-search-forward "^lines:[ \t]\\([0-9]+\\)" body t)
+         (delete-region (match-beginning 1) (match-end 1))
+         (insert (number-to-string lines))))))
   ;; Replace the article.
   (let ((buf (current-buffer)))
     (with-temp-buffer
-      (insert-buffer buf)
+      (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
@@ -7340,7 +8316,8 @@ groups."
        (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)
@@ -7460,28 +8437,31 @@ If optional argument UNMARK is negative, mark articles as unread instead."
 If N is negative, mark backward instead.  If UNMARK is non-nil, remove
 the process mark instead.  The difference between N and the actual
 number of articles marked is returned."
-  (interactive "p")
-  (let ((backward (< n 0))
-       (n (abs n)))
-    (while (and
-           (> n 0)
-           (if unmark
+  (interactive "P")
+  (if (and (null n) (gnus-region-active-p))
+      (gnus-uu-mark-region (region-beginning) (region-end) unmark)
+    (setq n (prefix-numeric-value n))
+    (let ((backward (< n 0))
+         (n (abs n)))
+      (while (and
+             (> n 0)
+             (if unmark
                (gnus-summary-remove-process-mark
                 (gnus-summary-article-number))
-             (gnus-summary-set-process-mark (gnus-summary-article-number)))
-           (zerop (gnus-summary-next-subject (if backward -1 1) nil t)))
-      (setq n (1- n)))
-    (when (/= 0 n)
-      (gnus-message 7 "No more articles"))
-    (gnus-summary-recenter)
-    (gnus-summary-position-point)
-    n))
+               (gnus-summary-set-process-mark (gnus-summary-article-number)))
+             (zerop (gnus-summary-next-subject (if backward -1 1) nil t)))
+       (setq n (1- n)))
+      (when (/= 0 n)
+       (gnus-message 7 "No more articles"))
+      (gnus-summary-recenter)
+      (gnus-summary-position-point)
+      n)))
 
 (defun gnus-summary-unmark-as-processable (n)
   "Remove the process mark from the next N articles.
 If N is negative, unmark backward instead.  The difference between N and
 the actual number of articles unmarked is returned."
-  (interactive "p")
+  (interactive "P")
   (gnus-summary-mark-as-processable n t))
 
 (defun gnus-summary-unmark-all-processable ()
@@ -7492,6 +8472,20 @@ the actual number of articles unmarked is returned."
       (gnus-summary-remove-process-mark (car gnus-newsgroup-processable))))
   (gnus-summary-position-point))
 
+(defun gnus-summary-add-mark (article type)
+  "Mark ARTICLE with a mark of TYPE."
+  (let ((vtype (car (assq type gnus-article-mark-lists)))
+       var)
+    (if (not vtype)
+       (error "No such mark type: %s" type)
+      (setq var (intern (format "gnus-newsgroup-%s" type)))
+      (set var (cons article (symbol-value var)))
+      (if (memq type '(processable cached replied forwarded saved))
+         (gnus-summary-update-secondary-mark article)
+       ;;; !!! This is bobus.  We should find out what primary
+       ;;; !!! mark we want to set.
+       (gnus-summary-update-mark gnus-del-mark 'unread)))))
+
 (defun gnus-summary-mark-as-expirable (n)
   "Mark N articles forward as expirable.
 If N is negative, mark backward instead.  The difference between N and
@@ -7500,11 +8494,25 @@ the actual number of articles marked is returned."
   (gnus-summary-mark-forward n gnus-expirable-mark))
 
 (defun gnus-summary-mark-article-as-replied (article)
-  "Mark ARTICLE replied and update the summary line."
-  (push article gnus-newsgroup-replied)
-  (let ((buffer-read-only nil))
-    (when (gnus-summary-goto-subject article)
-      (gnus-summary-update-secondary-mark article))))
+  "Mark ARTICLE as replied to and update the summary line.
+ARTICLE can also be a list of articles."
+  (interactive (list (gnus-summary-article-number)))
+  (let ((articles (if (listp article) article (list article))))
+    (dolist (article articles)
+      (push article gnus-newsgroup-replied)
+      (let ((buffer-read-only nil))
+       (when (gnus-summary-goto-subject article nil t)
+         (gnus-summary-update-secondary-mark article))))))
+
+(defun gnus-summary-mark-article-as-forwarded (article)
+  "Mark ARTICLE as forwarded and update the summary line.
+ARTICLE can also be a list of articles."
+  (let ((articles (if (listp article) article (list article))))
+    (dolist (article articles)
+      (push article gnus-newsgroup-forwarded)
+      (let ((buffer-read-only nil))
+       (when (gnus-summary-goto-subject article nil t)
+         (gnus-summary-update-secondary-mark article))))))
 
 (defun gnus-summary-set-bookmark (article)
   "Set a bookmark in current article."
@@ -7583,8 +8591,10 @@ the actual number of articles marked is returned."
   "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
@@ -7622,11 +8632,7 @@ returned."
     (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))
@@ -7665,7 +8671,6 @@ returned."
             (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))))
 
@@ -7677,25 +8682,22 @@ returned."
   "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)
@@ -7715,7 +8717,6 @@ marked."
             (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))))
 
@@ -7735,9 +8736,11 @@ marked."
          gnus-cached-mark)
         ((memq article gnus-newsgroup-replied)
          gnus-replied-mark)
+        ((memq article gnus-newsgroup-forwarded)
+         gnus-forwarded-mark)
         ((memq article gnus-newsgroup-saved)
          gnus-saved-mark)
-        (t gnus-unread-mark))
+        (t gnus-no-mark))
    'replied)
   (when (gnus-visual-p 'summary-highlight 'highlight)
     (gnus-run-hooks 'gnus-summary-update-hook))
@@ -7747,19 +8750,19 @@ marked."
   (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."
@@ -7840,14 +8843,15 @@ If N is negative, mark backwards instead.
 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.
@@ -7880,6 +8884,11 @@ The difference between N and the number of marks cleared is returned."
              (gnus-read-mark-p mark))
       (gnus-summary-mark-article gnus-current-article gnus-read-mark))))
 
+(defun gnus-summary-mark-unread-as-ticked ()
+   "Intended to be used by `gnus-summary-mark-article-hook'."
+  (when (memq gnus-current-article gnus-newsgroup-unreads)
+    (gnus-summary-mark-article gnus-current-article gnus-ticked-mark)))
+
 (defun gnus-summary-mark-region-as-read (point mark all)
   "Mark all unread articles between point and mark as read.
 If given a prefix, mark all articles between point and mark as read,
@@ -7953,8 +8962,8 @@ even ticked and dormant ones."
     (let ((scored gnus-newsgroup-scored)
          headers h)
       (while scored
-       (unless (gnus-summary-goto-subject (caar scored))
-         (and (setq h (gnus-summary-article-header (caar scored)))
+       (unless (gnus-summary-article-header (caar scored))
+         (and (setq h (gnus-number-to-header (caar scored)))
               (< (cdar scored) gnus-summary-expunge-below)
               (push h headers)))
        (setq scored (cdr scored)))
@@ -7962,6 +8971,11 @@ even ticked and dormant ones."
          (when (not no-error)
            (error "No expunged articles hidden"))
        (goto-char (point-min))
+       (push gnus-newsgroup-limit gnus-newsgroup-limits)
+       (setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
+       (mapcar (lambda (x) (push (mail-header-number x) 
+                                 gnus-newsgroup-limit))
+               headers)
        (gnus-summary-prepare-unthreaded (nreverse headers))
        (goto-char (point-min))
        (gnus-summary-position-point)
@@ -8028,8 +9042,9 @@ If ALL is non-nil, also mark ticked and dormant articles as read."
   (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.
-If prefix argument ALL is non-nil, all articles are marked as read."
+  "Mark all unread articles in this group as read, then exit.
+If prefix argument ALL is non-nil, all articles are marked as read.
+If QUIETLY is non-nil, no questions will be asked."
   (interactive "P")
   (when (gnus-summary-catchup all quietly nil 'fast)
     ;; Select next newsgroup or exit.
@@ -8043,7 +9058,6 @@ If prefix argument ALL is non-nil, all articles are marked as read."
   (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
@@ -8051,7 +9065,38 @@ read."
   (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.
 
@@ -8130,25 +9175,17 @@ is non-nil or the Subject: of both articles are the same."
                         (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))))
-         (with-temp-buffer
-           (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)
@@ -8223,9 +9260,7 @@ Returns nil if no threads were there to be hidden."
                (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.
@@ -8304,7 +9339,7 @@ taken."
 
 (defun gnus-summary-up-thread (n)
   "Go up thread N steps.
-If N is negative, go up instead.
+If N is negative, go down instead.
 Returns the difference between N and how many steps down that were
 taken."
   (interactive "p")
@@ -8357,14 +9392,14 @@ Argument REVERSE means reverse order."
 
 (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))
@@ -8382,27 +9417,45 @@ Argument REVERSE means reverse order."
   (gnus-summary-sort 'score reverse))
 
 (defun gnus-summary-sort-by-lines (&optional reverse)
-  "Sort the summary buffer by article length.
+  "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 'chars reverse))
+
+(defun gnus-summary-sort-by-original (&optional reverse)
+  "Sort the summary buffer using the default sorting method.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (let* ((buffer-read-only)
+        (gnus-summary-prepare-hook nil))
+    ;; We do the sorting by regenerating the threads.
+    (gnus-summary-prepare)
+    ;; Hide subthreads if needed.
+    (when (and gnus-show-threads gnus-thread-hide-subtree)
+      (gnus-summary-hide-all-threads))))
+
 (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.
@@ -8425,10 +9478,9 @@ The variable `gnus-default-article-saver' specifies the saver function."
         (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)
@@ -8457,6 +9509,7 @@ If N is a negative number, pipe the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 pipe those articles instead."
   (interactive "P")
+  (require 'gnus-art)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-pipe))
     (gnus-summary-save-article arg t))
   (gnus-configure-windows 'pipe))
@@ -8468,6 +9521,7 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (require 'gnus-art)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-mail))
     (gnus-summary-save-article arg)))
 
@@ -8478,7 +9532,8 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
-  (let ((gnus-default-article-saver 'rmail-output-to-rmail-file))
+  (require 'gnus-art)
+  (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
     (gnus-summary-save-article arg)))
 
 (defun gnus-summary-save-article-file (&optional arg)
@@ -8488,6 +9543,7 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (require 'gnus-art)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-file))
     (gnus-summary-save-article arg)))
 
@@ -8498,6 +9554,7 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (require 'gnus-art)
   (let ((gnus-default-article-saver 'gnus-summary-write-to-file))
     (gnus-summary-save-article arg)))
 
@@ -8508,6 +9565,7 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (require 'gnus-art)
   (let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
     (gnus-summary-save-article arg)))
 
@@ -8532,7 +9590,7 @@ save those articles instead."
        (set-buffer gnus-original-article-buffer)
        (save-restriction
          (nnheader-narrow-to-headers)
-         (while methods
+         (while (and methods (not split-name))
            (goto-char (point-min))
            (setq method (pop methods))
            (setq match (car method))
@@ -8551,23 +9609,21 @@ save those articles instead."
                    (save-restriction
                      (widen)
                      (setq result (eval match)))))
-             (setq split-name (append (cdr method) split-name))
+             (setq split-name (cdr method))
              (cond ((stringp result)
                     (push (expand-file-name
                            result gnus-article-save-directory)
                           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."
@@ -8598,7 +9654,8 @@ save those articles instead."
                                  (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))
@@ -8606,18 +9663,62 @@ save those articles instead."
       (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: "
+                     (or (car gnus-summary-save-parts-type-history)
+                         gnus-summary-save-parts-default-mime)
+                     'gnus-summary-save-parts-type-history)
+        (setq gnus-summary-save-parts-last-directory
+              (read-file-name "Save to directory: "
+                              gnus-summary-save-parts-last-directory
+                              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)
@@ -8653,7 +9754,7 @@ save those articles instead."
                                (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))
@@ -8730,8 +9831,10 @@ save those articles instead."
   "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.
@@ -8805,8 +9908,8 @@ save those articles instead."
 ;;;
 
 (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)))
@@ -8897,44 +10000,62 @@ save those articles instead."
        (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))))
 
 (defun gnus-offer-save-summaries ()
   "Offer to save all active summary buffers."
-  (save-excursion
-    (let ((buflist (buffer-list))
-         buffers bufname)
-      ;; Go through all buffers and find all summaries.
-      (while buflist
-       (and (setq bufname (buffer-name (car buflist)))
-            (string-match "Summary" bufname)
-            (save-excursion
-              (set-buffer bufname)
-              ;; We check that this is, indeed, a summary buffer.
-              (and (eq major-mode 'gnus-summary-mode)
-                   ;; Also make sure this isn't bogus.
-                   gnus-newsgroup-prepared
-                   ;; Also make sure that this isn't a dead summary buffer.
-                   (not gnus-dead-summary-mode)))
-            (push bufname buffers))
-       (setq buflist (cdr buflist)))
-      ;; Go through all these summary buffers and offer to save them.
-      (when buffers
+  (let (buffers)
+    ;; Go through all buffers and find all summaries.
+    (dolist (buffer (buffer-list))
+      (when (and (setq buffer (buffer-name buffer))
+                (string-match "Summary" buffer)
+                (save-excursion
+                  (set-buffer buffer)
+                  ;; We check that this is, indeed, a summary buffer.
+                  (and (eq major-mode 'gnus-summary-mode)
+                       ;; Also make sure this isn't bogus.
+                       gnus-newsgroup-prepared
+                       ;; Also make sure that this isn't a
+                       ;; dead summary buffer.
+                       (not gnus-dead-summary-mode))))
+       (push buffer buffers)))
+    ;; Go through all these summary buffers and offer to save them.
+    (when buffers
+      (save-excursion
        (map-y-or-n-p
         "Update summary buffer %s? "
         (lambda (buf)
@@ -8942,6 +10063,244 @@ save those articles instead."
           (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* ((ignored-charsets
+           (or gnus-newsgroup-ephemeral-ignored-charsets
+               (append
+                (and gnus-newsgroup-name
+                     (gnus-parameter-ignored-charsets gnus-newsgroup-name))
+                gnus-newsgroup-ignored-charsets))))
+      (setq gnus-newsgroup-charset
+           (or gnus-newsgroup-ephemeral-charset
+               (and gnus-newsgroup-name
+                    (gnus-parameter-charset gnus-newsgroup-name))
+               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)
+    (message-remove-header "Mime-Version")
+    (goto-char (point-max))
+    (insert "Mime-Version: 1.0\n")
+    (widen)
+    (when (search-forward "\n--" nil t)
+      (let ((separator (buffer-substring (point) (gnus-point-at-eol))))
+       (message-narrow-to-head)
+       (message-remove-header "Content-Type")
+       (goto-char (point-max))
+       (insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
+                       separator))
+       (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))
+
+(defun gnus-summary-insert-articles (articles)
+  (when (setq articles
+             (gnus-set-difference articles
+                                  (mapcar (lambda (h) (mail-header-number h))
+                                          gnus-newsgroup-headers)))
+    (setq gnus-newsgroup-headers 
+         (merge 'list
+                gnus-newsgroup-headers
+                (gnus-fetch-headers articles)
+                'gnus-article-sort-by-number))
+    ;; Suppress duplicates?
+    (when gnus-suppress-duplicates
+      (gnus-dup-suppress-articles))
+    
+    ;; We might want to build some more threads first.
+    (when (and gnus-fetch-old-headers
+              (eq gnus-headers-retrieved-by 'nov))
+      (if (eq gnus-fetch-old-headers 'invisible)
+       (gnus-build-all-threads)
+       (gnus-build-old-threads)))
+    ;; 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))
+    ;; First and last article in this newsgroup.
+    (when gnus-newsgroup-headers
+      (setq gnus-newsgroup-begin
+           (mail-header-number (car gnus-newsgroup-headers))
+           gnus-newsgroup-end
+           (mail-header-number
+            (gnus-last-element gnus-newsgroup-headers))))
+    (when gnus-use-scoring
+      (gnus-possibly-score-headers))))
+
+(defun gnus-summary-insert-old-articles (&optional all)
+  "Insert all old articles in this group.
+If ALL is non-nil, already read articles become readable.
+If ALL is a number, fetch this number of articles."
+  (interactive "P")
+  (prog1
+      (let ((old (mapcar 'car gnus-newsgroup-data))
+           (i (car gnus-newsgroup-active))
+           older len)
+       (while (<= i (cdr gnus-newsgroup-active))
+         (or (memq i old) (push i older))
+         (incf i))
+       (setq len (length older))
+       (cond 
+        ((null older) nil)
+        ((numberp all) 
+         (if (< all len)
+             (setq older (subseq older 0 all))))
+        (all nil)
+        (t
+         (if (and (numberp gnus-large-newsgroup)
+                  (> len gnus-large-newsgroup))
+             (let ((input
+                    (read-string
+                     (format
+                      "How many articles from %s (default %d): "
+                      (gnus-limit-string 
+                       (gnus-group-decoded-name gnus-newsgroup-name) 35)
+                      len))))
+               (unless (string-match "^[ \t]*$" input) 
+                 (setq all (string-to-number input))
+                 (if (< all len)
+                     (setq older (subseq older 0 all))))))))
+       (if (not older)
+           (message "No old news.")
+         (gnus-summary-insert-articles older)
+         (gnus-summary-limit (gnus-union older old))))
+    (gnus-summary-position-point)))
+
+(defun gnus-summary-insert-new-articles ()
+  "Insert all new articles in this group."
+  (interactive)
+  (prog1
+      (let ((old (mapcar 'car gnus-newsgroup-data))
+           (old-active gnus-newsgroup-active)
+           (nnmail-fetched-sources (list t))
+           i new)
+       (setq gnus-newsgroup-active 
+             (gnus-activate-group gnus-newsgroup-name 'scan))
+       (setq i (1+ (cdr old-active)))
+       (while (<= i (cdr gnus-newsgroup-active))
+         (push i new)
+         (incf i))
+       (if (not new)
+           (message "No gnus is bad news.")
+         (setq new (nreverse new))
+         (gnus-summary-insert-articles new)
+         (setq gnus-newsgroup-unreads
+               (append gnus-newsgroup-unreads new))
+         (gnus-summary-limit (gnus-union old new))))
+    (gnus-summary-position-point)))
+
+(gnus-summary-make-all-marking-commands)
+
 (gnus-ems-redefine)
 
 (provide 'gnus-sum)