Importing gnus-5.6.43
[elisp/gnus.git-] / lisp / gnus-sum.el
index 7b53900..8509f17 100644 (file)
@@ -33,6 +33,7 @@
 (require 'gnus-range)
 (require 'gnus-int)
 (require 'gnus-undo)
+(require 'gnus-util)
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
 
 (defcustom gnus-kill-summary-on-exit t
@@ -217,10 +218,10 @@ to expose hidden threads."
   :group 'gnus-thread
   :type 'boolean)
 
-(defcustom gnus-thread-ignore-subject nil
-  "*If non-nil, ignore subjects and do all threading based on the Reference header.
-If nil, which is the default, articles that have different subjects
-from their parents will start separate threads."
+(defcustom gnus-thread-ignore-subject t
+  "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
+If nil, articles that have different subjects from their parents will
+start separate threads."
   :group 'gnus-thread
   :type 'boolean)
 
@@ -281,7 +282,9 @@ will go to the next group without confirmation."
                 (sexp :menu-tag "on" t)))
 
 (defcustom gnus-auto-select-same nil
-  "*If non-nil, select the next article with the same subject."
+  "*If non-nil, select the next article with the same subject.
+If there are no more articles with the same subject, go to
+the first unread article."
   :group 'gnus-summary-maneuvering
   :type 'boolean)
 
@@ -1139,6 +1142,7 @@ increase the score of each group you read."
     [delete] gnus-summary-prev-page
     [backspace] gnus-summary-prev-page
     "\r" gnus-summary-scroll-up
+    "\M-\r" gnus-summary-scroll-down
     "n" gnus-summary-next-unread-article
     "p" gnus-summary-prev-unread-article
     "N" gnus-summary-next-article
@@ -1344,6 +1348,7 @@ increase the score of each group you read."
     [delete] gnus-summary-prev-page
     "p" gnus-summary-prev-page
     "\r" gnus-summary-scroll-up
+    "\M-\r" gnus-summary-scroll-down
     "<" gnus-summary-beginning-of-article
     ">" gnus-summary-end-of-article
     "b" gnus-summary-beginning-of-article
@@ -1379,6 +1384,7 @@ increase the score of each group you read."
     "b" gnus-article-hide-boring-headers
     "s" gnus-article-hide-signature
     "c" gnus-article-hide-citation
+    "C" gnus-article-hide-citation-in-followups
     "p" gnus-article-hide-pgp
     "P" gnus-article-hide-pem
     "\C-c" gnus-article-hide-citation-maybe)
@@ -1424,6 +1430,7 @@ increase the score of each group you read."
     "c" gnus-summary-copy-article
     "B" gnus-summary-crosspost-article
     "q" gnus-summary-respool-query
+    "t" gnus-summary-respool-trace
     "i" gnus-summary-import-article
     "p" gnus-summary-article-posted-p)
 
@@ -1546,6 +1553,7 @@ increase the score of each group you read."
                (gnus-check-backend-function
                 'request-expire-articles gnus-newsgroup-name)]
               ["Query respool" gnus-summary-respool-query t]
+             ["Trace respool" gnus-summary-respool-trace t]
               ["Delete expirable articles" gnus-summary-expire-articles-now
                (gnus-check-backend-function
                 'request-expire-articles gnus-newsgroup-name)])
@@ -1729,9 +1737,10 @@ increase the score of each group you read."
        ["Edit local kill file" gnus-summary-edit-local-kill t]
        ["Edit main kill file" gnus-summary-edit-global-kill t]
        ["Edit group parameters" gnus-summary-edit-parameters t]
+       ["Send a bug report" gnus-bug t]
        ("Exit"
        ["Catchup and exit" gnus-summary-catchup-and-exit t]
-       ["Catchup all and exit" gnus-summary-catchup-and-exit t]
+       ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
        ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
        ["Exit group" gnus-summary-exit t]
        ["Exit group without updating" gnus-summary-exit-no-update t]
@@ -1970,21 +1979,26 @@ The following commands are available:
   (when list
     (let ((data (and after-article (gnus-data-find-list after-article)))
          (ilist list))
-      (or data (not after-article) (error "No such article: %d" after-article))
-      ;; Find the last element in the list to be spliced into the main
-      ;; list.
-      (while (cdr list)
-       (setq list (cdr list)))
-      (if (not data)
-         (progn
-           (setcdr list gnus-newsgroup-data)
-           (setq gnus-newsgroup-data ilist)
+      (if (not (or data
+                  after-article))
+         (let ((odata gnus-newsgroup-data))
+           (setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
            (when offset
-             (gnus-data-update-list (cdr list) offset)))
-       (setcdr list (cdr data))
-       (setcdr data ilist)
-       (when offset
-         (gnus-data-update-list (cdr list) offset)))
+             (gnus-data-update-list odata offset)))
+       ;; Find the last element in the list to be spliced into the main
+       ;; list.
+       (while (cdr list)
+         (setq list (cdr list)))
+       (if (not data)
+           (progn
+             (setcdr list gnus-newsgroup-data)
+             (setq gnus-newsgroup-data ilist)
+             (when offset
+               (gnus-data-update-list (cdr list) offset)))
+         (setcdr list (cdr data))
+         (setcdr data ilist)
+         (when offset
+           (gnus-data-update-list (cdr list) offset))))
       (setq gnus-newsgroup-data-reverse nil))))
 
 (defun gnus-data-remove (article &optional offset)
@@ -2013,20 +2027,25 @@ The following commands are available:
 
 (defun gnus-data-update-list (data offset)
   "Add OFFSET to the POS of all data entries in DATA."
+  (setq gnus-newsgroup-data-reverse nil)
   (while data
     (setcar (nthcdr 2 (car data)) (+ offset (nth 2 (car data))))
     (setq data (cdr data))))
 
 (defun gnus-data-compute-positions ()
   "Compute the positions of all articles."
-  (let ((data gnus-newsgroup-data)
-       pos)
-    (while data
-      (when (setq pos (text-property-any
-                      (point-min) (point-max)
-                      'gnus-number (gnus-data-number (car data))))
-       (gnus-data-set-pos (car data) (+ pos 3)))
-      (setq data (cdr data)))))
+  (setq gnus-newsgroup-data-reverse nil)
+  (let ((data gnus-newsgroup-data))
+    (save-excursion
+      (gnus-save-hidden-threads
+       (gnus-summary-show-all-threads)
+       (goto-char (point-min))
+       (while data
+         (while (get-text-property (point) 'gnus-intangible)
+           (forward-line 1))
+         (gnus-data-set-pos (car data) (+ (point) 3))
+         (setq data (cdr data))
+         (forward-line 1))))))
 
 (defun gnus-summary-article-pseudo-p (article)
   "Say whether this article is a pseudo article or not."
@@ -2255,8 +2274,7 @@ marks of articles."
          (setq gnus-summary-buffer (current-buffer))
          (not gnus-newsgroup-prepared))
       ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>
-      (setq gnus-summary-buffer (set-buffer (get-buffer-create buffer)))
-      (gnus-add-current-to-buffer-list)
+      (setq gnus-summary-buffer (set-buffer (gnus-get-buffer-create buffer)))
       (gnus-summary-mode group)
       (when gnus-carpal
        (gnus-carpal-setup-buffer 'summary))
@@ -2339,7 +2357,7 @@ marks of articles."
          (gnus-score-over-mark 130)
          (gnus-download-mark 131)
          (spec gnus-summary-line-format-spec)
-         thread gnus-visual pos)
+         gnus-visual pos)
       (save-excursion
        (gnus-set-work-buffer)
        (let ((gnus-summary-line-format-spec spec)
@@ -2415,7 +2433,7 @@ marks of articles."
       (setq gnus-tmp-name gnus-tmp-from))
     (unless (numberp gnus-tmp-lines)
       (setq gnus-tmp-lines 0))
-    (gnus-put-text-property
+    (gnus-put-text-property-excluding-characters-with-faces
      (point)
      (progn (eval gnus-summary-line-format-spec) (point))
      'gnus-number gnus-tmp-number)
@@ -2501,7 +2519,8 @@ the thread are to be displayed."
             (set (car elem) (eval (nth 1 elem))))))))
 
 (defun gnus-summary-read-group (group &optional show-all no-article
-                                     kill-buffer no-display backward)
+                                     kill-buffer no-display backward
+                                     select-articles)
   "Start reading news in newsgroup GROUP.
 If SHOW-ALL is non-nil, already read articles are also listed.
 If NO-ARTICLE is non-nil, no article is selected initially.
@@ -2512,8 +2531,10 @@ If NO-DISPLAY, don't generate a summary buffer."
                            (let ((gnus-auto-select-next nil))
                              (or (gnus-summary-read-group-1
                                   group show-all no-article
-                                  kill-buffer no-display)
-                                 (setq show-all nil)))))
+                                  kill-buffer no-display
+                                  select-articles)
+                                 (setq show-all nil
+                                  select-articles nil)))))
                (eq gnus-auto-select-next 'quietly))
       (set-buffer gnus-group-buffer)
       ;; The entry function called above goes to the next
@@ -2527,7 +2548,8 @@ If NO-DISPLAY, don't generate a summary buffer."
     result))
 
 (defun gnus-summary-read-group-1 (group show-all no-article
-                                       kill-buffer no-display)
+                                       kill-buffer no-display
+                                       &optional select-articles)
   ;; Killed foreign groups can't be entered.
   (when (and (not (gnus-group-native-p group))
             (not (gnus-gethash group gnus-newsrc-hashtb)))
@@ -2535,7 +2557,8 @@ If NO-DISPLAY, don't generate a summary buffer."
   (gnus-message 5 "Retrieving newsgroup: %s..." group)
   (let* ((new-group (gnus-summary-setup-buffer group))
         (quit-config (gnus-group-quit-config group))
-        (did-select (and new-group (gnus-select-newsgroup group show-all))))
+        (did-select (and new-group (gnus-select-newsgroup
+                                    group show-all select-articles))))
     (cond
      ;; This summary buffer exists already, so we just select it.
      ((not new-group)
@@ -2924,7 +2947,6 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
            ;; Yuk!  This is a reference loop.  Make the article be a
            ;; root article.
            (progn
-             (debug)
              (mail-header-set-references (car (symbol-value id-dep)) "none")
              (setq ref nil))
          (setq ref (gnus-parent-id (mail-header-references ref-header)))))
@@ -2939,8 +2961,9 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
 
 (defun gnus-build-sparse-threads ()
   (let ((headers gnus-newsgroup-headers)
+       (gnus-summary-ignore-duplicates t)
        header references generation relations
-       cthread subject child end pthread relation new-child date)
+       subject child end new-child date)
     ;; First we create an alist of generations/relations, where
     ;; generations is how much we trust the relation, and the relation
     ;; is parent/child.
@@ -2957,12 +2980,14 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                generation 0)
          (while (search-backward ">" nil t)
            (setq end (1+ (point)))
-           (if (search-backward "<" nil t)
-               (push (list (incf generation)
-                           child (setq child new-child)
-                           subject date)
-                     relations)))
-         (push (list (1+ generation) child nil subject) relations)
+           (when (search-backward "<" nil t)
+             (setq new-child (buffer-substring (point) end))
+             (push (list (incf generation)
+                         child (setq child new-child)
+                         subject date)
+                   relations)))
+         (when child
+           (push (list (1+ generation) child nil subject) relations))
          (erase-buffer)))
       (kill-buffer (current-buffer)))
     ;; Sort over trustworthiness.
