For citing any message.
[elisp/gnus.git-] / lisp / gnus-sum.el
index 658a529..6637201 100644 (file)
@@ -1,8 +1,9 @@
-;;; gnus-sum.el --- summary mode commands for Gnus
+;;; gnus-sum.el --- summary mode commands for Semi-gnus
 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news
+;;         MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
 
 (require 'gnus-range)
 (require 'gnus-int)
 (require 'gnus-undo)
+(require 'mime-view)
+
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
+(autoload 'gnus-set-summary-default-charset "gnus-i18n" nil t)
 
 (defcustom gnus-kill-summary-on-exit t
   "*If non-nil, kill the summary buffer when you exit from it.
@@ -217,10 +221,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 +285,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)
 
@@ -325,7 +331,7 @@ variable."
   :group 'gnus-article-various
   :type 'boolean)
 
-(defcustom gnus-show-mime nil
+(defcustom gnus-show-mime t
   "*If non-nil, do mime processing of articles.
 The articles will simply be fed to the function given by
 `gnus-show-mime-method'."
@@ -509,6 +515,7 @@ with some simple extensions:
 %G  Group name
 %p  Unprefixed group name
 %A  Current article number
+%z  Current article score
 %V  Gnus version
 %U  Number of unread articles in the group
 %e  Number of unselected articles in the group
@@ -659,18 +666,24 @@ is not run if `gnus-visual' is nil."
   :group 'gnus-summary-visual
   :type 'hook)
 
-(defcustom gnus-structured-field-decoder 'identity
+(defcustom gnus-structured-field-decoder
+  #'eword-decode-and-unfold-structured-field
   "Function to decode non-ASCII characters in structured field for summary."
   :group 'gnus-various
   :type 'function)
 
-(defcustom gnus-unstructured-field-decoder 'identity
+(defcustom gnus-unstructured-field-decoder
+  (function
+   (lambda (string)
+     (eword-decode-unstructured-field-body
+      (std11-unfold-string string) 'must-unfold)
+     ))
   "Function to decode non-ASCII characters in unstructured field for summary."
   :group 'gnus-various
   :type 'function)
 
 (defcustom gnus-parse-headers-hook
-  (list 'gnus-hack-decode-rfc1522 'gnus-decode-rfc1522)
+  '(gnus-set-summary-default-charset)
   "*A hook called before parsing the headers."
   :group 'gnus-various
   :type 'hook)
@@ -864,6 +877,7 @@ variable (string, integer, character, etc).")
     (?d (length gnus-newsgroup-dormant) ?d)
     (?t (length gnus-newsgroup-marked) ?d)
     (?r (length gnus-newsgroup-reads) ?d)
+    (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
     (?E gnus-newsgroup-expunged-tally ?d)
     (?s (gnus-current-score-file-nondirectory) ?s)))
 
@@ -1137,6 +1151,7 @@ increase the score of each group you read."
     [delete] gnus-summary-prev-page
     [backspace] gnus-summary-prev-page
     "\r" gnus-summary-scroll-up
+    "\e\r" gnus-summary-scroll-down
     "n" gnus-summary-next-unread-article
     "p" gnus-summary-prev-unread-article
     "N" gnus-summary-next-article
@@ -1218,6 +1233,7 @@ increase the score of each group you read."
     "t" gnus-article-hide-headers
     "g" gnus-summary-show-article
     "l" gnus-summary-goto-last-article
+    "v" gnus-summary-preview-mime-message
     "\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
@@ -1361,7 +1377,6 @@ increase the score of each group you read."
     "e" gnus-article-emphasize
     "w" gnus-article-fill-cited-article
     "c" gnus-article-remove-cr
-    "q" gnus-article-de-quoted-unreadable
     "f" gnus-article-display-x-face
     "l" gnus-summary-stop-page-breaking
     "r" gnus-summary-caesar-message
@@ -1422,6 +1437,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)
 
@@ -1506,7 +1522,6 @@ increase the score of each group you read."
               ["Word wrap" gnus-article-fill-cited-article t]
               ["CR" gnus-article-remove-cr t]
               ["Show X-Face" gnus-article-display-x-face t]
-              ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
               ["UnHTMLize" gnus-article-treat-html t]
               ["Rot 13" gnus-summary-caesar-message t]
               ["Unix pipe" gnus-summary-pipe-message t]
@@ -1544,6 +1559,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)])
@@ -1727,6 +1743,7 @@ 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]
@@ -2011,12 +2028,14 @@ 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."
+  (setq gnus-newsgroup-data-reverse nil)
   (let ((data gnus-newsgroup-data)
        pos)
     (while data
@@ -2413,7 +2432,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)
@@ -2499,7 +2518,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.
@@ -2510,8 +2530,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
@@ -2525,7 +2547,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)))
@@ -2533,7 +2556,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)
@@ -2922,7 +2946,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)))))
@@ -2937,6 +2960,7 @@ 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)
     ;; First we create an alist of generations/relations, where
