*** empty log message ***
[gnus] / lisp / gnus-sum.el
index af6216f..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
@@ -357,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.")
 
@@ -416,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
@@ -441,10 +446,9 @@ automatically when it is selected.")
     table)
   "Display table used in summary mode buffers.")
 
-;;; Internal variables
-
 (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)
@@ -478,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)
@@ -633,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)
@@ -881,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
@@ -1009,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
@@ -1041,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
@@ -1059,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
@@ -1070,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
 
@@ -1113,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)
@@ -1640,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)
@@ -1726,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))
@@ -2822,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))
@@ -3100,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))
@@ -3124,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))
@@ -3137,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))
@@ -3490,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
@@ -3526,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."
@@ -4293,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"))
@@ -4339,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)
@@ -4392,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))))
@@ -4424,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)))
 
@@ -4502,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 ()
@@ -4771,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))))
@@ -4877,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
@@ -4939,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.
@@ -5031,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)
@@ -5067,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."
@@ -5093,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)
@@ -5113,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))
@@ -5208,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)))))
 
@@ -5608,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)
@@ -5621,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
@@ -5636,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.
@@ -5700,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)
@@ -5718,9 +6311,11 @@ groups."
     (gnus-article-edit-article
      `(lambda ()
        (gnus-summary-edit-article-done
-        ,(mail-header-references gnus-current-headers)
+        ,(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)
@@ -5733,15 +6328,16 @@ groups."
     ;; Update the summary buffer.
     (if (equal (message-tokenize-header references " ")
               (message-tokenize-header
-               (message-fetch-field "references") " "))
+               (or (message-fetch-field "references") "") " "))
        ;; We only have to update this line.
-       (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)))
+       (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)))
@@ -6167,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)
@@ -6361,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)
@@ -6838,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))))
@@ -6857,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))))
@@ -7188,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