@@ -2971,7 +2996,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
        (when (gnus-dependencies-add-header
              (make-full-mail-header
               gnus-reffed-article-number
-              (nth 3 relation) "" (nth 4 relation)
+              (nth 3 relation) "" (or (nth 4 relation) "")
               (nth 1 relation)
               (or (nth 2 relation) "") 0 0 "")
              gnus-newsgroup-dependencies nil)
@@ -3096,7 +3121,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
   "Read all the headers."
   (let ((gnus-summary-ignore-duplicates t)
        (dependencies gnus-newsgroup-dependencies)
-       found header article)
+       header article)
     (save-excursion
       (set-buffer nntp-server-buffer)
       (let ((case-fold-search nil))
@@ -3107,14 +3132,16 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                  header (gnus-nov-parse-line
                          article dependencies)))
          (when header
-           (push header gnus-newsgroup-headers)
-           (if (memq (setq article (mail-header-number header))
-                     gnus-newsgroup-unselected)
-               (progn
-                 (push article gnus-newsgroup-unreads)
-                 (setq gnus-newsgroup-unselected
-                       (delq article gnus-newsgroup-unselected)))
-             (push article gnus-newsgroup-ancient))
+           (save-excursion
+             (set-buffer gnus-summary-buffer)
+             (push header gnus-newsgroup-headers)
+             (if (memq (setq article (mail-header-number header))
+                       gnus-newsgroup-unselected)
+                 (progn
+                   (push article gnus-newsgroup-unreads)
+                   (setq gnus-newsgroup-unselected
+                         (delq article gnus-newsgroup-unselected)))
+               (push article gnus-newsgroup-ancient)))
            (forward-line 1)))))))
 
 (defun gnus-summary-update-article-line (article header)
@@ -3162,7 +3189,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
 (defun gnus-summary-update-article (article &optional iheader)
   "Update ARTICLE in the summary buffer."
   (set-buffer gnus-summary-buffer)
-  (let* ((header (or iheader (gnus-summary-article-header article)))
+  (let* ((header (gnus-summary-article-header article))
         (id (mail-header-id header))
         (data (gnus-data-find article))
         (thread (gnus-id-to-thread id))
@@ -3175,16 +3202,13 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                  references))
               "none")))
         (buffer-read-only nil)
-        (old (car thread))
-        (number (mail-header-number header))
-        pos)
+        (old (car thread)))
     (when thread
-      ;; !!! Should this be in or not?
       (unless iheader
-       (setcar thread nil))
-      (when parent
-       (delq thread parent))
-      (if (gnus-summary-insert-subject id header iheader)
+       (setcar thread nil)
+       (when parent
+         (delq thread parent)))
+      (if (gnus-summary-insert-subject id header)
          ;; Set the (possibly) new article number in the data structure.
          (gnus-data-set-number data (gnus-id-to-article id))
        (setcar thread old)
@@ -3236,10 +3260,11 @@ If LINE, insert the rebuilt thread starting on line LINE."
       ;;!!! then we want to insert at the beginning of the buffer.
       ;;!!! That happens to be true with Gnus now, but that may
       ;;!!! change in the future.  Perhaps.
-      (gnus-data-enter-list (if line nil current) data (- (point) old-pos))
-      (setq gnus-newsgroup-threads (nconc threads gnus-newsgroup-threads))
-      (when line
-       (gnus-data-compute-positions)))))
+      (gnus-data-enter-list
+       (if line nil current) data (- (point) old-pos))
+      (setq gnus-newsgroup-threads
+           (nconc threads gnus-newsgroup-threads))
+      (gnus-data-compute-positions))))
 
 (defun gnus-number-to-header (number)
   "Return the header for article NUMBER."
@@ -3315,9 +3340,8 @@ If LINE, insert the rebuilt thread starting on line LINE."
   "Remove the thread that has ID in it."
   (let (headers thread last-id)
     ;; First go up in this thread until we find the root.
-    (setq last-id (gnus-root-id id))
-    (setq headers (list (car (gnus-id-to-thread last-id))
-                       (caadr (gnus-id-to-thread last-id))))
+    (setq last-id (gnus-root-id id)
+         headers (message-flatten-list (gnus-id-to-thread last-id)))
     ;; We have now found the real root of this thread. It might have
     ;; been gathered into some loose thread, so we have to search
     ;; through the threads to find the thread we wanted.
@@ -3367,6 +3391,7 @@ If LINE, insert the rebuilt thread starting on line LINE."
                  (while thread
                    (gnus-remove-thread-1 (car thread))
                    (setq thread (cdr thread))))
+             (gnus-summary-show-all-threads)
              (gnus-remove-thread-1 thread))))))))
 
 (defun gnus-remove-thread-1 (thread)
@@ -3389,10 +3414,10 @@ If LINE, insert the rebuilt thread starting on line LINE."
   "Sort THREADS."
   (if (not gnus-thread-sort-functions)
       threads
-    (gnus-message 7 "Sorting threads...")
+    (gnus-message 8 "Sorting threads...")
     (prog1
        (sort threads (gnus-make-sort-function gnus-thread-sort-functions))
-      (gnus-message 7 "Sorting threads...done"))))
+      (gnus-message 8 "Sorting threads...done"))))
 
 (defun gnus-sort-articles (articles)
   "Sort ARTICLES."
@@ -3752,7 +3777,7 @@ or a straight list of headers."
              (setq gnus-tmp-name gnus-tmp-from))
            (unless (numberp gnus-tmp-lines)
              (setq gnus-tmp-lines 0))
