Revision: miles@gnu.org--gnu-2005/gnus--devo--0--patch-37
[gnus] / lisp / gnus-sum.el
index 850dc13..5de6067 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -44,6 +44,7 @@
 (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 'gnus-pick-line-number "gnus-salt" nil t)
 (autoload 'mm-uu-dissect "mm-uu")
 (autoload 'gnus-article-outlook-deuglify-article "deuglify"
   "Deuglify broken Outlook (Express) articles and redisplay."
@@ -63,7 +64,7 @@ it will be killed sometime later."
   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
 If an unread article in the group refers to an older, already read (or
 just marked as read) article, the old article will not normally be
-displayed in the Summary buffer.  If this variable is non-nil, Gnus
+displayed in the Summary buffer.  If this variable is t, Gnus
 will attempt to grab the headers to the old articles, and thereby
 build complete threads.  If it has the value `some', only enough
 headers to connect otherwise loose threads will be displayed.  This
@@ -74,7 +75,9 @@ old headers will be fetched, but none will be displayed.
 The server has to support NOV for any of this to work."
   :group 'gnus-thread
   :type '(choice (const :tag "off" nil)
+                (const :tag "on" t)
                 (const some)
+                (const invisible)
                 number
                 (sexp :menu-tag "other" t)))
 
@@ -116,6 +119,7 @@ given by the `gnus-summary-same-subject' variable.)"
 
 (defcustom gnus-summary-make-false-root-always nil
   "Always make a false dummy root."
+  :version "22.1"
   :group 'gnus-thread
   :type 'boolean)
 
@@ -216,6 +220,7 @@ If this variable is nil, scoring will be disabled."
   "*Default threshold for a high scored article.
 An article will be highlighted as high scored if its score is greater
 than this score."
+  :version "22.1"
   :group 'gnus-score-default
   :type 'integer)
 
@@ -223,6 +228,7 @@ than this score."
   "*Default threshold for a low scored article.
 An article will be highlighted as low scored if its score is smaller
 than this score."
+  :version "22.1"
   :group 'gnus-score-default
   :type 'integer)
 
@@ -258,7 +264,7 @@ to expose hidden threads."
                               (not (or (consp value) (functionp value))))
                      :value t)
                (const nil)
-               (sexp :tag "Predicate specifier" :size 0)))
+               (sexp :tag "Predicate specifier")))
 
 (defcustom gnus-thread-hide-killed t
   "*If non-nil, hide killed threads automatically."
@@ -318,6 +324,7 @@ the first unseen article), 'unseen-or-unread' (place point on the subject
 line of the first unseen article or, if all article have been seen, on the
 subject line of the first unread article), or a function to be called to
 place point on some subject line."
+  :version "22.1"
   :group 'gnus-group-select
   :type '(choice (const best)
                 (const unread)
@@ -361,6 +368,7 @@ ignores articles whose headers have not been fetched).
 
 NOTE: The list of unfetched articles will always be nil when plugged
 and, when unplugged, a subset of the undownloaded article list."
+  :version "22.1"
   :group 'gnus-summary-maneuvering
   :type '(choice (const :tag "None" nil)
                  (const :tag "Undownloaded when unplugged" undownloaded)
@@ -374,7 +382,7 @@ current article is unread."
   :group 'gnus-summary-maneuvering
   :type 'boolean)
 
-(defcustom gnus-auto-center-summary t
+(defcustom gnus-auto-center-summary 2
   "*If non-nil, always center the current summary buffer.
 In particular, if `vertical' do only vertical recentering.  If non-nil
 and non-`vertical', do both horizontal and vertical recentering."
@@ -421,6 +429,16 @@ this variable specifies group names."
                         (cons :value ("" "") regexp (repeat string))
                         (sexp :value nil))))
 
+(defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
+  "Function used to compute default prefix for article move/copy/etc prompts.
+The function should take one argument, a group name, and return a
+string with the suggested prefix."
+  :group 'gnus-summary-mail
+  :type 'function)
+
+;; FIXME: Although the custom type is `character' for the following variables,
+;; using multibyte characters (Latin-1, UTF-8) doesn't work.  -- rs
+
 (defcustom gnus-unread-mark ?           ;Whitespace
   "*Mark used for unread articles."
   :group 'gnus-summary-marks
@@ -458,6 +476,7 @@ this variable specifies group names."
 
 (defcustom gnus-spam-mark ?$
   "*Mark used for spam articles."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -488,11 +507,13 @@ this variable specifies group names."
 
 (defcustom gnus-forwarded-mark ?F
   "*Mark used for articles that have been forwarded."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
 (defcustom gnus-recent-mark ?N
   "*Mark used for articles that are recent."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -508,11 +529,13 @@ this variable specifies group names."
 
 (defcustom gnus-unseen-mark ?.
   "*Mark used for articles that haven't been seen."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
 (defcustom gnus-no-mark ?               ;Whitespace
   "*Mark used for articles that have no other secondary mark."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -538,6 +561,7 @@ this variable specifies group names."
 
 (defcustom gnus-undownloaded-mark ?-
   "*Mark used for articles that weren't downloaded."
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -671,6 +695,40 @@ score file."
   :group 'gnus-score-default
   :type 'integer)
 
+(defun gnus-widget-reversible-match (widget value)
+  "Ignoring WIDGET, convert VALUE to internal form.
+VALUE should have the form `FOO' or `(not FOO)', where FOO is an symbol."
+  ;; (debug value)
+  (or (symbolp value)
+      (and (listp value)
+           (eq (length value) 2)
+           (eq (nth 0 value) 'not)
+           (symbolp (nth 1 value)))))
+
+(defun gnus-widget-reversible-to-internal (widget value)
+  "Ignoring WIDGET, convert VALUE to internal form.
+VALUE should have the form `FOO' or `(not FOO)', where FOO is an atom.
+FOO is converted to (FOO nil) and (not FOO) is converted to (FOO t)."
+  ;; (debug value)
+  (if (atom value)
+      (list value nil)
+    (list (nth 1 value) t)))
+
+(defun gnus-widget-reversible-to-external (widget value)
+  "Ignoring WIDGET, convert VALUE to external form.
+VALUE should have the form `(FOO nil)' or `(FOO t)', where FOO is an atom.
+\(FOO  nil) is converted to FOO and (FOO t) is converted to (not FOO)."
+  ;; (debug value)
+  (if (nth 1 value)
+      (list 'not (nth 0 value))
+    (nth 0 value)))
+
+(define-widget 'gnus-widget-reversible 'group
+  "A `group' that convert values."
+  :match 'gnus-widget-reversible-match
+  :value-to-internal 'gnus-widget-reversible-to-internal
+  :value-to-external 'gnus-widget-reversible-to-external)
+
 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
   "*List of functions used for sorting articles in the summary buffer.
 
@@ -683,6 +741,9 @@ 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.)
 
+Each item can also be a list `(not F)' where F is a function;
+this reverses the sort order.
+
 Ready-made functions include `gnus-article-sort-by-number',
 `gnus-article-sort-by-author', `gnus-article-sort-by-subject',
 `gnus-article-sort-by-date', `gnus-article-sort-by-random'
@@ -691,13 +752,16 @@ 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)
-                        (function-item gnus-article-sort-by-subject)
-                        (function-item gnus-article-sort-by-date)
-                        (function-item gnus-article-sort-by-score)
-                        (function-item gnus-article-sort-by-random)
-                        (function :tag "other"))))
+  :type '(repeat (gnus-widget-reversible
+                  (choice (function-item gnus-article-sort-by-number)
+                          (function-item gnus-article-sort-by-author)
+                          (function-item gnus-article-sort-by-subject)
+                          (function-item gnus-article-sort-by-date)
+                          (function-item gnus-article-sort-by-score)
+                          (function-item gnus-article-sort-by-random)
+                          (function :tag "other"))
+                  (boolean :tag "Reverse order"))))
+
 
 (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
   "*List of functions used for sorting threads in the summary buffer.
@@ -712,6 +776,9 @@ 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.)
 
+Each list item can also be a list `(not F)' where F is a
+function; this specifies reversed sort order.
+
 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',
@@ -723,14 +790,19 @@ Ready-made functions include `gnus-thread-sort-by-number',
 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)
