*** empty log message ***
[gnus] / lisp / gnus-sum.el
index dd6591f..22c941d 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996,97 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
 ;; Keywords: news
@@ -122,9 +122,12 @@ comparing subjects."
 
 (defcustom gnus-simplify-subject-functions nil
   "List of functions taking a string argument that simplify subjects.
-The functions are applied recursively."
+The functions are applied recursively.
+
+Useful functions to put in this list include: `gnus-simplify-subject-re',
+`gnus-simplify-subject-fuzzy' and `gnus-simplify-whitespace'."
   :group 'gnus-thread
-  :type '(repeat (list function)))
+  :type '(repeat function))
 
 (defcustom gnus-simplify-ignored-prefixes nil
   "*Regexp, matches for which are removed from subject lines when simplifying fuzzily."
@@ -145,7 +148,7 @@ non-nil and non-`some', fill in all gaps that Gnus manages to guess."
 
 (defcustom gnus-summary-thread-gathering-function
   'gnus-gather-threads-by-subject
-  "Function used for gathering loose threads.
+  "*Function used for gathering loose threads.
 There are two pre-defined functions: `gnus-gather-threads-by-subject',
 which only takes Subjects into consideration; and
 `gnus-gather-threads-by-references', which compared the References
@@ -333,9 +336,9 @@ The articles will simply be fed to the function given by
   "*Variable used to suggest where articles are to be moved to.
 It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-summary-mail
-  :type '(repeat (choice (list function)
-                        (cons regexp (repeat string))
-                        sexp)))
+  :type '(repeat (choice (list :value (fun) function)
+                        (cons :value ("" "") regexp (repeat string))
+                        (sexp :value nil))))
 
 (defcustom gnus-unread-mark ? 
   "*Mark used for unread articles."
@@ -489,7 +492,7 @@ list of parameters to that command."
   :type 'boolean)
 
 (defcustom gnus-summary-dummy-line-format
-  "*  %(:                          :%) %S\n"
+  "  %(:                          :%) %S\n"
   "*The format specification for the dummy roots in the summary buffer.
 It works along the same lines as a normal formatting string,
 with some simple extensions.
@@ -572,7 +575,8 @@ Some functions you can use are `+', `max', or `min'."
   :type 'function)
 
 (defcustom gnus-summary-expunge-below nil
-  "All articles that have a score less than this variable will be expunged."
+  "All articles that have a score less than this variable will be expunged.
+This variable is local to the summary buffers."
   :group 'gnus-score-default
   :type '(choice (const :tag "off" nil)
                 integer))
@@ -580,7 +584,9 @@ Some functions you can use are `+', `max', or `min'."
 (defcustom gnus-thread-expunge-below nil
   "All threads that have a total score less than this variable will be expunged.
 See `gnus-thread-score-function' for en explanation of what a
-\"thread score\" is."
+\"thread score\" is.
+
+This variable is local to the summary buffers."
   :group 'gnus-treading
   :group 'gnus-score-default
   :type '(choice (const :tag "off" nil)
@@ -609,6 +615,11 @@ If you want to modify the summary buffer, you can use this hook."
   :group 'gnus-summary-various
   :type 'hook)
 
+(defcustom gnus-summary-prepared-hook nil
+  "*A hook called as the last thing after the summary buffer has been generated."
+  :group 'gnus-summary-various
+  :type 'hook)
+
 (defcustom gnus-summary-generate-hook nil
   "*A hook run just before generating the summary buffer.
 This hook is commonly used to customize threading variables and the
@@ -648,7 +659,6 @@ is not run if `gnus-visual' is nil."
   :group 'gnus-summary-visual
   :type 'hook)
 
-;; 1997/5/4 by MORIOKA Tomohiko <morioka@jaist.ac.jp>
 (defcustom gnus-structured-field-decoder 'identity
   "Function to decode non-ASCII characters in structured field for summary."
   :group 'gnus-various
@@ -727,7 +737,15 @@ automatically when it is selected."
      . gnus-summary-high-unread-face)
     ((and (< score default) (= mark gnus-unread-mark))
      . gnus-summary-low-unread-face)
-    ((and (= mark gnus-unread-mark))
+    ((= mark gnus-unread-mark)
+     . gnus-summary-normal-unread-face)
+    ((and (> score default) (memq mark (list gnus-downloadable-mark
+                                            gnus-undownloaded-mark)))
+     . gnus-summary-high-unread-face)
+    ((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))
      . gnus-summary-normal-unread-face)
     ((> score default)
      . gnus-summary-high-read-face)
@@ -735,7 +753,7 @@ automatically when it is selected."
      . gnus-summary-low-read-face)
     (t
      . gnus-summary-normal-read-face))
-  "Controls the highlighting of summary buffer lines.
+  "*Controls the highlighting of summary buffer lines.
 
 A list of (FORM . FACE) pairs.  When deciding how a a particular
 summary line should be displayed, each form is evaluated.  The content
@@ -1062,6 +1080,10 @@ See `gnus-simplify-buffer-fuzzy' for details."
   (save-excursion
     (gnus-set-work-buffer)
     (let ((case-fold-search t))
+      ;; Remove uninteresting prefixes.
+      (when (and gnus-simplify-ignored-prefixes
+                (string-match gnus-simplify-ignored-prefixes subject))
+       (setq subject (substring subject (match-end 0))))
       (insert subject)
       (inline (gnus-simplify-buffer-fuzzy))
       (buffer-string))))
@@ -1113,6 +1135,7 @@ increase the score of each group you read."
     " " gnus-summary-next-page
     "\177" gnus-summary-prev-page
     [delete] gnus-summary-prev-page
+    [backspace] gnus-summary-prev-page
     "\r" gnus-summary-scroll-up
     "n" gnus-summary-next-unread-article
     "p" gnus-summary-prev-unread-article
@@ -1198,6 +1221,7 @@ increase the score of each group you read."
     "\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
     "\C-c\C-b" gnus-bug
     "*" gnus-cache-enter-article
     "\M-*" gnus-cache-remove-article
@@ -1206,6 +1230,7 @@ increase the score of each group you read."
     "I" gnus-summary-increase-score
     "L" gnus-summary-lower-score
     "\M-i" gnus-symbolic-argument
+    "h" gnus-summary-select-article-buffer
     
     "V" gnus-summary-score-map
     "X" gnus-uu-extract-map
@@ -1343,7 +1368,8 @@ increase the score of each group you read."
     "t" gnus-article-hide-headers
     "v" gnus-summary-verbose-headers
     "m" gnus-summary-toggle-mime
-    "h" gnus-article-treat-html)
+    "h" gnus-article-treat-html
+    "d" gnus-article-treat-dumbquotes)
 
   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
     "a" gnus-article-hide
@@ -1367,6 +1393,7 @@ increase the score of each group you read."
     "l" gnus-article-date-local
     "e" gnus-article-date-lapsed
     "o" gnus-article-date-original
+    "i" gnus-article-date-iso8601
     "s" gnus-article-date-user)
 
   (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
@@ -1374,6 +1401,7 @@ increase the score of each group you read."
     "l" gnus-article-strip-leading-blank-lines
     "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)
 
   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
@@ -1567,6 +1595,7 @@ increase the score of each group you read."
        ["Citation" gnus-article-highlight-citation t])
        ("Date"
        ["Local" gnus-article-date-local t]
+       ["ISO8601" gnus-article-date-iso8601 t]
        ["UT" gnus-article-date-ut t]
        ["Original" gnus-article-date-original t]
        ["Lapsed" gnus-article-date-lapsed t]
@@ -1577,8 +1606,10 @@ increase the score of each group you read."
         ["Multiple" gnus-article-strip-multiple-blank-lines t]
         ["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])
        ["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]
        ["CR" gnus-article-remove-cr t]
@@ -1597,7 +1628,6 @@ increase the score of each group you read."
        ["Save in default format" gnus-summary-save-article t]
        ["Save in file" gnus-summary-save-article-file t]
        ["Save in Unix mail format" gnus-summary-save-article-mail t]
-       ["Write to file" gnus-summary-write-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]
@@ -1636,6 +1666,7 @@ increase the score of each group you read."
        ("Cache"
        ["Enter article" gnus-cache-enter-article t]
        ["Remove article" gnus-cache-remove-article 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]
        ["Beginning of the article" gnus-summary-beginning-of-article t]
@@ -1794,6 +1825,7 @@ increase the score of each group you read."
         'request-expire-articles gnus-newsgroup-name)]
        ["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]
        ("Exit"
        ["Catchup and exit" gnus-summary-catchup-and-exit t]
        ["Catchup all and exit" gnus-summary-catchup-and-exit t]
@@ -1806,7 +1838,7 @@ increase the score of each group you read."
        ["Rescan group" gnus-summary-rescan-group t]
        ["Update dribble" gnus-summary-save-newsrc t])))
 
-    (run-hooks 'gnus-summary-menu-hook)))
+    (gnus-run-hooks 'gnus-summary-menu-hook)))
 
 (defun gnus-score-set-default (var value)
   "A version of set that updates the GNU Emacs menu-bar."
@@ -1934,10 +1966,14 @@ The following commands are available:
   (setq gnus-newsgroup-name group)
   (make-local-variable 'gnus-summary-line-format)
   (make-local-variable 'gnus-summary-line-format-spec)
+  (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)
-  (run-hooks 'gnus-summary-mode-hook)
+  (make-local-hook 'pre-command-hook)
+  (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
+  (gnus-run-hooks 'gnus-summary-mode-hook)
   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
   (gnus-update-summary-mark-positions))
 
@@ -2148,10 +2184,12 @@ article number."
         (gnus-summary-last-subject))))
 
 (defmacro gnus-summary-article-header (&optional number)
+  "Return the header of article NUMBER."
   `(gnus-data-header (gnus-data-find
                      ,(or number '(gnus-summary-article-number)))))
 
 (defmacro gnus-summary-thread-level (&optional number)
+  "Return the level of thread that starts with article NUMBER."
   `(if (and (eq gnus-summary-make-false-root 'dummy)
            (get-text-property (point) 'gnus-intangible))
        0
@@ -2159,10 +2197,12 @@ article number."
                       ,(or number '(gnus-summary-article-number))))))
 
 (defmacro gnus-summary-article-mark (&optional number)
+  "Return the mark of article NUMBER."
   `(gnus-data-mark (gnus-data-find
                    ,(or number '(gnus-summary-article-number)))))
 
 (defmacro gnus-summary-article-pos (&optional number)
+  "Return the position of the line of article NUMBER."
   `(gnus-data-pos (gnus-data-find
                   ,(or number '(gnus-summary-article-number)))))
 
@@ -2185,6 +2225,7 @@ article number."
        gnus-summary-default-score 0))
 
 (defun gnus-summary-article-children (&optional number)
+  "Return a list of article numbers that are children of article NUMBER."
   (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))))
         (level (gnus-data-level (car data)))
         l children)
@@ -2196,6 +2237,7 @@ article number."
     (nreverse children)))
 
 (defun gnus-summary-article-parent (&optional number)
+  "Return the article number of the parent of article NUMBER."
   (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))
                                    (gnus-data-list t)))
         (level (gnus-data-level (car data))))
@@ -2220,6 +2262,11 @@ This is all marks except unread, ticked, dormant, and expirable."
           (= mark gnus-expirable-mark))))
 
 (defmacro gnus-article-mark (number)
+  "Return the MARK of article NUMBER.
+This macro should only be used when computing the mark the \"first\"
+time; i.e., when generating the summary lines.  After that,
+`gnus-summary-article-mark' should be used to examine the
+marks of articles."
   `(cond
     ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
     ((memq ,number gnus-newsgroup-undownloaded) gnus-undownloaded-mark)
@@ -2286,6 +2333,8 @@ This is all marks except unread, ticked, dormant, and expirable."
     ;; selective display).
     (aset table ?\n nil)
     (aset table ?\r nil)
+    ;; We keep TAB as well.
+    (aset table ?\t nil)
     ;; We nix out any glyphs over 126 that are not set already.
     (let ((i 256))
       (while (>= (setq i (1- i)) 127)
@@ -2334,17 +2383,17 @@ This is all marks except unread, ticked, dormant, and expirable."
          (score-file gnus-current-score-file))
       (save-excursion
        (set-buffer gnus-group-buffer)
-       (setq gnus-newsgroup-name name)
-       (setq gnus-newsgroup-marked marked)
-       (setq gnus-newsgroup-unreads unread)
-       (setq gnus-current-headers headers)
-       (setq gnus-newsgroup-data data)
-       (setq gnus-article-current gac)
-       (setq gnus-summary-buffer summary)
-       (setq gnus-article-buffer article-buffer)
-       (setq gnus-original-article-buffer original)
-       (setq gnus-reffed-article-number reffed)
-       (setq gnus-current-score-file score-file)
+       (setq gnus-newsgroup-name name
+             gnus-newsgroup-marked marked
+             gnus-newsgroup-unreads unread
+             gnus-current-headers headers
+             gnus-newsgroup-data data
+             gnus-article-current gac
+             gnus-summary-buffer summary
+             gnus-article-buffer article-buffer
+             gnus-original-article-buffer original
+             gnus-reffed-article-number reffed
+             gnus-current-score-file score-file)
        ;; The article buffer also has local variables.
        (when (gnus-buffer-live-p gnus-article-buffer)
          (set-buffer gnus-article-buffer)
@@ -2471,7 +2520,7 @@ This is all marks except unread, ticked, dormant, and expirable."
      'gnus-number gnus-tmp-number)
     (when (gnus-visual-p 'summary-highlight 'highlight)
       (forward-line -1)
-      (run-hooks 'gnus-summary-update-hook)
+      (gnus-run-hooks 'gnus-summary-update-hook)
       (forward-line 1))))
 
 (defun gnus-summary-update-line (&optional dont-update)
@@ -2503,7 +2552,7 @@ This is all marks except unread, ticked, dormant, and expirable."
         'score))
       ;; Do visual highlighting.
       (when (gnus-visual-p 'summary-highlight 'highlight)
-       (run-hooks 'gnus-summary-update-hook)))))
+       (gnus-run-hooks 'gnus-summary-update-hook)))))
 
 (defvar gnus-tmp-new-adopts nil)
 
@@ -2600,6 +2649,9 @@ If NO-DISPLAY, don't generate a summary buffer."
        (kill-buffer (current-buffer))
        (if (not quit-config)
            (progn
+             ;; Update the info -- marks might need to be removed,
+             ;; for instance.
+             (gnus-summary-update-info)
              (set-buffer gnus-group-buffer)
              (gnus-group-jump-to-group group)
              (gnus-group-next-unread-group 1))
@@ -2631,7 +2683,7 @@ If NO-DISPLAY, don't generate a summary buffer."
            (gnus-copy-sequence
             (gnus-active gnus-newsgroup-name)))
       ;; You can change the summary buffer in some way with this hook.
-      (run-hooks 'gnus-select-group-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
@@ -2669,7 +2721,7 @@ If NO-DISPLAY, don't generate a summary buffer."
              ((and gnus-newsgroup-scored show-all)
               (gnus-summary-limit-include-expunged t))))
       ;; Function `gnus-apply-kill-file' must be called in this hook.
-      (run-hooks 'gnus-apply-kill-hook)
+      (gnus-run-hooks 'gnus-apply-kill-hook)
       (if (and (zerop (buffer-size))
               (not no-display))
          (progn
@@ -2686,6 +2738,8 @@ If NO-DISPLAY, don't generate a summary buffer."
        (and gnus-show-threads
             gnus-thread-hide-subtree
             (gnus-summary-hide-all-threads))
+       (when kill-buffer
+         (gnus-kill-or-deaden-summary kill-buffer))
        ;; Show first unread article if requested.
        (if (and (not no-article)
                 (not no-display)
@@ -2699,10 +2753,8 @@ If NO-DISPLAY, don't generate a summary buffer."
          ;; article in the group.
          (goto-char (point-min))
          (gnus-summary-position-point)
-         (gnus-set-mode-line 'summary)
-         (gnus-configure-windows 'summary 'force))
-       (when kill-buffer
-         (gnus-kill-or-deaden-summary kill-buffer))
+         (gnus-configure-windows 'summary 'force)
+         (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.
@@ -2713,6 +2765,7 @@ If NO-DISPLAY, don't generate a summary buffer."
            (select-window owin)))
        ;; Mark this buffer as "prepared".
        (setq gnus-newsgroup-prepared t)
+       (gnus-run-hooks 'gnus-summary-prepared-hook)
        t)))))
 
 (defun gnus-summary-prepare ()
@@ -2722,7 +2775,7 @@ If NO-DISPLAY, don't generate a summary buffer."
     (erase-buffer)
     (setq gnus-newsgroup-data nil
          gnus-newsgroup-data-reverse nil)
-    (run-hooks 'gnus-summary-generate-hook)
+    (gnus-run-hooks 'gnus-summary-generate-hook)
     ;; Generate the buffer, either with threads or without.
     (when gnus-newsgroup-headers
       (gnus-summary-prepare-threads
@@ -2736,7 +2789,7 @@ If NO-DISPLAY, don't generate a summary buffer."
     (setq gnus-newsgroup-data (nreverse gnus-newsgroup-data))
     ;; Call hooks for modifying summary buffer.
     (goto-char (point-min))
-    (run-hooks 'gnus-summary-prepare-hook)))
+    (gnus-run-hooks 'gnus-summary-prepare-hook)))
 
 (defsubst gnus-general-simplify-subject (subject)
   "Simply subject by the same rules as gnus-gather-threads-by-subject."
@@ -2765,7 +2818,6 @@ If NO-DISPLAY, don't generate a summary buffer."
 (defun gnus-summary-simplify-subject-query ()
   "Query where the respool algorithm would put this article."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (message (gnus-general-simplify-subject (gnus-summary-article-subject))))
 
@@ -3663,7 +3715,7 @@ or a straight list of headers."
             'gnus-number number)
            (when gnus-visual-p
              (forward-line -1)
-             (run-hooks 'gnus-summary-update-hook)
+             (gnus-run-hooks 'gnus-summary-update-hook)
              (forward-line 1))
 
            (setq gnus-tmp-prev-subject subject)))
@@ -3967,7 +4019,7 @@ If READ-ALL is non-nil, all articles in the group are selected."
            (set var (delq article (symbol-value var))))))))))
 
 (defun gnus-update-missing-marks (missing)
-  "Go through the list of MISSING articles and remove them mark lists."
+  "Go through the list of MISSING articles and remove them from the mark lists."
   (when missing
     (let ((types gnus-article-mark-lists)
          var m)
@@ -4254,7 +4306,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
       (set-buffer nntp-server-buffer)
       ;; Translate all TAB characters into SPACE characters.
       (subst-char-in-region (point-min) (point-max) ?\t ?  t)
-      (run-hooks 'gnus-parse-headers-hook)
+      (gnus-run-hooks 'gnus-parse-headers-hook)
       (let ((case-fold-search t)
            in-reply-to header p lines)
        (goto-char (point-min))
@@ -4285,7 +4337,6 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nsubject: " nil t)
-                 ;; 1997/5/4 by MORIOKA Tomohiko <morioka@jaist.ac.jp>
                  (funcall
                   gnus-unstructured-field-decoder (nnheader-header-value))
                "(none)"))
@@ -4293,7 +4344,6 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nfrom: " nil t)
-                 ;; 1997/5/4 by MORIOKA Tomohiko <morioka@jaist.ac.jp>
                  (funcall
                   gnus-structured-field-decoder (nnheader-header-value))
                "(nobody)"))
@@ -4305,10 +4355,12 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            ;; Message-ID.
            (progn
              (goto-char p)
-             (setq id (if (search-forward "\nmessage-id:" nil t)
-                          (buffer-substring
-                           (1- (or (search-forward "<" nil t) (point)))
-                           (or (search-forward ">" nil t) (point)))
+             (setq id (if (re-search-forward
+                           "^message-id: *\\(<[^\n\t> ]+>\\)" nil t)
+                          ;; We do it this way to make sure the Message-ID
+                          ;; is (somewhat) syntactically valid.
+                          (buffer-substring (match-beginning 1)
+                                            (match-end 1))
                         ;; If there was no message-id, we just fake one
                         ;; to make subsequent routines simpler.
                         (nnheader-generate-fake-message-id))))
@@ -4335,8 +4387,14 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                (if (and (search-forward "\nin-reply-to: " nil t)
                         (setq in-reply-to (nnheader-header-value))
                         (string-match "<[^>]+>" in-reply-to))
-                   (setq ref (substring in-reply-to (match-beginning 0)
-                                        (match-end 0)))
+                   (let (ref2)
+                     (setq ref (substring in-reply-to (match-beginning 0)
+                                          (match-end 0)))
+                     (while (string-match "<[^>]+>" in-reply-to (match-end 0))
+                       (setq ref2 (substring in-reply-to (match-beginning 0)
+                                             (match-end 0)))
+                       (when (> (length ref2) (length ref))
+                         (setq ref ref2))))
                  (setq ref nil))))
            ;; Chars.
            0
@@ -4389,7 +4447,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                    (mail-header-set-id header id))
                (setcar (symbol-value id-dep) header))
            (set id-dep (list header)))
-         (when  header
+         (when header
            (if (boundp (setq ref-dep (intern (or ref "none") dependencies)))
                (setcdr (symbol-value ref-dep)
                        (nconc (cdr (symbol-value ref-dep))
@@ -4451,7 +4509,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                         (setq ref
                               (buffer-substring
                                (1+ (point))
-                               (search-backward "<" beg t)))
+                               (or (search-backward "<" beg t) beg)))
                       (setq ref nil))
                     (goto-char beg))
                   (gnus-nov-field))    ; refs
@@ -4519,7 +4577,7 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
     (save-excursion
       (set-buffer nntp-server-buffer)
       ;; Allow the user to mangle the headers before parsing them.
-      (run-hooks 'gnus-parse-headers-hook)
+      (gnus-run-hooks 'gnus-parse-headers-hook)
       (goto-char (point-min))
       (while (not (eobp))
        (condition-case ()
@@ -4581,8 +4639,13 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
 
 (defun gnus-summary-insert-subject (id &optional old-header use-old-header)
   "Find article ID and insert the summary line for that article."
-  (let ((header (if (and old-header use-old-header)
-                   old-header (gnus-read-header id)))
+  (let ((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))
        pos d)
     (when header
@@ -4604,6 +4667,7 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
            (delq (setq number (mail-header-number header))
                  gnus-newsgroup-sparse))
       (setq gnus-newsgroup-ancient (delq number gnus-newsgroup-ancient))
+      (push number gnus-newsgroup-limit)
       (gnus-rebuild-thread (mail-header-id header))
       (gnus-summary-goto-subject number nil t))
     (when (and (numberp number)
@@ -4627,44 +4691,47 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
   "Return a list of articles to be worked upon.         The prefix argument,
 the list of process marked articles, and the current article will be
 taken into consideration."
-  (cond
-   (n
-    ;; A numerical prefix has been given.
-    (setq n (prefix-numeric-value n))
-    (let ((backward (< n 0))
-         (n (abs (prefix-numeric-value n)))
-         articles article)
-      (save-excursion
-       (while
-           (and (> n 0)
-                (push (setq article (gnus-summary-article-number))
-                      articles)
-                (if backward
-                    (gnus-summary-find-prev nil article)
-                  (gnus-summary-find-next nil article)))
-         (decf n)))
-      (nreverse articles)))
-   ((gnus-region-active-p)
-    ;; Work on the region between point and mark.
-    (let ((max (max (point) (mark)))
-         articles article)
-      (save-excursion
-       (goto-char (min (point) (mark)))
-       (while
-           (and
-            (push (setq article (gnus-summary-article-number)) articles)
-            (gnus-summary-find-next nil article)
-            (< (point) max)))
-       (nreverse articles))))
-   (gnus-newsgroup-processable
-    ;; There are process-marked articles present.
-    ;; Save current state.
-    (gnus-summary-save-process-mark)
-    ;; Return the list.
-    (reverse gnus-newsgroup-processable))
-   (t
-    ;; Just return the current article.
-    (list (gnus-summary-article-number)))))
+  (save-excursion
+    (set-buffer gnus-summary-buffer)
+    (cond
+     (n
+      ;; A numerical prefix has been given.
+      (setq n (prefix-numeric-value n))
+      (let ((backward (< n 0))
+           (n (abs (prefix-numeric-value n)))
+           articles article)
+       (save-excursion
+         (while
+             (and (> n 0)
+                  (push (setq article (gnus-summary-article-number))
+                        articles)
+                  (if backward
+                      (gnus-summary-find-prev nil article)
+                    (gnus-summary-find-next nil article)))
+           (decf n)))
+       (nreverse articles)))
+     ((and (gnus-region-active-p) (mark))
+      (message "region active")
+      ;; Work on the region between point and mark.
+      (let ((max (max (point) (mark)))
+           articles article)
+       (save-excursion
+         (goto-char (min (min (point) (mark))))
+         (while
+             (and
+              (push (setq article (gnus-summary-article-number)) articles)
+              (gnus-summary-find-next nil article)
+              (< (point) max)))
+         (nreverse articles))))
+     (gnus-newsgroup-processable
+      ;; There are process-marked articles present.
+      ;; Save current state.
+      (gnus-summary-save-process-mark)
+      ;; Return the list.
+      (reverse gnus-newsgroup-processable))
+     (t
+      ;; Just return the current article.
+      (list (gnus-summary-article-number))))))
 
 (defun gnus-summary-save-process-mark ()
   "Push the current set of process marked articles on the stack."
@@ -4898,10 +4965,17 @@ displayed, no centering will be performed."
 
 ;; Various summary commands
 
+(defun gnus-summary-select-article-buffer ()
+  "Reconfigure windows to show article buffer."
+  (interactive)
+  (if (not (gnus-buffer-live-p gnus-article-buffer))
+      (error "There is no article buffer for this summary buffer")
+    (gnus-configure-windows 'article)
+    (select-window (get-buffer-window gnus-article-buffer))))
+
 (defun gnus-summary-universal-argument (arg)
   "Perform any operation on all articles that are process/prefixed."
   (interactive "P")
-  (gnus-set-global-variables)
   (let ((articles (gnus-summary-work-articles arg))
        func article)
     (if (eq
@@ -4935,7 +5009,6 @@ With arg, turn line truncation on iff arg is positive."
   "Exit and then reselect the current newsgroup.
 The prefix argument ALL means to select all articles."
   (interactive "P")
-  (gnus-set-global-variables)
   (when (gnus-ephemeral-group-p gnus-newsgroup-name)
     (error "Ephemeral groups can't be reselected"))
   (let ((current-subject (gnus-summary-article-number))
@@ -4959,43 +5032,39 @@ The prefix argument ALL means to select all articles."
 (defun gnus-summary-update-info (&optional non-destructive)
   (save-excursion
     (let ((group gnus-newsgroup-name))
-      (when gnus-newsgroup-kill-headers
-       (setq gnus-newsgroup-killed
-             (gnus-compress-sequence
-              (nconc
-               (gnus-set-sorted-intersection
-                (gnus-uncompress-range gnus-newsgroup-killed)
-                (setq gnus-newsgroup-unselected
-                      (sort gnus-newsgroup-unselected '<)))
-               (setq gnus-newsgroup-unreads
-                     (sort gnus-newsgroup-unreads '<)))
-              t)))
-      (unless (listp (cdr gnus-newsgroup-killed))
-       (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
-      (let ((headers gnus-newsgroup-headers))
-       (when (and (not gnus-save-score)
-                  (not non-destructive))
-         (setq gnus-newsgroup-scored nil))
-       ;; Set the new ranges of read articles.
-       (save-excursion
+      (when group
+       (when gnus-newsgroup-kill-headers
+         (setq gnus-newsgroup-killed
+               (gnus-compress-sequence
+                (nconc
+                 (gnus-set-sorted-intersection
+                  (gnus-uncompress-range gnus-newsgroup-killed)
+                  (setq gnus-newsgroup-unselected
+                        (sort gnus-newsgroup-unselected '<)))
+                 (setq gnus-newsgroup-unreads
+                       (sort gnus-newsgroup-unreads '<)))
+                t)))
+       (unless (listp (cdr gnus-newsgroup-killed))
+         (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
+       (let ((headers gnus-newsgroup-headers))
+         (when (and (not gnus-save-score)
+                    (not non-destructive))
+           (setq gnus-newsgroup-scored nil))
+         ;; Set the new ranges of read articles.
+         (save-excursion
+           (set-buffer gnus-group-buffer)
+           (gnus-undo-force-boundary))
+         (gnus-update-read-articles
+          group (append gnus-newsgroup-unreads gnus-newsgroup-unselected))
+         ;; Set the current article marks.
+         (gnus-update-marks)
+         ;; Do the cross-ref thing.
+         (when gnus-use-cross-reference
+           (gnus-mark-xrefs-as-read group headers gnus-newsgroup-unreads))
+         ;; Do not switch windows but change the buffer to work.
          (set-buffer gnus-group-buffer)
-         (gnus-undo-force-boundary))
-       (gnus-update-read-articles
-        group (append gnus-newsgroup-unreads gnus-newsgroup-unselected))
-       ;; Set the current article marks.
-       (gnus-update-marks)
-       ;; Do the cross-ref thing.
-       (when gnus-use-cross-reference
-         (gnus-mark-xrefs-as-read group headers gnus-newsgroup-unreads))
-       ;; Do adaptive scoring, and possibly save score files.
-       (when gnus-newsgroup-adaptive
-         (gnus-score-adaptive))
-       (when gnus-use-scoring
-         (gnus-score-save))
-       ;; Do not switch windows but change the buffer to work.
-       (set-buffer gnus-group-buffer)
-       (unless (gnus-ephemeral-group-p gnus-newsgroup-name)
-         (gnus-group-update-group group))))))
+         (unless (gnus-ephemeral-group-p group)
+           (gnus-group-update-group group)))))))
 
 (defun gnus-summary-save-newsrc (&optional force)
   "Save the current number of read/marked articles in the dribble buffer.
@@ -5013,12 +5082,13 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
   (interactive)
   (gnus-set-global-variables)
   (gnus-kill-save-kill-buffer)
+  (gnus-async-halt-prefetch)
   (let* ((group gnus-newsgroup-name)
         (quit-config (gnus-group-quit-config gnus-newsgroup-name))
         (mode major-mode)
          (group-point nil)
         (buf (current-buffer)))
-    (run-hooks 'gnus-summary-prepare-exit-hook)
+    (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
     ;; If we have several article buffers, we kill them at exit.
     (unless gnus-single-article-buffer
       (gnus-kill-buffer gnus-original-article-buffer)
@@ -5031,17 +5101,27 @@ 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))
+    ;; Remove entries for this group.
+    (nnmail-purge-split-history (gnus-group-real-name group))
     ;; Make all changes in this group permanent.
     (unless quit-config
-      (run-hooks 'gnus-exit-group-hook)
-      (gnus-summary-update-info))
+      (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-close-group group)
     ;; Make sure where we were, and go to next newsgroup.
     (set-buffer gnus-group-buffer)
     (unless quit-config
       (gnus-group-jump-to-group group))
-    (run-hooks 'gnus-summary-exit-hook)
-    (unless quit-config
+    (gnus-run-hooks 'gnus-summary-exit-hook)
+    (unless (or quit-config
+               ;; If this group has disappeared from the summary
+               ;; buffer, don't skip forwards.
+               (not (string= group (gnus-group-group-name))))
       (gnus-group-next-unread-group 1))
     (setq group-point (point))
     (if temporary
@@ -5083,12 +5163,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
 (defun gnus-summary-exit-no-update (&optional no-questions)
   "Quit reading current newsgroup without updating read article info."
   (interactive)
-  (gnus-set-global-variables)
   (let* ((group gnus-newsgroup-name)
         (quit-config (gnus-group-quit-config group)))
     (when (or no-questions
              gnus-expert-user
              (gnus-y-or-n-p "Discard changes to this group and exit? "))
+      (gnus-async-halt-prefetch)
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
        (gnus-kill-buffer gnus-article-buffer)
@@ -5200,25 +5280,26 @@ which existed when entering the ephemeral is reset."
 
 (defun gnus-kill-or-deaden-summary (buffer)
   "Kill or deaden the summary BUFFER."
-  (when (and (buffer-name buffer)
-            (not gnus-single-article-buffer))
-    (save-excursion
-      (set-buffer buffer)
-      (gnus-kill-buffer gnus-article-buffer)
-      (gnus-kill-buffer gnus-original-article-buffer)))
-  (cond (gnus-kill-summary-on-exit
-        (when (and gnus-use-trees
-                   (and (get-buffer buffer)
-                        (buffer-name (get-buffer buffer))))
+  (save-excursion
+    (when (and (buffer-name buffer)
+              (not gnus-single-article-buffer))
+      (save-excursion
+       (set-buffer buffer)
+       (gnus-kill-buffer gnus-article-buffer)
+       (gnus-kill-buffer gnus-original-article-buffer)))
+    (cond (gnus-kill-summary-on-exit
+          (when (and gnus-use-trees
+                     (and (get-buffer buffer)
+                          (buffer-name (get-buffer buffer))))
+            (save-excursion
+              (set-buffer (get-buffer buffer))
+              (gnus-tree-close gnus-newsgroup-name)))
+          (gnus-kill-buffer buffer))
+         ((and (get-buffer buffer)
+               (buffer-name (get-buffer buffer)))
           (save-excursion
-            (set-buffer (get-buffer buffer))
-            (gnus-tree-close gnus-newsgroup-name)))
-        (gnus-kill-buffer buffer))
-       ((and (get-buffer buffer)
-             (buffer-name (get-buffer buffer)))
-        (save-excursion
-          (set-buffer buffer)
-          (gnus-deaden-summary)))))
+            (set-buffer buffer)
+            (gnus-deaden-summary))))))
 
 (defun gnus-summary-wake-up-the-dead (&rest args)
   "Wake up the dead summary buffer."
@@ -5269,7 +5350,6 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected
 initially.  If NEXT-GROUP, go to this group.  If BACKWARD, go to
 previous group instead."
   (interactive "P")
-  (gnus-set-global-variables)
   ;; Stop pre-fetching.
   (gnus-async-halt-prefetch)
   (let ((current-group gnus-newsgroup-name)
@@ -5298,7 +5378,7 @@ previous group instead."
            (when (gnus-buffer-live-p current-buffer)
              (set-buffer current-buffer)
              (gnus-summary-exit))
-           (run-hooks 'gnus-group-no-more-groups-hook))
+           (gnus-run-hooks 'gnus-group-no-more-groups-hook))
        ;; We try to enter the target group.
        (gnus-group-jump-to-group target-group)
        (let ((unreads (gnus-group-group-unread)))
@@ -5413,7 +5493,6 @@ If FORCE, also allow jumping to articles not currently shown."
   "Make the summary buffer take up the entire Emacs frame.
 Given a prefix, will force an `article' buffer configuration."
   (interactive "P")
-  (gnus-set-global-variables)
   (if arg
       (gnus-configure-windows 'article 'force)
     (gnus-configure-windows 'summary 'force)))
@@ -5427,7 +5506,7 @@ Given a prefix, will force an `article' buffer configuration."
        (if gnus-summary-display-article-function
            (funcall gnus-summary-display-article-function article all-header)
          (gnus-article-prepare article all-header))
-      (run-hooks 'gnus-select-article-hook)
+      (gnus-run-hooks 'gnus-select-article-hook)
       (when (and gnus-current-article
                 (not (zerop gnus-current-article)))
        (gnus-summary-goto-subject gnus-current-article))
@@ -5490,7 +5569,6 @@ If UNREAD, only unread articles are selected.
 If SUBJECT, only articles with SUBJECT are selected.
 If BACKWARD, the previous article is selected instead of the next."
   (interactive "P")
-  (gnus-set-global-variables)
   (cond
    ;; Is there such an article?
    ((and (gnus-summary-search-forward unread subject backward)
@@ -5664,7 +5742,6 @@ Argument LINES specifies lines to be scrolled down.
 If MOVE, move to the previous unread article if point is at
 the beginning of the buffer."
   (interactive "P")
-  (gnus-set-global-variables)
   (let ((article (gnus-summary-article-number))
        (article-window (get-buffer-window gnus-article-buffer t))
        endp)
@@ -5700,7 +5777,6 @@ If at the beginning of the article, go to the next article."
   "Scroll up (or down) one line current article.
 Argument LINES specifies lines to be scrolled up (or down if negative)."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-configure-windows 'article)
   (gnus-summary-show-thread)
   (when (eq (gnus-summary-select-article nil nil 'pseudo) 'old)
@@ -5716,32 +5792,27 @@ Argument LINES specifies lines to be scrolled up (or down if negative)."
 (defun gnus-summary-next-same-subject ()
   "Select next article which has the same subject as current one."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-next-article nil (gnus-summary-article-subject)))
 
 (defun gnus-summary-prev-same-subject ()
   "Select previous article which has the same subject as current one."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-prev-article nil (gnus-summary-article-subject)))
 
 (defun gnus-summary-next-unread-same-subject ()
   "Select next unread article which has the same subject as current one."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-next-article t (gnus-summary-article-subject)))
 
 (defun gnus-summary-prev-unread-same-subject ()
   "Select previous unread article which has the same subject as current one."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-prev-article t (gnus-summary-article-subject)))
 
 (defun gnus-summary-first-unread-article ()
   "Select the first unread article.
 Return nil if there are no unread articles."
   (interactive)
-  (gnus-set-global-variables)
   (prog1
       (when (gnus-summary-first-subject t)
        (gnus-summary-show-thread)
@@ -5753,7 +5824,6 @@ Return nil if there are no unread articles."
   "Select the first article.
 Return nil if there are no articles."
   (interactive)
-  (gnus-set-global-variables)
   (prog1
       (when (gnus-summary-first-subject)
       (gnus-summary-show-thread)
@@ -5764,7 +5834,6 @@ Return nil if there are no articles."
 (defun gnus-summary-best-unread-article ()
   "Select the unread article with the highest score."
   (interactive)
-  (gnus-set-global-variables)
   (let ((best -1000000)
        (data gnus-newsgroup-data)
        article score)
@@ -5815,7 +5884,7 @@ If ALL-HEADERS is non-nil, no header lines are hidden."
   (interactive)
   (prog1
       (when gnus-last-article
-       (gnus-summary-goto-article gnus-last-article))
+       (gnus-summary-goto-article gnus-last-article nil t))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-pop-article (number)
@@ -5836,7 +5905,6 @@ NUMBER articles will be popped off."
   "Limit the summary buffer to the next N articles.
 If not given a prefix, use the process marked articles instead."
   (interactive "P")
-  (gnus-set-global-variables)
   (prog1
       (let ((articles (gnus-summary-work-articles n)))
        (setq gnus-newsgroup-processable nil)
@@ -5847,7 +5915,6 @@ If not given a prefix, use the process marked articles instead."
   "Restore the previous limit.
 If given a prefix, remove all limits."
   (interactive "P")
-  (gnus-set-global-variables)
   (when total
     (setq gnus-newsgroup-limits
          (list (mapcar (lambda (h) (mail-header-number h))
@@ -5936,7 +6003,6 @@ not marked with MARKS.  MARKS can either be a string of marks or a
 list of marks.
 Returns how many articles were removed."
   (interactive "sMarks: \nP")
-  (gnus-set-global-variables)
   (prog1
       (let ((data gnus-newsgroup-data)
            (marks (if (listp marks) marks
@@ -5953,7 +6019,6 @@ Returns how many articles were removed."
 (defun gnus-summary-limit-to-score (&optional score)
   "Limit to articles with score at or above SCORE."
   (interactive "P")
-  (gnus-set-global-variables)
   (setq score (if score
                  (prefix-numeric-value score)
                (or gnus-summary-default-score 0)))
@@ -5970,8 +6035,7 @@ Returns how many articles were removed."
 
 (defun gnus-summary-limit-include-thread (id)
   "Display all the hidden articles that in the current thread."
-  (interactive (mail-header-id (gnus-summary-article-header)))
-  (gnus-set-global-variables)
+  (interactive (list (mail-header-id (gnus-summary-article-header))))
   (let ((articles (gnus-articles-in-thread
                   (gnus-id-to-thread (gnus-root-id id)))))
     (prog1
@@ -5979,9 +6043,10 @@ Returns how many articles were removed."
       (gnus-summary-position-point))))
 
 (defun gnus-summary-limit-include-dormant ()
-  "Display all the hidden articles that are marked as dormant."
+  "Display all the hidden articles that are marked as dormant.
+Note that this command only works on a subset of the articles currently
+fetched for this group."
   (interactive)
-  (gnus-set-global-variables)
   (unless gnus-newsgroup-dormant
     (error "There are no dormant articles in this group"))
   (prog1
@@ -5991,7 +6056,6 @@ Returns how many articles were removed."
 (defun gnus-summary-limit-exclude-dormant ()
   "Hide all dormant articles."
   (interactive)
-  (gnus-set-global-variables)
   (prog1
       (gnus-summary-limit-to-marks (list gnus-dormant-mark) 'reverse)
     (gnus-summary-position-point)))
@@ -5999,7 +6063,6 @@ Returns how many articles were removed."
 (defun gnus-summary-limit-exclude-childless-dormant ()
   "Hide all dormant articles that have no children."
   (interactive)
-  (gnus-set-global-variables)
   (let ((data (gnus-data-list t))
        articles d children)
     ;; Find all articles that are either not dormant or have
@@ -6263,7 +6326,6 @@ fetch-old-headers verbiage, and so on."
 If N is negative, go to ancestor -N instead.
 The difference between N and the number of articles fetched is returned."
   (interactive "p")
-  (gnus-set-global-variables)
   (let ((skip 1)
        error header ref)
     (when (not (natnump n))
@@ -6306,7 +6368,6 @@ The difference between N and the number of articles fetched is returned."
   "Fetch all articles mentioned in the References header.
 Return the number of articles fetched."
   (interactive)
-  (gnus-set-global-variables)
   (let ((ref (mail-header-references (gnus-summary-article-header)))
        (current (gnus-summary-article-number))
        (n 0))
@@ -6329,7 +6390,6 @@ Return the number of articles fetched."
 If LIMIT (the numerical prefix), fetch that many old headers instead
 of what's specified by the `gnus-refer-thread-limit' variable."
   (interactive "P")
-  (gnus-set-global-variables)
   (let ((id (mail-header-id (gnus-summary-article-header)))
        (limit (if limit (prefix-numeric-value limit)
                 gnus-refer-thread-limit))
@@ -6368,17 +6428,20 @@ 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))))
-      (if (and header
-              (or (not (gnus-summary-article-sparse-p
-                        (mail-header-number header)))
-                  sparse))
-         (prog1
-              ;; The article is present in the buffer, so we just go to it.
-             (gnus-summary-goto-article
-               (mail-header-number header) nil t)
-           (when sparse
-             (gnus-summary-update-article (mail-header-number header))))
+                             gnus-newsgroup-limit)))
+          h)
+      (cond
+       ;; If the article is present in the buffer we just go to it.
+       ((and header
+            (or (not (gnus-summary-article-sparse-p
+                      (mail-header-number header)))
+                sparse))
+       (prog1
+           (gnus-summary-goto-article
+            (mail-header-number header) nil t)
+         (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)
@@ -6394,14 +6457,17 @@ or `gnus-select-method', no matter what backend the article comes from."
          ;; Fetch the header, and display the article.
          (if (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)))))))
+           (gnus-message 3 "Couldn't fetch article %s" message-id))))))))
+
+(defun gnus-summary-edit-parameters ()
+  "Edit the group parameters of the current group."
+  (gnus-group-edit-group gnus-newsgroup-name 'params))
 
 (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
 to guess what the document format is."
   (interactive "P")
-  (gnus-set-global-variables)
   (let ((conf gnus-current-window-configuration))
     (save-excursion
       (gnus-summary-select-article))
@@ -6499,12 +6565,12 @@ Obeys the standard process/prefix convention."
   "Do incremental search forward on the current article.
 If REGEXP-P (the prefix) is non-nil, do regexp isearch."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (gnus-configure-windows 'article)
   (gnus-eval-in-buffer-window gnus-article-buffer
-    ;;(goto-char (point-min))
-    (isearch-forward regexp-p)))
+    (save-restriction
+      (widen)
+      (isearch-forward regexp-p))))
 
 (defun gnus-summary-search-article-forward (regexp &optional backward)
   "Search for an article containing REGEXP forward.
@@ -6517,7 +6583,6 @@ If BACKWARD, search backward instead."
                      (concat ", default " gnus-last-search-regexp)
                    "")))
         current-prefix-arg))
-  (gnus-set-global-variables)
   (if (string-equal regexp "")
       (setq regexp (or gnus-last-search-regexp ""))
     (setq gnus-last-search-regexp regexp))
@@ -6639,7 +6704,6 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
         current-prefix-arg))
   (when (equal header "Body")
     (setq header ""))
-  (gnus-set-global-variables)
   ;; Hidden thread subtrees must be searched as well.
   (gnus-summary-show-all-threads)
   ;; We don't want to change current point nor window configuration.
@@ -6655,7 +6719,6 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
 (defun gnus-summary-beginning-of-article ()
   "Scroll the article back to the beginning."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (gnus-configure-windows 'article)
   (gnus-eval-in-buffer-window gnus-article-buffer
@@ -6667,7 +6730,6 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
 (defun gnus-summary-end-of-article ()
   "Scroll to the end of the article."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (gnus-configure-windows 'article)
   (gnus-eval-in-buffer-window gnus-article-buffer
@@ -6677,32 +6739,47 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
     (when gnus-page-broken
       (gnus-narrow-to-page))))
 
-(defun gnus-summary-print-article (&optional filename)
-  "Generate and print a PostScript image of the article buffer.
+(defun gnus-summary-print-article (&optional filename n)
+  "Generate and print a PostScript image of the N next (mail) articles.
 
-If the optional 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
+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
+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)))
-  (gnus-summary-select-article)
-  (gnus-eval-in-buffer-window gnus-article-buffer
-    (let ((buffer (generate-new-buffer " *print*")))
-      (unwind-protect
-         (progn
-           (copy-to-buffer buffer (point-min) (point-max))
-           (set-buffer buffer)
-           (gnus-article-delete-invisible-text)
-           (run-hooks 'gnus-ps-print-hook)
-           (ps-print-buffer-with-faces filename))
-       (kill-buffer buffer)))))
+  (interactive (list (ps-print-preprint current-prefix-arg)
+                    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
+      (let ((buffer (generate-new-buffer " *print*")))
+       (unwind-protect
+           (progn
+             (copy-to-buffer buffer (point-min) (point-max))
+             (set-buffer buffer)
+             (gnus-article-delete-invisible-text)
+             (let ((ps-left-header
+                    (list 
+                     (concat "("
+                             (mail-header-subject gnus-current-headers) ")")
+                     (concat "("
+                             (mail-header-from gnus-current-headers) ")")))
+                   (ps-right-header 
+                    (list 
+                     "/pagenumberstring load" 
+                     (concat "("
+                             (mail-header-date gnus-current-headers) ")"))))
+               (gnus-run-hooks 'gnus-ps-print-hook)
+               (ps-print-buffer-with-faces filename)))
+         (kill-buffer buffer))))))
 
 (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."
   (interactive "P")
-  (gnus-set-global-variables)
   (if (not arg)
       ;; Select the article the normal way.
       (gnus-summary-select-article nil 'force)
@@ -6722,7 +6799,6 @@ article massaging functions being run."
 If ARG is a positive number, turn header display on.
 If ARG is a negative number, turn header display off."
   (interactive "P")
-  (gnus-set-global-variables)
   (setq gnus-show-all-headers
        (cond ((or (not (numberp arg))
                   (zerop arg))
@@ -6736,7 +6812,6 @@ If ARG is a negative number, turn header display off."
 If ARG is a positive number, show the entire header.
 If ARG is a negative number, hide the unwanted header lines."
   (interactive "P")
-  (gnus-set-global-variables)
   (save-excursion
     (set-buffer gnus-article-buffer)
     (let* ((buffer-read-only nil)
@@ -6755,21 +6830,19 @@ If ARG is a negative number, hide the unwanted header lines."
        (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))
-       (run-hooks 'gnus-article-display-hook))
+       (gnus-run-hooks 'gnus-article-display-hook))
       (when (or (not hidden) (and (numberp arg) (< arg 0)))
        (gnus-article-hide-headers)))))
 
 (defun gnus-summary-show-all-headers ()
   "Make all header lines visible."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-article-show-all-headers))
 
 (defun gnus-summary-toggle-mime (&optional arg)
   "Toggle MIME processing.
 If ARG is a positive number, turn MIME processing on."
   (interactive "P")
-  (gnus-set-global-variables)
   (setq gnus-show-mime
        (if (null arg) (not gnus-show-mime)
          (> (prefix-numeric-value arg) 0)))
@@ -6780,7 +6853,6 @@ If ARG is a positive number, turn MIME processing on."
 The numerical prefix specifies how many places to rotate each letter
 forward."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (let ((mail-header-separator ""))
     (gnus-eval-in-buffer-window gnus-article-buffer
@@ -6794,14 +6866,14 @@ forward."
 (defun gnus-summary-stop-page-breaking ()
   "Stop page breaking in the current article."
   (interactive)
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
     (widen)
     (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-remove-text-with-property 'gnus-next))
+      (setq gnus-page-broken nil))))
 
 (defun gnus-summary-move-article (&optional n to-newsgroup
                                            select-method action)
@@ -6820,7 +6892,6 @@ and `request-accept' functions."
   (interactive "P")
   (unless action
     (setq action 'move))
-  (gnus-set-global-variables)
   ;; Disable marking as read.
   (let (gnus-mark-article-hook)
     (save-window-excursion
@@ -6886,9 +6957,9 @@ and `request-accept' functions."
        ((eq action 'copy)
         (save-excursion
           (set-buffer copy-buf)
-          (gnus-request-article-this-buffer article gnus-newsgroup-name)
-          (gnus-request-accept-article
-           to-newsgroup select-method (not articles))))
+          (when (gnus-request-article-this-buffer article gnus-newsgroup-name)
+            (gnus-request-accept-article
+             to-newsgroup select-method (not articles)))))
        ;; Crosspost the article.
        ((eq action 'crosspost)
         (let ((xref (message-tokenize-header
@@ -7005,6 +7076,9 @@ and `request-accept' functions."
              (gnus-request-replace-article
               article gnus-newsgroup-name (current-buffer)))))
 
+       ;;;!!!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))))
@@ -7077,7 +7151,6 @@ latter case, they will be copied into the relevant groups."
             (let ((ms-alist (mapcar (lambda (m) (cons (cadr m) m)) ms)))
               (cdr (assoc (completing-read "Server name: " ms-alist nil t)
                           ms-alist))))))))
-  (gnus-set-global-variables)
   (unless method
     (error "No method given for respooling"))
   (if (assoc (symbol-name
@@ -7089,7 +7162,6 @@ latter case, they will be copied into the relevant groups."
 (defun gnus-summary-import-article (file)
   "Import a random file into a mail newsgroup."
   (interactive "fImport file: ")
-  (gnus-set-global-variables)
   (let ((group gnus-newsgroup-name)
        (now (current-time))
        atts lines)
@@ -7138,7 +7210,6 @@ This will be the case if the article has both been mailed and posted."
 (defun gnus-summary-expire-articles (&optional now)
   "Expire all articles that are marked as expirable in the current group."
   (interactive)
-  (gnus-set-global-variables)
   (when (gnus-check-backend-function
         'request-expire-articles gnus-newsgroup-name)
     ;; This backend supports expiry.
@@ -7148,7 +7219,7 @@ This will be the case if the article has both been mailed and posted."
                            ;; We need to update the info for
                            ;; this group for `gnus-list-of-read-articles'
                            ;; to give us the right answer.
-                           (run-hooks 'gnus-exit-group-hook)
+                           (gnus-run-hooks 'gnus-exit-group-hook)
                            (gnus-summary-update-info)
                            (gnus-list-of-read-articles gnus-newsgroup-name))
                        (setq gnus-newsgroup-expirable
@@ -7162,13 +7233,14 @@ This will be the case if the article has both been mailed and posted."
        ;; through the expiry process.
        (gnus-message 6 "Expiring articles...")
        ;; The list of articles that weren't expired is returned.
-       (if expiry-wait
-           (let ((nnmail-expiry-wait-function nil)
-                 (nnmail-expiry-wait expiry-wait))
-             (setq es (gnus-request-expire-articles
-                       expirable gnus-newsgroup-name)))
-         (setq es (gnus-request-expire-articles
-                   expirable gnus-newsgroup-name)))
+       (save-excursion
+         (if expiry-wait
+             (let ((nnmail-expiry-wait-function nil)
+                   (nnmail-expiry-wait expiry-wait))
+               (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
@@ -7188,11 +7260,10 @@ This will be the case if the article has both been mailed and posted."
 This means that *all* articles that are marked as expirable will be
 deleted forever, right now."
   (interactive)
-  (gnus-set-global-variables)
-  (or gnus-expert-user
-      (gnus-yes-or-no-p
-       "Are you really, really, really sure you want to delete all these messages? ")
-      (error "Phew!"))
+  (unless gnus-expert-user
+    (gnus-yes-or-no-p
+     "Are you really, really, really sure you want to delete all these messages? ")
+    (error "Phew!"))
   (gnus-summary-expire-articles t))
 
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
@@ -7205,7 +7276,6 @@ If N is negative, delete backwards.
 If N is nil and articles have been marked with the process mark,
 delete these instead."
   (interactive "P")
-  (gnus-set-global-variables)
   (unless (gnus-check-backend-function 'request-expire-articles
                                       gnus-newsgroup-name)
     (error "The current newsgroup does not support article deletion"))
@@ -7306,14 +7376,14 @@ groups."
     (unless no-highlight
       (save-excursion
        (set-buffer gnus-article-buffer)
-       (run-hooks 'gnus-article-display-hook)
+       (gnus-run-hooks 'gnus-article-display-hook)
        (set-buffer gnus-original-article-buffer)
        (gnus-request-article
         (cdr gnus-article-current)
         (car gnus-article-current) (current-buffer))))
     ;; Prettify the summary buffer line.
     (when (gnus-visual-p 'summary-highlight 'highlight)
-      (run-hooks 'gnus-visual-mark-article-hook))))
+      (gnus-run-hooks 'gnus-visual-mark-article-hook))))
 
 (defun gnus-summary-edit-wash (key)
   "Perform editing command in the article buffer."
@@ -7332,7 +7402,6 @@ groups."
 (defun gnus-summary-respool-query (&optional silent)
   "Query where the respool algorithm would put this article."
   (interactive)
-  (gnus-set-global-variables)
   (let (gnus-mark-article-hook)
     (gnus-summary-select-article)
     (save-excursion
@@ -7354,7 +7423,6 @@ groups."
 If UNMARK is positive, remove any kind of mark.
 If UNMARK is negative, tick articles."
   (interactive "P")
-  (gnus-set-global-variables)
   (when unmark
     (setq unmark (prefix-numeric-value unmark)))
   (let ((count
@@ -7373,7 +7441,6 @@ If UNMARK is negative, tick articles."
 If UNMARK is positive, remove any kind of mark.
 If UNMARK is negative, tick articles."
   (interactive "P")
-  (gnus-set-global-variables)
   (when unmark
     (setq unmark (prefix-numeric-value unmark)))
   (let ((count
@@ -7424,7 +7491,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((backward (< n 0))
        (n (abs n)))
     (while (and
@@ -7446,13 +7512,11 @@ number of articles marked is returned."
 If N is negative, unmark backward instead.  The difference between N and
 the actual number of articles unmarked is returned."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-summary-mark-as-processable n t))
 
 (defun gnus-summary-unmark-all-processable ()
   "Remove the process mark from all articles."
   (interactive)
-  (gnus-set-global-variables)
   (save-excursion
     (while gnus-newsgroup-processable
       (gnus-summary-remove-process-mark (car gnus-newsgroup-processable))))
@@ -7463,7 +7527,6 @@ the actual number of articles unmarked is returned."
 If N is negative, mark backward instead.  The difference between N and
 the actual number of articles marked is returned."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-summary-mark-forward n gnus-expirable-mark))
 
 (defun gnus-summary-mark-article-as-replied (article)
@@ -7475,8 +7538,7 @@ the actual number of articles marked is returned."
 
 (defun gnus-summary-set-bookmark (article)
   "Set a bookmark in current article."
-  (interactive (gnus-summary-article-number))
-  (gnus-set-global-variables)
+  (interactive (list (gnus-summary-article-number)))
   (when (or (not (get-buffer gnus-article-buffer))
            (not gnus-current-article)
            (not gnus-article-current)
@@ -7505,8 +7567,7 @@ the actual number of articles marked is returned."
 
 (defun gnus-summary-remove-bookmark (article)
   "Remove the bookmark from the current article."
-  (interactive (gnus-summary-article-number))
-  (gnus-set-global-variables)
+  (interactive (list (gnus-summary-article-number)))
   ;; Remove old bookmark, if one exists.
   (let ((old (assq article gnus-newsgroup-bookmarks)))
     (if old
@@ -7522,7 +7583,6 @@ the actual number of articles marked is returned."
 If N is negative, mark backward instead.  The difference between N and
 the actual number of articles marked is returned."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-summary-mark-forward n gnus-dormant-mark))
 
 (defun gnus-summary-set-process-mark (article)
@@ -7553,7 +7613,6 @@ 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."
   (interactive "p")
-  (gnus-set-global-variables)
   (let ((backward (< n 0))
        (gnus-summary-goto-unread
         (and gnus-summary-goto-unread
@@ -7604,36 +7663,41 @@ returned."
 
 (defun gnus-summary-mark-article-as-unread (mark)
   "Mark the current article quickly as unread with MARK."
-  (let ((article (gnus-summary-article-number)))
-    (if (<= article 0)
-       (gnus-error 1 "Can't mark negative article numbers")
-      (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
-      (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
-      (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
-      (setq gnus-newsgroup-reads (delq article gnus-newsgroup-reads))
-      (cond ((= mark gnus-ticked-mark)
-            (push article gnus-newsgroup-marked))
-           ((= mark gnus-dormant-mark)
-            (push article gnus-newsgroup-dormant))
-           (t
-            (push article gnus-newsgroup-unreads)))
-      (setq gnus-newsgroup-reads
-           (delq (assq article gnus-newsgroup-reads)
-                 gnus-newsgroup-reads))
+  (let* ((article (gnus-summary-article-number))
+        (old-mark (gnus-summary-article-mark article)))
+    (if (eq mark old-mark)
+       t
+      (if (<= article 0)
+         (progn
+           (gnus-error 1 "Can't mark negative article numbers")
+           nil)
+       (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
+       (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
+       (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
+       (setq gnus-newsgroup-reads (delq article gnus-newsgroup-reads))
+       (cond ((= mark gnus-ticked-mark)
+              (push article gnus-newsgroup-marked))
+             ((= mark gnus-dormant-mark)
+              (push article gnus-newsgroup-dormant))
+             (t
+              (push article gnus-newsgroup-unreads)))
+       (setq gnus-newsgroup-reads
+             (delq (assq article gnus-newsgroup-reads)
+                   gnus-newsgroup-reads))
+
+       ;; See whether the article is to be put in the cache.
+       (and gnus-use-cache
+            (vectorp (gnus-summary-article-header article))
+            (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))))
 
-      ;; See whether the article is to be put in the cache.
-      (and gnus-use-cache
-          (vectorp (gnus-summary-article-header article))
-          (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))))
-
-      ;; Fix the mark.
-      (gnus-summary-update-mark mark 'unread))
-    t))
+       ;; Fix the mark.
+       (gnus-summary-update-mark mark 'unread)
+       t))))
 
 (defun gnus-summary-mark-article (&optional article mark no-expire)
   "Mark ARTICLE with MARK.  MARK can be any character.
@@ -7656,32 +7720,35 @@ marked."
                    (= mark gnus-duplicate-mark))))
        (setq mark gnus-expirable-mark))
   (let* ((mark (or mark gnus-del-mark))
-        (article (or article (gnus-summary-article-number))))
-    (unless article
-      (error "No article on current line"))
-    (if (or (= mark gnus-unread-mark)
-           (= mark gnus-ticked-mark)
-           (= mark gnus-dormant-mark))
-       (gnus-mark-article-as-unread article mark)
-      (gnus-mark-article-as-read article mark))
-
-    ;; See whether the article is to be put in the cache.
-    (and gnus-use-cache
-        (not (= mark gnus-canceled-mark))
-        (vectorp (gnus-summary-article-header article))
-        (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))))
-
-    (when (gnus-summary-goto-subject article nil t)
-      (let ((buffer-read-only nil))
-       (gnus-summary-show-thread)
-       ;; Fix the mark.
-       (gnus-summary-update-mark mark 'unread)
-       t))))
+        (article (or article (gnus-summary-article-number)))
+        (old-mark (gnus-summary-article-mark article)))
+    (if (eq mark old-mark)
+       t
+      (unless article
+       (error "No article on current line"))
+      (if (not (if (or (= mark gnus-unread-mark)
+                      (= mark gnus-ticked-mark)
+                      (= mark gnus-dormant-mark))
+                  (gnus-mark-article-as-unread article mark)
+                (gnus-mark-article-as-read article mark)))
+         t
+       ;; See whether the article is to be put in the cache.
+       (and gnus-use-cache
+            (not (= mark gnus-canceled-mark))
+            (vectorp (gnus-summary-article-header article))
+            (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))))
+
+       (when (gnus-summary-goto-subject article nil t)
+         (let ((buffer-read-only nil))
+           (gnus-summary-show-thread)
+           ;; Fix the mark.
+           (gnus-summary-update-mark mark 'unread)
+           t))))))
 
 (defun gnus-summary-update-secondary-mark (article)
   "Update the secondary (read, process, cache) mark."
@@ -7697,7 +7764,7 @@ marked."
         (t gnus-unread-mark))
    'replied)
   (when (gnus-visual-p 'summary-highlight 'highlight)
-    (run-hooks 'gnus-summary-update-hook))
+    (gnus-run-hooks 'gnus-summary-update-hook))
   t)
 
 (defun gnus-summary-update-mark (mark type)
@@ -7732,20 +7799,21 @@ marked."
     (push (cons article mark) gnus-newsgroup-reads)
     ;; Possibly remove from cache, if that is used.
     (when gnus-use-cache
-      (gnus-cache-enter-remove-article article))))
+      (gnus-cache-enter-remove-article article))
+    t))
 
 (defun gnus-mark-article-as-unread (article &optional mark)
   "Enter ARTICLE in the pertinent lists and remove it from others."
   (let ((mark (or mark gnus-ticked-mark)))
-    (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked)
-         gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant)
-         gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable)
-         gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
-
     (if (<= article 0)
        (progn
          (gnus-error 1 "Can't mark negative article numbers")
          nil)
+      (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked)
+           gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant)
+           gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable)
+           gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+
       ;; Unsuppress duplicates?
       (when gnus-suppress-duplicates
        (gnus-dup-unsuppress-article article))
@@ -7860,7 +7928,6 @@ even ticked and dormant ones."
 (defun gnus-summary-mark-below (score mark)
   "Mark articles with score less than SCORE with MARK."
   (interactive "P\ncMark: ")
-  (gnus-set-global-variables)
   (setq score (if score
                  (prefix-numeric-value score)
                (or gnus-summary-default-score 0)))
@@ -7876,25 +7943,21 @@ even ticked and dormant ones."
 (defun gnus-summary-kill-below (&optional score)
   "Mark articles with score below SCORE as read."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-mark-below score gnus-killed-mark))
 
 (defun gnus-summary-clear-above (&optional score)
   "Clear all marks from articles with score above SCORE."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-mark-above score gnus-unread-mark))
 
 (defun gnus-summary-tick-above (&optional score)
   "Tick all articles with score above SCORE."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-mark-above score gnus-ticked-mark))
 
 (defun gnus-summary-mark-above (score mark)
   "Mark articles with score over SCORE with MARK."
   (interactive "P\ncMark: ")
-  (gnus-set-global-variables)
   (setq score (if score
                  (prefix-numeric-value score)
                (or gnus-summary-default-score 0)))
@@ -7912,7 +7975,6 @@ even ticked and dormant ones."
 (defun gnus-summary-limit-include-expunged (&optional no-error)
   "Display all the hidden articles that were expunged for low scores."
   (interactive)
-  (gnus-set-global-variables)
   (let ((buffer-read-only nil))
     (let ((scored gnus-newsgroup-scored)
          headers h)
@@ -7942,7 +8004,6 @@ Note that this function will only catch up the unread article
 in the current summary buffer limitation.
 The number of articles marked as read is returned."
   (interactive "P")
-  (gnus-set-global-variables)
   (prog1
       (save-excursion
        (when (or quietly
@@ -7962,7 +8023,7 @@ The number of articles marked as read is returned."
                (when all
                  (setq gnus-newsgroup-marked nil
                        gnus-newsgroup-dormant nil))
-               (setq gnus-newsgroup-unreads nil))
+               (setq gnus-newsgroup-unreads gnus-newsgroup-downloadable))
            ;; We actually mark all articles as canceled, which we
            ;; have to do when using auto-expiry or adaptive scoring.
            (gnus-summary-show-all-threads)
@@ -7979,7 +8040,6 @@ The number of articles marked as read is returned."
   "Mark all unticked articles before the current one as read.
 If ALL is non-nil, also mark ticked and dormant articles as read."
   (interactive "P")
-  (gnus-set-global-variables)
   (save-excursion
     (gnus-save-hidden-threads
       (let ((beg (point)))
@@ -7991,14 +8051,12 @@ If ALL is non-nil, also mark ticked and dormant articles as read."
 (defun gnus-summary-catchup-all (&optional quietly)
   "Mark all articles in this newsgroup as read."
   (interactive "P")
-  (gnus-set-global-variables)
   (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."
   (interactive "P")
-  (gnus-set-global-variables)
   (when (gnus-summary-catchup all quietly nil 'fast)
     ;; Select next newsgroup or exit.
     (if (eq gnus-auto-select-next 'quietly)
@@ -8008,7 +8066,6 @@ If prefix argument ALL is non-nil, all articles are marked as read."
 (defun gnus-summary-catchup-all-and-exit (&optional quietly)
   "Mark all articles in this newsgroup as read, and then exit."
   (interactive "P")
-  (gnus-set-global-variables)
   (gnus-summary-catchup-and-exit t quietly))
 
 ;; Suggested by "Arne Eofsson" <arne@hodgkin.mbi.ucla.edu>.
@@ -8017,7 +8074,6 @@ If prefix argument ALL is non-nil, all articles are marked as read."
 If given a prefix, mark all articles, unread as well as ticked, as
 read."
   (interactive "P")
-  (gnus-set-global-variables)
   (save-excursion
     (gnus-summary-catchup all))
   (gnus-summary-next-article t nil nil t))
@@ -8064,7 +8120,6 @@ with that article."
 (defun gnus-summary-rethread-current ()
   "Rethread the thread the current article is part of."
   (interactive)
-  (gnus-set-global-variables)
   (let* ((gnus-show-threads t)
         (article (gnus-summary-article-number))
         (id (mail-header-id (gnus-summary-article-header)))
@@ -8100,14 +8155,20 @@ 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"))
-       (gnus-summary-select-article t t nil current-article)
+       ;; We don't want the article to be marked as read.
+       (let (gnus-mark-article-hook)
+         (gnus-summary-select-article t t nil current-article))
        (set-buffer gnus-original-article-buffer)
        (let ((buf (format "%s" (buffer-string))))
          (nnheader-temp-write nil
            (insert buf)
            (goto-char (point-min))
-           (if (search-forward-regexp "^References: " nil t)
-               (insert message-id " " )
+           (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)
@@ -8115,6 +8176,7 @@ is non-nil or the Subject: of both articles are the same."
              (error "Couldn't replace article"))))
        (set-buffer gnus-summary-buffer)
        (gnus-summary-unmark-all-processable)
+       (gnus-summary-update-article current-article)
        (gnus-summary-rethread-current)
        (gnus-message 3 "Article %d is now the child of article %d"
                      current-article parent-article)))))
@@ -8123,7 +8185,6 @@ is non-nil or the Subject: of both articles are the same."
   "Toggle showing conversation threads.
 If ARG is positive number, turn showing conversation threads on."
   (interactive "P")
-  (gnus-set-global-variables)
   (let ((current (or (gnus-summary-article-number) gnus-newsgroup-end)))
     (setq gnus-show-threads
          (if (null arg) (not gnus-show-threads)
@@ -8136,7 +8197,6 @@ If ARG is positive number, turn showing conversation threads on."
 (defun gnus-summary-show-all-threads ()
   "Show all threads."
   (interactive)
-  (gnus-set-global-variables)
   (save-excursion
     (let ((buffer-read-only nil))
       (subst-char-in-region (point-min) (point-max) ?\^M ?\n t)))
@@ -8146,7 +8206,6 @@ If ARG is positive number, turn showing conversation threads on."
   "Show thread subtrees.
 Returns nil if no thread was there to be shown."
   (interactive)
-  (gnus-set-global-variables)
   (let ((buffer-read-only nil)
        (orig (point))
        ;; first goto end then to beg, to have point at beg after let
@@ -8162,7 +8221,6 @@ Returns nil if no thread was there to be shown."
 (defun gnus-summary-hide-all-threads ()
   "Hide all thread subtrees."
   (interactive)
-  (gnus-set-global-variables)
   (save-excursion
     (goto-char (point-min))
     (gnus-summary-hide-thread)
@@ -8174,7 +8232,6 @@ Returns nil if no thread was there to be shown."
   "Hide thread subtrees.
 Returns nil if no threads were there to be hidden."
   (interactive)
-  (gnus-set-global-variables)
   (let ((buffer-read-only nil)
        (start (point))
        (article (gnus-summary-article-number)))
@@ -8223,7 +8280,6 @@ done.
 
 If SILENT, don't output messages."
   (interactive "p")
-  (gnus-set-global-variables)
   (let ((backward (< n 0))
        (n (abs n)))
     (while (and (> n 0)
@@ -8240,7 +8296,6 @@ If SILENT, don't output messages."
 Returns the difference between N and the number of skips actually
 done."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-summary-next-thread (- n)))
 
 (defun gnus-summary-go-down-thread ()
@@ -8261,7 +8316,6 @@ If N is negative, go up instead.
 Returns the difference between N and how many steps down that were
 taken."
   (interactive "p")
-  (gnus-set-global-variables)
   (let ((up (< n 0))
        (n (abs n)))
     (while (and (> n 0)
@@ -8279,13 +8333,11 @@ If N is negative, go up instead.
 Returns the difference between N and how many steps down that were
 taken."
   (interactive "p")
-  (gnus-set-global-variables)
   (gnus-summary-down-thread (- n)))
 
 (defun gnus-summary-top-thread ()
   "Go to the top of the thread."
   (interactive)
-  (gnus-set-global-variables)
   (while (gnus-summary-go-up-thread))
   (gnus-summary-article-number))
 
@@ -8294,7 +8346,6 @@ taken."
 If the prefix argument is positive, remove any kinds of marks.
 If the prefix argument is negative, tick articles instead."
   (interactive "P")
-  (gnus-set-global-variables)
   (when unmark
     (setq unmark (prefix-numeric-value unmark)))
   (let ((articles (gnus-summary-articles-in-thread)))
@@ -8363,7 +8414,6 @@ Argument REVERSE means reverse order."
 
 (defun gnus-summary-sort (predicate reverse)
   "Sort summary buffer by PREDICATE.  REVERSE means reverse order."
-  (gnus-set-global-variables)
   (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
         (article (intern (format "gnus-article-sort-by-%s" predicate)))
         (gnus-thread-sort-functions
@@ -8396,7 +8446,6 @@ If N is nil and any articles have been marked with the process mark,
 save those articles instead.
 The variable `gnus-default-article-saver' specifies the saver function."
   (interactive "P")
-  (gnus-set-global-variables)
   (let* ((articles (gnus-summary-work-articles n))
         (save-buffer (save-excursion
                        (nnheader-set-temp-buffer " *Gnus Save*")))
@@ -8433,7 +8482,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-pipe))
     (gnus-summary-save-article arg t))
   (gnus-configure-windows 'pipe))
@@ -8445,7 +8493,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-mail))
     (gnus-summary-save-article arg)))
 
@@ -8456,7 +8503,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
     (gnus-summary-save-article arg)))
 
@@ -8467,7 +8513,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-file))
     (gnus-summary-save-article arg)))
 