-           (gnus-put-text-property
+           (gnus-put-text-property-excluding-characters-with-faces
             (point)
             (progn (eval gnus-summary-line-format-spec) (point))
             'gnus-number number)
@@ -3806,13 +3831,14 @@ or a straight list of headers."
         (cdr (assq number gnus-newsgroup-scored))
         (memq number gnus-newsgroup-processable))))))
 
-(defun gnus-select-newsgroup (group &optional read-all)
+(defun gnus-select-newsgroup (group &optional read-all select-articles)
   "Select newsgroup GROUP.
-If READ-ALL is non-nil, all articles in the group are selected."
+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))
         ;;!!! Dirty hack; should be removed.
         (gnus-summary-ignore-duplicates
-         (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
+         (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
              t
            gnus-summary-ignore-duplicates))
         (info (nth 2 entry))
@@ -3857,10 +3883,13 @@ If READ-ALL is non-nil, all articles in the group are selected."
     (setq gnus-newsgroup-processable nil)
 
     (gnus-update-read-articles group gnus-newsgroup-unreads)
-    (unless (gnus-ephemeral-group-p gnus-newsgroup-name)
-      (gnus-group-update-group group))
 
-    (setq articles (gnus-articles-to-read group read-all))
+    (if (setq articles select-articles)
+       (setq gnus-newsgroup-unselected
+             (gnus-sorted-intersection
+              gnus-newsgroup-unreads
+              (gnus-sorted-complement gnus-newsgroup-unreads articles)))
+      (setq articles (gnus-articles-to-read group read-all)))
 
     (cond
      ((null articles)
@@ -3910,15 +3939,15 @@ If READ-ALL is non-nil, all articles in the group are selected."
       ;; Removed marked articles that do not exist.
       (gnus-update-missing-marks
        (gnus-sorted-complement fetched-articles articles))
-      ;; Let the Gnus agent mark articles as read.
-      (when gnus-agent
-       (gnus-agent-get-undownloaded-list))
       ;; We might want to build some more threads first.
       (when (and gnus-fetch-old-headers
                 (eq gnus-headers-retrieved-by 'nov))
        (if (eq gnus-fetch-old-headers 'invisible)
            (gnus-build-all-threads)
          (gnus-build-old-threads)))
+      ;; Let the Gnus agent mark articles as read.
+      (when gnus-agent
+       (gnus-agent-get-undownloaded-list))
       ;; Check whether auto-expire is to be done in this group.
       (setq gnus-newsgroup-auto-expire
            (gnus-group-auto-expirable-p group))
@@ -4344,7 +4373,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         (or dependencies
             (save-excursion (set-buffer gnus-summary-buffer)
                             gnus-newsgroup-dependencies)))
-       headers id id-dep ref-dep end ref)
+       headers id end ref)
     (save-excursion
       (set-buffer nntp-server-buffer)
       ;; Translate all TAB characters into SPACE characters.
@@ -4437,7 +4466,8 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                        (setq ref2 (substring in-reply-to (match-beginning 0)
                                              (match-end 0)))
                        (when (> (length ref2) (length ref))
-                         (setq ref ref2))))
+                         (setq ref ref2)))
+                     ref)
                  (setq ref nil))))
            ;; Chars.
            (progn
@@ -4563,7 +4593,7 @@ the subject line on."
                      (t
                       (gnus-read-header id))))
        (number (and (numberp id) id))