-                        (function-item gnus-thread-sort-by-subject)
-                        (function-item gnus-thread-sort-by-date)
-                        (function-item gnus-thread-sort-by-score)
-                        (function-item gnus-thread-sort-by-total-score)
-                        (function-item gnus-thread-sort-by-random)
-                        (function :tag "other"))))
+  :type '(repeat 
+          (gnus-widget-reversible
+           (choice (function-item gnus-thread-sort-by-number)
+                   (function-item gnus-thread-sort-by-author)
+                   (function-item gnus-thread-sort-by-subject)
+                   (function-item gnus-thread-sort-by-date)
+                   (function-item gnus-thread-sort-by-score)
+                   (function-item gnus-thread-sort-by-most-recent-number)
+                   (function-item gnus-thread-sort-by-most-recent-date)
+                   (function-item gnus-thread-sort-by-random)
+                   (function-item gnus-thread-sort-by-total-score)
+                   (function :tag "other"))
+           (boolean :tag "Reverse order"))))
 
 (defcustom gnus-thread-score-function '+
   "*Function used for calculating the total score of a thread.
@@ -876,16 +948,19 @@ automatically when it is selected."
 
 (defcustom gnus-summary-article-move-hook nil
   "*A hook called after an article is moved, copied, respooled, or crossposted."
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
 (defcustom gnus-summary-article-delete-hook nil
   "*A hook called after an article is deleted."
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
 (defcustom gnus-summary-article-expire-hook nil
   "*A hook called after an article is expired."
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
@@ -893,7 +968,7 @@ automatically when it is selected."
   (and (fboundp 'display-graphic-p)
        (display-graphic-p))
   "*If non-nil, display an arrow highlighting the current article."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-summary
   :type 'boolean)
 
@@ -1071,22 +1146,23 @@ type of files to save."
 This is mostly relevant for slow back ends where the user may
 wish to widen the summary buffer to include all headers
 that were fetched.  Say, for nnultimate groups."
+  :version "22.1"
   :group 'gnus-summary
   :type '(choice boolean regexp))
 
 (defcustom gnus-summary-muttprint-program "muttprint"
   "Command (and optional arguments) used to run Muttprint."
-  :version "21.3"
+  :version "22.1"
   :group 'gnus-summary
   :type 'string)
 
-(defcustom gnus-article-loose-mime nil
+(defcustom gnus-article-loose-mime t
   "If non-nil, don't require MIME-Version header.
 Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
-supply the MIME-Version header or deliberately strip it From the mail.
-Set it to non-nil, Gnus will treat some articles as MIME even if
-the MIME-Version header is missed."
-  :version "21.3"
+supply the MIME-Version header or deliberately strip it from the mail.
+If non-nil (the default), Gnus will treat some articles as MIME
+even if the MIME-Version header is missing."
+  :version "22.1"
   :type 'boolean
   :group 'gnus-article-mime)
 
@@ -1095,6 +1171,7 @@ the MIME-Version header is missed."
 This means that Gnus will search message bodies for text that look
 like uuencoded bits, yEncoded bits, and so on, and present that using
 the normal Gnus MIME machinery."
+  :version "22.1"
   :type 'boolean
   :group 'gnus-article-mime)
 
@@ -1166,7 +1243,6 @@ the normal Gnus MIME machinery."
     (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
     (?i gnus-tmp-score ?d)
     (?z gnus-tmp-score-char ?c)
-    (?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 gnus-tmp-from)
@@ -1379,11 +1455,19 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
 (defvar gnus-newsgroup-variables nil
   "A list of variables that have separate values in different newsgroups.
 A list of newsgroup (summary buffer) local variables, or cons of
-variables and their default values (when the default values are not
-nil), that should be made global while the summary buffer is active.
+variables and their default expressions to be evalled (when the default
+values are not nil), that should be made global while the summary buffer
+is active.
+
+Note: The default expressions will be evaluated (using function `eval')
+before assignment to the local variable rather than just assigned to it.
+If the default expression is the symbol `global', that symbol will not
+be evaluated but the global value of the local variable will be used
+instead.
+
 These variables can be used to set variables in the group parameters
-while still allowing them to affect operations done in other
-buffers. For example:
+while still allowing them to affect operations done in other buffers.
+For example:
 
 \(setq gnus-newsgroup-variables
      '(message-use-followup-to
@@ -1405,7 +1489,6 @@ buffers. For example:
         nil
       (load "gnus-sum.el" t t t))
     (require 'gnus)
-    (require 'gnus-agent)
     (require 'gnus-art)))
 
 ;; MIME stuff.
@@ -1646,6 +1729,7 @@ increase the score of each group you read."
   "\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-t" gnus-summary-sort-by-recipient
   "\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
@@ -1673,6 +1757,7 @@ increase the score of each group you read."
   "Q" gnus-summary-exit-no-update
   "\C-c\C-i" gnus-info-find-node
   gnus-mouse-2 gnus-mouse-pick-article
+  [follow-link] mouse-face
   "m" gnus-summary-mail-other-window
   "a" gnus-summary-post-news
   "i" gnus-summary-news-other-window
@@ -1755,7 +1840,9 @@ increase the score of each group you read."
   "c" gnus-summary-limit-exclude-childless-dormant
   "C" gnus-summary-limit-mark-excluded-as-read
   "o" gnus-summary-insert-old-articles
-  "N" gnus-summary-insert-new-articles)
+  "N" gnus-summary-insert-new-articles
+  "r" gnus-summary-limit-to-replied
+  "R" gnus-summary-limit-to-recipient)
 
 (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
   "n" gnus-summary-next-unread-article
@@ -1845,6 +1932,7 @@ increase the score of each group you read."
   "q" gnus-article-de-quoted-unreadable
   "6" gnus-article-de-base64-unreadable
   "Z" gnus-article-decode-HZ
+  "A" gnus-article-treat-ansi-sequences
   "h" gnus-article-wash-html
   "u" gnus-article-unsplit-urls
   "s" gnus-summary-force-verify-and-decrypt
@@ -1857,7 +1945,8 @@ increase the score of each group you read."
   "v" gnus-summary-verbose-headers
   "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
   "p" gnus-article-verify-x-pgp-sig
-  "d" gnus-article-treat-dumbquotes)
+  "d" gnus-article-treat-dumbquotes
+  "i" gnus-summary-idna-message)
 
 (gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
   ;; mnemonic: deuglif*Y*
@@ -2109,19 +2198,19 @@ increase the score of each group you read."
               :active (not (gnus-group-read-only-p))
               ,@(if (featurep 'xemacs) nil
                   '(:help "Encrypt the message body on disk"))]
-             ["Extract all parts" gnus-summary-save-parts t]
+             ["Extract all parts..." gnus-summary-save-parts t]
              ("Multipart"
               ["Repair multipart" gnus-summary-repair-multipart t]
-              ["Pipe part" gnus-article-pipe-part t]
+              ["Pipe part..." gnus-article-pipe-part t]
               ["Inline part" gnus-article-inline-part t]
               ["Encrypt body" gnus-article-encrypt-body
                :active (not (gnus-group-read-only-p))
               ,@(if (featurep 'xemacs) nil
                   '(:help "Encrypt the message body on disk"))]
               ["View part externally" gnus-article-view-part-externally t]
-              ["View part with charset" gnus-article-view-part-as-charset t]
+              ["View part with charset..." gnus-article-view-part-as-charset t]
               ["Copy part" gnus-article-copy-part t]
-              ["Save part" gnus-article-save-part t]
+              ["Save part..." gnus-article-save-part t]
               ["View part" gnus-article-view-part t]))
             ("Date"
              ["Local" gnus-article-date-local t]
@@ -2174,12 +2263,13 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["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]
+             ["Remove CR" gnus-article-remove-cr t]
              ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
              ["Base64" gnus-article-de-base64-unreadable t]
              ["Rot 13" gnus-summary-caesar-message
               ,@(if (featurep 'xemacs) '(t)
                   '(:help "\"Caesar rotate\" article by 13"))]
+             ["De-IDNA" gnus-summary-idna-message t]
              ["Morse decode" gnus-summary-morse-message t]
              ["Unix pipe..." gnus-summary-pipe-message t]
              ["Add buttons" gnus-article-add-buttons t]
@@ -2190,9 +2280,10 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["Unfold headers" gnus-article-treat-unfold-headers t]
              ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
              ["Html" gnus-article-wash-html t]
-             ["URLs" gnus-article-unsplit-urls t]
+             ["Unsplit URLs" gnus-article-unsplit-urls t]
              ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
-             ["HZ" gnus-article-decode-HZ t]
+             ["Decode HZ" gnus-article-decode-HZ t]
+             ["ANSI sequences" gnus-article-treat-ansi-sequences t]
              ("(Outlook) Deuglify"
               ["Unwrap lines" gnus-article-outlook-unwrap-lines t]
               ["Repair attribution" gnus-article-outlook-repair-attribution t]
@@ -2201,22 +2292,26 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
                gnus-article-outlook-deuglify-article t])
              )
             ("Output"
-             ["Save in default format" gnus-summary-save-article
+             ["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
+             ["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]
-             ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
-             ["Save body in file" gnus-summary-save-article-body-file t]
-             ["Pipe through a filter" gnus-summary-pipe-output t]
+             ["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]
+             ["Save in RMAIL mbox..." gnus-summary-save-article-rmail t]
+             ["Save body in file..." gnus-summary-save-article-body-file t]
+             ["Pipe through a filter..." gnus-summary-pipe-output t]
              ["Add to SOUP packet" gnus-soup-add-article t]
-             ["Print with Muttprint" gnus-summary-muttprint t]
-             ["Print" gnus-summary-print-article t])
-            ("Backend"
+             ["Print with Muttprint..." gnus-summary-muttprint t]
+             ["Print" gnus-summary-print-article
+              ,@(if (featurep 'xemacs) '(t)
+                  '(:help "Generate and print a PostScript image"))])
+            ("Copy, move,... (Backend)"
+             ,@(if (featurep 'xemacs) nil
+                 '(:help "Copying, moving, expiring articles..."))
              ["Respool article..." gnus-summary-respool-article t]
              ["Move article..." gnus-summary-move-article
               (gnus-check-backend-function
@@ -2307,7 +2402,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
       `("Post"
        ["Send a message (mail or news)" gnus-summary-post-news
         ,@(if (featurep 'xemacs) '(t)
-            '(:help "Post an article"))]
+            '(:help "Compose a new message (mail or news)"))]
        ["Followup" gnus-summary-followup
         ,@(if (featurep 'xemacs) '(t)
             '(:help "Post followup to this article"))]
@@ -2386,12 +2481,14 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
         ["Marks..." gnus-summary-limit-to-marks t]
         ["Subject..." gnus-summary-limit-to-subject t]
         ["Author..." gnus-summary-limit-to-author t]
+        ["Recipient..." gnus-summary-limit-to-recipient t]
         ["Age..." gnus-summary-limit-to-age t]
         ["Extra..." gnus-summary-limit-to-extra t]
         ["Score..." gnus-summary-limit-to-score t]
         ["Display Predicate" gnus-summary-limit-to-display-predicate t]
         ["Unread" gnus-summary-limit-to-unread t]
         ["Unseen" gnus-summary-limit-to-unseen t]
+        ["Replied" gnus-summary-limit-to-replied t]
         ["Non-dormant" gnus-summary-limit-exclude-dormant t]
         ["Next articles" gnus-summary-limit-to-articles t]
         ["Pop limit" gnus-summary-pop-limit t]
@@ -2405,6 +2502,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
         ["Set mark" gnus-summary-mark-as-processable t]
         ["Remove mark" gnus-summary-unmark-as-processable t]
         ["Remove all marks" gnus-summary-unmark-all-processable t]
+        ["Invert marks" gnus-uu-invert-processable t]
         ["Mark above" gnus-uu-mark-over t]
         ["Mark series" gnus-uu-mark-series t]
         ["Mark region" gnus-uu-mark-region (gnus-mark-active-p)]
@@ -2448,6 +2546,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
        ("Sort"
         ["Sort by number" gnus-summary-sort-by-number t]
         ["Sort by author" gnus-summary-sort-by-author t]
+        ["Sort by recipient" gnus-summary-sort-by-recipient t]
         ["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]
@@ -2541,6 +2640,8 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
               '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-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
@@ -2649,7 +2750,7 @@ and backwards while displaying articles, type `\\[gnus-summary-next-unread-artic
 respectively.
 
 You can also post articles and send mail from this buffer.  To
-follow up an article, type `\\[gnus-summary-followup]'.         To mail a reply to the author
+follow up an article, type `\\[gnus-summary-followup]'.  To mail a reply to the author
 of an article, type `\\[gnus-summary-reply]'.
 
 There are approx. one gazillion commands you can execute in this
@@ -2673,7 +2774,8 @@ The following commands are available:
   (make-local-variable 'minor-mode-alist)
   (use-local-map gnus-summary-mode-map)
   (buffer-disable-undo)
-  (setq buffer-read-only t)            ;Disable modification
+  (setq buffer-read-only t             ;Disable modification
+       show-trailing-whitespace nil)
   (setq truncate-lines t)
   (setq selective-display t)
   (setq selective-display-ellipses t)  ;Display `...'
@@ -2712,9 +2814,9 @@ The following commands are available:
   (let ((locals gnus-summary-local-variables))
     (while locals
       (if (consp (car locals))
-         (and (vectorp (caar locals))
+         (and (symbolp (caar locals))
               (set (caar locals) nil))
-       (and (vectorp (car locals))
+       (and (symbolp (car locals))
             (set (car locals) nil)))
       (setq locals (cdr locals)))))
 
@@ -2786,10 +2888,9 @@ The following commands are available:
            (setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
            (when offset
              (gnus-data-update-list odata offset)))
-      ;; Find the last element in the list to be spliced into the main
+       ;; Find the last element in the list to be spliced into the main
        ;; list.
-       (while (cdr list)
-         (setq list (cdr list)))
+       (setq list (last list))
        (if (not data)
            (progn
              (setcdr list gnus-newsgroup-data)
@@ -3138,8 +3239,7 @@ buffer that was in action when the last article was fetched."
            (push (eval (car locals)) vlist))
          (setq locals (cdr locals)))
        (setq vlist (nreverse vlist)))
-      (save-excursion
-       (set-buffer gnus-group-buffer)
+      (with-current-buffer gnus-group-buffer
        (setq gnus-newsgroup-name name
              gnus-newsgroup-marked marked
              gnus-newsgroup-spam-marked spam
@@ -3197,34 +3297,55 @@ buffer that was in action when the last article was fetched."
   (save-excursion
     (when (gnus-buffer-exists-p gnus-summary-buffer)
       (set-buffer gnus-summary-buffer))
-    (let ((gnus-replied-mark 129)
-         (gnus-score-below-mark 130)
-         (gnus-score-over-mark 130)
-         (gnus-undownloaded-mark 131)
-         (spec gnus-summary-line-format-spec)
-         gnus-visual pos)
+    (let ((spec gnus-summary-line-format-spec)
+         pos)
       (save-excursion
        (gnus-set-work-buffer)
-       (let ((gnus-summary-line-format-spec spec)
-             (gnus-newsgroup-downloadable '(0)))
-         (gnus-summary-insert-line
-          [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil]
-          0 nil t 128 t nil "" nil 1)
+       (let ((gnus-tmp-unread ?Z)
+             (gnus-replied-mark ?Z)
+             (gnus-score-below-mark ?Z)
+             (gnus-score-over-mark ?Z)
+             (gnus-undownloaded-mark ?Z)
+             (gnus-summary-line-format-spec spec)
+             (gnus-newsgroup-downloadable '(0))
+             (header [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil])
+             case-fold-search ignores)
+         ;; Here, all marks are bound to Z.
+         (gnus-summary-insert-line header
+                                   0 nil t gnus-tmp-unread t nil "" nil 1)
+         (goto-char (point-min))
+         ;; Memorize the positions of the same characters as dummy marks.
+         (while (re-search-forward "[A-D]" nil t)
+           (push (point) ignores))
+         (erase-buffer)
+         ;; We use A-D as dummy marks in order to know column positions
+         ;; where marks should be inserted.
+         (setq gnus-tmp-unread ?A
+               gnus-replied-mark ?B
+               gnus-score-below-mark ?C
+               gnus-score-over-mark ?C
+               gnus-undownloaded-mark ?D)
+         (gnus-summary-insert-line header
+                                   0 nil t gnus-tmp-unread t nil "" nil 1)
+         ;; Ignore characters which aren't dummy marks.
+         (dolist (p ignores)
+           (delete-region (goto-char (1- p)) p)
+           (insert ?Z))
          (goto-char (point-min))
-         (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
-                                            (- (point) (point-min) 1)))))
+         (setq pos (list (cons 'unread
+                               (and (search-forward "A" nil t)
+                                    (- (point) (point-min) 1)))))
          (goto-char (point-min))
-         (push (cons 'replied (and (search-forward "\201" nil t)
+         (push (cons 'replied (and (search-forward "B" nil t)
                                    (- (point) (point-min) 1)))
                pos)
          (goto-char (point-min))
-         (push (cons 'score (and (search-forward "\202" nil t)
+         (push (cons 'score (and (search-forward "C" nil t)
                                  (- (point) (point-min) 1)))
                pos)
          (goto-char (point-min))
-         (push (cons 'download
-                     (and (search-forward "\203" nil t)
-                          (- (point) (point-min) 1)))
+         (push (cons 'download (and (search-forward "D" nil t)
+                                    (- (point) (point-min) 1)))
                pos)))
       (setq gnus-summary-mark-positions pos))))
 
@@ -3244,8 +3365,8 @@ buffer that was in action when the last article was fetched."
        ; Is it really necessary to do this next part for each summary line?
        ; Luckily, doesn't seem to slow things down much.
        (mail-parse-ignored-charsets
-        (save-excursion (set-buffer gnus-summary-buffer)
-                        gnus-newsgroup-ignored-charsets)))
+        (with-current-buffer gnus-summary-buffer
+          gnus-newsgroup-ignored-charsets)))
     (or
      (and gnus-ignored-from-addresses
          (string-match gnus-ignored-from-addresses gnus-tmp-from)
@@ -3407,12 +3528,8 @@ This function is intended to be used in
 
 (defun gnus-summary-set-local-parameters (group)
   "Go through the local params of GROUP and set all variable specs in that list."
-  (let ((params (gnus-group-find-parameter group))
-       (vars '(quit-config))           ; Ignore quit-config.
-       elem)
-    (while params
-      (setq elem (car params)
-           params (cdr params))
+  (let ((vars '(quit-config)))          ; Ignore quit-config.
+    (dolist (elem (gnus-group-find-parameter group))
       (and (consp elem)                        ; Has to be a cons.
           (consp (cdr elem))           ; The cdr has to be a list.
           (symbolp (car elem))         ; Has to be a symbol in there.
@@ -3521,9 +3638,11 @@ 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)
-      (gnus-update-format-specifications
-       nil 'summary 'summary-mode 'summary-dummy)
-      (gnus-update-summary-mark-positions)
+      (when (memq 'summary (gnus-update-format-specifications
+                           nil 'summary 'summary-mode 'summary-dummy))
+       ;; The format specification for the summary line was updated,
+       ;; so we need to update the mark positions as well.
+       (gnus-update-summary-mark-positions))
       ;; Do score processing.
       (when gnus-use-scoring
        (gnus-possibly-score-headers))
@@ -3531,16 +3650,10 @@ If NO-DISPLAY, don't generate a summary buffer."
       (when gnus-build-sparse-threads
        (gnus-build-sparse-threads))
       ;; Find the initial limit.
-      (if gnus-show-threads
-         (if show-all
-             (let ((gnus-newsgroup-dormant nil))
-               (gnus-summary-initial-limit show-all))
+      (if show-all
+         (let ((gnus-newsgroup-dormant nil))
            (gnus-summary-initial-limit show-all))
-       ;; When unthreaded, all articles are always shown.
-       (setq gnus-newsgroup-limit
-             (mapcar
-              (lambda (header) (mail-header-number header))
-              gnus-newsgroup-headers)))
+       (gnus-summary-initial-limit show-all))
       ;; Generate the summary buffer.
       (unless no-display
        (gnus-summary-prepare))
@@ -3980,13 +4093,12 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
   "Translate STRING into something that doesn't contain weird characters."
   (mm-subst-char-in-string
    ?\r ?\-
-   (mm-subst-char-in-string
-    ?\n ?\- string)))
+   (mm-subst-char-in-string ?\n ?\- string t) t))
 
 ;; 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)
-  (let ((eol (gnus-point-at-eol))
+  (let ((eol (point-at-eol))
        (buffer (current-buffer))
        header references in-reply-to)
 
@@ -4011,7 +4123,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                               (setq x (nnheader-nov-field))))
                   (error x))
                 (nnheader-nov-field)   ; date
-                (nnheader-nov-read-message-id) ; id
+                (nnheader-nov-read-message-id number)  ; id
                 (setq references (nnheader-nov-field)) ; refs
                 (nnheader-nov-read-integer) ; chars
                 (nnheader-nov-read-integer) ; lines
@@ -4085,8 +4197,7 @@ the id of the parent article (if any)."
            (setq article (read (current-buffer))
                  header (gnus-nov-parse-line article dependencies)))
          (when header
-           (save-excursion
-             (set-buffer gnus-summary-buffer)
+           (with-current-buffer gnus-summary-buffer
              (push header gnus-newsgroup-headers)
              (if (memq (setq article (mail-header-number header))
                        gnus-newsgroup-unselected)
@@ -4183,7 +4294,7 @@ If LINE, insert the rebuilt thread starting on line LINE."
        (setq thread (list (car (gnus-id-to-thread id))))
       ;; Get the thread this article is part of.
       (setq thread (gnus-remove-thread id)))
-    (setq old-pos (gnus-point-at-bol))
+    (setq old-pos (point-at-bol))
     (setq current (save-excursion
                    (and (re-search-backward "[\r\n]" nil t)
                         (gnus-summary-article-number))))
@@ -4365,9 +4476,9 @@ If LINE, insert the rebuilt thread starting on line LINE."
       (gnus-summary-show-thread)
       (gnus-data-remove
        number
-       (- (gnus-point-at-bol)
+       (- (point-at-bol)
          (prog1
-             (1+ (gnus-point-at-eol))
+             (1+ (point-at-eol))
            (gnus-delete-line)))))))
 
 (defun gnus-sort-threads-1 (threads func)
@@ -4464,6 +4575,18 @@ using some other form will lead to serious barfage."
   (gnus-article-sort-by-author
    (gnus-thread-header h1)  (gnus-thread-header h2)))
 
+(defsubst gnus-article-sort-by-recipient (h1 h2)
+  "Sort articles by recipient."
+  (string-lessp
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (or (cdr (assq 'To (mail-header-extra h1))) ""))))
+     (or (car extract) (cadr extract)))
+   (let ((extract (funcall
+                  gnus-extract-address-components
+                  (or (cdr (assq 'To (mail-header-extra h2))) ""))))
+     (or (car extract) (cadr extract)))))
+
 (defsubst gnus-article-sort-by-subject (h1 h2)
   "Sort articles by root subject."
   (string-lessp
@@ -4581,32 +4704,39 @@ Unscored articles will be counted as having a score of zero."
 (defcustom gnus-sum-thread-tree-root "> "
   "With %B spec, used for the root of a thread.
 If nil, use subject instead."
-  :type '(radio (const :format "%v  " nil) (string :size 0))
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-false-root "> "
   "With %B spec, used for a false root of a thread.
 If nil, use subject instead."
-  :type '(radio (const :format "%v  " nil) (string :size 0))
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-single-indent ""
   "With %B spec, used for a thread with just one message.
 If nil, use subject instead."
-  :type '(radio (const :format "%v  " nil) (string :size 0))
+  :version "22.1"
+  :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-vertical "| "
   "With %B spec, used for drawing a vertical line."
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-indent "  "
   "With %B spec, used for indenting."
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-leaf-with-other "+-> "
   "With %B spec, used for a leaf with brothers."
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-single-leaf "\\-> "
   "With %B spec, used for a leaf without brothers."
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 
@@ -4958,23 +5088,20 @@ or a straight list of headers."
                  gnus-list-identifiers))
        changed subject)
     (when regexp
+      (setq regexp (concat "^\\(?:R[Ee]: +\\)*\\(" regexp " *\\)"))
       (dolist (header gnus-newsgroup-headers)
        (setq subject (mail-header-subject header)
              changed nil)
-       (while (string-match
-               (concat "^\\(R[Ee]: +\\)*\\(" regexp " *\\)")
-               subject)
+       (while (string-match regexp subject)
          (setq subject
-               (concat (substring subject 0 (match-beginning 2))
+               (concat (substring subject 0 (match-beginning 1))
                        (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
+         (when (string-match "^\\(\\(?:R[Ee]: +\\)+\\)R[Ee]: +" subject)
+           (setq subject
+                 (concat (substring subject 0 (match-beginning 1))
+                         (substring subject (match-end 1)))))
          (mail-header-set-subject header subject))))))
 
 (defun gnus-fetch-headers (articles)
@@ -5002,7 +5129,7 @@ or a straight list of headers."
   "Select newsgroup GROUP.
 If READ-ALL is non-nil, all articles in the group are selected.
 If SELECT-ARTICLES, only select those articles from GROUP."
-  (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
+  (let* ((entry (gnus-group-entry group))
         ;;!!! Dirty hack; should be removed.
         (gnus-summary-ignore-duplicates
          (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
@@ -5031,21 +5158,12 @@ If SELECT-ARTICLES, only select those articles from GROUP."
             group (gnus-status-message group)))
 
     (when gnus-agent
-      ;; The agent may be storing articles that are no longer in the
-      ;; server's active range.  If that is the case, the active range
-      ;; needs to be expanded such that the agent's articles can be
-      ;; included in the summary.
-      (let* ((gnus-command-method (gnus-find-method-for-group group))
-             (alist (gnus-agent-load-alist group))
-             (active (gnus-active group)))
-        (if (and (car alist)
-                 (< (caar alist) (car active)))
-            (gnus-set-active group (cons (caar alist) (cdr active)))))
+      (gnus-agent-possibly-alter-active group (gnus-active group) info)
 
       (setq gnus-summary-use-undownloaded-faces
-            (not (gnus-agent-find-parameter
-                  group
-                  'agent-disable-undownloaded-faces))))
+           (gnus-agent-find-parameter
+            group
+            'agent-enable-undownloaded-faces)))
 
     (setq gnus-newsgroup-name group
          gnus-newsgroup-unselected nil
@@ -5243,8 +5361,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
 
 (defun gnus-articles-to-read (group &optional read-all)
   "Find out what articles the user wants to read."
-  (let* ((display (gnus-group-find-parameter group 'display))
-        (articles
+  (let* ((articles
          ;; Select all articles if `read-all' is non-nil, or if there
          ;; are no unread articles.
          (if (or read-all
@@ -5370,7 +5487,8 @@ If SELECT-ARTICLES, only select those articles from GROUP."
         (min (car active))
         (max (cdr active))
         (types gnus-article-mark-lists)
-        marks var articles article mark mark-type)
+        marks var articles article mark mark-type
+         bgn end)
 
     (dolist (marks marked-lists)
       (setq mark (car marks)
@@ -5380,13 +5498,30 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       ;; We set the variable according to the type of the marks list,
       ;; and then adjust the marks to a subset of the active articles.
       (cond
-       ;; Adjust "simple" lists.
+       ;; Adjust "simple" lists - compressed yet unsorted
        ((eq mark-type 'list)
-       (set var (setq articles (gnus-uncompress-range (cdr marks))))
-       (when (memq mark '(tick dormant expire reply save))
-         (while articles
-           (when (or (< (setq article (pop articles)) min) (> article max))
-             (set var (delq article (symbol-value var)))))))
+        ;; Simultaneously uncompress and clip to active range
+        ;; See gnus-uncompress-range for a description of possible marks
+        (let (l lh)
+          (if (not (cadr marks))
+              (set var nil)
+            (setq articles (if (numberp (cddr marks))
+                               (list (cdr marks))
+                             (cdr marks))
+                  lh (cons nil nil)
+                  l lh)
+
+            (while (setq article (pop articles))
+              (cond ((consp article)
+                     (setq bgn (max (car article) min)
+                           end (min (cdr article) max))
+                     (while (<= bgn end)
+                       (setq l (setcdr l (cons bgn nil))
+                             bgn (1+ bgn))))
+                    ((and (<= min article)
+                          (>= max article))
+                     (setq l (setcdr l (cons article nil))))))
+            (set var (cdr lh)))))
        ;; Adjust assocs.
        ((eq mark-type 'tuple)
        (set var (setq articles (cdr marks)))
@@ -5596,7 +5731,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
 (defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
   "Look through all the headers and mark the Xrefs as read."
   (let ((virtual (gnus-virtual-group-p from-newsgroup))
-       name entry info xref-hashtb idlist method nth4)
+       name info xref-hashtb idlist method nth4)
     (save-excursion
       (set-buffer gnus-group-buffer)
       (when (setq xref-hashtb
@@ -5607,8 +5742,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
             (setq idlist (symbol-value group))
             ;; Dead groups are not updated.
             (and (prog1
-                     (setq entry (gnus-gethash name gnus-newsrc-hashtb)
-                           info (nth 2 entry))
+                     (setq info (gnus-get-info name))
                    (when (stringp (setq nth4 (gnus-info-method info)))
                      (setq nth4 (gnus-server-to-method nth4))))
                  ;; Only do the xrefs if the group has the same
@@ -5630,7 +5764,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         xref-hashtb)))))
 
 (defun gnus-compute-read-articles (group articles)
-  (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
+  (let* ((entry (gnus-group-entry group))
         (info (nth 2 entry))
         (active (gnus-active group))
         ninfo)
@@ -5667,14 +5801,13 @@ The resulting hash table is returned, or nil if no Xrefs were found."
 (defun gnus-group-make-articles-read (group articles)
   "Update the info of GROUP to say that ARTICLES are read."
   (let* ((num 0)
-        (entry (gnus-gethash group gnus-newsrc-hashtb))
+        (entry (gnus-group-entry group))
         (info (nth 2 entry))
         (active (gnus-active group))
         range)
     (when entry
       (setq range (gnus-compute-read-articles group articles))
-      (save-excursion
-       (set-buffer gnus-group-buffer)
+      (with-current-buffer gnus-group-buffer
        (gnus-undo-register
          `(progn
             (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
@@ -5713,9 +5846,9 @@ The resulting hash table is returned, or nil if no Xrefs were found."
   (let ((cur nntp-server-buffer)
        (dependencies
         (or dependencies
-            (save-excursion (set-buffer gnus-summary-buffer)
-                            gnus-newsgroup-dependencies)))
-       headers id end ref
+            (with-current-buffer gnus-summary-buffer
+              gnus-newsgroup-dependencies)))
+       headers id end ref number
        (mail-parse-charset gnus-newsgroup-charset)
        (mail-parse-ignored-charsets
         (save-excursion (condition-case nil
@@ -5748,7 +5881,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
           (vector
            ;; Number.
            (prog1
-               (read cur)
+               (setq number (read cur))
              (end-of-line)
              (setq p (point))
              (narrow-to-region (point)
@@ -5785,7 +5918,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                                             (match-end 1))
                         ;; If there was no message-id, we just fake one
                         ;; to make subsequent routines simpler.
-                        (nnheader-generate-fake-message-id))))
+                        (nnheader-generate-fake-message-id number))))
            ;; References.
            (progn
              (goto-char p)
@@ -5931,8 +6064,8 @@ Return a list of headers that match SEQUENCE (see
 (defun gnus-article-get-xrefs ()
   "Fill in the Xref value in `gnus-current-headers', if necessary.
 This is meant to be called in `gnus-article-internal-prepare-hook'."
-  (let ((headers (save-excursion (set-buffer gnus-summary-buffer)
-                                gnus-current-headers)))
+  (let ((headers (with-current-buffer gnus-summary-buffer
+                  gnus-current-headers)))
     (or (not gnus-use-cross-reference)
        (not headers)
        (and (mail-header-xref headers)
@@ -5947,7 +6080,7 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
                           (looking-at "Xref:"))
                      (search-forward "\nXref:" nil t))
              (goto-char (1+ (match-end 0)))
-             (setq xref (buffer-substring (point) (gnus-point-at-eol)))
+             (setq xref (buffer-substring (point) (point-at-eol)))
              (mail-header-set-xref headers xref)))))))
 
 (defun gnus-summary-insert-subject (id &optional old-header use-old-header)
@@ -5975,10 +6108,14 @@ the subject line on."
          (goto-char (gnus-data-pos d))
          (gnus-data-remove
           number
-          (- (gnus-point-at-bol)
+          (- (point-at-bol)
              (prog1
-                 (1+ (gnus-point-at-eol))
+                 (1+ (point-at-eol))
                (gnus-delete-line))))))
+      ;; Remove list identifiers from subject.
+      (when gnus-list-identifiers
+       (let ((gnus-newsgroup-headers (list header)))
+         (gnus-summary-remove-list-identifiers)))
       (when old-header
        (mail-header-set-number header (mail-header-number old-header)))
       (setq gnus-newsgroup-sparse
@@ -6087,8 +6224,7 @@ executed with point over the summary line of the articles."
 (defun gnus-summary-process-mark-set (set)
   "Make SET into the current process marked articles."
   (gnus-summary-unmark-all-processable)
-  (while set
-    (gnus-summary-set-process-mark (pop set))))
+  (mapc 'gnus-summary-set-process-mark set))
 
 ;;; Searching and stuff
 
@@ -6104,8 +6240,7 @@ If optional argument BACKWARD is non-nil, search backward instead."
 (defun gnus-summary-best-group (&optional exclude-group)
   "Find the name of the best unread group.
 If EXCLUDE-GROUP, do not go to this group."
-  (save-excursion
-    (set-buffer gnus-group-buffer)
+  (with-current-buffer gnus-group-buffer
     (save-excursion
       (gnus-group-best-unread-group exclude-group))))
 
@@ -6236,7 +6371,7 @@ displayed, no centering will be performed."
                      ((< (window-height) 7) 1)
                      (t (if (numberp gnus-auto-center-summary)
                             gnus-auto-center-summary
-                          2))))
+                           (/ (1- (window-height)) 2)))))
           (height (1- (window-height)))
           (bottom (save-excursion (goto-char (point-max))
                                   (forward-line (- height))
@@ -6294,7 +6429,8 @@ displayed, no centering will be performed."
 (defun gnus-list-of-unread-articles (group)
   (let* ((read (gnus-info-read (gnus-get-info group)))
         (active (or (gnus-active group) (gnus-activate-group group)))
-        (last (cdr active))
+        (last (or (cdr active)
+                  (error "Group %s couldn't be activated " group)))
         first nlast unread)
     ;; If none are read, then all are unread.
     (if (not read)
@@ -6315,15 +6451,15 @@ displayed, no centering will be performed."
        (while read
          (when first
            (while (< first nlast)
-             (push first unread)
-             (setq first (1+ first))))
+             (setq unread (cons first unread)
+                    first (1+ first))))
          (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
          (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
          (setq read (cdr read)))))
     ;; And add the last unread articles.
     (while (<= first last)
-      (push first unread)
-      (setq first (1+ first)))
+      (setq unread (cons first unread)
+            first (1+ first)))
     ;; Return the list of unread articles.
     (delq 0 (nreverse unread))))
 
@@ -6341,6 +6477,44 @@ displayed, no centering will be performed."
           (cdr (assq 'dormant marked)))
          (cdr (assq 'tick marked))))))
 
+;; This function returns a sequence of article numbers based on the
+;; difference between the ranges of read articles in this group and
+;; the range of active articles.
+(defun gnus-sequence-of-unread-articles (group)
+  (let* ((read (gnus-info-read (gnus-get-info group)))
+        (active (or (gnus-active group) (gnus-activate-group group)))
+        (last (cdr active))
+        first nlast unread)
+    ;; If none are read, then all are unread.
+    (if (not read)
+       (setq first (car active))
+      ;; 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 (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))
+                                 (caar read)))
+                 1)
+         (setq first (car active)))
+       (while read
+         (when first
+            (push (cons first nlast) unread))
+         (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
+         (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
+         (setq read (cdr read)))))
+    ;; And add the last unread articles.
+    (cond ((< first last)
+           (push (cons first last) unread))
+          ((= first last)
+           (push first unread)))
+    ;; Return the sequence of unread articles.
+    (delq 0 (nreverse unread))))
+
 ;; Various summary commands
 
 (defun gnus-summary-select-article-buffer ()
@@ -6439,8 +6613,7 @@ The prefix argument ALL means to select all articles."
          (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
        (let ((headers gnus-newsgroup-headers))
          ;; Set the new ranges of read articles.
-         (save-excursion
-           (set-buffer gnus-group-buffer)
+         (with-current-buffer gnus-group-buffer
            (gnus-undo-force-boundary))
          (gnus-update-read-articles
           group (gnus-sorted-union
@@ -6551,25 +6724,16 @@ If FORCE (the prefix), also save the .newsrc file(s)."
          (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)
-       (let ((gnus-summary-local-variables gnus-newsgroup-variables))
-         (gnus-summary-clear-local-variables))
        ;; Return to group mode buffer.
        (when (eq mode 'gnus-summary-mode)
          (gnus-kill-buffer buf)))
       (setq gnus-current-select-method gnus-select-method)
-      (if leave-hidden
-         (set-buffer gnus-group-buffer)
-       (pop-to-buffer gnus-group-buffer))
-      (if (not quit-config)
-         (progn
-           (goto-char group-point)
-           (unless leave-hidden
-             (gnus-configure-windows 'group 'force)))
-       (gnus-handle-ephemeral-exit quit-config))
+      (set-buffer gnus-group-buffer)
+      (if quit-config
+         (gnus-handle-ephemeral-exit quit-config)
+       (goto-char group-point)
+       (unless leave-hidden
+         (gnus-configure-windows 'group 'force)))
       ;; Clear the current group name.
       (unless quit-config
        (setq gnus-newsgroup-name nil)))))
@@ -6603,10 +6767,6 @@ If FORCE (the prefix), also save the .newsrc file(s)."
          (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))
        (gnus-kill-buffer gnus-summary-buffer))
@@ -6690,7 +6850,7 @@ The state which existed when entering the ephemeral is reset."
          (if (null arg) (not gnus-dead-summary-mode)
            (> (prefix-numeric-value arg) 0)))
     (when gnus-dead-summary-mode
-      (gnus-add-minor-mode
+      (add-minor-mode
        'gnus-dead-summary-mode " Dead" gnus-dead-summary-mode-map))))
 
 (defun gnus-deaden-summary ()
@@ -6698,8 +6858,7 @@ The state which existed when entering the ephemeral is reset."
   ;; Kill any previous dead summary buffer.
   (when (and gnus-dead-summary
             (buffer-name gnus-dead-summary))
-    (save-excursion
-      (set-buffer gnus-dead-summary)
+    (with-current-buffer gnus-dead-summary
       (when gnus-dead-summary-mode
        (kill-buffer (current-buffer)))))
   ;; Make this the current dead summary.
@@ -6718,8 +6877,7 @@ The state which existed when entering the ephemeral is reset."
   (save-excursion
     (when (and (buffer-name buffer)
               (not gnus-single-article-buffer))
-      (save-excursion
-       (set-buffer buffer)
+      (with-current-buffer buffer
        (gnus-kill-buffer gnus-article-buffer)
        (gnus-kill-buffer gnus-original-article-buffer)))
     (cond
@@ -6759,7 +6917,7 @@ in."
     (when current-prefix-arg
       (completing-read
        "FAQ dir: " (and (listp gnus-group-faq-directory)
-                       (mapcar (lambda (file) (list file))
+                       (mapcar 'list
                                gnus-group-faq-directory))))))
   (let (gnus-faq-buffer)
     (when (setq gnus-faq-buffer
@@ -6932,7 +7090,7 @@ If optional argument UNREAD is non-nil, only unread article is selected."
       (gnus-summary-goto-subject article t)))
   (gnus-summary-limit (append articles gnus-newsgroup-limit))
   (gnus-summary-position-point))
+
 (defun gnus-summary-goto-subject (article &optional force silent)
   "Go the subject line of ARTICLE.
 If FORCE, also allow jumping to articles not currently shown."
@@ -7085,8 +7243,7 @@ If BACKWARD, the previous article is selected instead of the next."
       (gnus-summary-jump-to-group gnus-newsgroup-name))
     (let ((cmd last-command-char)
          (point
-          (save-excursion
-            (set-buffer gnus-group-buffer)
+          (with-current-buffer gnus-group-buffer
             (point)))
          (group
           (if (eq gnus-keep-same-level 'best)
@@ -7137,11 +7294,12 @@ If BACKWARD, the previous article is selected instead of the next."
             (if (and group
                      (not (gnus-ephemeral-group-p gnus-newsgroup-name)))
                 (format " (Type %s for %s [%s])"
-                        (single-key-description cmd) group
-                        (car (gnus-gethash group gnus-newsrc-hashtb)))
+                        (single-key-description cmd)
+                        (gnus-group-decoded-name group)
+                        (gnus-group-unread group))
               (format " (Type %s to exit %s)"
                       (single-key-description cmd)
-                      gnus-newsgroup-name))))
+                      (gnus-group-decoded-name gnus-newsgroup-name)))))
       ;; Confirm auto selection.
       (setq key (car (setq keve (gnus-read-event-char prompt)))
            ended t)
@@ -7441,7 +7599,7 @@ is a number, it is the line the article is to be displayed on."
     t))
   (prog1
       (if (and (stringp article)
-              (string-match "@" article))
+              (string-match "@\\|%40" article))
          (gnus-summary-refer-article article)
        (when (stringp article)
          (setq article (string-to-number article)))
@@ -7526,6 +7684,49 @@ If NOT-MATCHING, excluding articles that have authors that match a regexp."
         current-prefix-arg))
   (gnus-summary-limit-to-subject from "from" not-matching))
 
+(defun gnus-summary-limit-to-recipient (recipient &optional not-matching)
+  "Limit the summary buffer to articles with the given RECIPIENT.
+
+If NOT-MATCHING, exclude RECIPIENT.
+
+To and Cc headers are checked.  You need to include them in
+`nnmail-extra-headers'."
+  ;; Unlike `rmail-summary-by-recipients', doesn't include From.
+  (interactive
+   (list (read-string (format "%s recipient (regexp): "
+                             (if current-prefix-arg "Exclude" "Limit to")))
+        current-prefix-arg))
+  (when (not (equal "" recipient))
+    (prog1 (let* ((to
+                  (if (memq 'To nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'To) recipient 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`To' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    nil))
+                 (cc
+                  (if (memq 'Cc nnmail-extra-headers)
+                      (gnus-summary-find-matching
+                       (cons 'extra 'Cc) recipient 'all nil nil
+                       not-matching)
+                    (gnus-message
+                     1 "`Cc' isn't present in `nnmail-extra-headers'")
+                    (sit-for 1)
+                    nil))
+                 (articles
+                  (if not-matching
+                      ;; We need the numbers that are in both lists:
+                      (mapcar (lambda (a)
+                                (and (memq a to) a))
+                              cc)
+                    (nconc to cc))))
+            (unless articles
+              (error "Found no matches for \"%s\"" recipient))
+            (gnus-summary-limit articles))
+      (gnus-summary-position-point))))
+
 (defun gnus-summary-limit-to-age (age &optional younger-p)
   "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
@@ -7544,10 +7745,9 @@ articles that are younger than AGE days."
        (if (numberp days)
           (progn
             (setq days-got t)
-            (if (< days 0)
-                (progn
-                  (setq younger (not younger))
-                  (setq days (* days -1)))))
+            (when (< days 0)
+              (setq younger (not younger))
+              (setq days (* days -1))))
         (message "Please enter a number.")
         (sleep-for 1)))
      (list days younger)))
@@ -7632,6 +7832,17 @@ If ALL is non-nil, limit strictly to unread articles."
           gnus-duplicate-mark gnus-souped-mark)
      'reverse)))
 
+(defun gnus-summary-limit-to-replied (&optional unreplied)
+  "Limit the summary buffer to replied articles.
+If UNREPLIED (the prefix), limit to unreplied articles."
+  (interactive "P")
+  (if unreplied
+      (gnus-summary-limit
+       (gnus-set-difference gnus-newsgroup-articles
+       gnus-newsgroup-replied))
+    (gnus-summary-limit gnus-newsgroup-replied))
+  (gnus-summary-position-point))
+
 (defalias 'gnus-summary-delete-marked-with 'gnus-summary-limit-exclude-marks)
 (make-obsolete 'gnus-summary-delete-marked-with
               'gnus-summary-limit-exclude-marks)
@@ -7977,13 +8188,12 @@ fetch-old-headers verbiage, and so on."
            (and gnus-newsgroup-display
                 (not (funcall gnus-newsgroup-display)))
            ;; Check NoCeM things.
-           (if (and gnus-use-nocem
-                    (gnus-nocem-unwanted-article-p
-                     (mail-header-id (car thread))))
-               (progn
-                 (setq gnus-newsgroup-unreads
-                       (delq number gnus-newsgroup-unreads))
-                 t))))
+           (when (and gnus-use-nocem
+                      (gnus-nocem-unwanted-article-p
+                       (mail-header-id (car thread))))
+             (setq gnus-newsgroup-unreads
+                   (delq number gnus-newsgroup-unreads))
+             t)))
          ;; Nope, invisible article.
          0
        ;; Ok, this article is to be visible, so we add it to the limit
@@ -8113,6 +8323,9 @@ of what's specified by the `gnus-refer-thread-limit' variable."
       (setq message-id (concat "<" message-id)))
     (unless (string-match ">$" message-id)
       (setq message-id (concat message-id ">")))
+    ;; People often post MIDs from URLs, so unhex it:
+    (unless (string-match "@" message-id)
+      (setq message-id (gnus-url-unhex-string message-id)))
     (let* ((header (gnus-id-to-header message-id))
           (sparse (and header
                        (gnus-summary-article-sparse-p
@@ -8192,8 +8405,7 @@ to guess what the document format is."
     (let* ((name (format "%s-%d"
                         (gnus-group-prefixed-name
                          gnus-newsgroup-name (list 'nndoc ""))
-                        (save-excursion
-                          (set-buffer gnus-summary-buffer)
+                        (with-current-buffer gnus-summary-buffer
                           gnus-current-article)))
           (ogroup gnus-newsgroup-name)
           (params (append (gnus-info-params (gnus-get-info ogroup))
@@ -8250,12 +8462,11 @@ This will allow you to read digests and other similar
 documents as newsgroups.
 Obeys the standard process/prefix convention."
   (interactive "P")
-  (let* ((articles (gnus-summary-work-articles n))
-        (ogroup gnus-newsgroup-name)
+  (let* ((ogroup gnus-newsgroup-name)
         (params (append (gnus-info-params (gnus-get-info ogroup))
                         (list (cons 'to-group ogroup))))
-        article group egroup groups vgroup)
-    (while (setq article (pop articles))
+        group egroup groups vgroup)
+    (dolist (article (gnus-summary-work-articles n))
       (setq group (format "%s-%d" gnus-newsgroup-name article))
       (gnus-summary-remove-process-mark article)
       (when (gnus-summary-display-article article)
@@ -8266,7 +8477,7 @@ Obeys the standard process/prefix convention."
            ;; the wrong guess.
            (message-narrow-to-head)
            (goto-char (point-min))
-           (delete-matching-lines "^\\(Path\\):\\|^From ")
+           (delete-matching-lines "^Path:\\|^From ")
            (widen)
            (if (setq egroup
                      (gnus-group-read-ephemeral-group
@@ -8325,7 +8536,7 @@ If BACKWARD, search backward instead."
   (let ((gnus-last-article gnus-last-article))
     (if (gnus-summary-search-article regexp backward)
        (gnus-summary-show-thread)
-      (error "Search failed: \"%s\"" regexp))))
+      (signal 'search-failed (list regexp)))))
 
 (defun gnus-summary-search-article-backward (regexp)
   "Search for an article containing REGEXP backward."
@@ -8506,7 +8717,7 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
   (gnus-eval-in-buffer-window gnus-article-buffer
     (widen)
     (goto-char (point-min))
-    (when gnus-page-broken
+    (when gnus-break-pages
       (gnus-narrow-to-page))))
 
 (defun gnus-summary-end-of-article ()
@@ -8518,7 +8729,9 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
     (widen)
     (goto-char (point-max))
     (recenter -3)
-    (when gnus-page-broken
+    (when gnus-break-pages
+      (when (re-search-backward page-delimiter nil t)
+       (narrow-to-region (match-end 0) (point-max)))
       (gnus-narrow-to-page))))
 
 (defun gnus-summary-print-truncate-and-quote (string &optional len)
@@ -8529,10 +8742,16 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
                          "[()]" "\\\\\\&"))
 
 (defun gnus-summary-print-article (&optional filename n)
-  "Generate and print a PostScript image of the N next (mail) articles.
+  "Generate and print a PostScript image of the process-marked (mail) articles.
 
-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 used interactively, print the current article if none are
+process-marked.  With prefix arg, prompt the user for the name of the
+file to save in.
+
+When used from Lisp, accept two optional args FILENAME and N.  N means
+to print the next N articles.  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 first argument FILENAME is nil, send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
@@ -8599,8 +8818,7 @@ strokes are `C-u g'."
           (or (cdr (assq arg gnus-summary-show-article-charset-alist))
               (mm-read-coding-system
                "View as charset: " ;; actually it is coding system.
-               (save-excursion
-                 (set-buffer gnus-article-buffer)
+               (with-current-buffer gnus-article-buffer
                  (mm-detect-coding-region (point) (point-max))))))
          (gnus-newsgroup-ignored-charsets 'gnus-all))
       (gnus-summary-select-article nil 'force)
@@ -8689,7 +8907,8 @@ If ARG is a negative number, hide the unwanted header lines."
             (inhibit-point-motion-hooks t)
             (hidden (if (numberp arg)
                         (>= arg 0)
-                      (gnus-article-hidden-text-p 'headers)))
+                      (or (not (looking-at "[^ \t\n]+:"))
+                          (gnus-article-hidden-text-p 'headers))))
             s e)
        (delete-region (point-min) (point-max))
        (with-current-buffer gnus-original-article-buffer
@@ -8708,10 +8927,12 @@ If ARG is a negative number, hide the unwanted header lines."
        (widen)
        (if window
            (set-window-start window (goto-char (point-min))))
-       (setq gnus-page-broken
-             (when gnus-break-pages
-               (gnus-narrow-to-page)
-               t))
+       (if gnus-break-pages
+           (gnus-narrow-to-page)
+         (when (gnus-visual-p 'page-marker)
+           (let ((buffer-read-only nil))
+             (gnus-remove-text-with-property 'gnus-prev)
+             (gnus-remove-text-with-property 'gnus-next))))
        (gnus-set-mode-line 'article)))))
 
 (defun gnus-summary-show-all-headers ()
@@ -8734,6 +8955,32 @@ forward."
          (message-caesar-buffer-body arg)
          (set-window-start (get-buffer-window (current-buffer)) start))))))
 
+(defun gnus-summary-idna-message (&optional arg)
+  "Decode IDNA encoded domain names in the current articles.
+IDNA encoded domain names looks like `xn--bar'.  If a string
+remain unencoded after running this function, it is likely an
+invalid IDNA string (`xn--bar' is invalid).
+
+You must have GNU Libidn (`http://www.gnu.org/software/libidn/')
+installed for this command to work."
+  (interactive "P")
+  (if (not (and (condition-case nil (require 'idna)
+                 (file-error))
+               (mm-coding-system-p 'utf-8)
+               (executable-find (symbol-value 'idna-program))))
+      (gnus-message
+       5 "GNU Libidn not installed properly (`idn' or `idna.el' missing)")
+    (gnus-summary-select-article)
+    (let ((mail-header-separator ""))
+      (gnus-eval-in-buffer-window gnus-article-buffer
+       (save-restriction
+         (widen)
+         (let ((start (window-start))
+               buffer-read-only)
+           (while (re-search-forward "\\(xn--[-0-9a-z]+\\)" nil t)
+             (replace-match (idna-to-unicode (match-string 1))))
+           (set-window-start (get-buffer-window (current-buffer)) start)))))))
+
 (autoload 'unmorse-region "morse"
   "Convert morse coded text in region to ordinary ASCII text."
   t)
@@ -8753,7 +9000,7 @@ forward."
            (when (message-goto-body)
              (gnus-narrow-to-body))
            (goto-char (point-min))
-           (while (re-search-forward "·" (point-max) t)
+           (while (search-forward "·" (point-max) t)
              (replace-match "."))
            (unmorse-region (point-min) (point-max))
            (widen)
@@ -8806,7 +9053,8 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
   (let ((articles (gnus-summary-work-articles n))
        (prefix (if (gnus-check-backend-function
                     'request-move-article gnus-newsgroup-name)
-                   (gnus-group-real-prefix gnus-newsgroup-name)
+                   (funcall gnus-move-group-prefix-function
+                            gnus-newsgroup-name)
                  ""))
        (names '((move "Move" "Moving")
                 (copy "Copy" "Copying")
@@ -8872,6 +9120,10 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
         (save-excursion
           (set-buffer copy-buf)
           (when (gnus-request-article-this-buffer article gnus-newsgroup-name)
+            (save-restriction
+              (nnheader-narrow-to-headers)
+              (dolist (hdr gnus-copy-article-ignored-headers)
+                (message-remove-header hdr t)))
             (gnus-request-accept-article
              to-newsgroup select-method (not articles) t))))
        ;; Crosspost the article.
@@ -8924,9 +9176,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
        (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))
+              (info (gnus-get-info pto-group))
               (to-group (gnus-info-group info))
               to-marks)
          ;; Update the group that has been moved to.
@@ -9014,7 +9264,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
 
        ;;;!!!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))))
@@ -9030,8 +9280,8 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
     (gnus-set-mode-line 'summary)))
 
 (defun gnus-summary-copy-article (&optional n to-newsgroup select-method)
-  "Move the current article to a different newsgroup.
-If TO-NEWSGROUP is string, do not prompt for a newsgroup to move to.
+  "Copy the current article to some other group.
+If TO-NEWSGROUP is string, do not prompt for a newsgroup to copy to.
 When called interactively, if TO-NEWSGROUP is nil, use the value of
 the variable `gnus-move-split-methods' for finding a default target
 newsgroup.
@@ -9055,6 +9305,7 @@ If nil, use to the current newsgroup method."
   "If non-nil, show and update the summary buffer as it's being built.
 If the value is t, update the buffer after every line is inserted.  If
 the value is an integer (N), update the display every N lines."
+  :version "22.1"
   :group 'gnus-thread
   :type '(choice (const :tag "off" nil)
                 number
@@ -9293,10 +9544,10 @@ confirmation before the articles are deleted."
        (unless (memq (car articles) not-deleted)
          (gnus-summary-mark-article (car articles) gnus-canceled-mark))
        (let* ((article (car articles))
-              (id (mail-header-id (gnus-data-header
-                                   (assoc article (gnus-data-list nil))))))
+              (ghead  (gnus-data-header
+                                   (assoc article (gnus-data-list nil)))))
          (run-hook-with-args 'gnus-summary-article-delete-hook
-                             'delete id gnus-newsgroup-name nil
+                             'delete ghead gnus-newsgroup-name nil
                              nil))
        (setq articles (cdr articles)))
       (when not-deleted
@@ -9675,8 +9926,7 @@ ARTICLE can also be a list of articles."
   ;; (article-number . line-number-in-body).
   (push
    (cons article
-        (save-excursion
-          (set-buffer gnus-article-buffer)
+        (with-current-buffer gnus-article-buffer
           (count-lines
            (min (point)
                 (save-excursion
@@ -9920,7 +10170,7 @@ If NO-EXPIRE, auto-expiry will be inhibited."
 (defun gnus-summary-update-mark (mark type)
   (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)
+    (re-search-backward "[\n\r]" (point-at-bol) 'move-to-limit)
     (when forward
       (when (looking-at "\r")
        (incf forward))
@@ -10444,7 +10694,7 @@ Returns nil if no thread was there to be shown."
   (interactive)
   (let ((buffer-read-only nil)
        (orig (point))
-       (end (gnus-point-at-eol))
+       (end (point-at-eol))
        ;; Leave point at bol
        (beg (progn (beginning-of-line) (point))))
     (prog1
@@ -10658,6 +10908,13 @@ Argument REVERSE means reverse order."
   (interactive "P")
   (gnus-summary-sort 'author reverse))
 
+(defun gnus-summary-sort-by-recipient (&optional reverse)
+  "Sort the summary buffer by recipient name alphabetically.
+If `case-fold-search' is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'recipient 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.
@@ -10931,8 +11188,7 @@ save those articles instead."
           (t
            (gnus-completing-read-with-default
             nil prom
-            (mapcar (lambda (el) (list el))
-                    (nreverse split-name))
+            (mapcar 'list (nreverse split-name))
             nil nil nil
             'gnus-group-history))))
         (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
@@ -10996,6 +11252,8 @@ If REVERSE, save parts that do not match TYPE."
                     (or
                      (mail-content-type-get
                       (mm-handle-disposition handle) 'filename)
+                     (mail-content-type-get
+                      (mm-handle-type handle) 'name)
                      (concat gnus-newsgroup-name
                              "." (number-to-string
                                   (cdr gnus-article-current))))))
@@ -11038,7 +11296,7 @@ If REVERSE, save parts that do not match TYPE."
                                (lambda (f)
                                  (if (equal f " ")
                                      f
-                                   (mm-quote-arg f)))
+                                   (shell-quote-argument f)))
                                files " ")))))
          (setq ps (cdr ps)))))
     (if (and gnus-view-pseudos (not not-view))
@@ -11133,14 +11391,6 @@ If REVERSE, save parts that do not match TYPE."
             (not (gnus-summary-article-sparse-p (mail-header-number header))))
        ;; We have found the header.
        header
-      ;; If this is a sparse article, we have to nix out its
-      ;; previous entry in the thread hashtb.
-      (when (and header
-                (gnus-summary-article-sparse-p (mail-header-number header)))
-       (let* ((parent (gnus-parent-id (mail-header-references header)))
-              (thread (and parent (gnus-id-to-thread parent))))
-         (when thread
-           (delq (assq header thread) thread))))
       ;; We have to really fetch the header to this article.
       (save-excursion
        (set-buffer nntp-server-buffer)
@@ -11198,8 +11448,8 @@ If REVERSE, save parts that do not match TYPE."
   ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
   (when gnus-summary-selected-face
     (save-excursion
-      (let* ((beg (gnus-point-at-bol))
-            (end (gnus-point-at-eol))
+      (let* ((beg (point-at-bol))
+            (end (point-at-eol))
             ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
             (from (if (get-text-property beg gnus-mouse-face-prop)
                       beg
@@ -11248,7 +11498,7 @@ If REVERSE, save parts that do not match TYPE."
 
 (defun gnus-summary-highlight-line ()
   "Highlight current line according to `gnus-summary-highlight'."
-  (let* ((beg (gnus-point-at-bol))
+  (let* ((beg (point-at-bol))
         (article (or (gnus-summary-article-number) gnus-current-article))
         (score (or (cdr (assq article
                               gnus-newsgroup-scored))
@@ -11259,11 +11509,12 @@ If REVERSE, save parts that do not match TYPE."
         (default-high gnus-summary-default-high-score)
         (default-low gnus-summary-default-low-score)
         (uncached (and gnus-summary-use-undownloaded-faces
-                        (memq article gnus-newsgroup-undownloaded))))
+                        (memq article gnus-newsgroup-undownloaded)
+                        (not (memq article gnus-newsgroup-cached)))))
     (let ((face (funcall (gnus-summary-highlight-line-0))))
       (unless (eq face (get-text-property beg 'face))
        (gnus-put-text-property-excluding-characters-with-faces
-        beg (gnus-point-at-eol) 'face
+        beg (point-at-eol) 'face
         (setq face (if (boundp face) (symbol-value face) face)))
        (when gnus-summary-highlight-line-function
          (funcall gnus-summary-highlight-line-function article face))))))
@@ -11271,11 +11522,10 @@ If REVERSE, save parts that do not match TYPE."
 (defun gnus-update-read-articles (group unread &optional compute)
   "Update the list of read articles in GROUP.
 UNREAD is a sorted list."
-  (let* ((active (or gnus-newsgroup-active (gnus-active group)))
-        (entry (gnus-gethash group gnus-newsrc-hashtb))
-        (info (nth 2 entry))
-        (prev 1)
-        read)
+  (let ((active (or gnus-newsgroup-active (gnus-active group)))
+       (info (gnus-get-info group))
+       (prev 1)
+       read)
     (if (or (not info) (not active))
        ;; There is no info on this group if it was, in fact,
        ;; killed.  Gnus stores no information on killed groups, so
@@ -11343,8 +11593,7 @@ UNREAD is a sorted list."
     (dolist (buffer (buffer-list))
       (when (and (setq buffer (buffer-name buffer))
                 (string-match "Summary" buffer)
-                (save-excursion
-                  (set-buffer buffer)
+                (with-current-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.
@@ -11405,7 +11654,7 @@ treated as multipart/mixed."
     (insert "Mime-Version: 1.0\n")
     (widen)
     (when (search-forward "\n--" nil t)
-      (let ((separator (buffer-substring (point) (gnus-point-at-eol))))
+      (let ((separator (buffer-substring (point) (point-at-eol))))
        (message-narrow-to-head)
        (message-remove-header "Content-Type")
        (goto-char (point-max))
@@ -11625,7 +11874,7 @@ If ALL is a number, fetch this number of articles."
          (push i new)
          (decf i))
        (if (not new)
-           (message "No gnus is bad news.")
+           (message "No gnus is bad news")
          (gnus-summary-insert-articles new)
          (setq gnus-newsgroup-unreads
                (gnus-sorted-nunion gnus-newsgroup-unreads new))
@@ -11644,4 +11893,5 @@ If ALL is a number, fetch this number of articles."
 ;; coding: iso-8859-1
 ;; End:
 
+;; arch-tag: 17c6748f-6d00-4d36-bf01-835c42f31235
 ;;; gnus-sum.el ends here