*** empty log message ***
[gnus] / lisp / gnus-sum.el
index e9496b3..dbc1c62 100644 (file)
@@ -30,9 +30,9 @@
 (require 'gnus-spec)
 (require 'gnus-range)
 (require 'gnus-int)
+(require 'gnus-undo)
 (require 'gnus)
 
-
 (defvar gnus-kill-summary-on-exit t
   "*If non-nil, kill the summary buffer when you exit from it.
 If nil, the summary will become a \"*Dead Summary*\" buffer, and
@@ -258,6 +258,8 @@ It uses the same syntax as the `gnus-split-methods' variable.")
   "*Mark used for sparsely reffed articles.")
 (defvar gnus-canceled-mark ?G
   "*Mark used for canceled articles.")
+(defvar gnus-duplicate-mark ?M
+  "*Mark used for duplicate articles.")
 (defvar gnus-score-over-mark ?+
   "*Score mark used for articles with high scores.")
 (defvar gnus-score-below-mark ?-
@@ -283,63 +285,6 @@ list of parameters to that command.")
 (defvar gnus-insert-pseudo-articles t
   "*If non-nil, insert pseudo-articles when decoding articles.")
 
-(defvar gnus-summary-line-format "%U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
-  "*The format specification of the lines in the summary buffer.
-
-It works along the same lines as a normal formatting string,
-with some simple extensions.
-
-%N   Article number, left padded with spaces (string)
-%S   Subject (string)
-%s   Subject if it is at the root of a thread, and \"\" otherwise (string)
-%n   Name of the poster (string)
-%a   Extracted name of the poster (string)
-%A   Extracted address of the poster (string)
-%F   Contents of the From: header (string)
-%x   Contents of the Xref: header (string)
-%D   Date of the article (string)
-%d   Date of the article (string) in DD-MMM format
-%M   Message-id of the article (string)
-%r   References of the article (string)
-%c   Number of characters in the article (integer)
-%L   Number of lines in the article (integer)
-%I   Indentation based on thread level (a string of spaces)
-%T   A string with two possible values: 80 spaces if the article
-     is on thread level two or larger and 0 spaces on level one
-%R   \"A\" if this article has been replied to, \" \" otherwise (character)
-%U   Status of this article (character, \"R\", \"K\", \"-\" or \" \")
-%[   Opening bracket (character, \"[\" or \"<\")
-%]   Closing bracket (character, \"]\" or \">\")
-%>   Spaces of length thread-level (string)
-%<   Spaces of length (- 20 thread-level) (string)
-%i   Article score (number)
-%z   Article zcore (character)
-%t   Number of articles under the current thread (number).
-%e   Whether the thread is empty or not (character).
-%l   GroupLens score (string).
-%u   User defined specifier.  The next character in the format string should
-     be a letter.  Gnus will call the function gnus-user-format-function-X,
-     where X is the letter following %u.  The function will be passed the
-     current header as argument.  The function should return a string, which
-     will be inserted into the summary just like information from any other
-     summary specifier.
-
-Text between %( and %) will be highlighted with `gnus-mouse-face'
-when the mouse point is placed inside the area.         There can only be one
-such area.
-
-The %U (status), %R (replied) and %z (zcore) specs have to be handled
-with care.  For reasons of efficiency, Gnus will compute what column
-these characters will end up in, and \"hard-code\" that.  This means that
-it is illegal to have these specs after a variable-length spec.         Well,
-you might not be arrested, but your summary buffer will look strange,
-which is bad enough.
-
-The smart choice is to have these specs as for to the left as
-possible.
-
-This restriction may disappear in later versions of Gnus.")
-
 (defvar gnus-summary-dummy-line-format
   "*  %(:                          :%) %S\n"
   "*The format specification for the dummy roots in the summary buffer.
@@ -412,6 +357,9 @@ See `gnus-thread-score-function' for en explanation of what a
   "*A hook for Gnus summary mode.
 This hook is run before any variables are set in the summary buffer.")
 
+(defvar gnus-summary-menu-hook nil
+  "*Hook run after the creation of the summary mode menu.")
+
 (defvar gnus-summary-exit-hook nil
   "*A hook called on exit from the summary buffer.")
 
@@ -471,6 +419,8 @@ variable.")
 The hook is intended to mark an article as read (or unread)
 automatically when it is selected.")
 
+;;; Internal variables
+
 (defvar gnus-summary-display-table 
   ;; Change the display table. Odd characters have a tendency to mess
   ;; up nicely formatted displays - we make all possible glyphs
@@ -496,11 +446,9 @@ automatically when it is selected.")
     table)
   "Display table used in summary mode buffers.")
 
-;;; Internal variables
-
-(defvar gnus-original-article-buffer " *Original Article*")
 (defvar gnus-original-article nil)
 (defvar gnus-article-internal-prepare-hook nil)
+(defvar gnus-newsgroup-process-stack nil)
 
 (defvar gnus-thread-indent-array nil)
 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
@@ -534,6 +482,7 @@ automatically when it is selected.")
     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
     (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
     (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
+    (?o (gnus-date-iso8601 gnus-tmp-header) ?s)
     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
@@ -556,7 +505,8 @@ automatically when it is selected.")
     (?e (gnus-summary-number-of-articles-in-thread
         (and (boundp 'thread) (car thread)) gnus-tmp-level t)
        ?c)
-    (?u gnus-tmp-user-defined ?s))
+    (?u gnus-tmp-user-defined ?s)
+    (?P (gnus-pick-line-number) ?d))
   "An alist of format specifications that can appear in summary lines,
 and what variables they correspond with, along with the type of the
 variable (string, integer, character, etc).")
@@ -688,7 +638,7 @@ variable (string, integer, character, etc).")
     (gnus-summary-mark-below . global)
     gnus-newsgroup-active gnus-scores-exclude-files
     gnus-newsgroup-history gnus-newsgroup-ancient
-    gnus-newsgroup-sparse
+    gnus-newsgroup-sparse gnus-newsgroup-process-stack
     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
     gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
     (gnus-newsgroup-expunged-tally . 0)
@@ -936,6 +886,7 @@ increase the score of each group you read."
     "l" gnus-summary-goto-last-article
     "\C-c\C-v\C-v" gnus-uu-decode-uu-view
     "\C-d" gnus-summary-enter-digest-group
+    "\M-\C-d" gnus-summary-read-document
     "\C-c\C-b" gnus-bug
     "*" gnus-cache-enter-article
     "\M-*" gnus-cache-remove-article
@@ -1064,7 +1015,6 @@ increase the score of each group you read."
     "e" gnus-article-emphasize
     "w" gnus-article-fill-cited-article
     "c" gnus-article-remove-cr
-    "L" gnus-article-remove-trailing-blank-lines
     "q" gnus-article-de-quoted-unreadable
     "f" gnus-article-display-x-face
     "l" gnus-summary-stop-page-breaking
@@ -1096,6 +1046,12 @@ increase the score of each group you read."
     "e" gnus-article-date-lapsed
     "o" gnus-article-date-original)
 
+  (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
+    "t" gnus-article-remove-trailing-blank-lines
+    "l" gnus-article-strip-leading-blank-lines
+    "m" gnus-article-strip-multiple-blank-lines
+    "a" gnus-article-strip-blank-lines)
+
   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
     "v" gnus-version
     "f" gnus-summary-fetch-faq
@@ -1114,7 +1070,8 @@ increase the score of each group you read."
     "c" gnus-summary-copy-article
     "B" gnus-summary-crosspost-article
     "q" gnus-summary-respool-query
-    "i" gnus-summary-import-article)
+    "i" gnus-summary-import-article
+    "p" gnus-summary-article-posted-p)
 
   (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
     "o" gnus-summary-save-article
@@ -1125,8 +1082,471 @@ increase the score of each group you read."
     "h" gnus-summary-save-article-folder
     "v" gnus-summary-save-article-vm
     "p" gnus-summary-pipe-output
-    "s" gnus-soup-add-article)
-  )
+    "s" gnus-soup-add-article))
+
+(defun gnus-summary-make-menu-bar ()
+  (gnus-turn-off-edit-menu 'summary)
+
+  (unless (boundp 'gnus-summary-misc-menu)
+
+    (easy-menu-define
+     gnus-summary-kill-menu gnus-summary-mode-map ""
+     (cons
+      "Score"
+      (nconc
+       (list
+       ["Enter score..." gnus-summary-score-entry t])
+       (gnus-make-score-map 'increase)
+       (gnus-make-score-map 'lower)
+       '(("Mark"
+         ["Kill below" gnus-summary-kill-below t]
+         ["Mark above" gnus-summary-mark-above t]
+         ["Tick above" gnus-summary-tick-above t]
+         ["Clear above" gnus-summary-clear-above t])
+        ["Current score" gnus-summary-current-score t]
+        ["Set score" gnus-summary-set-score t]
+        ["Customize score file" gnus-score-customize t]
+        ["Switch current score file..." gnus-score-change-score-file t]
+        ["Set mark below..." gnus-score-set-mark-below t]
+        ["Set expunge below..." gnus-score-set-expunge-below t]
+        ["Edit current score file" gnus-score-edit-current-scores t]
+        ["Edit score file" gnus-score-edit-file t]
+        ["Trace score" gnus-score-find-trace t]
+        ["Find words" gnus-score-find-favuorite-words t]
+        ["Rescore buffer" gnus-summary-rescore t]
+        ["Increase score..." gnus-summary-increase-score t]
+        ["Lower score..." gnus-summary-lower-score t]))))
+
+    '(("Default header"
+       ["Ask" (gnus-score-set-default 'gnus-score-default-header nil)
+       :style radio 
+       :selected (null gnus-score-default-header)]
+       ["From" (gnus-score-set-default 'gnus-score-default-header 'a)
+       :style radio 
+       :selected (eq gnus-score-default-header 'a)]
+       ["Subject" (gnus-score-set-default 'gnus-score-default-header 's)
+       :style radio 
+       :selected (eq gnus-score-default-header 's)]
+       ["Article body"
+       (gnus-score-set-default 'gnus-score-default-header 'b)
+       :style radio 
+       :selected (eq gnus-score-default-header 'b )]
+       ["All headers"
+       (gnus-score-set-default 'gnus-score-default-header 'h)
+       :style radio 
+       :selected (eq gnus-score-default-header 'h )]
+       ["Message-Id" (gnus-score-set-default 'gnus-score-default-header 'i)
+       :style radio 
+       :selected (eq gnus-score-default-header 'i )]
+       ["Thread" (gnus-score-set-default 'gnus-score-default-header 't)
+       :style radio 
+       :selected (eq gnus-score-default-header 't )]
+       ["Crossposting"
+       (gnus-score-set-default 'gnus-score-default-header 'x)
+       :style radio 
+       :selected (eq gnus-score-default-header 'x )]
+       ["Lines" (gnus-score-set-default 'gnus-score-default-header 'l)
+       :style radio 
+       :selected (eq gnus-score-default-header 'l )]
+       ["Date" (gnus-score-set-default 'gnus-score-default-header 'd)
+       :style radio 
+       :selected (eq gnus-score-default-header 'd )]
+       ["Followups to author"
+       (gnus-score-set-default 'gnus-score-default-header 'f)
+       :style radio 
+       :selected (eq gnus-score-default-header 'f )])
+      ("Default type"
+       ["Ask" (gnus-score-set-default 'gnus-score-default-type nil)
+       :style radio 
+       :selected (null gnus-score-default-type)]
+       ;; The `:active' key is commented out in the following,
+       ;; because the GNU Emacs hack to support radio buttons use
+       ;; active to indicate which button is selected.  
+       ["Substring" (gnus-score-set-default 'gnus-score-default-type 's)
+       :style radio 
+       ;; :active (not (memq gnus-score-default-header '(l d)))
+       :selected (eq gnus-score-default-type 's)]
+       ["Regexp" (gnus-score-set-default 'gnus-score-default-type 'r)
+       :style radio
+       ;; :active (not (memq gnus-score-default-header '(l d)))
+       :selected (eq gnus-score-default-type 'r)]
+       ["Exact" (gnus-score-set-default 'gnus-score-default-type 'e)
+       :style radio
+       ;; :active (not (memq gnus-score-default-header '(l d)))
+       :selected (eq gnus-score-default-type 'e)]
+       ["Fuzzy" (gnus-score-set-default 'gnus-score-default-type 'f)
+       :style radio 
+       ;; :active (not (memq gnus-score-default-header '(l d)))
+       :selected (eq gnus-score-default-type 'f)]
+       ["Before date" (gnus-score-set-default 'gnus-score-default-type 'b)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'd))
+       :selected (eq gnus-score-default-type 'b)]
+       ["At date" (gnus-score-set-default 'gnus-score-default-type 'n)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'd))
+       :selected (eq gnus-score-default-type 'n)]
+       ["After date" (gnus-score-set-default 'gnus-score-default-type 'a)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'd))
+       :selected (eq gnus-score-default-type 'a)]
+       ["Less than number"
+       (gnus-score-set-default 'gnus-score-default-type '<)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'l))
+       :selected (eq gnus-score-default-type '<)]
+       ["Equal to number"
+       (gnus-score-set-default 'gnus-score-default-type '=)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'l))
+       :selected (eq gnus-score-default-type '=)]
+       ["Greater than number" 
+       (gnus-score-set-default 'gnus-score-default-type '>)
+       :style radio 
+       ;; :active (eq (gnus-score-default-header 'l))
+       :selected (eq gnus-score-default-type '>)])
+      ["Default fold" gnus-score-default-fold-toggle
+       :style toggle
+       :selected gnus-score-default-fold]
+      ("Default duration"
+       ["Ask" (gnus-score-set-default 'gnus-score-default-duration nil)
+       :style radio
+       :selected (null gnus-score-default-duration)]
+       ["Permanent"
+       (gnus-score-set-default 'gnus-score-default-duration 'p)
+       :style radio
+       :selected (eq gnus-score-default-duration 'p)]
+       ["Temporary"
+       (gnus-score-set-default 'gnus-score-default-duration 't)
+       :style radio
+       :selected (eq gnus-score-default-duration 't)]
+       ["Immediate" 
+       (gnus-score-set-default 'gnus-score-default-duration 'i)
+       :style radio
+       :selected (eq gnus-score-default-duration 'i)]))
+
+    (easy-menu-define
+     gnus-summary-article-menu gnus-summary-mode-map ""
+     '("Article"
+       ("Hide"
+       ["All" gnus-article-hide t]
+       ["Headers" gnus-article-hide-headers t]
+       ["Signature" gnus-article-hide-signature t]
+       ["Citation" gnus-article-hide-citation t]
+       ["PGP" gnus-article-hide-pgp t]
+       ["Boring headers" gnus-article-hide-boring-headers t])
+       ("Highlight"
+       ["All" gnus-article-highlight t]
+       ["Headers" gnus-article-highlight-headers t]
+       ["Signature" gnus-article-highlight-signature t]
+       ["Citation" gnus-article-highlight-citation t])
+       ("Date"
+       ["Local" gnus-article-date-local t]
+       ["UT" gnus-article-date-ut t]
+       ["Original" gnus-article-date-original t]
+       ["Lapsed" gnus-article-date-lapsed t])
+       ("Filter"
+       ("Remove Blanks"
+        ["Leading" gnus-article-strip-leading-blank-lines t]
+        ["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])
+       ["Overstrike" gnus-article-treat-overstrike t]
+       ["Emphasis" gnus-article-emphasize t]
+       ["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]
+       ["Rot 13" gnus-summary-caesar-message t]
+       ["Add buttons" gnus-article-add-buttons t]
+       ["Add buttons to head" gnus-article-add-buttons-to-head t]
+       ["Stop page breaking" gnus-summary-stop-page-breaking t]
+       ["Toggle MIME" gnus-summary-toggle-mime t]
+       ["Verbose header" gnus-summary-verbose-headers t]
+       ["Toggle header" gnus-summary-toggle-header t])
+       ("Output"
+       ["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]
+       ["Save in MH folder" gnus-summary-save-article-folder t]
+       ["Save in VM folder" gnus-summary-save-article-vm t]
+       ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
+       ["Save body in file" gnus-summary-save-article-body-file t]
+       ["Pipe through a filter" gnus-summary-pipe-output t]
+       ["Add to SOUP packet" gnus-soup-add-article t])
+       ("Backend"
+       ["Respool article..." gnus-summary-respool-article t]
+       ["Move article..." gnus-summary-move-article
+        (gnus-check-backend-function
+         'request-move-article gnus-newsgroup-name)]
+       ["Copy article..." gnus-summary-copy-article t]
+       ["Crosspost article..." gnus-summary-crosspost-article
+        (gnus-check-backend-function
+         'request-replace-article gnus-newsgroup-name)]
+       ["Import file..." gnus-summary-import-article t]
+       ["Chek if posted" gnus-summary-article-posted-p t]
+       ["Edit article" gnus-summary-edit-article
+        (not (gnus-group-read-only-p))]
+       ["Delete article" gnus-summary-delete-article
+        (gnus-check-backend-function
+         'request-expire-articles gnus-newsgroup-name)]
+       ["Query respool" gnus-summary-respool-query t]
+       ["Delete expirable articles" gnus-summary-expire-articles-now
+        (gnus-check-backend-function
+         'request-expire-articles gnus-newsgroup-name)])
+       ("Extract"
+       ["Uudecode" gnus-uu-decode-uu t]
+       ["Uudecode and save" gnus-uu-decode-uu-and-save t]
+       ["Unshar" gnus-uu-decode-unshar t]
+       ["Unshar and save" gnus-uu-decode-unshar-and-save t]
+       ["Save" gnus-uu-decode-save t]
+       ["Binhex" gnus-uu-decode-binhex t]
+       ["Postscript" gnus-uu-decode-postscript t])
+       ["Enter digest buffer" gnus-summary-enter-digest-group t]
+       ["Isearch article..." gnus-summary-isearch-article t]
+       ["Search articles forward..." gnus-summary-search-article-forward t]
+       ["Search articles backward..." gnus-summary-search-article-backward t]
+       ["Beginning of the article" gnus-summary-beginning-of-article t]
+       ["End of the article" gnus-summary-end-of-article t]
+       ["Fetch parent of article" gnus-summary-refer-parent-article t]
+       ["Fetch referenced articles" gnus-summary-refer-references t]
+       ["Fetch article with id..." gnus-summary-refer-article t]
+       ["Redisplay" gnus-summary-show-article t]))
+
+    (easy-menu-define
+     gnus-summary-thread-menu gnus-summary-mode-map ""
+     '("Threads"
+       ["Toggle threading" gnus-summary-toggle-threads t]
+       ["Hide threads" gnus-summary-hide-all-threads t]
+       ["Show threads" gnus-summary-show-all-threads t]
+       ["Hide thread" gnus-summary-hide-thread t]
+       ["Show thread" gnus-summary-show-thread t]
+       ["Go to next thread" gnus-summary-next-thread t]
+       ["Go to previous thread" gnus-summary-prev-thread t]
+       ["Go down thread" gnus-summary-down-thread t]
+       ["Go up thread" gnus-summary-up-thread t]
+       ["Top of thread" gnus-summary-top-thread t]
+       ["Mark thread as read" gnus-summary-kill-thread t]
+       ["Lower thread score" gnus-summary-lower-thread t]
+       ["Raise thread score" gnus-summary-raise-thread t]
+       ["Rethread current" gnus-summary-rethread-current t]
+       ))
+
+    (easy-menu-define
+     gnus-summary-post-menu gnus-summary-mode-map ""
+     '("Post"
+       ["Post an article" gnus-summary-post-news t]
+       ["Followup" gnus-summary-followup t]
+       ["Followup and yank" gnus-summary-followup-with-original t]
+       ["Supersede article" gnus-summary-supersede-article t]
+       ["Cancel article" gnus-summary-cancel-article t]
+       ["Reply" gnus-summary-reply t]
+       ["Reply and yank" gnus-summary-reply-with-original t]
+       ["Mail forward" gnus-summary-mail-forward t]
+       ["Post forward" gnus-summary-post-forward t]
+       ["Digest and mail" gnus-uu-digest-mail-forward t]
+       ["Digest and post" gnus-uu-digest-post-forward t]
+       ["Resend message" gnus-summary-resend-message t]
+       ["Send bounced mail" gnus-summary-resend-bounced-mail t]
+       ["Send a mail" gnus-summary-mail-other-window t]
+       ["Uuencode and post" gnus-uu-post-news t]
+       ;;("Draft"
+       ;;["Send" gnus-summary-send-draft t]
+       ;;["Send bounced" gnus-resend-bounced-mail t])
+       ))
+
+    (easy-menu-define
+     gnus-summary-misc-menu gnus-summary-mode-map ""
+     '("Misc"
+       ("Mark"
+       ("Read"
+        ["Mark as read" gnus-summary-mark-as-read-forward t]
+        ["Mark same subject and select"
+         gnus-summary-kill-same-subject-and-select t]
+        ["Mark same subject" gnus-summary-kill-same-subject t]
+        ["Catchup" gnus-summary-catchup t]
+        ["Catchup all" gnus-summary-catchup-all t]
+        ["Catchup to here" gnus-summary-catchup-to-here t]
+        ["Catchup region" gnus-summary-mark-region-as-read t]
+        ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
+       ("Various"
+        ["Tick" gnus-summary-tick-article-forward t]
+        ["Mark as dormant" gnus-summary-mark-as-dormant t]
+        ["Remove marks" gnus-summary-clear-mark-forward t]
+        ["Set expirable mark" gnus-summary-mark-as-expirable t]
+        ["Set bookmark" gnus-summary-set-bookmark t]
+        ["Remove bookmark" gnus-summary-remove-bookmark t])
+       ("Limit"
+        ["Marks..." gnus-summary-limit-to-marks t]
+        ["Subject..." gnus-summary-limit-to-subject t]
+        ["Author..." gnus-summary-limit-to-author t]
+        ["Score" gnus-summary-limit-to-score t]
+        ["Unread" gnus-summary-limit-to-unread t]
+        ["Non-dormant" gnus-summary-limit-exclude-dormant t]
+        ["Articles" gnus-summary-limit-to-articles t]
+        ["Pop limit" gnus-summary-pop-limit t]
+        ["Show dormant" gnus-summary-limit-include-dormant t]
+        ["Hide childless dormant" 
+         gnus-summary-limit-exclude-childless-dormant t]
+        ;;["Hide thread" gnus-summary-limit-exclude-thread t]
+        ["Show expunged" gnus-summary-show-all-expunged t])
+       ("Process mark"
+        ["Set mark" gnus-summary-mark-as-processable t]
+        ["Remove mark" gnus-summary-unmark-as-processable t]
+        ["Remove all marks" gnus-summary-unmark-all-processable t]
+        ["Mark above" gnus-uu-mark-over t]
+        ["Mark series" gnus-uu-mark-series t]
+        ["Mark region" gnus-uu-mark-region t]
+        ["Mark by regexp..." gnus-uu-mark-by-regexp t]
+        ["Mark all" gnus-uu-mark-all t]
+        ["Mark buffer" gnus-uu-mark-buffer t]
+        ["Mark sparse" gnus-uu-mark-sparse t]
+        ["Mark thread" gnus-uu-mark-thread t]
+        ["Unmark thread" gnus-uu-unmark-thread t]
+        ("Process Mark Sets"
+         ["Kill" gnus-summary-kill-process-mark t]
+         ["Yank" gnus-summary-yank-process-mark
+          gnus-newsgroup-process-stack]
+         ["Save" gnus-summary-save-process-mark t])))
+       ("Scroll article"
+       ["Page forward" gnus-summary-next-page t]
+       ["Page backward" gnus-summary-prev-page t]
+       ["Line forward" gnus-summary-scroll-up t])
+       ("Move"
+       ["Next unread article" gnus-summary-next-unread-article t]
+       ["Previous unread article" gnus-summary-prev-unread-article t]
+       ["Next article" gnus-summary-next-article t]
+       ["Previous article" gnus-summary-prev-article t]
+       ["Next unread subject" gnus-summary-next-unread-subject t]
+       ["Previous unread subject" gnus-summary-prev-unread-subject t]
+       ["Next article same subject" gnus-summary-next-same-subject t]
+       ["Previous article same subject" gnus-summary-prev-same-subject t]
+       ["First unread article" gnus-summary-first-unread-article t]
+       ["Best unread article" gnus-summary-best-unread-article t]
+       ["Go to subject number..." gnus-summary-goto-subject t]
+       ["Go to article number..." gnus-summary-goto-article t]
+       ["Go to the last article" gnus-summary-goto-last-article t]
+       ["Pop article off history" gnus-summary-pop-article t]) 
+       ("Sort"
+       ["Sort by number" gnus-summary-sort-by-number t]
+       ["Sort by author" gnus-summary-sort-by-author t]
+       ["Sort by subject" gnus-summary-sort-by-subject t]
+       ["Sort by date" gnus-summary-sort-by-date t]
+       ["Sort by score" gnus-summary-sort-by-score t])
+       ("Help"
+       ["Fetch group FAQ" gnus-summary-fetch-faq t]
+       ["Describe group" gnus-summary-describe-group t]
+       ["Read manual" gnus-info-find-node t])
+       ("Cache"
+       ["Enter article" gnus-cache-enter-article t]
+       ["Remove article" gnus-cache-remove-article t])
+       ("Modes"
+       ["Pick and read" gnus-pick-mode t]
+       ["Binary" gnus-binary-mode t])
+       ["Filter articles..." gnus-summary-execute-command t]
+       ["Run command on subjects..." gnus-summary-universal-argument t]
+       ["Toggle line truncation" gnus-summary-toggle-truncation t]
+       ["Expand window" gnus-summary-expand-window t]
+       ["Expire expirable articles" gnus-summary-expire-articles
+       (gnus-check-backend-function
+        '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]
+       ("Exit"
+       ["Catchup and exit" gnus-summary-catchup-and-exit t]
+       ["Catchup all and exit" gnus-summary-catchup-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]
+       ["Exit and goto next group" gnus-summary-next-group t]
+       ["Exit and goto prev group" gnus-summary-prev-group t]
+       ["Reselect group" gnus-summary-reselect-current-group t]
+       ["Rescan group" gnus-summary-rescan-group t])))
+
+    (run-hooks 'gnus-summary-menu-hook)))
+
+(defun gnus-score-set-default (var value)
+  "A version of set that updates the GNU Emacs menu-bar."
+  (set var value)
+  ;; It is the message that forces the active status to be updated.
+  (message ""))
+
+(defun gnus-make-score-map (type)
+  "Make a summary score map of type TYPE."
+  (if t
+      nil
+    (let ((headers '(("author" "from" string)
+                    ("subject" "subject" string)
+                    ("article body" "body" string)
+                    ("article head" "head" string)
+                    ("xref" "xref" string)
+                    ("lines" "lines" number)
+                    ("followups to author" "followup" string)))
+         (types '((number ("less than" <)
+                          ("greater than" >)
+                          ("equal" =))
+                  (string ("substring" s)
+                          ("exact string" e)
+                          ("fuzzy string" f)
+                          ("regexp" r))))
+         (perms '(("temporary" (current-time-string))
+                  ("permanent" nil)
+                  ("immediate" now)))
+         header)
+      (list 
+       (apply 
+       'nconc
+       (list
+        (if (eq type 'lower)
+            "Lower score"
+          "Increase score"))
+       (let (outh)
+         (while headers
+           (setq header (car headers))
+           (setq outh 
+                 (cons 
+                  (apply 
+                   'nconc
+                   (list (car header))
+                   (let ((ts (cdr (assoc (nth 2 header) types)))
+                         outt)
+                     (while ts
+                       (setq outt
+                             (cons 
+                              (apply 
+                               'nconc
+                               (list (caar ts))
+                               (let ((ps perms)
+                                     outp)
+                                 (while ps
+                                   (setq outp
+                                         (cons
+                                          (vector
+                                           (caar ps) 
+                                           (list
+                                            'gnus-summary-score-entry
+                                            (nth 1 header)
+                                            (if (or (string= (nth 1 header) 
+                                                             "head")
+                                                    (string= (nth 1 header)
+                                                             "body"))
+                                                ""
+                                              (list 'gnus-summary-header 
+                                                    (nth 1 header)))
+                                            (list 'quote (nth 1 (car ts)))
+                                            (list 'gnus-score-default nil)
+                                            (nth 1 (car ps))
+                                            t)
+                                           t)
+                                          outp))
+                                   (setq ps (cdr ps)))
+                                 (list (nreverse outp))))
+                              outt))
+                       (setq ts (cdr ts)))
+                     (list (nreverse outt))))
+                  outh))
+           (setq headers (cdr headers)))
+         (list (nreverse outh))))))))
 
 \f
 
@@ -1168,6 +1588,7 @@ The following commands are available:
   (setq selective-display t)
   (setq selective-display-ellipses t)  ;Display `...'
   (setq buffer-display-table gnus-summary-display-table)
+  (gnus-set-default-directory)
   (setq gnus-newsgroup-name group)
   (make-local-variable 'gnus-summary-line-format)
   (make-local-variable 'gnus-summary-line-format-spec)
@@ -1235,6 +1656,9 @@ The following commands are available:
 (defmacro gnus-data-unread-p (data)
   `(= (nth 1 ,data) gnus-unread-mark))
 
+(defmacro gnus-data-read-p (data)
+  `(/= (nth 1 ,data) gnus-unread-mark))
+
 (defmacro gnus-data-pseudo-p (data)
   `(consp (nth 3 ,data)))
 
@@ -1429,6 +1853,15 @@ This is all marks except unread, ticked, dormant, and expirable."
           (= mark gnus-dormant-mark)
           (= mark gnus-expirable-mark))))
 
+(defmacro gnus-article-mark (number)
+  `(cond
+    ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
+    ((memq ,number gnus-newsgroup-marked) gnus-ticked-mark)
+    ((memq ,number gnus-newsgroup-dormant) gnus-dormant-mark)
+    ((memq ,number gnus-newsgroup-expirable) gnus-expirable-mark)
+    (t (or (cdr (assq ,number gnus-newsgroup-reads))
+          gnus-ancient-mark))))
+
 ;; Saving hidden threads.
 
 (put 'gnus-save-hidden-threads 'lisp-indent-function 0)
@@ -1683,7 +2116,7 @@ This is all marks except unread, ticked, dormant, and expirable."
 
 (defun gnus-summary-set-local-parameters (group)
  "Go through the local params of GROUP and set all variable specs in that list."
-  (let ((params (gnus-info-params (gnus-get-info group)))
+  (let ((params (gnus-group-find-parameter group))
        elem)
     (while params
       (setq elem (car params)
@@ -1769,7 +2202,8 @@ If NO-DISPLAY, don't generate a summary buffer."
       (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)
+      (gnus-update-format-specifications
+       nil 'summary 'summary-mode 'summary-dummy)
       ;; Do score processing.
       (when gnus-use-scoring
        (gnus-possibly-score-headers))
@@ -2104,6 +2538,34 @@ If NO-DISPLAY, don't generate a summary buffer."
                      (delq number gnus-newsgroup-unselected)))
            (push number gnus-newsgroup-ancient)))))))
 
+(defun gnus-summary-update-article-line (article header)
+  "Update the line for ARTICLE using HEADERS."
+  (let* ((id (mail-header-id header))
+        (thread (gnus-id-to-thread id)))
+    (unless thread
+      (error "Article in no thread"))
+    ;; Update the thread.
+    (setcar thread header)
+    (gnus-summary-goto-subject article)
+    (let* ((datal (gnus-data-find-list article))
+          (data (car datal))
+          (length (when (cdr datal)
+                    (- (gnus-data-pos data)
+                       (gnus-data-pos (cadr datal)))))
+          (buffer-read-only nil)
+          (level (gnus-summary-thread-level)))
+      (gnus-delete-line)
+      (gnus-summary-insert-line
+       header level nil (gnus-article-mark article)
+       (memq article gnus-newsgroup-replied)
+       (memq article gnus-newsgroup-expirable)
+       (mail-header-subject header)
+       nil (cdr (assq article gnus-newsgroup-scored))
+       (memq article gnus-newsgroup-processable))
+      (when length
+       (gnus-data-update-list
+        (cdr datal) (- length (- (gnus-data-pos data) (point))))))))
+     
 (defun gnus-summary-update-article (article &optional iheader)
   "Update ARTICLE in the summary buffer."
   (set-buffer gnus-summary-buffer)
@@ -2596,15 +3058,7 @@ or a straight list of headers."
              (setq gnus-tmp-dummy-line nil))
 
            ;; Compute the mark.
-           (setq
-            gnus-tmp-unread
-            (cond
-             ((memq number gnus-newsgroup-unreads) gnus-unread-mark)
-             ((memq number gnus-newsgroup-marked) gnus-ticked-mark)
-             ((memq number gnus-newsgroup-dormant) gnus-dormant-mark)
-             ((memq number gnus-newsgroup-expirable) gnus-expirable-mark)
-             (t (or (cdr (assq number gnus-newsgroup-reads))
-                    gnus-ancient-mark))))
+           (setq gnus-tmp-unread (gnus-article-mark number))
 
            (push (gnus-data-make number gnus-tmp-unread (1+ (point))
                                  gnus-tmp-header gnus-tmp-level)
@@ -2714,14 +3168,7 @@ or a straight list of headers."
            (push (cons number gnus-low-score-mark)
                  gnus-newsgroup-reads)))
 
-       (setq mark
-             (cond
-              ((memq number gnus-newsgroup-marked) gnus-ticked-mark)
-              ((memq number gnus-newsgroup-dormant) gnus-dormant-mark)
-              ((memq number gnus-newsgroup-unreads) gnus-unread-mark)
-              ((memq number gnus-newsgroup-expirable) gnus-expirable-mark)
-              (t (or (cdr (assq number gnus-newsgroup-reads))
-                     gnus-ancient-mark))))
+       (setq mark (gnus-article-mark number))
        (setq gnus-newsgroup-data
              (cons (gnus-data-make number mark (1+ (point)) header 0)
                    gnus-newsgroup-data))
@@ -2809,6 +3256,10 @@ If READ-ALL is non-nil, all articles in the group are selected."
       (when cached
        (setq gnus-newsgroup-cached cached))
 
+      ;; Suppress duplicates?
+      (when gnus-suppress-duplicates
+       (gnus-dup-suppress-articles))
+
       ;; Set the initial limit.
       (setq gnus-newsgroup-limit (copy-sequence articles))
       ;; Remove canceled articles from the list of unread articles.
@@ -2848,7 +3299,9 @@ If READ-ALL is non-nil, all articles in the group are selected."
          ;; are no unread articles.
          (if (or read-all
                  (and (zerop (length gnus-newsgroup-marked))
-                      (zerop (length gnus-newsgroup-unreads))))
+                      (zerop (length gnus-newsgroup-unreads)))
+                 (eq (gnus-group-find-parameter group 'display)
+                     'all))
              (gnus-uncompress-range (gnus-active group))
            (sort (append gnus-newsgroup-dormant gnus-newsgroup-marked
                          (copy-sequence gnus-newsgroup-unreads))
@@ -3009,33 +3462,6 @@ If READ-ALL is non-nil, all articles in the group are selected."
          (when (nthcdr (decf i) info)
            (setcdr (nthcdr i info) nil)))))))
 
-(defun gnus-add-marked-articles (group type articles &optional info force)
-  ;; Add ARTICLES of TYPE to the info of GROUP.
-  ;; If INFO is non-nil, use that info.         If FORCE is non-nil, don't
-  ;; add, but replace marked articles of TYPE with ARTICLES.
-  (let ((info (or info (gnus-get-info group)))
-       (uncompressed '(score bookmark killed))
-       marked m)
-    (or (not info)
-       (and (not (setq marked (nthcdr 3 info)))
-            (or (null articles)
-                (setcdr (nthcdr 2 info)
-                        (list (list (cons type (gnus-compress-sequence
-                                                articles t)))))))
-       (and (not (setq m (assq type (car marked))))
-            (or (null articles)
-                (setcar marked
-                        (cons (cons type (gnus-compress-sequence articles t) )
-                              (car marked)))))
-       (if force
-           (if (null articles)
-               (setcar (nthcdr 3 info)
-                       (delq (assq type (car marked)) (car marked)))
-             (setcdr m (gnus-compress-sequence articles t)))
-         (setcdr m (gnus-compress-sequence
-                    (sort (nconc (gnus-uncompress-range (cdr m))
-                                 (copy-sequence articles)) '<) t))))))
-
 (defun gnus-set-mode-line (where)
   "This function sets the mode line of the article or summary buffers.
 If WHERE is `summary', the summary mode line format will be used."
@@ -3153,6 +3579,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         xref-hashtb)))))
 
 (defun gnus-group-make-articles-read (group articles)
+  "Update the info of GROUP to say that only ARTICLES are unread."
   (let* ((num 0)
         (entry (gnus-gethash group gnus-newsrc-hashtb))
         (info (nth 2 entry))
@@ -3177,6 +3604,11 @@ The resulting hash table is returned, or nil if no Xrefs were found."
          (when (or (> id (cdr active))
                    (< id (car active)))
            (setq articles (delq id articles))))))
+    (gnus-undo-register
+      `(progn
+        (gnus-info-set-marks ,info ,(gnus-info-marks info))
+        (gnus-info-set-read ,info ,(gnus-info-read info))
+        (gnus-group-update-group group t)))
     ;; If the read list is nil, we init it.
     (and active
         (null (gnus-info-read info))
@@ -3190,25 +3622,24 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (gnus-info-read info) (setq articles (sort articles '<)))))
     ;; Then we have to re-compute how many unread
     ;; articles there are in this group.
-    (if active
-       (progn
-         (cond
-          ((not range)
-           (setq num (- (1+ (cdr active)) (car active))))
-          ((not (listp (cdr range)))
-           (setq num (- (cdr active) (- (1+ (cdr range))
-                                        (car range)))))
-          (t
-           (while range
-             (if (numberp (car range))
-                 (setq num (1+ num))
-               (setq num (+ num (- (1+ (cdar range)) (caar range)))))
-             (setq range (cdr range)))
-           (setq num (- (cdr active) num))))
-         ;; Update the number of unread articles.
-         (setcar entry num)
-         ;; Update the group buffer.
-         (gnus-group-update-group group t)))))
+    (when active
+      (cond
+       ((not range)
+       (setq num (- (1+ (cdr active)) (car active))))
+       ((not (listp (cdr range)))
+       (setq num (- (cdr active) (- (1+ (cdr range))
+                                    (car range)))))
+       (t
+       (while range
+         (if (numberp (car range))
+             (setq num (1+ num))
+           (setq num (+ num (- (1+ (cdar range)) (caar range)))))
+         (setq range (cdr range)))
+       (setq num (- (cdr active) num))))
+      ;; Update the number of unread articles.
+      (setcar entry num)
+      ;; Update the group buffer.
+      (gnus-group-update-group group t))))
 
 (defun gnus-methods-equal-p (m1 m2)
   (let ((m1 (or m1 gnus-select-method))
@@ -3543,6 +3974,8 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
     ;; Report back a success?
     (and header (mail-header-number header))))
 
+;;; Process/prefix in the summary buffer
+
 (defun gnus-summary-work-articles (n)
   "Return a list of articles to be worked upon.         The prefix argument,
 the list of process marked articles, and the current article will be
@@ -3579,11 +4012,41 @@ taken into consideration."
        (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."
+  (interactive)
+  (push (copy-sequence gnus-newsgroup-processable)
+       gnus-newsgroup-process-stack))
+
+(defun gnus-summary-kill-process-mark ()
+  "Push the current set of process marked articles on the stack and unmark."
+  (interactive)
+  (gnus-summary-save-process-mark)
+  (gnus-summary-unmark-all-processable))
+
+(defun gnus-summary-yank-process-mark ()
+  "Pop the last process mark state off the stack and restore it."
+  (interactive)
+  (unless gnus-newsgroup-process-stack
+    (error "Empty mark stack"))
+  (gnus-summary-process-mark-set (pop gnus-newsgroup-process-stack)))
+
+(defun gnus-summary-process-mark-set (set)
+  "Make SET into the current process marked articles."
+  (gnus-summary-unmark-all-processable)
+  (while set
+    (gnus-summary-set-process-mark (pop set))))
+
+;;; Searching and stuff
+
 (defun gnus-summary-search-group (&optional backward use-level)
   "Search for next unread newsgroup.
 If optional argument BACKWARD is non-nil, search backward instead."
@@ -3848,7 +4311,7 @@ The prefix argument ALL means to select all articles."
   (gnus-summary-reselect-current-group all t))
 
 (defun gnus-summary-update-info ()
-  (let* ((group gnus-newsgroup-name))
+  (let ((group gnus-newsgroup-name))
     (when gnus-newsgroup-kill-headers
       (setq gnus-newsgroup-killed
            (gnus-compress-sequence
@@ -3902,6 +4365,8 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
       (gnus-cache-possibly-remove-articles)
       (gnus-cache-save-buffers))
     (gnus-async-prefetch-remove-group group)
+    (when gnus-suppress-duplicates
+      (gnus-dup-enter-articles))
     (when gnus-use-trees
       (gnus-tree-close group))
     ;; Make all changes in this group permanent.
@@ -4344,6 +4809,11 @@ If BACKWARD, the previous article is selected instead of the next."
    ;; If not, we try the first unread, if that is wanted.
    ((and subject
         gnus-auto-select-same
+        ;; Make sure that we don't select the current article.
+        (not (eq (gnus-summary-article-number)
+                 (save-excursion
+                   (gnus-summary-first-subject t)
+                   (gnus-summary-article-number))))
         (gnus-summary-first-unread-article))
     (gnus-summary-position-point)
     (gnus-message 6 "Wrapped"))
@@ -4390,6 +4860,7 @@ If BACKWARD, the previous article is selected instead of the next."
 (defun gnus-summary-walk-group-buffer (from-group cmd unread backward)
   (let ((keystrokes '((?\C-n (gnus-group-next-unread-group 1))
                      (?\C-p (gnus-group-prev-unread-group 1))))
+       (cursor-in-echo-area t)
        keve key group ended)
     (save-excursion
       (set-buffer gnus-group-buffer)
@@ -4443,7 +4914,7 @@ If UNREAD is non-nil, only unread articles are selected."
   (gnus-summary-next-article unread subject t))
 
 (defun gnus-summary-prev-unread-article ()
-  "Select unred article before current one."
+  "Select unread article before current one."
   (interactive)
   (gnus-summary-prev-article t (and gnus-auto-select-same
                                    (gnus-summary-article-subject))))
@@ -4475,16 +4946,16 @@ article."
          (gnus-summary-display-article article)
        (gnus-eval-in-buffer-window gnus-article-buffer
          (setq endp (gnus-article-next-page lines)))
-       (if endp
-           (cond (circular
-                  (gnus-summary-beginning-of-article))
-                 (lines
-                  (gnus-message 3 "End of message"))
-                 ((null lines)
-                  (if (and (eq gnus-summary-goto-unread 'never)
-                           (not (gnus-summary-last-article-p article)))
-                      (gnus-summary-next-article)
-                    (gnus-summary-next-unread-article)))))))
+       (when endp
+         (cond (circular
+                (gnus-summary-beginning-of-article))
+               (lines
+                (gnus-message 3 "End of message"))
+               ((null lines)
+                (if (and (eq gnus-summary-goto-unread 'never)
+                         (not (gnus-summary-last-article-p article)))
+                    (gnus-summary-next-article)
+                  (gnus-summary-next-unread-article)))))))
     (gnus-summary-recenter)
     (gnus-summary-position-point)))
 
@@ -4553,11 +5024,10 @@ Return nil if there are no unread articles."
   (interactive)
   (gnus-set-global-variables)
   (prog1
-      (if (gnus-summary-first-subject t)
-         (progn
-           (gnus-summary-show-thread)
-           (gnus-summary-first-subject t)
-           (gnus-summary-display-article (gnus-summary-article-number))))
+      (when (gnus-summary-first-subject t)
+       (gnus-summary-show-thread)
+       (gnus-summary-first-subject t)
+       (gnus-summary-display-article (gnus-summary-article-number)))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-best-unread-article ()
@@ -4687,7 +5157,8 @@ If ALL is non-nil, limit strictly to unread articles."
      (list gnus-del-mark gnus-read-mark gnus-ancient-mark
           gnus-killed-mark gnus-kill-file-mark
           gnus-low-score-mark gnus-expirable-mark
-          gnus-canceled-mark gnus-catchup-mark gnus-sparse-mark)
+          gnus-canceled-mark gnus-catchup-mark gnus-sparse-mark
+          gnus-duplicate-mark)
      'reverse)))
 
 (defalias 'gnus-summary-delete-marked-with 'gnus-summary-limit-to-marks)
@@ -4821,21 +5292,19 @@ If ALL, mark even excluded ticked and dormants as read."
         (gnus-summary-hide-all-threads))
     ;; Try to return to the article you were at, or one in the
     ;; neighborhood.
-    (if data
-       ;; We try to find some article after the current one.
-       (while data
-         (and (gnus-summary-goto-subject
-               (gnus-data-number (car data)) nil t)
-              (setq data nil
-                    found t))
-         (setq data (cdr data))))
-    (or found
-       ;; If there is no data, that means that we were after the last
-       ;; article.  The same goes when we can't find any articles
-       ;; after the current one.
-       (progn
-         (goto-char (point-max))
-         (gnus-summary-find-prev)))
+    (when data
+      ;; We try to find some article after the current one.
+      (while data
+       (when (gnus-summary-goto-subject (gnus-data-number (car data)) nil t)
+         (setq data nil
+               found t))
+       (setq data (cdr data))))
+    (unless found
+      ;; If there is no data, that means that we were after the last
+      ;; article.  The same goes when we can't find any articles
+      ;; after the current one.
+      (goto-char (point-max))
+      (gnus-summary-find-prev))
     ;; We return how many articles were removed from the summary
     ;; buffer as a result of the new limit.
     (- total (length gnus-newsgroup-data))))
@@ -4927,43 +5396,47 @@ fetch-old-headers verbiage, and so on."
             0))
          (number (mail-header-number (car thread)))
          score)
-      (if (or
-          ;; If this article is dormant and has absolutely no visible
-          ;; children, then this article isn't visible.
-          (and (memq number gnus-newsgroup-dormant)
-               (= children 0))
-          ;; If this is "fetch-old-headered" and there is only one
-          ;; visible child (or less), then we don't want this article.
-          (and (eq gnus-fetch-old-headers 'some)
-               (memq number gnus-newsgroup-ancient)
-               (zerop children))
-          ;; If this is a sparsely inserted article with no children,
-          ;; we don't want it.
-          (and (eq gnus-build-sparse-threads 'some)
-               (memq number gnus-newsgroup-sparse)
-               (zerop children))
-          ;; If we use expunging, and this article is really
-          ;; low-scored, then we don't want this article.
-          (when (and gnus-summary-expunge-below
-                     (< (setq score
-                              (or (cdr (assq number gnus-newsgroup-scored))
-                                  gnus-summary-default-score))
-                        gnus-summary-expunge-below))
-            ;; We increase the expunge-tally here, but that has
-            ;; nothing to do with the limits, really.
-            (incf gnus-newsgroup-expunged-tally)
-            ;; We also mark as read here, if that's wanted.
-            (when (and gnus-summary-mark-below
-                       (< score gnus-summary-mark-below))
-              (setq gnus-newsgroup-unreads
-                    (delq number gnus-newsgroup-unreads))
-              (if gnus-newsgroup-auto-expire
-                  (push number gnus-newsgroup-expirable)
-                (push (cons number gnus-low-score-mark)
-                      gnus-newsgroup-reads)))
-            t)
-          (and gnus-use-nocem
-               (gnus-nocem-unwanted-article-p (mail-header-id (car thread)))))
+      (if (and
+          (not (memq number gnus-newsgroup-marked))
+          (or
+           ;; If this article is dormant and has absolutely no visible
+           ;; children, then this article isn't visible.
+           (and (memq number gnus-newsgroup-dormant)
+                (= children 0))
+           ;; If this is "fetch-old-headered" and there is only one
+           ;; visible child (or less), then we don't want this article.
+           (and (eq gnus-fetch-old-headers 'some)
+                (memq number gnus-newsgroup-ancient)
+                (zerop children))
+           ;; If this is a sparsely inserted article with no children,
+           ;; we don't want it.
+           (and (eq gnus-build-sparse-threads 'some)
+                (memq number gnus-newsgroup-sparse)
+                (zerop children))
+           ;; If we use expunging, and this article is really
+           ;; low-scored, then we don't want this article.
+           (when (and gnus-summary-expunge-below
+                      (< (setq score
+                               (or (cdr (assq number gnus-newsgroup-scored))
+                                   gnus-summary-default-score))
+                         gnus-summary-expunge-below))
+             ;; We increase the expunge-tally here, but that has
+             ;; nothing to do with the limits, really.
+             (incf gnus-newsgroup-expunged-tally)
+             ;; We also mark as read here, if that's wanted.
+             (when (and gnus-summary-mark-below
+                        (< score gnus-summary-mark-below))
+               (setq gnus-newsgroup-unreads
+                     (delq number gnus-newsgroup-unreads))
+               (if gnus-newsgroup-auto-expire
+                   (push number gnus-newsgroup-expirable)
+                 (push (cons number gnus-low-score-mark)
+                       gnus-newsgroup-reads)))
+             t)
+           ;; Check NoCeM things.
+           (and gnus-use-nocem
+                (gnus-nocem-unwanted-article-p
+                 (mail-header-id (car thread))))))
          ;; Nope, invisible article.
          0
        ;; Ok, this article is to be visible, so we add it to the limit
@@ -4989,41 +5462,46 @@ fetch-old-headers verbiage, and so on."
 
 (defun gnus-summary-refer-parent-article (n)
   "Refer parent article N times.
+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)
-  (while
-      (and
-       (> n 0)
-       (let* ((header (gnus-summary-article-header))
-             (ref
-              ;; If we try to find the parent of the currently
-              ;; displayed article, then we take a look at the actual
-              ;; References header, since this is slightly more
-              ;; reliable than the References field we got from the
-              ;; server.
-              (if (and (eq (mail-header-number header)
-                           (cdr gnus-article-current))
-                       (equal gnus-newsgroup-name
-                              (car gnus-article-current)))
-                  (save-excursion
-                    (set-buffer gnus-original-article-buffer)
-                    (nnheader-narrow-to-headers)
-                    (prog1
-                        (message-fetch-field "references")
-                      (widen)))
-                ;; It's not the current article, so we take a bet on
-                ;; the value we got from the server.
-                (mail-header-references header))))
-        (if (setq ref (or ref (mail-header-references header)))
-            (or (gnus-summary-refer-article (gnus-parent-id ref))
-                (gnus-message 1 "Couldn't find parent"))
-          (gnus-message 1 "No references in article %d"
-                        (gnus-summary-article-number))
-          nil)))
-    (setq n (1- n)))
-  (gnus-summary-position-point)
-  n)
+  (let ((skip 1)
+       error header ref)
+    (when (not (natnump n))
+      (setq skip (abs n)
+           n 1))
+    (while (and (> n 0)
+               (not error))
+      (setq header (gnus-summary-article-header))
+      (setq ref
+           ;; If we try to find the parent of the currently
+           ;; displayed article, then we take a look at the actual
+           ;; References header, since this is slightly more
+           ;; reliable than the References field we got from the
+           ;; server.
+           (if (and (eq (mail-header-number header)
+                        (cdr gnus-article-current))
+                    (equal gnus-newsgroup-name
+                           (car gnus-article-current)))
+               (save-excursion
+                 (set-buffer gnus-original-article-buffer)
+                 (nnheader-narrow-to-headers)
+                 (prog1
+                     (message-fetch-field "references")
+                   (widen)))
+             ;; It's not the current article, so we take a bet on
+             ;; the value we got from the server.
+             (mail-header-references header)))
+      (if ref 
+         (unless (gnus-summary-refer-article (gnus-parent-id ref skip))
+           (gnus-message 1 "Couldn't find parent"))
+       (gnus-message 1 "No references in article %d"
+                     (gnus-summary-article-number))
+       (setq error t))
+      (decf n))
+    (gnus-summary-position-point)
+    n))
 
 (defun gnus-summary-refer-references ()
   "Fetch all articles mentioned in the References header.
@@ -5081,7 +5559,9 @@ Return how many articles were fetched."
            (gnus-message 3 "Couldn't fetch article %s" message-id)))))))
 
 (defun gnus-summary-enter-digest-group (&optional force)
-  "Enter a digest group based on the current article."
+  "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)
   (gnus-summary-select-article)
@@ -5117,6 +5597,52 @@ Return how many articles were fetched."
          (gnus-message 3 "Article couldn't be entered?"))
       (kill-buffer dig))))
 
+(defun gnus-summary-read-document (n)
+  "Open a new group based on the current article(s).
+Obeys the standard process/prefix convention."
+  (interactive "P")
+  (let ((articles (gnus-summary-work-articles n))
+       (ogroup gnus-newsgroup-name)
+       article group egroup groups vgroup)
+    (while (setq article (pop articles))
+      (setq group (format "%s-%d" gnus-newsgroup-name gnus-current-article))
+      (gnus-summary-remove-process-mark article)
+      (when (gnus-summary-display-article article)
+       (save-excursion
+         (nnheader-temp-write nil
+           (insert-buffer-substring gnus-original-article-buffer)
+           ;; Remove some headers that may lead nndoc to make
+           ;; the wrong guess.
+           (message-narrow-to-head)
+           (goto-char (point-min))
+           (delete-matching-lines "^\\(Path\\):\\|^From ")
+           (widen)
+           (if (setq egroup
+                     (gnus-group-read-ephemeral-group
+                      group `(nndoc ,group (nndoc-address ,(current-buffer))
+                                    (nndoc-article-type guess))
+                      t nil t))
+               (progn
+                 ;; Make all postings to this group go to the parent group.
+                 (nconc (gnus-info-params (gnus-get-info egroup))
+                        (list (cons 'to-group ogroup)))
+                 (push egroup groups))
+             ;; Couldn't select this doc group.
+             (gnus-error 3 "Article couldn't be entered"))))))
+    ;; Now we have selected all the documents.
+    (cond
+     ((not groups)
+      (error "None of the articles could be interpreted as documents"))
+     ((gnus-group-read-ephemeral-group
+       (setq vgroup (format
+                    "%s-%s" gnus-newsgroup-name
+                    (format-time-string "%Y%m%dT%H%M%S" (current-time))))
+       `(nnvirtual ,vgroup (nnvirtual-component-groups ,groups))
+       t
+       (cons (current-buffer) 'summary)))
+     (t
+      (error "Couldn't select virtual nndoc group")))))
+      
 (defun gnus-summary-isearch-article (&optional regexp-p)
   "Do incremental search forward on the current article.
 If REGEXP-P (the prefix) is non-nil, do regexp isearch."
@@ -5143,7 +5669,8 @@ If BACKWARD, search backward instead."
   (if (string-equal regexp "")
       (setq regexp (or gnus-last-search-regexp ""))
     (setq gnus-last-search-regexp regexp))
-  (unless (gnus-summary-search-article regexp backward)
+  (if (gnus-summary-search-article regexp backward)
+      (gnus-summary-show-thread)
     (error "Search failed: \"%s\"" regexp)))
 
 (defun gnus-summary-search-article-backward (regexp)
@@ -5163,6 +5690,7 @@ Optional argument BACKWARD means do search for backward.
   (let ((gnus-select-article-hook nil) ;Disable hook.
        (gnus-article-display-hook nil)
        (gnus-mark-article-hook nil)    ;Inhibit marking as read.
+       (gnus-use-article-prefetch nil)
        (re-search
         (if backward
             're-search-backward 're-search-forward))
@@ -5258,7 +5786,7 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
       (gnus-message 6 "Executing %s..." (key-description command))
       ;; We'd like to execute COMMAND interactively so as to give arguments.
       (gnus-execute header regexp
-                   `(lambda () (call-interactively ',(key-binding command)))
+                   `(call-interactively ',(key-binding command))
                    backward)
       (gnus-message 6 "Executing %s...done" (key-description command)))))
 
@@ -5658,6 +6186,20 @@ latter case, they will be copied into the relevant groups."
       (gnus-request-accept-article group nil t)
       (kill-buffer (current-buffer)))))
 
+(defun gnus-summary-article-posted-p ()
+  "Say whether the current (mail) article is available from `gnus-select-method' as well.
+This will be the case if the article has both been mailed and posted."
+  (interactive)
+  (let ((id (mail-header-references (gnus-summary-article-header)))
+       (gnus-override-method
+        (or gnus-refer-article-method gnus-select-method)))
+    (if (gnus-request-head id "")
+       (gnus-message 2 "The current message was found on %s"
+                     gnus-override-method)
+      (gnus-message 2 "The current message couldn't be found on %s"
+                   gnus-override-method)
+      nil)))
+
 (defun gnus-summary-expire-articles (&optional now)
   "Expire all articles that are marked as expirable in the current group."
   (interactive)
@@ -5671,7 +6213,7 @@ latter case, they will be copied into the relevant groups."
                        (setq gnus-newsgroup-expirable
                              (sort gnus-newsgroup-expirable '<))))
           (expiry-wait (if now 'immediate
-                         (gnus-group-get-parameter
+                         (gnus-group-find-parameter
                           gnus-newsgroup-name 'expiry-wait)))
           es)
       (when expirable
@@ -5686,7 +6228,8 @@ latter case, they will be copied into the relevant groups."
                        expirable gnus-newsgroup-name)))
          (setq es (gnus-request-expire-articles
                    expirable gnus-newsgroup-name)))
-       (or total (setq gnus-newsgroup-expirable es))
+       (unless total
+         (setq gnus-newsgroup-expirable es))
        ;; We go through the old list of expirable, and mark all
        ;; really expired articles as nonexistent.
        (unless (eq es expirable)       ;If nothing was expired, we don't mark.
@@ -5750,10 +6293,10 @@ delete these instead."
     not-deleted))
 
 (defun gnus-summary-edit-article (&optional force)
-  "Enter into a buffer and edit the current article.
+  "Edit the current article.
 This will have permanent effect only in mail groups.
 If FORCE is non-nil, allow editing of articles even in read-only
-groups."
+groups." 
   (interactive "P")
   (save-excursion
     (set-buffer gnus-summary-buffer)
@@ -5761,66 +6304,50 @@ groups."
     (when (and (not force)
               (gnus-group-read-only-p))
       (error "The current newsgroup does not support article editing."))
-    (gnus-summary-select-article t nil t)
-    (gnus-configure-windows 'article)
-    (select-window (get-buffer-window gnus-article-buffer))
-    (gnus-message 6 "C-c C-c to end edits")
-    (setq buffer-read-only nil)
-    (gnus-article-edit-mode)
-    (buffer-enable-undo)
-    (widen)
-    (goto-char (point-min))
-    (search-forward "\n\n" nil t)))
-
-(defun gnus-summary-edit-article-done ()
+    ;; Select article if needed.
+    (unless (eq (gnus-summary-article-number)
+               gnus-current-article)
+      (gnus-summary-select-article t))
+    (gnus-article-edit-article
+     `(lambda ()
+       (gnus-summary-edit-article-done
+        ,(or (mail-header-references gnus-current-headers) "")
+        ,(gnus-group-read-only-p) ,gnus-summary-buffer)))))
+
+(defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit)
+
+(defun gnus-summary-edit-article-done (references read-only buffer)
   "Make edits to the current article permanent."
   (interactive)
-  (if (gnus-group-read-only-p)
-      (progn
-       (let ((beep (not (eq major-mode 'text-mode))))
-         (gnus-summary-edit-article-postpone)
-         (when beep
-           (gnus-error
-            3 "The current newsgroup does not support article editing."))))
-    (let ((buf (format "%s" (buffer-string))))
-      (erase-buffer)
-      (insert buf)
-      (if (not (gnus-request-replace-article
-               (cdr gnus-article-current) (car gnus-article-current)
-               (current-buffer)))
-         (error "Couldn't replace article.")
-       (gnus-article-mode)
-       (use-local-map gnus-article-mode-map)
-       (setq buffer-read-only t)
-       (buffer-disable-undo (current-buffer))
-       (gnus-configure-windows 'summary)
-       (gnus-summary-update-article (cdr gnus-article-current))
-       (when gnus-use-cache
-         (gnus-cache-update-article    
-          (car gnus-article-current) (cdr gnus-article-current)))
-       (when gnus-keep-backlog
-         (gnus-backlog-remove-article 
-          (car gnus-article-current) (cdr gnus-article-current))))
-      (save-excursion
-       (when (get-buffer gnus-original-article-buffer)
-         (set-buffer gnus-original-article-buffer)
-         (setq gnus-original-article nil)))
-      (setq gnus-article-current nil
-           gnus-current-article nil)
-      (run-hooks 'gnus-article-display-hook)
-      (and (gnus-visual-p 'summary-highlight 'highlight)
-          (run-hooks 'gnus-visual-mark-article-hook)))))
-
-(defun gnus-summary-edit-article-postpone ()
-  "Postpone changes to the current article."
-  (interactive)
-  (gnus-article-mode)
-  (use-local-map gnus-article-mode-map)
-  (setq buffer-read-only t)
-  (buffer-disable-undo (current-buffer))
-  (gnus-configure-windows 'summary)
-  (and (gnus-visual-p 'summary-highlight 'highlight)
-       (run-hooks 'gnus-visual-mark-article-hook)))
+  ;; 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 (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 ((header (nnheader-parse-head t)))
+             (set-buffer buffer)
+             (mail-header-set-number header (cdr gnus-article-current))
+             (gnus-summary-update-article-line
+              (cdr gnus-article-current) header))))
+      ;; Update threads.
+      (set-buffer buffer)
+      (gnus-summary-update-article (cdr gnus-article-current)))
+    ;; Prettify the article buffer again.
+    (save-excursion
+      (set-buffer gnus-article-buffer)
+      (run-hooks 'gnus-article-display-hook))
+    ;; Prettify the summary buffer line.
+    (when (gnus-visual-p 'summary-highlight 'highlight)
+      (run-hooks 'gnus-visual-mark-article-hook))))
 
 (defun gnus-summary-edit-wash (key)
   "Perform editing command in the article buffer."
@@ -5832,7 +6359,7 @@ groups."
   (message "")
   (gnus-summary-edit-article)
   (execute-kbd-macro (concat (this-command-keys) key))
-  (gnus-summary-edit-article-done))
+  (gnus-article-edit-done))
 
 ;;; Respooling
 
@@ -6095,7 +6622,8 @@ returned."
               (or (= mark gnus-killed-mark) (= mark gnus-del-mark)
                   (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
                   (= mark gnus-ancient-mark)
-                  (= mark gnus-read-mark) (= mark gnus-souped-mark)))
+                  (= mark gnus-read-mark) (= mark gnus-souped-mark)
+                  (= mark gnus-duplicate-mark)))
       (setq mark gnus-expirable-mark)
       (push article gnus-newsgroup-expirable))
     ;; Set the mark in the buffer.
@@ -6152,7 +6680,8 @@ marked."
           (and (numberp mark)
                (or (= mark gnus-killed-mark) (= mark gnus-del-mark)
                    (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
-                   (= mark gnus-read-mark) (= mark gnus-souped-mark))))
+                   (= mark gnus-read-mark) (= mark gnus-souped-mark)
+                   (= mark gnus-duplicate-mark))))
        (setq mark gnus-expirable-mark))
   (let* ((mark (or mark gnus-del-mark))
         (article (or article (gnus-summary-article-number))))
@@ -6199,20 +6728,21 @@ marked."
   t)
 
 (defun gnus-summary-update-mark (mark type)
-  (beginning-of-line)
   (let ((forward (cdr (assq type gnus-summary-mark-positions)))
-       (buffer-read-only nil))
+        (buffer-read-only nil))
+    (re-search-backward "[\n\r]" (gnus-point-at-bol) 'move-to-limit)
+    (and (looking-at "\r") (setq forward (1+ forward)))
     (when (and forward
-              (<= (+ forward (point)) (point-max)))
+               (<= (+ forward (point)) (point-max)))
       ;; Go to the right position on the line.
       (goto-char (+ forward (point)))
       ;; Replace the old mark with the new mark.
       (subst-char-in-region (point) (1+ (point)) (following-char) mark)
       ;; Optionally update the marks by some user rule.
       (when (eq type 'unread)
-       (gnus-data-set-mark
-        (gnus-data-find (gnus-summary-article-number)) mark)
-       (gnus-summary-update-line (eq mark gnus-unread-mark))))))
+        (gnus-data-set-mark
+         (gnus-data-find (gnus-summary-article-number)) mark)
+        (gnus-summary-update-line (eq mark gnus-unread-mark))))))
 
 (defun gnus-mark-article-as-read (article &optional mark)
   "Enter ARTICLE in the pertinent lists and remove it from others."
@@ -6233,10 +6763,15 @@ marked."
 (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))
-    (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
-    (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
-    (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
+    (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))
+
     (cond ((= mark gnus-ticked-mark)
           (push article gnus-newsgroup-marked))
          ((= mark gnus-dormant-mark)
@@ -6427,36 +6962,37 @@ The number of articles marked as read is returned."
   (interactive "P")
   (gnus-set-global-variables)
   (prog1
-      (if (or quietly
-             (not gnus-interactive-catchup) ;Without confirmation?
-             gnus-expert-user
-             (gnus-y-or-n-p
-              (if all
-                  "Mark absolutely all articles as read? "
-                "Mark all unread articles as read? ")))
-         (if (and not-mark
-                  (not gnus-newsgroup-adaptive)
-                  (not gnus-newsgroup-auto-expire))
-             (progn
-               (when all
-                 (setq gnus-newsgroup-marked nil
-                       gnus-newsgroup-dormant nil))
-               (setq gnus-newsgroup-unreads nil))
-           ;; We actually mark all articles as canceled, which we
-           ;; have to do when using auto-expiry or adaptive scoring.
-           (gnus-summary-show-all-threads)
-           (if (gnus-summary-first-subject (not all))
-               (while (and
-                       (if to-here (< (point) to-here) t)
-                       (gnus-summary-mark-article-as-read gnus-catchup-mark)
-                       (gnus-summary-find-next (not all)))))
-           (unless to-here
+      (when (or quietly
+               (not gnus-interactive-catchup) ;Without confirmation?
+               gnus-expert-user
+               (gnus-y-or-n-p
+                (if all
+                    "Mark absolutely all articles as read? "
+                  "Mark all unread articles as read? ")))
+       (if (and not-mark
+                (not gnus-newsgroup-adaptive)
+                (not gnus-newsgroup-auto-expire)
+                (not gnus-suppress-duplicates))
+           (progn
+             (when all
+               (setq gnus-newsgroup-marked nil
+                     gnus-newsgroup-dormant nil))
              (setq gnus-newsgroup-unreads nil))
-           (gnus-set-mode-line 'summary)))
+         ;; We actually mark all articles as canceled, which we
+         ;; have to do when using auto-expiry or adaptive scoring.
+         (gnus-summary-show-all-threads)
+         (when (gnus-summary-first-subject (not all))
+           (while (and
+                   (if to-here (< (point) to-here) t)
+                   (gnus-summary-mark-article-as-read gnus-catchup-mark)
+                   (gnus-summary-find-next (not all)))))
+         (unless to-here
+           (setq gnus-newsgroup-unreads nil))
+         (gnus-set-mode-line 'summary)))
     (let ((method (gnus-find-method-for-group gnus-newsgroup-name)))
-      (if (and (not to-here) (eq 'nnvirtual (car method)))
-         (nnvirtual-catchup-group
-          (gnus-group-real-name gnus-newsgroup-name) (nth 1 method) all)))
+      (when (and (not to-here) (eq 'nnvirtual (car method)))
+       (nnvirtual-catchup-group
+        (gnus-group-real-name gnus-newsgroup-name) (nth 1 method) all)))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-catchup-to-here (&optional all)
@@ -6904,10 +7440,11 @@ 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*")))
-       header article file)
+  (let* ((articles (gnus-summary-work-articles n))
+        (save-buffer (save-excursion 
+                       (nnheader-set-temp-buffer " *Gnus Save*")))
+        (num (length articles))
+        header article file)
     (while articles
       (setq header (gnus-summary-article-header
                    (setq article (pop articles))))
@@ -6923,7 +7460,7 @@ The variable `gnus-default-article-saver' specifies the saver function."
          (set-buffer save-buffer)
          (erase-buffer)
          (insert-buffer-substring gnus-original-article-buffer))
-       (setq file (gnus-article-save save-buffer file))
+       (setq file (gnus-article-save save-buffer file num))
        (gnus-summary-remove-process-mark article)
        (unless not-saved
          (gnus-summary-set-saved-mark article))))
@@ -7254,6 +7791,71 @@ save those articles instead."
       (when (cdr headers)
        (setcdr headers (cddr headers))))))
 
+;;;
+;;; summary highlights
+;;;
+
+(defun gnus-highlight-selected-summary ()
+  ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
+  ;; Highlight selected article in summary buffer
+  (when gnus-summary-selected-face
+    (save-excursion
+      (let* ((beg (progn (beginning-of-line) (point)))
+            (end (progn (end-of-line) (point)))
+            ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
+            (from (if (get-text-property beg gnus-mouse-face-prop) 
+                      beg
+                    (or (next-single-property-change 
+                         beg gnus-mouse-face-prop nil end) 
+                        beg)))
+            (to
+             (if (= from end)
+                 (- from 2)
+               (or (next-single-property-change
+                    from gnus-mouse-face-prop nil end)
+                   end))))
+       ;; If no mouse-face prop on line we will have to = from = end,
+       ;; so we highlight the entire line instead.
+       (when (= (+ to 2) from)
+         (setq from beg)
+         (setq to end))
+       (if gnus-newsgroup-selected-overlay
+           ;; Move old overlay.
+           (gnus-move-overlay
+            gnus-newsgroup-selected-overlay from to (current-buffer))
+         ;; Create new overlay.
+         (gnus-overlay-put
+          (setq gnus-newsgroup-selected-overlay (gnus-make-overlay from to))
+          'face gnus-summary-selected-face))))))
+
+;; New implementation by Christian Limpach <Christian.Limpach@nice.ch>.
+(defun gnus-summary-highlight-line ()
+  "Highlight current line according to `gnus-summary-highlight'."
+  (let* ((list gnus-summary-highlight)
+        (p (point))
+        (end (progn (end-of-line) (point)))
+        ;; now find out where the line starts and leave point there.
+        (beg (progn (beginning-of-line) (point)))
+        (article (gnus-summary-article-number))
+        (score (or (cdr (assq (or article gnus-current-article)
+                              gnus-newsgroup-scored))
+                   gnus-summary-default-score 0))
+        (mark (or (gnus-summary-article-mark) gnus-unread-mark))
+        (inhibit-read-only t))
+    ;; Eval the cars of the lists until we find a match.
+    (let ((default gnus-summary-default-score))
+      (while (and list
+                 (not (eval (caar list))))
+       (setq list (cdr list))))
+    (let ((face (cdar list)))
+      (unless (eq face (get-text-property beg 'face))
+       (gnus-put-text-property 
+        beg end 'face 
+        (setq face (if (boundp face) (symbol-value face) face)))
+       (when gnus-summary-highlight-line-function
+         (funcall gnus-summary-highlight-line-function article face))))
+    (goto-char p)))
+
 (provide 'gnus-sum)
 
 ;;; gnus-sum.el ends here