-       pos d)
+       d)
     (when header
       ;; Rebuild the thread that this article is part of and go to the
       ;; article we have fetched.
@@ -4650,6 +4680,19 @@ current article will be taken into consideration."
       ;; Just return the current article.
       (list (gnus-summary-article-number))))))
 
+(defmacro gnus-summary-iterate (arg &rest forms)
+  "Iterate over the process/prefixed articles and do FORMS.
+ARG is the interactive prefix given to the command.  FORMS will be
+executed with point over the summary line of the articles."
+  (let ((articles (make-symbol "gnus-summary-iterate-articles")))
+    `(let ((,articles (gnus-summary-work-articles ,arg)))
+       (while ,articles
+        (gnus-summary-goto-subject (car ,articles))
+        ,@forms))))
+
+(put 'gnus-summary-iterate 'lisp-indent-function 1)
+(put 'gnus-summary-iterate 'edebug-form-spec '(form body))
+
 (defun gnus-summary-save-process-mark ()
   "Push the current set of process marked articles on the stack."
   (interactive)
@@ -4848,12 +4891,12 @@ displayed, no centering will be performed."
       ;; first unread article is the article after the last read
       ;; article.  Sounds logical, doesn't it?
       (if (not (listp (cdr read)))
-         (setq first (1+ (cdr read)))
+         (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 1))
+         (setq first (car active)))
        (while read
          (when first
            (while (< first nlast)
@@ -5073,12 +5116,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
          (gnus-kill-buffer buf)))
       (setq gnus-current-select-method gnus-select-method)
       (pop-to-buffer gnus-group-buffer)
-      ;; Clear the current group name.
       (if (not quit-config)
          (progn
            (goto-char group-point)
            (gnus-configure-windows 'group 'force))
        (gnus-handle-ephemeral-exit quit-config))
+      ;; Clear the current group name.
       (unless quit-config
        (setq gnus-newsgroup-name nil)))))
 
@@ -5415,6 +5458,7 @@ If FORCE, also allow jumping to articles not currently shown."
            (gnus-message 3 "Can't find article %d" article))
          nil)
       (goto-char (gnus-data-pos data))
+      (gnus-summary-position-point)
       article)))
 
 ;; Walking around summary lines with displaying articles.
@@ -5722,6 +5766,12 @@ Argument LINES specifies lines to be scrolled up (or down if negative)."
   (gnus-summary-recenter)
   (gnus-summary-position-point))
 
+(defun gnus-summary-scroll-down (lines)
+  "Scroll down (or up) one line current article.
+Argument LINES specifies lines to be scrolled down (or up if negative)."
+  (interactive "p")
+  (gnus-summary-scroll-up (- lines)))
+
 (defun gnus-summary-next-same-subject ()
   "Select next article which has the same subject as current one."
   (interactive)
@@ -6032,7 +6082,8 @@ If ALL, mark even excluded ticked and dormants as read."
                    '<)
                   (sort gnus-newsgroup-limit '<)))
        article)
-    (setq gnus-newsgroup-unreads gnus-newsgroup-limit)
+    (setq gnus-newsgroup-unreads
+         (gnus-intersection gnus-newsgroup-unreads gnus-newsgroup-limit))
     (if all
        (setq gnus-newsgroup-dormant nil
              gnus-newsgroup-marked nil
@@ -6080,6 +6131,7 @@ If ALL, mark even excluded ticked and dormants as read."
       ;; after the current one.
       (goto-char (point-max))
       (gnus-summary-find-prev))
+    (gnus-set-mode-line 'summary)
     ;; We return how many articles were removed from the summary
     ;; buffer as a result of the new limit.
     (- total (length gnus-newsgroup-data))))
@@ -6329,8 +6381,7 @@ of what's specified by the `gnus-refer-thread-limit' variable."
   (interactive "P")
   (let ((id (mail-header-id (gnus-summary-article-header)))
        (limit (if limit (prefix-numeric-value limit)
-                gnus-refer-thread-limit))
-       fmethod root)
+                gnus-refer-thread-limit)))
     ;; We want to fetch LIMIT *old* headers, but we also have to
     ;; re-fetch all the headers in the current buffer, because many of
     ;; them may be undisplayed.  So we adjust LIMIT.