@@ -8478,7 +8523,6 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-write-to-file))
     (gnus-summary-save-article arg)))
 
@@ -8489,14 +8533,12 @@ 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")
-  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
     (gnus-summary-save-article arg)))
 
 (defun gnus-summary-pipe-message (program)
   "Pipe the current article through PROGRAM."
   (interactive "sProgram: ")
-  (gnus-set-global-variables)
   (gnus-summary-select-article)
   (let ((mail-header-separator "")
         (art-buf (get-buffer gnus-article-buffer)))
@@ -8677,7 +8719,7 @@ save those articles instead."
   (cond ((assq 'execute props)
         (gnus-execute-command (cdr (assq 'execute props)))))
   (let ((gnus-current-article (gnus-summary-article-number)))
-    (run-hooks 'gnus-mark-article-hook)))
+    (gnus-run-hooks 'gnus-mark-article-hook)))
 
 (defun gnus-execute-command (command &optional automatic)
   (save-excursion
@@ -8698,16 +8740,13 @@ save those articles instead."
 
 (defun gnus-summary-edit-global-kill (article)
   "Edit the \"global\" kill file."
-  (interactive (gnus-summary-article-number))
-  (gnus-set-global-variables)
+  (interactive (list (gnus-summary-article-number)))
   (gnus-group-edit-global-kill article))
 
 (defun gnus-summary-edit-local-kill ()
   "Edit a local kill file applied to the current newsgroup."
   (interactive)
-  (gnus-set-global-variables)
   (setq gnus-current-headers (gnus-summary-article-header))
-  (gnus-set-global-variables)
   (gnus-group-edit-local-kill
    (gnus-summary-article-number) gnus-newsgroup-name))
 
@@ -8731,6 +8770,16 @@ save those articles instead."
             (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-gethash parent gnus-newsgroup-dependencies))))
+         (when thread
+           (delq (assq header thread) thread))))
       ;; We have to really fetch the header to this article.
       (save-excursion
        (set-buffer nntp-server-buffer)
@@ -8916,7 +8965,9 @@ save those articles instead."
       (when buffers
        (map-y-or-n-p
         "Update summary buffer %s? "
-        (lambda (buf) (switch-to-buffer buf) (gnus-summary-exit))
+        (lambda (buf)
+          (switch-to-buffer buf)
+          (gnus-summary-exit))
         buffers)))))
 
 (gnus-ems-redefine)