@@ -2955,12 +2979,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.
@@ -2969,7 +2995,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)
@@ -3160,7 +3186,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))
@@ -3177,12 +3203,11 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
         (number (mail-header-number header))
         pos)
     (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)
@@ -3256,13 +3281,13 @@ If LINE, insert the rebuilt thread starting on line LINE."
        (headers in-headers)
        references)
     (while (and parent
-               headers
                (not (zerop generation))
                (setq references (mail-header-references headers)))
-      (when (and references
-                (setq parent (gnus-parent-id references))
-                (setq headers (car (gnus-id-to-thread parent))))
-       (decf generation)))
+      (setq headers (if (and references
+                            (setq parent (gnus-parent-id references)))
+                       (car (gnus-id-to-thread parent))
+                     nil))
+      (decf generation))
     (and (not (eq headers in-headers))
         headers)))
 
@@ -3750,7 +3775,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)
@@ -3804,9 +3829,10 @@ 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
@@ -3858,7 +3884,12 @@ If READ-ALL is non-nil, all articles in the group are selected."
     (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)
@@ -3908,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))
@@ -4349,7 +4380,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
       (subst-char-in-region (point-min) (point-max) ?\t ?  t)
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (let ((case-fold-search t)
-           in-reply-to header p lines)
+           in-reply-to header p lines chars)
        (goto-char (point-min))
        ;; Search to the beginning of the next header.  Error messages
        ;; do not begin with 2 or 3.
@@ -4438,7 +4469,12 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                          (setq ref ref2))))
                  (setq ref nil))))
            ;; Chars.
-           0
+           (progn
+             (goto-char p)
+             (if (search-forward "\nchars: " nil t)
+                 (if (numberp (setq chars (ignore-errors (read cur))))
+                     chars 0)
+               0))
            ;; Lines.
            (progn
              (goto-char p)
@@ -4626,7 +4662,7 @@ current article will be taken into consideration."
       (let ((max (max (point) (mark)))
            articles article)
        (save-excursion
-         (goto-char (min (min (point) (mark))))
+         (goto-char (min (point) (mark)))
          (while
              (and
               (push (setq article (gnus-summary-article-number)) articles)
@@ -4643,6 +4679,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)
@@ -4841,12 +4890,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)
@@ -5147,6 +5196,23 @@ The state which existed when entering the ephemeral is reset."
       (gnus-summary-recenter)
       (gnus-summary-position-point))))
 
+(defun gnus-summary-preview-mime-message (arg)
+  "MIME decode and play this message."
+  (interactive "P")
+  (or gnus-show-mime
+      (let ((gnus-break-pages nil)
+           (gnus-show-mime t))
+       (gnus-summary-select-article t t)
+       ))
+  (select-window (get-buffer-window gnus-article-buffer))
+  )
+
+(defun gnus-summary-scroll-down ()
+  "Scroll down one line current article."
+  (interactive)
+  (gnus-summary-scroll-up -1)
+  )
+
 ;;; Dead summaries.
 
 (defvar gnus-dead-summary-mode-map nil)