@@ -6365,8 +6416,7 @@ 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)))
-          h)
+                             gnus-newsgroup-limit))))
       (cond
        ;; If the article is present in the buffer we just go to it.
        ((and header
@@ -6938,15 +6988,10 @@ and `request-accept' functions."
        (gnus-summary-mark-article article gnus-canceled-mark)
        (gnus-message 4 "Deleted article %s" article))
        (t
-       (let* ((entry
-               (or
-                (gnus-gethash (car art-group) gnus-newsrc-hashtb)
-                (gnus-gethash
-                 (gnus-group-prefixed-name
-                  (car art-group)
-                  (or select-method
-                      (gnus-find-method-for-group to-newsgroup)))
-                 gnus-newsrc-hashtb)))
+       (let* ((pto-group (gnus-group-prefixed-name
+                          (car art-group) to-method))
+              (entry
+               (gnus-gethash pto-group gnus-newsrc-hashtb))
               (info (nth 2 entry))
               (to-group (gnus-info-group info)))
          ;; Update the group that has been moved to.
@@ -7110,7 +7155,7 @@ latter case, they will be copied into the relevant groups."
        (not (file-regular-p file))
        (error "Can't read %s" file))
     (save-excursion
-      (set-buffer (get-buffer-create " *import file*"))
+      (set-buffer (gnus-get-buffer-create " *import file*"))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
       (insert-file-contents file)
@@ -7274,55 +7319,58 @@ groups."
   "Make edits to the current article permanent."
   (interactive)
   ;; Replace the article.
-  (if (and (not read-only)
-          (not (gnus-request-replace-article
-                (cdr gnus-article-current) (car gnus-article-current)
-                (current-buffer))))
-      (error "Couldn't replace article")
-    ;; Update the summary buffer.
-    (if (and references
-            (equal (message-tokenize-header references " ")
-                   (message-tokenize-header
-                    (or (message-fetch-field "references") "") " ")))
-       ;; We only have to update this line.
-       (save-excursion
-         (save-restriction
-           (message-narrow-to-head)
-           (let ((head (buffer-string))
-                 header)
-             (nnheader-temp-write nil
-               (insert (format "211 %d Article retrieved.\n"
-                               (cdr gnus-article-current)))
-               (insert head)
-               (insert ".\n")
-               (let ((nntp-server-buffer (current-buffer)))
-                 (setq header (car (gnus-get-newsgroup-headers
-                                    (save-excursion
-                                      (set-buffer gnus-summary-buffer)
-                                      gnus-newsgroup-dependencies)
-                                    t))))
-               (save-excursion
-                 (set-buffer gnus-summary-buffer)
-                 (gnus-data-set-header
-                  (gnus-data-find (cdr gnus-article-current))
-                  header)
-                 (gnus-summary-update-article-line
-                  (cdr gnus-article-current) header))))))
-      ;; Update threads.
-      (set-buffer (or buffer gnus-summary-buffer))
-      (gnus-summary-update-article (cdr gnus-article-current)))
-    ;; Prettify the article buffer again.
-    (unless no-highlight
-      (save-excursion
-       (set-buffer gnus-article-buffer)
-       (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)
-      (gnus-run-hooks 'gnus-visual-mark-article-hook))))
+  (let ((buf (current-buffer)))
+    (nnheader-temp-write nil
+      (insert-buffer buf)
+      (if (and (not read-only)
+              (not (gnus-request-replace-article
+                    (cdr gnus-article-current) (car gnus-article-current)
+                    (current-buffer))))
+         (error "Couldn't replace article")
+       ;; Update the summary buffer.
+       (if (and references
+                (equal (message-tokenize-header references " ")
+                       (message-tokenize-header
+                        (or (message-fetch-field "references") "") " ")))
+           ;; We only have to update this line.
+           (save-excursion
+             (save-restriction
+               (message-narrow-to-head)
+               (let ((head (buffer-string))
+                     header)
+                 (nnheader-temp-write nil
+                   (insert (format "211 %d Article retrieved.\n"
+                                   (cdr gnus-article-current)))
+                   (insert head)
+                   (insert ".\n")
+                   (let ((nntp-server-buffer (current-buffer)))
+                     (setq header (car (gnus-get-newsgroup-headers
+                                        (save-excursion
+                                          (set-buffer gnus-summary-buffer)
+                                          gnus-newsgroup-dependencies)
+                                        t))))
+                   (save-excursion
+                     (set-buffer gnus-summary-buffer)
+                     (gnus-data-set-header
+                      (gnus-data-find (cdr gnus-article-current))
+                      header)
+                     (gnus-summary-update-article-line
+                      (cdr gnus-article-current) header))))))
+         ;; Update threads.
+         (set-buffer (or buffer gnus-summary-buffer))
+         (gnus-summary-update-article (cdr gnus-article-current)))
+       ;; Prettify the article buffer again.
+       (unless no-highlight
+         (save-excursion
+           (set-buffer gnus-article-buffer)
+           (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)
+         (gnus-run-hooks 'gnus-visual-mark-article-hook))))))
 
 (defun gnus-summary-edit-wash (key)
   "Perform editing command KEY in the article buffer."
@@ -7338,7 +7386,7 @@ groups."
 
 ;;; Respooling
 
-(defun gnus-summary-respool-query (&optional silent)
+(defun gnus-summary-respool-query (&optional silent trace)
   "Query where the respool algorithm would put this article."
   (interactive)
   (let (gnus-mark-article-hook)
@@ -7347,7 +7395,7 @@ groups."
       (set-buffer gnus-original-article-buffer)
       (save-restriction
        (message-narrow-to-head)
-       (let ((groups (nnmail-article-group 'identity)))
+       (let ((groups (nnmail-article-group 'identity trace)))
          (unless silent
            (if groups
                (message "This message would go to %s"
@@ -7355,6 +7403,12 @@ groups."
              (message "This message would go to no groups"))
            groups))))))
 
+(defun gnus-summary-respool-trace ()
+  "Trace where the respool algorithm would put this article.
+Display a buffer showing all fancy splitting patterns which matched."
+  (interactive)
+  (gnus-summary-respool-query nil t))
+
 ;; Summary marking commands.
 
 (defun gnus-summary-kill-same-subject-and-select (&optional unmark)
@@ -7531,6 +7585,7 @@ the actual number of articles marked is returned."
              (delq article gnus-newsgroup-processable)))
   (when (gnus-summary-goto-subject article)
     (gnus-summary-show-thread)
+    (gnus-summary-goto-subject article)
     (gnus-summary-update-secondary-mark article)))
 
 (defun gnus-summary-remove-process-mark (article)
@@ -7538,6 +7593,7 @@ the actual number of articles marked is returned."
   (setq gnus-newsgroup-processable (delq article gnus-newsgroup-processable))
   (when (gnus-summary-goto-subject article)
     (gnus-summary-show-thread)
+    (gnus-summary-goto-subject article)
     (gnus-summary-update-secondary-mark article)))
 
 (defun gnus-summary-set-saved-mark (article)
@@ -7595,6 +7651,8 @@ returned."
                   (= mark gnus-read-mark) (= mark gnus-souped-mark)
                   (= mark gnus-duplicate-mark)))
       (setq mark gnus-expirable-mark)
+      ;; Let the backend know about the mark change.
+      (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
       (push article gnus-newsgroup-expirable))
     ;; Set the mark in the buffer.
     (gnus-summary-update-mark mark 'unread)
@@ -7604,6 +7662,8 @@ returned."
   "Mark the current article quickly as unread with MARK."
   (let* ((article (gnus-summary-article-number))
         (old-mark (gnus-summary-article-mark article)))
+    ;; Allow the backend to change the mark.
+    (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     (if (eq mark old-mark)
        t
       (if (<= article 0)
@@ -7659,6 +7719,8 @@ marked."
   (let* ((mark (or mark gnus-del-mark))
         (article (or article (gnus-summary-article-number)))
         (old-mark (gnus-summary-article-mark article)))
+    ;; Allow the backend to change the mark.
+    (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     (if (eq mark old-mark)
        t
       (unless article
@@ -8476,8 +8538,7 @@ save those articles instead."
   "Pipe the current article through PROGRAM."
   (interactive "sProgram: ")
   (gnus-summary-select-article)
-  (let ((mail-header-separator "")
-        (art-buf (get-buffer gnus-article-buffer)))
+  (let ((mail-header-separator ""))
     (gnus-eval-in-buffer-window gnus-article-buffer
       (save-restriction
         (widen)
@@ -8820,7 +8881,7 @@ save those articles instead."
        (setq list (cdr list))))
     (let ((face (cdar list)))
       (unless (eq face (get-text-property beg 'face))
-       (gnus-put-text-property
+       (gnus-put-text-property-excluding-characters-with-faces
         beg end 'face
         (setq face (if (boundp face) (symbol-value face) face)))
        (when gnus-summary-highlight-line-function