@@ -5408,6 +5474,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.
@@ -5888,8 +5955,8 @@ articles that are younger than AGE days."
                              (nnmail-time-since (nnmail-date-to-time date))
                              cutoff))
            (when (if younger-p
-                     (not is-younger)
-                   is-younger)
+                     is-younger
+                   (not is-younger))
              (push (gnus-data-number d) articles))))
        (gnus-summary-limit (nreverse articles)))
     (gnus-summary-position-point)))
@@ -6025,7 +6092,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
@@ -6073,6 +6141,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))))
@@ -7106,7 +7175,7 @@ latter case, they will be copied into the relevant groups."
       (set-buffer (get-buffer-create " *import file*"))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (insert-file-contents file)
+      (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (unless (nnheader-article-p)
        ;; This doesn't look like an article, so we fudge some headers.
@@ -7212,7 +7281,7 @@ delete these instead."
                                       gnus-newsgroup-name)
     (error "The current newsgroup does not support article deletion"))
   ;; Compute the list of articles to delete.
-  (let ((articles (gnus-summary-work-articles n))
+  (let ((articles (sort (copy-sequence (gnus-summary-work-articles n)) '<))
        not-deleted)
     (if (and gnus-novice-user
             (not (gnus-yes-or-no-p
@@ -7267,55 +7336,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."
@@ -7331,7 +7403,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)
@@ -7340,7 +7412,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"
@@ -7348,6 +7420,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)
@@ -7613,9 +7691,7 @@ returned."
               (push article gnus-newsgroup-dormant))
              (t
               (push article gnus-newsgroup-unreads)))
-       (setq gnus-newsgroup-reads
-             (delq (assq article gnus-newsgroup-reads)
-                   gnus-newsgroup-reads))
+       (gnus-pull article gnus-newsgroup-reads)
 
        ;; See whether the article is to be put in the cache.
        (and gnus-use-cache
@@ -7756,9 +7832,7 @@ marked."
             (push article gnus-newsgroup-dormant))
            (t
             (push article gnus-newsgroup-unreads)))
-      (setq gnus-newsgroup-reads
-           (delq (assq article gnus-newsgroup-reads)
-                 gnus-newsgroup-reads))
+      (gnus-pull article gnus-newsgroup-reads)
       t)))
 
 (defalias 'gnus-summary-mark-as-unread-forward
@@ -8817,7 +8891,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
@@ -8901,6 +8975,38 @@ save those articles instead."
           (gnus-summary-exit))
         buffers)))))
 
+
+;;; @ for mime-partial
+;;;
+
+(defun gnus-request-partial-message ()
+  (save-excursion
+    (let ((number (gnus-summary-article-number))
+         (group gnus-newsgroup-name)
+         (mother gnus-article-buffer))
+      (set-buffer (get-buffer-create " *Partial Article*"))
+      (erase-buffer)
+      (setq mime-preview-buffer mother)
+      (gnus-request-article-this-buffer number group)
+      (mime-parse-buffer)
+      )))
+
+(autoload 'mime-combine-message/partial-pieces-automatically
+  "mime-partial"
+  "Internal method to combine message/partial messages automatically.")
+
+(mime-add-condition
+ 'action '((type . message)(subtype . partial)
+          (major-mode . gnus-original-article-mode)
+          (method . mime-combine-message/partial-pieces-automatically)
+          (summary-buffer-exp . gnus-summary-buffer)
+          (request-partial-message-method . gnus-request-partial-message)
+          ))
+
+
+;;; @ end
+;;;
+
 (gnus-ems-redefine)
 
 (provide 'gnus-sum)