*** empty log message ***
authorLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 01:32:20 +0000 (01:32 +0000)
committerLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 01:32:20 +0000 (01:32 +0000)
18 files changed:
Makefile
lisp/ChangeLog
lisp/Makefile [new file with mode: 0644]
lisp/gnus-mh.el
lisp/gnus-uu.el
lisp/gnus-visual.el
lisp/gnus.el
lisp/mhspool.el [deleted file]
lisp/nndir.el [new file with mode: 0644]
lisp/nnheader.el
lisp/nnmail.el
lisp/nnmbox.el [new file with mode: 0644]
lisp/nnmh.el
lisp/nnml.el
lisp/nnspool.el
lisp/nntp.el
lisp/nnvirtual.el
texi/gnus.texi

index 75dda36..60c6c37 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,8 @@ EMACS=emacs
 all: elc info
 
 elc:
-       cd lisp; $(EMACS) -batch -l ./dgnushack.el -f dgnushack -f batch-byte-compile *.el
+       cd lisp; make DEMACS=$(EMACS) elc
 
 info:
        cd texi; makeinfo gnus.texi
+
index 5489686..e2b47c3 100644 (file)
@@ -1,3 +1,552 @@
+Fri Feb 17 05:06:28 1995  Lars Magne Ingebrigtsen  <larsi@gymir.ifi.uio.no>
+
+       * gnus.el (gnus-mail-reply-using-mail): Don't remove all text
+       properties from headers, just invisible.
+
+Thu Feb 16 04:21:19 1995  Lars Magne Ingebrigtsen  <larsi@gjalp.ifi.uio.no>
+
+       * gnus.el (gnus-group-browse-foreign-server): Did not intern the
+       select method.
+       (gnus-summary-search-subject): Don't ignore hidden articles.
+       (gnus-make-directory): Would not properly create new directories. 
+       (gnus-mail-reply-using-mail): Include Cc's when replying.
+       (gnus-adjust-marked-articles): Infinite loop.
+
+       * nnvirtual.el (nnvirtual-retrieve-headers): Would not allow
+       people to enter groups.
+
+       * gnus-mh.el (gnus-mail-other-window-using-mhe): Tried to fetch
+       subject where none was to be fetched.
+
+       * gnus.el (gnus-browse-read-group): Movement commands did not
+       work. 
+       (gnus-score-interactive-default-score): New variable, default
+       1000. 
+
+Mon Feb  6 15:44:42 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-configure-windows): Bury the group buffer
+       somewhat. 
+       (gnus-mail-reply-using-mail): Don't bind `C-c C-y' to anything in
+       the mail buffer.
+
+       * nndir.el (nndir-retrieve-headers): Retrieve with NOV, if that is
+       posssible. 
+
+Sun Feb  5 21:15:45 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el: Introduction of pseudo-articles. Changes throughout
+       Gnus.
+
+       * gnus-uu.el: Rewrite. New keymap and new interface.
+
+       * gnus.el (gnus-get-newsgroup-headers): Would barf on In-Reply-To
+       headers. 
+
+Sat Feb  4 18:16:21 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-uu.el (gnus-uu-get-list-of-articles): Would not get list of
+       articles. 
+
+Sat Feb  4 13:47:14 1995  Lars Magne Ingebrigtsen  <larsi@hnoss.ifi.uio.no>
+
+       * gnus.el (gnus-summary-quit): Did not the kill summary buffer.
+
+       * gnus-visual.el (gnus-visual-highlight-selected-summary): Limit
+       the highligting to the same area highligted by mouse-face.
+
+Sat Feb  4 09:49:31 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-build-get-header): Faster searching.
+
+Fri Feb  3 18:25:42 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-newsgroup-ancient): New variable.
+       (gnus-summary-local-variables): Initialize it.
+       (gnus-build-get-header): Build it.
+       (gnus-trim-thread): New function.
+       (gnus-make-threads): Call it.
+       (gnus-ancient-mark): New variable.
+       (gnus-summary-prepare-threads): Use it.
+       (gnus-fetch-old-headers): Updated documentation.
+
+Mon Jan 30 05:11:47 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-articles-to-read): Don't inform the user if the
+       only scored articles are tiched or dormant.
+
+Sat Feb  4 09:39:21 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-read-init-file): Also load .gnus.el and .gnus.elc. 
+
+       * gnus.el: Removed the last vestiges of the invisible text in the
+       group and summary buffers.
+
+Fri Feb  3 19:27:29 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-group-make-directory-group): New command and
+       keystroke. 
+       (gnus-subscribe-hierarchical-interactive): Would not let you
+       subscribe to anything.
+       (gnus-get-newsgroup-headers): Would barf when presented with
+       message-id-less articles.
+
+       * nndir.el: New backend for reading directories.
+
+Thu Feb  2 17:42:51 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-group-prepare): Zombie and killed groups could not
+       be chosen.
+       (gnus-group-search-forward): Didn't return nil when no group was
+       found. 
+       (gnus-summary-prepare): Sorting was done after gathering loose
+       threads, so the losse threads were not sorted properly.
+
+Thu Feb  2 15:31:11 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el: Implemented support for SCORE files.
+
+Thu Feb  2 17:23:17 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-group-list-groups): Don't go to the first group
+       after listing.
+       (gnus-group-list-groups): Go to the first unread group at startup,
+       not the second.
+
+Tue Jan 31 15:13:10 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-inews-full-address): Use the full machine name in
+       the message-ids.
+       (gnus-get-unread-articles-in-group): Groups that have no articles
+       are marked as such.
+
+       * nnmail.el (nnmail-article-group): Catch regexp overflow errors. 
+
+       * gnus.el (gnus-update-read-articles): Would not update virtual
+       groups. 
+       (gnus-mail-send-and-exit): Don't return to the Gnus window
+       configuration from the mail buffer if Gnus isn't active.
+       (gnus-summary-next-group): Go to the group buffer if the user
+       answers "0" after selecting a new group from a different group. 
+       (gnus-select-newsgroup): Catch up properly if the only articles in
+       a group have expired.
+
+Tue Jan 31 08:01:19 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-kill): Arguments to `gnus-days-between' was
+       swapped. 
+
+Tue Jan 31 07:09:36 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-pp-gnus-kill): Don't quote quoted objects.
+
+Tue Jan 31 05:51:52 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus): Check whether Gnus has been started already. If
+       so, don't re-start, just switch to the buffer and get new news.
+       (gnus-batch-score): Didn't work.
+
+       * nnspool.el (nnspool-nov-is-evil): New variable.
+       (nnspool-lib-dir): New variable.
+       (nnspool-retrieve-headers-with-nov): nnspool can now return NOV
+       lines instead of plain article headers.
+
+       * nntp.el (nntp-nov-is-evil): Changed name of `nntp-xover-is-evil'
+       to `nntp-nov-is-evil'.
+
+Mon Jan 30 12:27:30 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-summary-search-subject): Would go to the first
+       article when searching backward.
+       (gnus-gather-threads): When gathering loose threads, they would be
+       gathered in reverse order.
+       (gnus-summary-prev-article): Did retrieve old articles when
+       executed on the first article in the buffer.
+       (gnus-read-header): Would not read old headers when requested one
+       by one.
+
+       * gnus.el: Converted all mark variables from strings to characters.
+
+Sun Jan 29 05:56:51 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-select-group-hook): Remove description of how to
+       sort, since it doesn't work.
+       (gnus-make-sub-thread): Removed silly lambda expression.
+       (gnus-thread-sort-functions): New variable.
+       (gnus-make-threads): Do not sort here.
+       (gnus-thread-sort-by-number): New function.
+       (gnus-thread-sort-by-author): New function.
+       (gnus-thread-sort-by-subject): New function.
+       (gnus-thread-sort-by-date): New function.
+       (gnus-thread-sort-by-score): New function.
+       (gnus-thread-sort-by-total-score): New function.
+       (gnus-thread-total-score): New function.
+       (gnus-thread-header): New function.
+       (gnus-sort-threads): New function.
+       (gnus-summary-prepare): Sort here.
+
+Sat Jan 28 18:44:09 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-articles-to-read): Provide default values instead
+       of initial input.
+
+Mon Jan 30 01:41:43 1995  Lars Magne Ingebrigtsen  <larsi@hymir.ifi.uio.no>
+
+       * gnus.el (gnus-mark-article-hook): Don't mark expirable articles
+       as read when selecting them.
+       (gnus-summary-mode): Removed " Thread" from the summary mode line.
+       (gnus-inews-message-id): Use domain name instead of host name in
+       message-ids.
+
+Sun Jan 29 09:37:31 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-apply-kill-file): Update dates when expiring
+       kills. 
+       (gnus-article-mode): Changed all the mode lines to really use a
+       buffer-local spec.
+       (gnus-group-search-forward): gnus-keep-same-level now works. 
+
+       * gnus.el: Got rid of all the invisible text and changed all the
+       functions to use text properties.
+
+Sat Jan 28 03:13:13 1995  Lars Magne Ingebrigtsen  <larsi@hymir.ifi.uio.no>
+
+       * gnus.el (gnus-inews-insert-headers): Remove any old
+       NNTP-Posting-Host headers.
+       (gnus-group-catchup): Mark dormant as read.
+
+Fri Jan 27 20:50:07 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-inews-news): Make followups default to all groups.
+
+Fri Jan 27 20:07:31 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-summary-prepare-threads): Move assignment to
+       `gnus-tmp-prev-subject' to after the check for equality with
+       `subject'. 
+
+Thu Jan 26 15:47:35 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-set-mouse-face): New function.
+       (gnus-parse-format): New function.
+       (gnus-parse-simple-format): Renamed from `gnus-parse-format'.
+       (gnus-group-insert-group-line): Do not set mouse face here.
+       (gnus-summary-insert-line): Do not set mouse face here.
+       (gnus-group-line-format): Add mouse face delimiters.
+       (gnus-summary-line-format): Add mouse face delimiters.
+       (gnus-update-format-specifications): Don't depend on
+       `gnus-group-line-format-spec' being a simple list.
+
+Tue Jan 24 20:18:42 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-clear-system): Kill global KILL file.
+
+Tue Jan 24 14:43:33 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-inews-insert-headers): Only check if first
+       `gnus-summary-gather-subject-limit' characters are the same.
+
+Mon Jan 23 22:18:56 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-summary-update-line): Protect call to
+       `gnus-summary-mark-article' with `save-excursion'.
+
+Sat Jan 28 00:55:19 1995  Lars Magne Ingebrigtsen  <larsi@mimir.ifi.uio.no>
+
+       * gnus.el (gnus-extract-address-components): Would fail if the
+       address contained special characters.
+
+Fri Jan 27 04:45:09 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-active-to-gnus-format): Condition-cased the active
+       file reading to be a bit more lenient with active files.
+       (gnus-group-get-new-news): Would always request info on each
+       individual group, even when the active file has been read.
+
+Thu Jan 26 00:16:45 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-inews-unique-id): Check for illegal characters in
+       the user name.
+       (gnus-summary-set-score): Removed the invisible score from the
+       summary lines. (assq article-number gnus-newsgroup-scored) can be
+       used instead.
+       (gnus-add-to-range): Would not give the right result if the ranges
+       did not start at 1.
+
+Wed Jan 25 02:49:39 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-summary-move-article): Would not properly respool
+       articles. 
+       (gnus-pp-gnus-kill): Removed (quote) from where it wasn't needed. 
+
+       * nnml.el (nnml-request-accept-article): Wouldn't do anything
+       much. 
+       (nnml-request-move-article): Would not properly move an article.
+
+       * gnus.el (gnus-apply-kill-file): Don't score already scored
+       articles. 
+       (gnus-newsgroup-scored): New list of articles.
+       (gnus-select-newsgroup, gnus-articles-to-read): Changed to take
+       into account previously scored articles, if any.
+
+Tue Jan 24 00:19:11 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-inews-organization): If organization is wanted,
+       and no organization is found, the user will be prompted for one. 
+       (gnus-inews-check-post): Bug in checking for multuple headers.
+       (gnus-inews-check-post): Check for version and sendsys.
+       (gnus-inews-insert-signature): Don't insert stuff that looks like
+       file names in signatures.
+
+       * nntp.el (nntp-request-article): unwind-protect the article
+       fetching. Might have caused bugs elsewhere.
+
+       * gnus.el (gnus-inews-organization): New implementation. The
+       `gnus-local-organization' variable can now also be a function.
+       (gnus-inews-check-post): Check for multiple headers.
+       (gnus-check-bogus-newsgroups): Would not remove bogus dead groups. 
+
+Mon Jan 23 23:49:15 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-inews-user-name): Use `user-mail-address' only as
+       a last resort.
+
+Mon Jan 23 19:40:02 1995  Lars Magne Ingebrigtsen  <larsi@gymir.ifi.uio.no>
+
+       * gnus.el (gnus-build-get-header): Did not work with multiple
+       articles with the same message-id.
+       (gnus-inews-organization): Remove trailing newlines.
+
+       * nnspool.el (nnspool-find-article-by-message-id): Grep for
+       message-ids instead of loading the entire history file.
+
+Mon Jan 23 18:59:27 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus-visual.el (gnus-visual-summary-highlight): Use and document
+       free variables. 
+       (gnus-visual-summary-highlight-line): Remove unnecessary test for
+       `gnus-visual' and add workaround face changes in start of line.
+
+Mon Jan 23 18:48:31 1995  Lars Magne Ingebrigtsen  <larsi@gymir.ifi.uio.no>
+
+       * nnmbox.el (nnmbox-read-mbox): Fix for no newsgroups.
+
+       * gnus.el (gnus-ask-server-for-new-groups): Did not work. :-)
+       (gnus-summary-make-false-root): This variable has now swallowed
+       the functionality of `gnus-gather-loose-threads'.
+
+Mon Jan 23 18:03:21 1994  Lars Magne Ingebrigtsen  <larsi@gymir.ifi.uio.no>
+
+       * gnus.el (gnus-group-unsubscribe-current-group): Would go two
+       steps forward.
+
+Mon Jan 23 17:09:10 1995  Lars Magne Ingebrigtsen  <larsi@mimir.ifi.uio.no>
+
+       * nnmail.el (nnmail-insert-lines): Compute a new Lines header and
+       remove any old ones.
+
+       * nnvirtual.el (nnvirtual-retrieve-headers): Removed checking for
+       multiple articles with the same ID.
+
+       * gnus.el (gnus-get-newsgroup-headers): Ignore multiple articles
+       with the same Message-ID.
+       (gnus-get-newsgroup-headers-xover): The same.
+
+Mon Jan 23 00:42:33 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-inews-insert-headers): Ask when empty headers
+       are detected.
+       (gnus-cancel-news): Avoid sending an empty cancel message.
+       (gnus-signature-function): New variable to return a signature file
+       name. 
+       (gnus-inews-insert-signature): Now warns the user if the signature
+       is more than 4 lines long. Also uses `gnus-signature-function'.
+       Also, if the string isn't a file name, the string itself is
+       inserted as a signature.
+       (gnus-inews-insert-signature): If mail-signature has already
+       inserted a .sig, delete this and insert Gnus' own.
+       (gnus-inews-check-post): Warn the user if the article to be posted
+       is more than 60k long.
+       (gnus-inews-insert-headers): Insert Sender header if the From
+       header doesn't seem to be the name of the user that posts.
+       (gnus-inews-check-post): Check for control characters.
+       (gnus-inews-insert-headers): Added "_-_" to message-id if the
+       thread has changed name.
+
+Sun Jan 22 02:37:06 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-article-prepare): Mark cancelled articles as
+       cancelled. 
+       (gnus-summary-expire-articles): Mark expired articles as
+       cancelled. 
+       (gnus-inews-insert-signature): Changed .sig predix from "--" to
+       "-- ".
+       (gnus-article-display-hook): Added "treat overstrike" to the
+       default display hook.
+       (gnus-inews-date): Changed to generate a valid date.
+
+       * nnmbox.el (nnmbox-request-article): Don't include the "From "
+       line when returning an article.
+
+       * nnmh.el (nnmh-save-mail): Rename "From " lines.
+
+       * nnml.el (nnml-save-mail): Rename "From " lines. 
+
+       * gnus.el (gnus-gnus-to-newsrc-format): Don't write foreign groups
+       to .newsrc.
+       (gnus-summary-remove-lines-marked-as-read,
+       gnus-summary-remove-lines-marked-with): Renamed functions 
+       from *-delete-marked-*.
+       (gnus-check-new-newsgroups): New possible value: `ask-server'.
+       (gnus-ask-server-for-new-groups): Ask the server for new groups
+       instead of comparing the killed list and the active hashtb. 
+       (gnus-parse-newsrc-body): Parse ! and : in the way they are
+       supposed to be parsed.
+       (gnus-get-unread-articles): Now works with any combination of
+       startup level, gnus-read-active-file status and
+       gnus-activate-foreign-newsgroup level.
+
+Sat Jan 21 21:27:23 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * nnvirtual.el: Big rewrite.
+       (nnvirtual-update-marked): Now updates marks in source groups.
+       (nnvirtual-create-mapping): Use marks from source groups.
+       (nnvirtual-possibly-change-newsgroups): Several nnvirtual groups
+       may be active at the same time. nnvirtual groups can also include
+       other nnvirtual groups.
+
+       * gnus.el (gnus-add-marked-articles): New function,
+
+Sat Jan 21 15:22:51 1995  Lars Magne Ingebrigtsen  <larsi@hnoss.ifi.uio.no>
+
+       * gnus.el (gnus-mark-xrefs-as-read): Would mark xreffed articles
+       that were ticked (or dormant) as read.
+       (gnus-summary-refer-parent-article): Now understands the numeric
+       prefix. 
+       (gnus-build-get-header): Would make it impossible to select old
+       fetched articles.
+
+       * gnus-visual.el (gnus-article-make-menu-bar): Added all treatment
+       functions to a menu.
+
+       * gnus.el (gnus-close-group): New backend call to perform
+       cleanups. 
+       (gnus-article-de-quoted-unreadable): New article treatment
+       function. 
+
+Sat Jan 21 01:15:26 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * nnmail.el (nnmail-article-group): Don't enter a mail into the
+       same mail group twice,
+
+       * gnus.el (gnus-build-old-threads): Don't build old threads
+       backwards from dormant articles.
+
+Fri Jan 20 23:31:16 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-summary-mark-article): Changed the expiry mark. It
+       is now a "read" mark, and occupies the same position as the other
+       read marks ("DX+- "). 
+
+Fri Jan 20 19:19:01 1995  Lars Magne Ingebrigtsen  <larsi@drott.ifi.uio.no>
+
+       * gnus.el (gnus-get-unread-articles): Did not properly activate
+       foreign newsgroups.
+
+Fri Jan 20 18:49:58 1995  Lars Magne Ingebrigtsen  <larsi@drott.ifi.uio.no>
+
+       * gnus.el (gnus-group-list-matching): New function and keystroke.
+
+Tue Jan 17 19:19:30 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-summary-keysort-summary,
+       gnus-summary-sort-summary, gnus-keysort-headers, gnus-keysort,
+       gnus-sort-headers, gnus-string-lessp, gnus-date-lessp): Deleted.
+       (gnus-sortable-date): New function.
+       (gnus-summary-sort-by-date, gnus-summary-sort-by-subject,
+       gnus-summary-sort-by-author, gnus-summary-sort-by-number): Use it.
+       (gnus-summary-sort-by-score): New function.
+       (gnus-summary-mode-map): Bind it.
+       (gnus-select-group-hook): Updated documentation.
+
+       * gnus.el (gnus-summary-best-unread-article): New function.
+       (gnus-summary-mode-map): Add binding.
+       (gnus-summary-mode): Document it.
+
+Mon Jan 16 15:49:37 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-summary-gather-subject-limit): New variable.
+       (gnus-gather-threads): Use it.
+
+       * nntp.el (nntp-request-post-buffer): Support
+       `gnus-auto-mail-to-author'.
+
+       * gnus.el (gnus-mail-self-blind): New variable.
+       (gnus-post-news): Use it.
+       (gnus-inews-news): Recognize "BCC" field.
+
+Thu Jan 19 21:37:33 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-build-old-threads): Fetch old headers and build
+       complete threads.
+
+Wed Jan 18 08:36:26 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * nnmh.el: Rewrite.
+
+       * gnus.el (gnus-get-newsgroup-headers): New implementation. Twice
+       as fast.
+
+       * nnmbox.el: Rewrite. Now supports crossposting.
+
+       * nnml.el: Rewrite.
+
+       * nnmail.el: Gathered all mail support functions in this file. 
+
+       * nnmbox.el: Renamed nnmail to nnmbox.
+
+       * gnus.el (gnus-summary-exit): Kill expunged buffer on exit.
+
+       * nntp.el (nntp-server-opened-hook): Send "MODE READER" to the
+       server at startup.
+
+Mon Jan 16 11:56:39 1995  Lars Magne Ingebrigtsen  <larsi@hymir.ifi.uio.no>
+
+       * gnus.el (gnus-summary-read-group): Update the specs after the
+       select-group-hook has bene run.
+
+Sun Jan 15 11:01:20 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el: Add autoload for `gnus-article-make-menu-bar'.
+        (gnus-article-mode-map): Call `gnus-article-make-menu-bar'.
+
+       * gnus-visual.el (gnus-group-make-menu-bar): Added entry for
+       `gnus-group-edit-global-kill',
+       (gnus-summary-make-menu-bar): Added entry for
+       `gnus-summary-raise-followups-to-author', and
+       `gnus-summary-lower-followups-to-author'.  Removed entries for
+       `gnus-summary-raise-by-thread', and
+       `gnus-summary-lower-by-thread'.
+       Renamed `xref' to `crossposting' since more people know that term.
+       Merged `Sort' menu with `Misc' since the menu-bar had not space
+       enough for all entries.
+       (gnus-article-make-menu-bar): New function.  Add menu bar for
+       article mode.
+
+Sun Jan 15 18:08:53 1995  Per Abrahamsen  <abraham@iesd.auc.dk>
+
+       * gnus.el (gnus-pp-gnus-kill): Don't assume (nth 0 object) is
+       `gnus-kill'. 
+
+Sun Jan 15 14:11:29 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-summary-refer-article): Don't fetch an article if
+       it is fetched already.
+       (gnus-gnus-to-newsrc-format): Write killed groups to the .newsrc
+       file as unsubscribed without numbers.
+       (gnus-summary-exit): Go to next group in the Group buffer when
+       quitting. 
+
 Sun Jan 15 07:44:09 1995  Lars Magne Ingebrigtsen  <larsi@hnoss.ifi.uio.no>
 
        * gnus.el (gnus-article-refer-article): Would not scroll to the
diff --git a/lisp/Makefile b/lisp/Makefile
new file mode 100644 (file)
index 0000000..c085bde
--- /dev/null
@@ -0,0 +1,69 @@
+EMACS=emacs
+
+#This is Jack's additions to reduce amount of stuff compiled
+#do "make X Y.." where X Y... are the gnus packages being used.
+#i.e.  "make nntp" will make gnus for nntp access only.
+# virtual - adds stuff for virtual groups
+# nnmbox - adds back end for mbox mail groups
+# nnml - adds back end for nnml mail groups
+# nnmh - adds back end for nnmh mail groups
+# nnspool - adds back ends for local news spool
+# mh - adds functions for using MH interface for mail and mail output
+
+syntax:
+       @echo "" ;\
+       echo "*** make one or more of: nntp virtual nnmbox nnml nnmh nnspool mh all gnus" ;\
+       echo "" ;\
+       exit 1
+
+nnheader.elc: nnheader.el
+       $(EMACS) -batch -f batch-byte-compile $(@:.elc=.el)
+gnus.elc: gnus.el
+       $(EMACS) -batch -l ./nnheader.elc -f batch-byte-compile $(@:.elc=.el)
+gnus-visual.elc: gnus-visual.el
+       $(EMACS) -batch -f batch-byte-compile $(@:.elc=.el)
+gnus-uu.elc: gnus-uu.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./gnus-visual.elc -l ./gnus.elc -f batch-byte-compile $(@:.elc=.el)
+nntp.elc: nntp.el
+       $(EMACS) -batch -l ./nnheader.elc -f batch-byte-compile $(@:.elc=.el)
+nnvirtual.elc: nnvirtual.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./gnus-visual.elc -l ./gnus.elc -l ./nntp.elc -f batch-byte-compile $(@:.elc=.el)
+nnmbox.elc: nnmbox.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./nnmail.elc -f batch-byte-compile $(@:.elc=.el)
+nnml.elc: nnml.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./nnmail.elc -l ./nnheader.elc -f batch-byte-compile $(@:.elc=.el)
+nnmh.elc: nnmh.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./gnus-visual.elc -l ./nnmail.elc -l ./gnus.elc -f batch-byte-compile $(@:.elc=.el)
+nnspool.elc: nnspool.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./nntp.elc -f batch-byte-compile $(@:.elc=.el)
+gnus-mh.elc: gnus-mh.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./gnus.elc -f batch-byte-compile $(@:.elc=.el)
+nnmail.elc: nnmail.el
+       $(EMACS) -batch -l ./nnheader.elc -f batch-byte-compile $(@:.elc=.el)
+mhspool.elc: mhspool.el
+       $(EMACS) -batch -l ./nnheader.elc -l ./nntp.elc -f batch-byte-compile $(@:.elc=.el)
+
+
+gnus:   nnheader.elc gnus.elc gnus-visual.elc gnus-uu.elc
+nntp:  gnus nntp.elc 
+virtual: nntp nnvirtual.elc
+nnmbox: gnus nnmail.elc  nnmbox.elc
+nnml:  gnus nnmail.elc nnml.elc
+nnmh:  gnus nnmail.elc nnmh.elc mhspool.elc 
+nnspool: nntp nnspool.elc
+mh:    gnus gnus-mh.elc
+all:   nntp virtual nnmbox nnml nnmh nnspool mh
+
+# This is what Lars wrote
+# all: elc info
+
+elc:
+       $(EMACS) -batch -l ./dgnushack.el -f dgnushack -f batch-byte-compile *.el
+
+info:
+       cd ../texi; makeinfo gnus.texi
+
+
+
+
+
index 4eee96c..67fded4 100644 (file)
@@ -141,7 +141,7 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
   "Compose mail other window using mh-e."
   (let ((to (read-string "To: "))
        (cc (read-string "Cc: "))
-       (subject (read-string "Subject: " (gnus-fetch-field "subject"))))
+       (subject (read-string "Subject: ")))
     (gnus-article-show-all-headers)    ;I don't think this is really needed.
     (setq mh-show-buffer (current-buffer))
     (mh-find-path)
@@ -169,3 +169,4 @@ Otherwise, it is like +news/group."
                  newsgroup
                (gnus-newsgroup-directory-form newsgroup)))))
 
+;;; gnus-mh.el ends here
index 3f56243..4bc6b5d 100644 (file)
@@ -1,10 +1,9 @@
-;;; gnus-uu.el --- extract, view or save (uu)encoded files from Gnus
+;;; gnus-uu.el --- extract (uu)encoded files in Gnus
 ;; Copyright (C) 1985,86,87,93,94,95 Free Software Foundation, Inc.
 
 ;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
 ;; Created: 2 Oct 1993
-;; Version: v2.9.4
-;; Last Modified: 1994/10/03
+;; Version: v3.0
 ;; Keyword: news
 
 ;; This file is part of GNU Emacs.
 
 ;;; Commentary:
 
-;; All gnus-uu commands start with `C-c C-v'.
-;;
-;; Short user manual for this package:
-;;
-;; Type `C-c C-v C-v' to decode and view all articles of the current
-;; series. The defaults should be reasonable for most systems.
-;;
-;; Type `C-c C-v C-i' to toggle interactive mode. When using
-;; interactive mode, gnus-uu will which display a buffer that will let
-;; you see the suggested commands to be executed.
-;;
-;; To post an uuencoded file, type `C-c C-v p', which will enter you
-;; into a buffer analogous to the one you will get when typing `a'. Do
-;; an `M-x describe-mode' in this buffer to get a description of what
-;; this buffer lets you do.
-;;
-;; Read the documentation of the `gnus-uu' dummy function for a more
-;; complete description of what this package does and how you can
-;; customize it to fit your needs.
-;; 
-;;
-;;
-;; History
-;;
-;; v1.0: First version released Oct 2 1992.
-;;
-;; v1.1: Changed `C-c C-r' to `C-c C-e' and `C-c C-p' to `C-c C-k'.
-;; Changed (setq gnus-exit-group-hook) to (add-hook).  Removed
-;; checking for "Re:" for finding parts.
-;;
-;; v2.2: Fixed handling of currupted archives. Changed uudecoding to
-;; an asynchronous process to avoid loading tons of data into emacs
-;; buffers. No longer reads articles emacs already have aboard.  Fixed
-;; a firmer support for shar files. Made regexp searches for files
-;; more convenient. Added `C-c C-l' for editing uucode begin
-;; lines. Added multi-system decoder entry point. Added interactive
-;; view mode. Added function for decoding and saving all uuencoded
-;; articles in the current newsgroup.
-;;
-;; v2.3: After suggestions I have changed all the gnus-uu key bindings
-;; to avoid hogging all the user keys (C-c LETTER). Also added
-;; (provide) and fixed some saving stuff. First posted version to
-;; gnu.emacs.sources.
-;;
-;; v2.4: Fixed some more in the save-all category. Automatic fixing of
-;; uucode "begin" lines: names on the form of "dir/file" are
-;; translated into "dir-file". Added a function for fixing stripped
-;; uucode articles. Added binhex save.
-;;
-;; v2.5: First version copyrighted by FSF. Changed lots of
-;; documentation strings.
-;;
-;; v2.5.1: Added uuencode/posting code to post binary files. 
-;;
-;; v2.6: Thread support. gnus-uu is now able to decode uuencoded files
-;; posted in threads. gnus-uu can also post in threads. I don't know
-;; if this ability is of much use - I've never seen anyone post
-;; uuencoded files in threads.
-;;
-;; v2.7: gnus-uu is now able to decode (and view/save) multiple
-;; encoded files in one big gulp. Also added pseudo-mime support
-;; (users can use metamail to view files), posting uuencoded/mime
-;; files and various other bits and pieces.
-;;
-;; v2.7.1: New functions for decoding/saving threads bound to `C-c
-;; C-v C-j'. Handy to save entire threads, not very useful for
-;; decoding, as nobody posts encoded files in threads...
-;;
-;; v2.7.2: New functions for digesting and forwarding articles added
-;; on the suggestion of Per Abrahamsen. Also added a function for
-;; marking threads. 
-;;
-;; v2.8: Fixed saving original files in interactive mode. Fixed ask
-;; before/save after view. Fixed setting up interactive buffers. Added
-;; scanning and rescanning from interactive mode. Added the
-;; `gnus-uu-ignore-file-by-name' and `...-by-type' variables to allow
-;; users to sift files they don't want to view. At the suggestion of
-;; boris@cs.rochester.edu, `C-c C-v C-h' has been undefined to allow
-;; users to view list of binding beginning with `C-c C-v'. Fixed
-;; viewing with `gnus-uu-asynchronous' set. The
-;; "decode-and-save/view-all-articles" functions now accepts the
-;; numeric prefix to delimit the maximum number of files to be
-;; decoded.
-;;
-;; v2.9: Speeded up fetching of articles by bypassing the gnus
-;; function and going directly to `gnus-request-article'
-;; instead. Significant speed increase, especially when using a local
-;; spool. Added the `gnus-uu-universal-prefix' command (`C-c C-v C-u')
-;; to allow users to perform any job on all marked articles.
-;;
-;; v2.9.1: Disabled buffer-undo, which stopped gnus-uu from making
-;; emacs *very* large in big newsgroups.
-;;
-;; v2.9.2: A few minor bug-fixes.
-;;
-;; v2.9.3: Finally managed to fix the bug that made gnus-uu core dump
-;; emacs in huge newsgroups. The error was a result of not deleting a
-;; process that had terminated with an error, which led to
-;; select() failing miserably later. Added the `C-c C-v M-C-w' and
-;; `C-c C-v M-w' keystrokes and the `...-marked-files' functions to
-;; allow users to walk around the newsgroup and mark some articles
-;; here and there, without having to worry about marking exactly
-;; right, and then decoding all files that had had some articles
-;; marked. 
-
 ;;; Code: 
 
 (require 'gnus)
 
-;; Binding of keys to the gnus-uu functions.
-
-(defvar gnus-uu-ctl-map nil)
-(define-prefix-command 'gnus-uu-ctl-map)
-(define-key gnus-summary-mode-map "\C-c\C-v" gnus-uu-ctl-map)
-
-(define-key gnus-uu-ctl-map "\C-v" 'gnus-uu-decode-and-view)
-(define-key gnus-uu-ctl-map "v" 'gnus-uu-decode-and-save)
-(define-key gnus-uu-ctl-map "\C-s" 'gnus-uu-shar-and-view)
-(define-key gnus-uu-ctl-map "s" 'gnus-uu-shar-and-save)
-(define-key gnus-uu-ctl-map "\C-m" 'gnus-uu-multi-decode-and-view)
-(define-key gnus-uu-ctl-map "m" 'gnus-uu-multi-decode-and-save)
-
-(define-key gnus-uu-ctl-map "\C-b" 'gnus-uu-decode-and-show-in-buffer)
-
-(define-key gnus-uu-ctl-map "u" 'gnus-summary-unmark-all-processable)
-(define-key gnus-uu-ctl-map "\C-r" 'gnus-uu-mark-by-regexp)
-(define-key gnus-uu-ctl-map "r" 'gnus-uu-mark-region)
-(define-key gnus-uu-ctl-map "t" 'gnus-uu-mark-thread)
-
-(define-key gnus-uu-ctl-map "\C-u" 'gnus-uu-marked-universal-argument)
-
-(define-key gnus-uu-ctl-map "\M-\C-v" 'gnus-uu-marked-decode-and-view)
-(define-key gnus-uu-ctl-map "\M-v" 'gnus-uu-marked-decode-and-save)
-(define-key gnus-uu-ctl-map "\M-\C-s" 'gnus-uu-marked-shar-and-view)
-(define-key gnus-uu-ctl-map "\M-s" 'gnus-uu-marked-shar-and-save)
-(define-key gnus-uu-ctl-map "\M-\C-m" 'gnus-uu-marked-multi-decode-and-view)
-(define-key gnus-uu-ctl-map "\M-m" 'gnus-uu-marked-multi-decode-and-save)
-
-(define-key gnus-uu-ctl-map "f" 'gnus-uu-digest-and-forward)
-(define-key gnus-uu-ctl-map "\M-f" 'gnus-uu-marked-digest-and-forward)
-
-(define-key gnus-uu-ctl-map "\C-i" 'gnus-uu-toggle-interactive-view)
-(define-key gnus-uu-ctl-map "\C-t" 'gnus-uu-toggle-any-variable)
-
-(define-key gnus-uu-ctl-map "\C-l" 'gnus-uu-edit-begin-line)
-
-(define-key gnus-uu-ctl-map "a" 'gnus-uu-decode-and-save-all-unread-articles)
-(define-key gnus-uu-ctl-map "w" 'gnus-uu-decode-and-save-all-articles)
-(define-key gnus-uu-ctl-map "\C-a" 'gnus-uu-decode-and-view-all-unread-articles)
-(define-key gnus-uu-ctl-map "\C-w" 'gnus-uu-decode-and-view-all-articles)
-(define-key gnus-uu-ctl-map "\M-\C-w" 'gnus-uu-decode-and-view-all-marked-files)
-(define-key gnus-uu-ctl-map "\M-w" 'gnus-uu-decode-and-save-all-marked-files)
-
-(define-key gnus-uu-ctl-map "\C-j" 'gnus-uu-threaded-multi-decode-and-view)
-(define-key gnus-uu-ctl-map "j" 'gnus-uu-threaded-multi-decode-and-save)
-
-(define-key gnus-uu-ctl-map "p" 'gnus-uu-post-news)
-
-;; Dummy function gnus-uu
-
-(defun gnus-uu ()
-  "gnus-uu is a package for uudecoding and viewing articles."
-  (interactive))
-
 ;; Default viewing action rules
 
 (defvar gnus-uu-default-view-rules 
-  (list 
-   '("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "xv")
-   '("\\.tga$" "tgatoppm %s | xv -")
-   '("\\.te?xt$\\|\\.doc$\\|read.*me" "xterm -e less")
-   '("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$" 
+  '(("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed s/\r//g")
+    ("\\.pas$" "cat %s | sed s/\r//g")
+    ("\\.[1-9]$" "groff -mandoc -Tascii %s | sed s/\b.//g")
+    ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "xv")
+    ("\\.tga$" "tgatoppm %s | xv -")
+    ("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$" 
      "sox -v .5 %s -t .au -u - > /dev/audio")
-   '("\\.au$" "cat %s > /dev/audio")
-   '("\\.mod$" "str32")
-   '("\\.ps$" "ghostview")
-   '("\\.dvi$" "xdvi")
-   '("\\.[1-6]$" "xterm -e groff -mandoc -Tascii")
-   '("\\.html$" "xmosaic")
-   '("\\.mpe?g$" "mpeg_play")
-   '("\\.\\(flc\\|fli\\|rle\\|iff\\|pfx\\|avi\\|sme\\|rpza\\|dl\\|qt\\|rsrc\\|mov\\)$" "xanim")
-   '("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$" 
+    ("\\.au$" "cat %s > /dev/audio")
+    ("\\.mod$" "str32")
+    ("\\.ps$" "ghostview")
+    ("\\.dvi$" "xdvi")
+    ("\\.html$" "xmosaic")
+    ("\\.mpe?g$" "mpeg_play")
+    ("\\.\\(flc\\|fli\\|rle\\|iff\\|pfx\\|avi\\|sme\\|rpza\\|dl\\|qt\\|rsrc\\|mov\\)$" "xanim")
+    ("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$" 
      "gnus-uu-archive"))
 
   "Default actions to be taken when the user asks to view a file.  
@@ -218,7 +57,7 @@ For example:
 To make gnus-uu use 'xli' to display JPEG and GIF files, put the
 following in your .emacs file
 
-  (setq gnus-uu-user-view-rules (list '(\"jpg$\\\\|gif$\" \"xli\")))
+  (setq gnus-uu-user-view-rules '((\"jpg$\\\\|gif$\" \"xli\")))
 
 Both these variables are lists of lists with two string elements. The
 first string is a regular expression. If the file name matches this
@@ -236,56 +75,31 @@ variable gnus-uu first consults when trying to decide how to view a
 file. If this variable contains no matches, gnus-uu examines the
 default rule vaiable provided in this package. If gnus-uu finds no
 match here, it uses `gnus-uu-user-view-rules-end' to try to make a
-match.
-
-Unless, of course, you are using the interactive view mode. Then
-`gnus-uu-user-interactive-view-rules' and
-`gnus-uu-user-interactive-view-rules-end' will be used instead.")
+match.")
 
 (defvar gnus-uu-user-view-rules nil 
   "Variable detailing what actions are to be taken to view a file.
 See the documentation on the `gnus-uu-default-view-rules' variable for 
 details.")
 
-(defvar gnus-uu-user-view-rules-end nil
+(defvar gnus-uu-user-view-rules-end 
+  '(("" "file"))
   "Variable saying what actions are to be taken if no rule matched the file name.
 See the documentation on the `gnus-uu-default-view-rules' variable for 
 details.")
 
-(defvar gnus-uu-user-interactive-view-rules nil
-  "Variable detailing what actions are to be taken to view a file when using interactive mode.
-See the documentation on the `gnus-uu-default-view-rules' variable for 
-details.")
-
-(defvar gnus-uu-user-interactive-view-rules-end nil
-  "Variable saying what actions are to be taken if no rule matched the file name when using interactive mode.
-See the documentation on the `gnus-uu-default-view-rules' variable for 
-details.")
-
-(defvar gnus-uu-default-interactive-view-rules-begin
-  (list
-   '("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed s/\r//g")
-   '("\\.pas$" "cat %s | sed s/\r//g")
-   '("\\.[1-9]$" "groff -mandoc -Tascii %s | sed s/\b.//g")
-   ))
-
-(defvar gnus-uu-default-interactive-view-rules-end
-  (list
-   '(".*" "file")))
-
 ;; Default unpacking commands
 
 (defvar gnus-uu-default-archive-rules 
-  (list '("\\.tar$" "tar xf")
-       '("\\.zip$" "unzip -o")
-       '("\\.ar$" "ar x")
-       '("\\.arj$" "unarj x")
-       '("\\.zoo$" "zoo -e")
-       '("\\.\\(lzh\\|lha\\)$" "lha x")
-       '("\\.Z$" "uncompress")
-       '("\\.gz$" "gunzip")
-       '("\\.arc$" "arc -x"))
-  )
+  '(("\\.tar$" "tar xf")
+    ("\\.zip$" "unzip -o")
+    ("\\.ar$" "ar x")
+    ("\\.arj$" "unarj x")
+    ("\\.zoo$" "zoo -e")
+    ("\\.\\(lzh\\|lha\\)$" "lha x")
+    ("\\.Z$" "uncompress")
+    ("\\.gz$" "gunzip")
+    ("\\.arc$" "arc -x")))
 
 (defvar gnus-uu-destructive-archivers 
   (list "uncompress" "gunzip"))
@@ -295,8 +109,8 @@ details.")
 To use, for instance, 'untar' to unpack tar files and 'zip -x' to
 unpack zip files, say the following:
   (setq gnus-uu-user-archive-rules 
-    (list '(\"\\\\.tar$\" \"untar\")
-          '(\"\\\\.zip$\" \"zip -x\")))")
+    '((\"\\\\.tar$\" \"untar\")
+      (\"\\\\.zip$\" \"zip -x\")))")
 
 (defvar gnus-uu-ignore-files-by-name nil
   "A regular expression saying what files should not be viewed based on name.
@@ -321,43 +135,43 @@ Note that this variable can be used in conjunction with the
 ;; Pseudo-MIME support
 
 (defconst gnus-uu-ext-to-mime-list
-  (list '("\\.gif$" "image/gif")
-       '("\\.jpe?g$" "image/jpeg")
-       '("\\.tiff?$" "image/tiff")
-       '("\\.xwd$" "image/xwd")
-       '("\\.pbm$" "image/pbm")
-       '("\\.pgm$" "image/pgm")
-       '("\\.ppm$" "image/ppm")
-       '("\\.xbm$" "image/xbm")
-       '("\\.pcx$" "image/pcx")
-       '("\\.tga$" "image/tga")
-       '("\\.ps$" "image/postscript")
-       '("\\.fli$" "video/fli")
-       '("\\.wav$" "audio/wav")
-       '("\\.aiff$" "audio/aiff")
-       '("\\.hcom$" "audio/hcom")
-       '("\\.voc$" "audio/voc")
-       '("\\.smp$" "audio/smp")
-       '("\\.mod$" "audio/mod")
-       '("\\.dvi$" "image/dvi")
-       '("\\.mpe?g$" "video/mpeg")
-       '("\\.au$" "audio/basic")
-       '("\\.\\(te?xt\\|doc\\|c\\|h\\)$" "text/plain")
-       '("\\.\\(c\\|h\\)$" "text/source")
-       '("read.*me" "text/plain")
-       '("\\.html$" "text/html")
-       '("\\.bat$" "text/bat")
-       '("\\.[1-6]$" "text/man")
-       '("\\.flc$" "video/flc")
-       '("\\.rle$" "video/rle")
-       '("\\.pfx$" "video/pfx")
-       '("\\.avi$" "video/avi")
-       '("\\.sme$" "video/sme")
-       '("\\.rpza$" "video/prza")
-       '("\\.dl$" "video/dl")
-       '("\\.qt$" "video/qt")
-       '("\\.rsrc$" "video/rsrc")
-       '("\\..*$" "unknown/unknown")))
+  '(("\\.gif$" "image/gif")
+    ("\\.jpe?g$" "image/jpeg")
+    ("\\.tiff?$" "image/tiff")
+    ("\\.xwd$" "image/xwd")
+    ("\\.pbm$" "image/pbm")
+    ("\\.pgm$" "image/pgm")
+    ("\\.ppm$" "image/ppm")
+    ("\\.xbm$" "image/xbm")
+    ("\\.pcx$" "image/pcx")
+    ("\\.tga$" "image/tga")
+    ("\\.ps$" "image/postscript")
+    ("\\.fli$" "video/fli")
+    ("\\.wav$" "audio/wav")
+    ("\\.aiff$" "audio/aiff")
+    ("\\.hcom$" "audio/hcom")
+    ("\\.voc$" "audio/voc")
+    ("\\.smp$" "audio/smp")
+    ("\\.mod$" "audio/mod")
+    ("\\.dvi$" "image/dvi")
+    ("\\.mpe?g$" "video/mpeg")
+    ("\\.au$" "audio/basic")
+    ("\\.\\(te?xt\\|doc\\|c\\|h\\)$" "text/plain")
+    ("\\.\\(c\\|h\\)$" "text/source")
+    ("read.*me" "text/plain")
+    ("\\.html$" "text/html")
+    ("\\.bat$" "text/bat")
+    ("\\.[1-6]$" "text/man")
+    ("\\.flc$" "video/flc")
+    ("\\.rle$" "video/rle")
+    ("\\.pfx$" "video/pfx")
+    ("\\.avi$" "video/avi")
+    ("\\.sme$" "video/sme")
+    ("\\.rpza$" "video/prza")
+    ("\\.dl$" "video/dl")
+    ("\\.qt$" "video/qt")
+    ("\\.rsrc$" "video/rsrc")
+    ("\\..*$" "unknown/unknown")))
 
 ;; Various variables users may set 
 
@@ -374,15 +188,6 @@ Default is nil.")
 If the variable is nil, the suer will only be asked to save if the
 viewing is unsuccessful. Default is nil.")
 
-(defvar gnus-uu-asynchronous nil
-  "Non-nil means that files will be viewed asynchronously.
-Default is nil.")
-
-(defvar gnus-uu-ask-before-view nil
-  "Non-nil means that gnus-uu will ask you before viewing each file. 
-Especially useful when `gnus-uu-asynchronous' is set. Default is
-nil.")
-
 (defvar gnus-uu-ignore-default-view-rules nil
   "Non-nil means that gnus-uu will ignore the default viewing rules.
 Only the user viewing rules will be consulted. Default is nil.")
@@ -405,19 +210,10 @@ it nil.")
   "Non-nil means that gnus-uu will mark articles that were unsuccessfully decoded as unread. 
 Default is nil.")
 
-(defvar gnus-uu-output-window-height 20 
-  "This variable says how tall the output buffer window is to be when using interactive view mode. 
-Change it at your convenience. Default is 20.")
-
 (defvar gnus-uu-correct-stripped-uucode nil
   "Non-nil means that gnus-uu will *try* to fix uuencoded files that have had traling spaces deleted. 
 Default is nil.")
 
-(defvar gnus-uu-use-interactive-view nil
-  "Non-nil means that gnus-uu will use interactive viewing mode.
-Gnus-uu will create a special buffer where the user may choose
-interactively which files to view and how. Default is nil.")
-
 (defvar gnus-uu-save-in-digest nil
   "Non-nil means that gnus-uu, when asked to save without decoding, will save in digests.
 If this variable is nil, gnus-uu will just save everything in a 
@@ -426,11 +222,12 @@ no easy way to specify any meaningful volume and issue numbers were found,
 so I simply dropped them.")
 
 (defvar gnus-uu-save-separate-articles nil
-  "Non-nil means that gnus-uu will save artilces in separate files.")
-
+  "Non-nil means that gnus-uu will save articles in separate files.")
 
 ;; Internal variables
 
+(defvar gnus-uu-saved-article-name nil)
+
 (defconst gnus-uu-begin-string "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
 (defconst gnus-uu-end-string "^end[ \t]*$")
 
@@ -451,508 +248,148 @@ so I simply dropped them.")
 (defvar gnus-uu-list-of-files-decoded nil)
 (defconst gnus-uu-uudecode-process nil)
 
-(defvar gnus-uu-interactive-file-list nil)
 (defvar gnus-uu-generated-file-list nil)
 (defvar gnus-uu-work-dir nil)
 
-(defconst gnus-uu-interactive-buffer-name "*gnus-uu interactive*")
 (defconst gnus-uu-output-buffer-name "*Gnus UU Output*")
 
 (defconst gnus-uu-highest-article-number 1)
 
-;; Interactive functions
-
-;; UUdecode and view
-
-(defun gnus-uu-decode-and-view ()
-  "UUdecodes and 'views' (if possible) the resulting file.
-'Viewing' can be any action at all, as defined in the
-`gnus-uu-file-action-list' variable. Running 'xv' on gifs and 'cat
->/dev/audio' on au files are popular actions. If the file can't be
-viewed, the user is asked if she would like to save the file instead."
-  (interactive) 
-  (gnus-uu-decode-and-view-or-save t nil))
-
-(defun gnus-uu-decode-and-save ()
-  "Decodes and saves the resulting file."
-  (interactive)
-  (gnus-uu-decode-and-view-or-save nil nil))
-
-(defun gnus-uu-marked-decode-and-view ()
-  "Decodes and views articles marked.
-The marked equivalent to `gnus-uu-decode-and-view'."
-  (interactive)
-  (gnus-uu-decode-and-view-or-save t t))
-
-(defun gnus-uu-marked-decode-and-save ()
-  "Decodes and saves articles marked.
-The marked equivalent to `gnus-uu-decode-and-save'."
-  (interactive)
-  (gnus-uu-decode-and-view-or-save nil t))
-      
-
-;; Unshar and view
-
-(defun gnus-uu-shar-and-view ()
-  "Unshars and views articles.
-The shar equivalent of `gnus-uu-decode-and-view'."
-  (interactive)
-  (gnus-uu-unshar-and-view-or-save t nil))
-
-(defun gnus-uu-shar-and-save ()
-  "Unshars and saves files.
-The shar equivalent to `gnus-uu-decode-and-save'."
-  (interactive)
-  (gnus-uu-unshar-and-view-or-save nil nil))
-
-(defun gnus-uu-marked-shar-and-view ()
-  "Unshars and views articles marked.
-The marked equivalent to `gnus-uu-shar-and-view'."
-  (interactive)
-  (gnus-uu-unshar-and-view-or-save t t))
-
-(defun gnus-uu-marked-shar-and-save ()
-  "Unshars and saves articles marked.
-The marked equivalent to `gnus-uu-shar-and-save'."
-  (interactive)
-  (gnus-uu-unshar-and-view-or-save nil t))
-
-;; Threaded decode
-
-(defun gnus-uu-threaded-decode-and-view ()
-  "Decodes and saves the resulting file."
-  (interactive)
-  (gnus-uu-threaded-decode-and-view-or-save t))
-
-(defun gnus-uu-threaded-decode-and-save ()
-  "Decodes and saves the resulting file."
-  (interactive)
-  (gnus-uu-threaded-decode-and-view-or-save nil))
+;; Commands.
 
-(defun gnus-uu-threaded-multi-decode-and-view ()
-  "Decodes and saves the resulting file."
-  (interactive)
-  (gnus-uu-threaded-multi-decode-and-view-or-save t))
+(defun gnus-uu-decode-uu (n)
+  "Uudecodes the current article."
+  (interactive "P") 
+  (gnus-uu-decode-with-method 'gnus-uu-uustrip-article n))
 
-(defun gnus-uu-threaded-multi-decode-and-save ()
+(defun gnus-uu-decode-uu-and-save (n dir)
   "Decodes and saves the resulting file."
-  (interactive)
-  (gnus-uu-threaded-multi-decode-and-view-or-save nil))
-
-(defun gnus-uu-threaded-decode-and-view-or-save (&optional view)
-  (gnus-summary-unmark-all-processable)
-  (gnus-uu-mark-thread)
-  (gnus-uu-decode-and-view-or-save view t))
-
-(defun gnus-uu-threaded-multi-decode-and-view-or-save (view)
-  (let (type)
-    (message "Decode type: [u]udecode, (s)har, s(a)ve, (b)inhex: ")
-    (setq type (read-char))
-    (if (not (or (= type ?u) (= type ?s) (= type ?b) (= type ?a)))
-       (error "No such decoding method '%c'" type))
-    
-    (gnus-summary-unmark-all-processable)
-    (gnus-uu-mark-thread)
-
-    (if (= type ?\r) (setq type ?u))
-    (cond ((= type ?u) (gnus-uu-decode-and-view-or-save view t))
-         ((= type ?s) (gnus-uu-unshar-and-view-or-save view t))
-         ((= type ?b) (gnus-uu-binhex-and-save view t))
-         ((= type ?a) (gnus-uu-save-articles view t))
-         (t (error "No such decoding method: %s" type)))))
-    
-
-;; Toggle commands      
+  (interactive "P\nDWhere do you want to save the file(s)? ")
+  (gnus-uu-decode-with-method 'gnus-uu-uustrip-article n dir))
+
+(defun gnus-uu-decode-unshar (n)
+  "Unshars the current article."
+  (interactive "P")
+  (gnus-uu-decode-with-method 'gnus-uu-unshar-article n))
+
+(defun gnus-uu-decode-unshar-and-save (n dir)
+  "Unshars and saves the current article."
+  (interactive "P\nDWhere do you want to save the file(s)? ")
+  (gnus-uu-decode-with-method 'gnus-uu-unshar-article n dir))
+
+(defun gnus-uu-decode-save (n file)
+  "Saves the current article."
+  (interactive "P\nDWhere do you want to save the file(s)? ")
+  (setq gnus-uu-saved-article-name file)
+  (gnus-uu-decode-with-method 'gnus-uu-save-article n nil)
+  (setq gnus-uu-generated-file-list 
+       (delete file gnus-uu-generated-file-list)))
+
+(defun gnus-uu-decode-binhex (n dir)
+  "Unbinhexes the current article."
+  (interactive "P\nDWhere do you want to save the file(s)? ")
+  (gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
 
-(defun gnus-uu-toggle-asynchronous ()
-  "This function toggles asynchronous viewing."
-  (interactive)
-  (if (setq gnus-uu-asynchronous (not gnus-uu-asynchronous))
-      (message "gnus-uu will now view files asynchronously")
-    (message "gnus-uu will now view files synchronously")))
-
-(defun gnus-uu-toggle-query ()
-  "This function toggles whether to ask before viewing or not."
-  (interactive)
-  (if (setq gnus-uu-ask-before-view (not gnus-uu-ask-before-view))
-      (message "gnus-uu will now ask before viewing")
-    (message "gnus-uu will now view without asking first")))
-
-(defun gnus-uu-toggle-always-ask ()
-  "This function toggles whether to always ask to save a file after viewing."
-  (interactive)
-  (if (setq gnus-uu-view-and-save (not gnus-uu-view-and-save))
-      (message "gnus-uu will now ask to save the file after viewing")
-    (message "gnus-uu will now not ask to save after successful viewing")))
-
-(defun gnus-uu-toggle-interactive-view ()
-  "This function toggles whether to use interactive view."
-  (interactive)
-  (if (setq gnus-uu-use-interactive-view (not gnus-uu-use-interactive-view))
-      (message "gnus-uu will now use interactive view")
-    (message "gnus-uu will now use non-interactive view")))
-
-(defun gnus-uu-toggle-unmark-undecoded ()
-  "This function toggles whether to unmark articles not decoded."
-  (interactive)
-  (if (setq gnus-uu-unmark-articles-not-decoded 
-           (not gnus-uu-unmark-articles-not-decoded))
-      (message "gnus-uu will now unmark articles not decoded")
-    (message "gnus-uu will now not unmark articles not decoded")))
-
-(defun gnus-uu-toggle-kill-carriage-return ()
-  "This function toggles the stripping of carriage returns from the articles."
-  (interactive)
-  (if (setq gnus-uu-kill-carriage-return (not gnus-uu-kill-carriage-return))
-      (message "gnus-uu will now strip carriage returns")
-    (message "gnus-uu won't strip carriage returns")))
-
-(defun gnus-uu-toggle-view-with-metamail ()
-  "This function toggles whether to view files with metamail."
-  (interactive)
-  (if (setq gnus-uu-view-with-metamail (not gnus-uu-view-with-metamail))
-      (message "gnus-uu will now view with metamail")
-    (message "gnus-uu will now view with the gnus-uu viewing functions")))
-
-(defun gnus-uu-toggle-correct-stripped-uucode ()
-  "This function toggles whether to correct stripped uucode."
-  (interactive)
-  (if (setq gnus-uu-correct-stripped-uucode 
-           (not gnus-uu-correct-stripped-uucode))
-      (message "gnus-uu will now correct stripped uucode")
-    (message "gnus-uu won't check and correct stripped uucode")))
-
-(defun gnus-uu-toggle-any-variable ()
-  "This function ask what variable the user wants to toggle."
-  (interactive)
-  (let (rep)
-    (message "(a)sync, (q)uery, (p)ask, (k)ill CR, (i)nteract, (u)nmark, (c)orrect, (m)eta")
-    (setq rep (read-char))
-    (if (= rep ?a)
-       (gnus-uu-toggle-asynchronous))
-    (if (= rep ?q)
-       (gnus-uu-toggle-query))
-    (if (= rep ?p)
-       (gnus-uu-toggle-always-ask))
-    (if (= rep ?k)
-       (gnus-uu-toggle-kill-carriage-return))
-    (if (= rep ?u)
-       (gnus-uu-toggle-unmark-undecoded))
-    (if (= rep ?c)
-       (gnus-uu-toggle-correct-stripped-uucode))
-    (if (= rep ?m)
-       (gnus-uu-toggle-view-with-metamail))
-    (if (= rep ?i)
-       (gnus-uu-toggle-interactive-view))))
-
-
-;; Misc interactive functions
-
-(defun gnus-uu-decode-and-show-in-buffer ()
-  "Uudecodes the current article and displays the result in a buffer.
-Might be useful if someone has, for instance, some text uuencoded in
-their sigs. (Stranger things have happened.)"
-  (interactive)
-  (gnus-uu-initialize)
-  (let ((uu-buffer (get-buffer-create gnus-uu-output-buffer-name))
-       file-name)
-    (save-excursion
-      (and 
-       (gnus-summary-select-article)
-       (gnus-uu-grab-articles (list gnus-current-article) 
-                             'gnus-uu-uustrip-article-as)
-       (setq file-name (concat gnus-uu-work-dir gnus-uu-file-name))
-       (progn
-        (save-excursion
-          (set-buffer uu-buffer)
-          (erase-buffer)
-          (insert-file-contents file-name))
-        (set-window-buffer (get-buffer-window gnus-article-buffer) 
-                           uu-buffer)
-        (message "Showing file %s in buffer" file-name)
-        (delete-file file-name))))))
-
-(defun gnus-uu-edit-begin-line ()
-  "Edit the begin line of the current article."
-  (interactive)
-  (let ((buffer-read-only nil)
-       begin b)
-    (save-excursion
-      (gnus-summary-select-article)
-      (set-buffer gnus-article-buffer)
-      (goto-line 1)
-      (if (not (re-search-forward "begin " nil t))
-         (error "No begin line in the current article")
-       (beginning-of-line)
-       (setq b (point))
-       (end-of-line)
-       (setq begin (buffer-substring b (point)))
-       (setq begin (read-string "" begin))
-       (setq buffer-read-only nil)
-       (delete-region b (point))
-       (insert-string begin)))))
-
-
-;; Multi functions
-
-(defun gnus-uu-multi-decode-and-view ()
-  "Choose a method of decoding and then decode and view.
-This function lets the user decide what method to use for decoding.
-Other than that, it's equivalent to the other decode-and-view
-functions."
-  (interactive)
-  (gnus-uu-multi-decode-and-view-or-save t nil))
-
-(defun gnus-uu-multi-decode-and-save ()
-  "Choose a method of decoding and then decode and save.
-This function lets the user decide what method to use for decoding.
-Other than that, it's equivalent to the other decode-and-save 
-functions."
-  (interactive)
-  (gnus-uu-multi-decode-and-view-or-save nil nil))
-
-(defun gnus-uu-marked-multi-decode-and-view ()
-  "Choose a method of decoding and then decode and view the marked articles.
-This function lets the user decide what method to use for decoding.
-Other than that, it's equivalent to the other marked decode-and-view 
-functions."
-  (interactive)
-  (gnus-uu-multi-decode-and-view-or-save t t))
+;; Digest and forward articles
 
-(defun gnus-uu-marked-multi-decode-and-save ()
-  "Choose a method of decoding and then decode and save the marked articles.
-This function lets the user decide what method to use for decoding.
-Other than that, it's equivalent to the other marked decode-and-save 
-functions."
-  (interactive)
-  (gnus-uu-multi-decode-and-view-or-save nil t))
-
-(defun gnus-uu-multi-decode-and-view-or-save (view marked)
-  (let (type)
-    (message "[u]udecode, (s)har, s(a)ve, (b)inhex: ")
-    (setq type (read-char))
-    (if (= type ?\r) (setq type ?u))
-    (cond ((= type ?u) (gnus-uu-decode-and-view-or-save view marked))
-         ((= type ?s) (gnus-uu-unshar-and-view-or-save view marked))
-         ((= type ?b) (gnus-uu-binhex-and-save view marked))
-         ((= type ?a) (gnus-uu-save-articles view marked))
-         (t (error "Unknown decode method '%c'." type)))))
-
-
-;; "All articles" commands
-
-(defconst gnus-uu-rest-of-articles nil)
-(defvar gnus-uu-current-save-dir nil)
-
-(defun gnus-uu-decode-and-view-all-articles (arg)
-  "Try to decode all articles and view the result.
-ARG delimits the number of files to be decoded."
-  (interactive "p")
-  (gnus-uu-decode-and-view-or-save-all-articles arg nil t))
-
-(defun gnus-uu-decode-and-view-all-unread-articles (arg)
-  "Try to decode all unread articles and view the result.
-ARG delimits the number of files to be decoded."
-  (interactive "p")
-  (gnus-uu-decode-and-view-or-save-all-articles arg t t))
-
-(defun gnus-uu-decode-and-save-all-unread-articles (arg)
-  "Try to decode all unread articles and saves the result.
-This function reads all unread articles in the current group and sees
-whether it can uudecode the articles. The user will be prompted for an
-directory to put the resulting (if any) files.
-ARG delimits the number of files to be decoded."
-  (interactive "p")
-  (gnus-uu-decode-and-view-or-save-all-articles arg t nil))
-
-(defun gnus-uu-decode-and-save-all-articles (arg)
-  "Try to decode all articles and saves the result.
-Does the same as `gnus-uu-decode-and-save-all-unread-articles', except
-that it grabs all articles visible, unread or not.
-ARG delimits the number of files to be decoded."
-  (interactive "p")
-  (gnus-uu-decode-and-view-or-save-all-articles arg nil nil))
-
-(defun gnus-uu-decode-and-view-or-save-all-articles 
-  (limit &optional unread view article-list)
+(defun gnus-uu-digest-and-forward (n)
+  "Digests and forwards all articles in this series."
+  (interactive "P")
   (gnus-uu-initialize)
-  (let ((artreg (if unread "^[ -]" "^."))
-       dir list-for-file result-files)
-
-    (if article-list
-       ()
-      (gnus-summary-mark-as-read gnus-current-article ? )
-      (goto-char 1)
-      (while (re-search-forward artreg nil t)
-       (setq article-list 
-             (cons (gnus-summary-article-number) article-list)))
-      (setq article-list (nreverse article-list))
-      (gnus-summary-mark-as-read gnus-current-article ?D))
-
-    (if (not article-list)
-       (error "No %sarticles in this newsgroup" (if unread "unread " "")))
-    (if (not view)
-       (setq dir (gnus-uu-read-directory "Where do you want the files? ")))
-
-    (if (= 1 limit) (setq limit (1+ (length article-list))))
-
-    (while (and article-list (> limit 0))
-      (setq limit (1- limit))
-      (gnus-summary-goto-article (car article-list))
-      (setq list-for-file (gnus-uu-get-list-of-articles))
-      (let ((lft list-for-file))
-       (while lft
-         (setq article-list (delq (car lft) article-list))
-         (setq gnus-newsgroup-processable (delq (car lft) 
-                                                gnus-newsgroup-processable))
-         (setq lft (cdr lft))))
-      (setq result-files 
-           (append 
-            (gnus-uu-grab-articles list-for-file 
-                                   'gnus-uu-uustrip-article-as t nil t)
-            result-files)))
-
-    (setq gnus-uu-list-of-files-decoded result-files)
-
-    (if (not result-files)
-       (error "No files after decoding"))
-
-    (if view
-       (gnus-uu-view-directory gnus-uu-work-dir gnus-uu-use-interactive-view)
-      (gnus-uu-save-directory gnus-uu-work-dir dir dir)
-      (message "Saved.")
-      (gnus-uu-check-for-generated-files))
-
-    (gnus-uu-summary-next-subject)
+  (let ((gnus-uu-save-in-digest t)
+       (file (concat gnus-uu-work-dir (make-temp-name "forward"))))
+    (gnus-uu-decode-save n file)
+    (switch-to-buffer (get-buffer-create "*gnus-uu-forward*"))
+    (erase-buffer)
+    (delete-other-windows)
+    (insert-file file)
+    (goto-char (point-min))
+    (funcall gnus-mail-forward-method)))
 
-    (if (and gnus-uu-use-interactive-view view)
-       (gnus-uu-do-interactive))
+;; Process marking.
 
-    (if (or (not view) (not gnus-uu-use-interactive-view))
-       (gnus-uu-clean-up))))
+(defun gnus-uu-mark-by-regexp (regexp)
+  "Ask for a regular expression and set the process mark on all articles that match."
+  (interactive (list (read-from-minibuffer "Mark (regexp): ")))
+  (let ((articles (gnus-uu-find-articles-matching regexp)))
+    (while articles
+      (gnus-summary-set-process-mark (car articles))
+      (setq articles (cdr articles)))
+    (message ""))
+  (gnus-summary-position-cursor))
 
-(defun gnus-uu-decode-and-view-all-marked-files ()
-  "This function will decode and view all files that have had one or more articles in its series marked.
-For instance, if you have marked part 2 of one series, and part 9 of
-another, this function will decode both series of articles. In other
-words, you can walk around the summary buffer and mark what series you
-want to see, and then using this function to decode all the files you
-are interested in, without worrying exactly what articles belong to
-what files."
+(defun gnus-uu-mark-region (beg end)
+  "Marks all articles between point and mark."
+  (interactive "r")
+  (save-excursion
+    (goto-char beg)
+    (while (< (point) end)
+      (gnus-summary-set-process-mark (gnus-summary-article-number))
+      (forward-line 1)))
+  (gnus-summary-position-cursor))
+      
+(defun gnus-uu-mark-thread ()
+  "Marks all articles downwards in this thread."
   (interactive)
-  (if (not gnus-newsgroup-processable)
-      (error "No articles marked for decoding"))
-  (gnus-uu-decode-and-view-or-save-all-articles 
-   1 nil t (setq gnus-newsgroup-processable 
-                (nreverse gnus-newsgroup-processable))))
-
-(defun gnus-uu-decode-and-save-all-marked-files ()
-  "This function will decode and save all files that have had one or more articles in its series marked.
-For instance, if you have marked part 2 of one series, and part 9 of
-another, this function will decode both series of articles. In other
-words, you can walk around the summary buffer and mark what series you
-want to save, and then using this function to decode all the files you
-are interested in, without worrying exactly what articles belong to
-what files."
+  (save-excursion
+    (let ((level (gnus-summary-thread-level)))
+    (while (and (gnus-summary-set-process-mark (gnus-summary-article-number))
+               (zerop (gnus-summary-next-subject 1))
+               (> (gnus-summary-thread-level) level)))))
+  (gnus-summary-position-cursor))
+
+(defun gnus-uu-mark-sparse ()
+  "Mark all series that have some articles marked."
   (interactive)
-  (if (not gnus-newsgroup-processable)
-      (error "No articles marked for decoding"))
-  (gnus-uu-decode-and-view-or-save-all-articles 
-   1 nil nil (setq gnus-newsgroup-processable 
-                  (nreverse gnus-newsgroup-processable))))
-
+  (let ((marked (nreverse gnus-newsgroup-processable))
+       subject articles total)
+    (or marked (error "No articles marked with the process mark"))
+    (setq gnus-newsgroup-processable nil)
+    (save-excursion
+      (while marked
+       (setq subject (header-subject 
+                      (gnus-gethash 
+                       (int-to-string (car marked))
+                       gnus-newsgroup-headers-hashtb-by-number)))
+       (setq articles (gnus-uu-find-articles-matching 
+                       (gnus-uu-reginize-string subject)))
+       (setq total (nconc total articles))
+       (while articles
+         (gnus-summary-set-process-mark (car articles))
+         (setcdr marked (delq (car articles) (cdr marked)))
+         (setq articles (cdr articles)))
+       (setq marked (cdr marked)))
+      (setq gnus-newsgroup-processable (nreverse total)))
+    (gnus-summary-position-cursor)))
 
 ;; Work functions
 
-; All the interactive uudecode/view/save/marked functions are interfaces
-; to this function, which does the rest.
-(defun gnus-uu-decode-and-view-or-save (view marked &optional save-dir limit)
-  (gnus-uu-initialize)
-  (save-excursion
-    (if (gnus-uu-decode-and-strip nil marked limit)
-       (progn
-         (if view 
-             (gnus-uu-view-directory gnus-uu-work-dir 
-                                     gnus-uu-use-interactive-view)
-           (gnus-uu-save-directory gnus-uu-work-dir save-dir save-dir)
-           (gnus-uu-check-for-generated-files)))))
-
-  (gnus-uu-summary-next-subject)
-
-  (if (and gnus-uu-use-interactive-view view)
-      (gnus-uu-do-interactive))
-
-  (if (or (not view) (not gnus-uu-use-interactive-view))
-      (gnus-uu-clean-up)))
-
-; Unshars and views/saves marked/unmarked articles.
-(defun gnus-uu-unshar-and-view-or-save (view marked &optional save-dir)
+(defun gnus-uu-decode-with-method (method n &optional save)
   (gnus-uu-initialize)
-  (let (tar-file files)
-    (save-excursion
-      (gnus-uu-decode-and-strip t marked)
-      (if (setq gnus-uu-list-of-files-decoded 
-              (gnus-uu-directory-files gnus-uu-work-dir t))
-         (progn
-           (gnus-uu-add-file gnus-uu-list-of-files-decoded)
-           (if view 
-               (gnus-uu-view-directory gnus-uu-work-dir 
-                                       gnus-uu-use-interactive-view)
-             (gnus-uu-save-directory gnus-uu-work-dir save-dir save-dir)
-             (gnus-uu-check-for-generated-files)))))
-
-    (gnus-uu-summary-next-subject)
-
-    (if (and gnus-uu-use-interactive-view view)
-       (gnus-uu-do-interactive))
-
-    (if (or (not view) (not gnus-uu-use-interactive-view))
-       (gnus-uu-clean-up))))
-
+  (let ((articles (gnus-uu-get-list-of-articles n))
+       files)
+    (setq files (gnus-uu-grab-articles articles method t))
+    (and save (gnus-uu-save-files files save))
+    (setq files (gnus-uu-unpack-files files))
+    (gnus-uu-add-file (mapcar (lambda (file) (cdr (assq 'name file))) files))
+    (setq files (gnus-uu-get-actions files))
+    (gnus-summary-insert-pseudos files)))
+
+(defun gnus-uu-save-files (files dir)
+  (let ((len (length files))
+       file)
+    (while files
+      (setq file (cdr (assq 'name (car files))))
+      (copy-file file (if (file-directory-p dir)
+                         (concat dir (file-name-nondirectory file))
+                       dir))
+      (setq files (cdr files)))
+    (message "Saved %d file%s" len (if (> len 1) "s" ""))))
 
 ;; Functions for saving and possibly digesting articles without
 ;; any decoding.
 
-(defconst gnus-uu-saved-article-name nil)
-
-; VIEW isn't used, but is here anyway, to provide similar interface to
-; the other related functions.  If MARKED is non-nil, the list of
-; marked articles is used.  If NO-SAVE is non-nil, the articles aren't
-; actually saved in a permanent location, but the collecting is done
-; and a temporary file with the result is returned.
-(defun gnus-uu-save-articles (view marked &optional no-save)
-  (let (list-of-articles)
-    (save-excursion
-      (gnus-uu-initialize)
-      (if (not marked)
-         (setq list-of-articles (gnus-uu-get-list-of-articles))
-       (setq list-of-articles (setq gnus-newsgroup-processable 
-                                    (nreverse gnus-newsgroup-processable)))
-       (gnus-summary-unmark-all-processable))
-
-      (if (not list-of-articles)
-         (error "No list of articles"))
-
-      (if gnus-uu-save-separate-articles
-         (progn
-           (setq gnus-uu-saved-article-name 
-                 (gnus-uu-read-directory 
-                  (concat "Where do you want the files? "))))
-
-       (setq gnus-uu-saved-article-name 
-             (concat gnus-uu-work-dir 
-                     (if no-save
-                         gnus-newsgroup-name
-                       (read-file-name "Enter file name: " gnus-newsgroup-name
-                                       gnus-newsgroup-name))))
-       (gnus-uu-add-file gnus-uu-saved-article-name))
-
-      (if (and (gnus-uu-grab-articles list-of-articles 'gnus-uu-save-article t)
-              (not no-save) (not gnus-uu-save-separate-articles))
-         (gnus-uu-save-file gnus-uu-saved-article-name)
-       gnus-uu-saved-article-name))))
-
-; Function called by gnus-uu-grab-articles to treat each article.
+;; Function called by gnus-uu-grab-articles to treat each article.
 (defun gnus-uu-save-article (buffer in-state)
   (cond 
    (gnus-uu-save-separate-articles
@@ -961,7 +398,8 @@ what files."
       (write-region 1 (point-max) (concat gnus-uu-saved-article-name 
                                          gnus-current-article))
       (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
-           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name 'begin 'end))
+           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name 
+                                                'begin 'end))
            ((eq in-state 'last) (list 'end))
            (t (list 'middle)))))
    ((not gnus-uu-save-in-digest)
@@ -969,7 +407,8 @@ what files."
       (set-buffer buffer)
       (write-region 1 (point-max) gnus-uu-saved-article-name t)
       (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
-           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name 'begin 'end))
+           ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name 
+                                                'begin 'end))
            ((eq in-state 'last) (list 'end))
            (t (list 'middle)))))
     (t
@@ -1045,29 +484,6 @@ what files."
          (cons gnus-uu-saved-article-name state)
        state)))))
 
-;; Digest and forward articles
-
-(defun gnus-uu-digest-and-forward (&optional marked)
-  "Digests and forwards all articles in this series."
-  (interactive)
-  (let ((gnus-uu-save-in-digest t)
-       file buf)
-    (setq file (gnus-uu-save-articles nil marked t))
-    (switch-to-buffer (setq buf (get-buffer-create "*gnus-uu-forward*")))
-    (erase-buffer)
-    (delete-other-windows)
-    (erase-buffer)
-    (insert-file file)
-    (goto-char 1)
-    (bury-buffer buf)
-    (funcall gnus-mail-forward-method)))
-
-(defun gnus-uu-marked-digest-and-forward (&optional marked)
-  "Digests and forwards all marked articles."
-  (interactive)
-  (gnus-uu-digest-and-forward t))
-
-
 ;; Binhex treatment - not very advanced. 
 
 (defconst gnus-uu-binhex-body-line 
@@ -1078,32 +494,6 @@ what files."
   ":$")
 (defvar gnus-uu-binhex-article-name nil)
 
-; This just concatenates and strips stuff from binhexed articles.
-; No actual unbinhexing takes place. VIEW is ignored.
-(defun gnus-uu-binhex-and-save (view marked)
-  (gnus-uu-initialize)
-  (let (list-of-articles)
-    (save-excursion
-      (if (not marked)
-         (setq list-of-articles (gnus-uu-get-list-of-articles))
-       (setq list-of-articles 
-             (setq gnus-newsgroup-processable 
-                   (nreverse gnus-newsgroup-processable)))
-       (gnus-summary-unmark-all-processable))
-      (if (not list-of-articles)
-         (error "No list of articles"))
-
-      (setq gnus-uu-binhex-article-name 
-           (concat gnus-uu-work-dir 
-                   (read-file-name "Enter binhex file name: " 
-                                   gnus-newsgroup-name
-                                   gnus-newsgroup-name)))
-      (gnus-uu-add-file gnus-uu-binhex-article-name)
-      (if (gnus-uu-grab-articles list-of-articles 'gnus-uu-binhex-article t)
-         (gnus-uu-save-file gnus-uu-binhex-article-name))))
-  (gnus-uu-check-for-generated-files)
-  (gnus-uu-summary-next-subject))
-
 (defun gnus-uu-binhex-article (buffer in-state)
   (let (state start-char)
     (save-excursion
@@ -1139,68 +529,21 @@ what files."
       state)))
       
 
-;; Internal view commands
-
-; This function takes two parameters. The first is name of the file to
-; be viewed. `gnus-uu-view-file' will look for an action associated
-; with the file type of the file. If it finds an appropriate action,
-; the file will be attempted displayed.
-; 
-; The second parameter specifies if the user is to be asked whether to
-; save the file if viewing is unsuccessful. t means "do not ask."
-;
-; Note that the file given will be deleted by this function, one way
-; or another. If `gnus-uu-asynchronous' is set, it won't be deleted
-; right away, but sometime later. If the user is offered to save the
-; file, it'll be moved to wherever the user wants it.
-
-; `gnus-uu-view-file' returns t if viewing is successful.
-
-(defun gnus-uu-view-file (file &optional silent)
-  (let (action did-view)
-    (cond 
-     ((not (setq action (gnus-uu-get-action file)))
-      (if (and (not silent) (not gnus-uu-use-interactive-view))
-         (progn
-           (message "Couldn't find any rule for file '%s'" file)
-           (sleep-for 2)
-           (gnus-uu-ask-to-save-file file))))
-     
-     ((and gnus-uu-use-interactive-view 
-          (not (string= (or action "") "gnus-uu-archive")))
-      (gnus-uu-enter-interactive-file (or action "") file))
-
-     (gnus-uu-ask-before-view
-      (if (y-or-n-p (format "Do you want to view %s? " file))
-         (setq did-view (gnus-uu-call-file-action file action)))
-      (message ""))
-     
-     ((setq did-view (gnus-uu-call-file-action file action)))
-
-     ((not silent)
-      (gnus-uu-ask-to-save-file file)))
-
-    (if (and (file-exists-p file) 
-            (not gnus-uu-use-interactive-view)
-            (or 
-             (not (and gnus-uu-asynchronous did-view))
-             (string= (or action  "") "gnus-uu-archive")))
-       (delete-file file))
-
-  did-view))
-
-(defun gnus-uu-call-file-action (file action)
-  (prog1
-      (if gnus-uu-asynchronous
-         (gnus-uu-call-asynchronous file action)
-       (gnus-uu-call-synchronous file action))
-    (if gnus-uu-view-and-save
-       (gnus-uu-ask-to-save-file file))))
+;; Find actions.
 
-(defun gnus-uu-ask-to-save-file (file)
-  (if (y-or-n-p (format "Do you want to save the file %s? " file))
-      (gnus-uu-save-file file))
-  (message ""))
+(defun gnus-uu-get-actions (files)
+  (let ((ofiles files)
+       action name)
+    (while files
+      (setq name (cdr (assq 'name (car files))))
+      (and 
+       (setq action (gnus-uu-get-action name))
+       (setcar files (cons (cons 'execute (if (string-match "%" action)
+                                             (format action name)
+                                           (concat action " " name)))
+                          (car files))))
+      (setq files (cdr files)))
+    ofiles))
 
 (defun gnus-uu-get-action (file-name)
   (let (action)
@@ -1208,23 +551,11 @@ what files."
          (gnus-uu-choose-action 
           file-name
           (append 
-           (if (and gnus-uu-use-interactive-view 
-                    gnus-uu-user-interactive-view-rules)
-               gnus-uu-user-interactive-view-rules
-             gnus-uu-user-view-rules)
-           (if (or gnus-uu-ignore-default-view-rules 
-                   (not gnus-uu-use-interactive-view))
-               ()
-             gnus-uu-default-interactive-view-rules-begin)
+           gnus-uu-user-view-rules
            (if gnus-uu-ignore-default-view-rules 
                nil 
              gnus-uu-default-view-rules)
-           (if gnus-uu-use-interactive-view
-               (append gnus-uu-user-interactive-view-rules-end
-                       (if gnus-uu-ignore-default-view-rules
-                           ()
-                         gnus-uu-default-interactive-view-rules-end))
-             gnus-uu-user-view-rules-end))))
+           gnus-uu-user-view-rules-end)))
     (if (and (not (string= (or action "") "gnus-uu-archive")) 
             gnus-uu-view-with-metamail)
        (if (setq action 
@@ -1232,82 +563,16 @@ what files."
            (setq action (format "metamail -d -b -c \"%s\"" action))))
     action))
 
-; `gnus-uu-call-synchronous' takes two parameters: The name of the
-; file to be displayed and the command to display it with. Returns t
-; on success and nil if the file couldn't be displayed.
-(defun gnus-uu-call-synchronous (file-name action)
-  (let (did-view command)
-    (save-excursion
-      (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
-      (erase-buffer)
-      (setq command (gnus-uu-command action file-name))
-      (message "Viewing with '%s'" command)
-      (if (not (= 0 (call-process "sh" nil t nil "-c" command)))
-         (progn
-           (goto-char 1)
-           (while (re-search-forward "\n" nil t)
-             (replace-match " "))
-           (message (concat "Error: " (buffer-substring 1 (point-max))))
-           (sit-for 2))
-       (message "")
-       (setq did-view t)))
-    did-view))
-
-; `gnus-uu-call-asyncronous' takes two parameters: The name of the
-; file to be displayed and the command to display it with. Since the
-; view command is executed asynchronously, it's kinda hard to decide
-; whether the command succeded or not, so this function always returns
-; t. It also adds "; rm -f file-name" to the end of the execution
-; string, so the file will be removed after viewing has ended.
-(defun gnus-uu-call-asynchronous (file-name action)
-  (let (command file tmp-file start)
-    (while (string-match "/" file-name start)
-      (setq start (1+ (match-beginning 0))))
-    (setq file (substring file-name start))
-    (setq tmp-file (concat gnus-uu-work-dir file))
-    (if (string= tmp-file file-name)
-       ()
-      (rename-file file-name tmp-file t)
-      (setq file-name tmp-file))
-
-    (setq command (gnus-uu-command action file-name))
-    (setq command (format "%s ; rm -f %s" command file-name))
-    (message "Viewing with %s" command)
-    (start-process "gnus-uu-view" nil "sh" "-c" command)
-    t))
-
-; `gnus-uu-decode-and-strip' does all the main work. It finds out what
-; articles to grab, grabs them, strips the result and decodes. If any
-; of these operations fail, it returns nil, t otherwise.  If shar is
-; t, it will pass this on to `gnus-uu-grab-articles', which will
-; (probably) unshar the articles. If use-marked is non-nil, it won't
-; try to find articles, but use the marked list.
-(defun gnus-uu-decode-and-strip (&optional shar use-marked limit)
-  (let (list-of-articles)
-    (save-excursion
 
-      (if use-marked
-         (if (not gnus-newsgroup-processable)
-             (message "No articles marked")
-           (setq list-of-articles 
-                 (setq gnus-newsgroup-processable 
-                       (nreverse gnus-newsgroup-processable)))
-           (gnus-summary-unmark-all-processable))
-       (setq list-of-articles (gnus-uu-get-list-of-articles)))
-      
-      (and list-of-articles
-          (gnus-uu-grab-articles 
-           list-of-articles 
-           (if shar 'gnus-uu-unshar-article 'gnus-uu-uustrip-article-as)
-           t limit)))))
-
-; Takes a string and puts a \ in front of every special character;
-; ignores any leading "version numbers" thingies that they use in the
-; comp.binaries groups, and either replaces anything that looks like
-; "2/3" with "[0-9]+/[0-9]+" or, if it can't find something like that,
-; replaces the last two numbers with "[0-9]+". This, in my experience,
-; should get most postings of a series.
+;; Functions for treating subjects and collecting series.
+
 (defun gnus-uu-reginize-string (string)
+  ;; Takes a string and puts a \ in front of every special character;
+  ;; ignores any leading "version numbers" thingies that they use in
+  ;; the comp.binaries groups, and either replaces anything that looks
+  ;; like "2/3" with "[0-9]+/[0-9]+" or, if it can't find something
+  ;; like that, replaces the last two numbers with "[0-9]+". This, in
+  ;; my experience, should get most postings of a series.
   (let ((count 2)
        (vernum "v[0-9]+[a-z][0-9]+:")
        reg beg)
@@ -1349,73 +614,76 @@ what files."
 
       (buffer-substring 1 (point-max)))))
 
-(defsubst gnus-uu-string< (l1 l2)
+(defun gnus-uu-get-list-of-articles (n)
+  ;; If N is non-nil, the article numbers of the N next articles
+  ;; will be returned.
+  ;; If any articles have been marked as processable, they will be
+  ;; returned. 
+  ;; Failing that, articles that have subjects that are part of the
+  ;; same "series" as the current will be returned.
+  (let (articles process)
+  (cond 
+   (n
+    (let ((backward (< n 0))
+         (n (abs n)))
+      (save-excursion
+       (while (and (> n 0)
+                   (setq articles (cons (gnus-summary-article-number) 
+                                        articles))
+                   (gnus-summary-search-forward nil nil backward))
+         (setq n (1- n))))
+      (nreverse articles)))
+   (gnus-newsgroup-processable
+    (reverse gnus-newsgroup-processable))
+   (t
+    (gnus-uu-find-articles-matching)))))
+
+(defun gnus-uu-string< (l1 l2)
   (string< (car l1) (car l2)))
 
-; Finds all articles that matches the regular expression given.
-; Returns the resulting list. SUBJECT is the regular expression to be
-; matched. If it is nil, the current article name will be used. If
-; MARK-ARTICLES is non-nil, articles found are marked. If ONLY-UNREAD
-; is non-nil, only unread articles are chose. If DO-NOT-TRANSLATE is
-; non-nil, article names are not equialized before sorting.
-(defun gnus-uu-get-list-of-articles (&optional subject mark-articles only-unread do-not-translate)
-  (let (beg end reg-subject list-of-subjects list-of-numbers art-num)
+(defun gnus-uu-find-articles-matching 
+  (&optional subject only-unread do-not-translate)
+  ;; Finds all articles that matches the regexp SUBJECT.  If it is
+  ;; nil, the current article name will be used. If ONLY-UNREAD is
+  ;; non-nil, only unread articles are chosen. If DO-NOT-TRANSLATE is
+  ;; non-nil, article names are not equalized before sorting.
+  (let ((subject (or subject 
+                    (gnus-uu-reginize-string (gnus-summary-subject-string))))
+       beg end list-of-subjects)
     (save-excursion
-      
-; If the subject is not given, this function looks at the current subject
-; and takes that.
-
-      (if subject
-         (setq reg-subject subject)
-       (setq reg-subject 
-             (format "%s [-0-9]+ %s [-0-9]+ [-0-9]+[\n\r]"
-              (gnus-uu-reginize-string (gnus-summary-subject-string))
-              (if only-unread "[- ]" "."))))
-
-      (if reg-subject
-         (progn
-
-; Collect all subjects matching reg-subject.
-
-           (let ((case-fold-search t))
-             (goto-char 1)
-             (while (re-search-forward reg-subject nil t)
-               (progn
-                 (goto-char (match-beginning 0))
-                 (setq list-of-subjects 
-                       (cons (cons (gnus-summary-subject-string)
-                                   (gnus-summary-article-number))
-                             list-of-subjects))
-                 (forward-line 1))))
-
-; Expand all numbers in all the subjects: (hi9 -> hi0009, etc).
-
-           (setq list-of-subjects 
-                 (gnus-uu-expand-numbers list-of-subjects
-                                         (not do-not-translate)))
-
-; Sort the subjects.
-
-           (setq list-of-subjects (sort list-of-subjects 'gnus-uu-string<))
-
-; Get the article numbers from the sorted list of subjects.
-
-           (while list-of-subjects 
-             (setq art-num (cdr (car list-of-subjects)))
-             (if mark-articles (gnus-summary-mark-as-read art-num ?#))
-             (setq list-of-numbers (cons art-num list-of-numbers))
-             (setq list-of-subjects (cdr list-of-subjects)))
-
-           (setq list-of-numbers (nreverse list-of-numbers))))
-
-      list-of-numbers)))
+      (if (not subject)
+         ()
+       ;; Collect all subjects matching subject.
+       (let ((case-fold-search t)
+             subj mark)
+         (goto-char (point-min))
+         (while (not (eobp))
+           (and (setq subj (gnus-summary-subject-string))
+                (string-match subject subj)
+                (or (not only-unread)
+                    (= (setq mark (gnus-summary-article-mark)) 
+                       gnus-unread-mark)
+                    (= mark gnus-ticked-mark)
+                    (= mark gnus-dormant-mark))
+                (setq list-of-subjects 
+                      (cons (cons subj (gnus-summary-article-number))
+                            list-of-subjects)))
+           (forward-line 1)))
+
+       ;; Expand numbers, sort, and return the list of article
+       ;; numbers.
+       (mapcar (lambda (sub) (cdr sub)) 
+               (sort (gnus-uu-expand-numbers 
+                      list-of-subjects
+                      (not do-not-translate)) 
+                     'gnus-uu-string<))))))
 
-; Takes a list of strings and "expands" all numbers in all the
-; strings.  That is, this function makes all numbers equal length by
-; prepending lots of zeroes before each number. This is to ease later
-; sorting to find out what sequence the articles are supposed to be
-; decoded in. Returns the list of expanded strings.
 (defun gnus-uu-expand-numbers (string-list &optional translate)
+  ;; Takes a list of strings and "expands" all numbers in all the
+  ;; strings.  That is, this function makes all numbers equal length by
+  ;; prepending lots of zeroes before each number. This is to ease later
+  ;; sorting to find out what sequence the articles are supposed to be
+  ;; decoded in. Returns the list of expanded strings.
   (let ((out-list string-list)
        string pos num)
     (save-excursion
@@ -1446,31 +714,29 @@ what files."
     out-list))
 
 
-;; gnus-uu-grab-article
-;
-; This is the general multi-article treatment function.  It takes a
-; list of articles to be grabbed and a function to apply to each
-; article. 
-;
-; The function to be called should take two parameters.  The first
-; parameter is the article buffer. The function should leave the
-; result, if any, in this buffer. Most treatment functions will just
-; generate files...
-;
-; The second parameter is the state of the list of articles, and can
-; have four values: `first', `middle', `last' and `first-and-last'.
-;
-; The function should return a list. The list may contain the
-; following symbols:
-; `error' if an error occurred
-; `begin' if the beginning of an encoded file has been received
-;   If the list returned contains a `begin', the first element of
-;   the list *must* be a string with the file name of the decoded
-;   file.
-; `end' if the the end of an encoded file has been received
-; `middle' if the article was a body part of an encoded file
-; `wrong-type' if the article was not a part of an encoded file
-; `ok', which can be used everything is ok
+;; `gnus-uu-grab-articles' is the general multi-article treatment
+;; function.  It takes a list of articles to be grabbed and a function
+;; to apply to each article.
+;;
+;; The function to be called should take two parameters.  The first
+;; parameter is the article buffer. The function should leave the
+;; result, if any, in this buffer. Most treatment functions will just
+;; generate files...
+;;
+;; The second parameter is the state of the list of articles, and can
+;; have four values: `first', `middle', `last' and `first-and-last'.
+;;
+;; The function should return a list. The list may contain the
+;; following symbols:
+;; `error' if an error occurred
+;; `begin' if the beginning of an encoded file has been received
+;;   If the list returned contains a `begin', the first element of
+;;   the list *must* be a string with the file name of the decoded
+;;   file.
+;; `end' if the the end of an encoded file has been received
+;; `middle' if the article was a body part of an encoded file
+;; `wrong-type' if the article was not a part of an encoded file
+;; `ok', which can be used everything is ok
 
 (defvar gnus-uu-has-been-grabbed nil)
 
@@ -1489,12 +755,13 @@ what files."
       (if dont-unmark-last-article
          (setq gnus-uu-has-been-grabbed (list art))))))
 
-; This function takes a list of articles and a function to apply to
-; each article grabbed. 
-; 
-; This function returns a list of files decoded if the grabbing and
-; the process-function has been successful and nil otherwise.
-(defun gnus-uu-grab-articles (list-of-articles process-function &optional sloppy limit no-errors)
+;; This function takes a list of articles and a function to apply to
+;; each article grabbed. 
+;; 
+;; This function returns a list of files decoded if the grabbing and
+;; the process-function has been successful and nil otherwise.
+(defun gnus-uu-grab-articles 
+  (articles process-function &optional sloppy limit no-errors)
   (let ((state 'first) 
        (wrong-type t)
        has-been-begin has-been-end 
@@ -1507,30 +774,25 @@ what files."
 
     (setq gnus-uu-has-been-grabbed nil)
 
-    (while (and list-of-articles 
+    (while (and articles 
                (not (memq 'error process-state))
                (or sloppy
                    (not (memq 'end process-state))))
 
-      (setq article (car list-of-articles))
-      (setq list-of-articles (cdr list-of-articles))
+      (setq article (car articles))
+      (setq articles (cdr articles))
       (setq gnus-uu-has-been-grabbed (cons article gnus-uu-has-been-grabbed))
 
       (if (> article gnus-uu-highest-article-number) 
          (setq gnus-uu-highest-article-number article))
 
-      (if (eq list-of-articles ()) 
+      (if (eq articles ()) 
          (if (eq state 'first)
              (setq state 'first-and-last)
            (setq state 'last)))
 
       (message "Getting article %d" article)
 
-      (if (not (gnus-server-opened gnus-current-select-method))
-         (progn
-           (gnus-start-news-server)
-           (gnus-request-group gnus-newsgroup-name)))
-
       (if (not (= (or gnus-current-article 0) article))
          (progn
            (gnus-request-article article gnus-newsgroup-name
@@ -1544,6 +806,8 @@ what files."
 
       (buffer-disable-undo article-buffer)
       (gnus-summary-mark-as-read article)
+      (and (memq article gnus-newsgroup-processable)
+          (gnus-summary-remove-process-mark article))
 
       (setq process-state (funcall process-function article-buffer state))
 
@@ -1565,17 +829,15 @@ what files."
            (setq result-files (cons result-file result-files))
            (setq has-been-end t)
            (setq has-been-begin nil)
-           (if (and limit (= (length result-files) limit))
-               (progn
-                 (setq list-of-articles nil)
-                 (setq gnus-newsgroup-processable nil)))))
+           (and limit (= (length result-files) limit)
+                (setq articles nil))))
 
       (if (and (or (eq state 'last) (eq state 'first-and-last))
               (not (memq 'end process-state)))
                (if (and result-file (file-exists-p result-file))
                    (delete-file result-file)))
 
-      (setq result-file nil)
+;      (setq result-file nil)
 
       (if (not (memq 'wrong-type process-state))
          (setq wrong-type nil)
@@ -1594,8 +856,8 @@ what files."
            (sleep-for 2))
        (setq state 'middle)))
 
-    ; Make sure the last article is put in the article buffer
-    ; & fix windows etc.
+    ;; Make sure the last article is put in the article buffer & fix
+    ;; windows etc.
 
     (if (not (string= article-buffer gnus-article-buffer))
        (save-excursion
@@ -1621,13 +883,14 @@ what files."
                (setq result-files nil))
            (gnus-uu-unmark-list-of-grabbed)))))
     (setq gnus-uu-list-of-files-decoded result-files)
-    result-files))
+    (and result-files
+        (mapcar (lambda (file) (list (cons 'name file))) result-files))))
 
 (defun gnus-uu-uudecode-sentinel (process event)
   (delete-process (get-process process)))
 
-; Uudecodes a file asynchronously.
-(defun gnus-uu-uustrip-article-as (process-buffer in-state)
+(defun gnus-uu-uustrip-article (process-buffer in-state)
+  ;; Uudecodes a file asynchronously.
   (let ((state (list 'ok))
        (process-connection-type nil)
        start-char pst name-beg name-end)
@@ -1736,8 +999,8 @@ what files."
          (cons (concat gnus-uu-work-dir gnus-uu-file-name) state)
        state))))
 
-; This function is used by `gnus-uu-grab-articles' to treat
-; a shared article.
+;; This function is used by `gnus-uu-grab-articles' to treat
+;; a shared article.
 (defun gnus-uu-unshar-article (process-buffer in-state)
   (let ((state (list 'ok))
        start-char)
@@ -1754,7 +1017,7 @@ what files."
        "-c" (concat "cd " gnus-uu-work-dir " ; sh"))))
     state))
 
-; Returns the name of what the shar file is going to unpack.
+;; Returns the name of what the shar file is going to unpack.
 (defun gnus-uu-find-name-in-shar ()
   (let ((oldpoint (point))
        res)
@@ -1764,17 +1027,9 @@ what files."
     (goto-char oldpoint)
     res))
 
-; Returns the article number of the given subject.
-(defun gnus-uu-article-number (subject)
-  (let (end)
-    (string-match "[0-9]+[^0-9]" subject 1)
-    (setq end (match-end 0))
-    (string-to-int 
-     (substring subject (string-match "[0-9]" subject 1) end)))) 
-             
-; `gnus-uu-choose-action' chooses what action to perform given the name
-; and `gnus-uu-file-action-list'.  Returns either nil if no action is
-; found, or the name of the command to run if such a rule is found.
+;; `gnus-uu-choose-action' chooses what action to perform given the name
+;; and `gnus-uu-file-action-list'.  Returns either nil if no action is
+;; found, or the name of the command to run if such a rule is found.
 (defun gnus-uu-choose-action (file-name file-action-list &optional no-ignore)
   (let ((action-list (copy-sequence file-action-list))
        rule action)
@@ -1796,70 +1051,8 @@ what files."
           (setq action (car (cdr rule))))))
     action))
 
-(defun gnus-uu-save-directory (from-dir &optional default-dir ignore-existing)
-  (let (dir file-name command files file)
-    (setq files (directory-files from-dir t))
-    (if default-dir
-       (setq dir default-dir)
-      (setq dir (gnus-uu-read-directory 
-                (concat "Where do you want the file" 
-                        (if (< 3 (length files)) "s" "") "? "))))
-
-    (while files
-      (setq file (car files))
-      (setq files (cdr files))
-      (string-match "/[^/]*$" file)
-      (setq file-name (substring file (1+ (match-beginning 0))))
-      (if (string-match "^\\.\\.?$" file-name)
-         ()
-       (if (and (not ignore-existing) (file-exists-p (concat dir file-name)))
-           (setq file-name
-                 (read-file-name "File exists. Enter a new name: " dir 
-                                 (concat dir file-name) nil file-name))
-         (setq file-name (concat dir file-name)))
-       (rename-file file file-name t)))))
-
-; Moves the file from the tmp directory to where the user wants it.
-(defun gnus-uu-save-file (from-file-name &optional default-dir ignore-existing)
-  (let (dir file-name command)
-    (string-match "/[^/]*$" from-file-name)
-    (setq file-name (substring from-file-name (1+ (match-beginning 0))))
-    (if default-dir
-       (setq dir default-dir)
-      (setq dir (gnus-uu-read-directory "Where do you want the file? ")))
-    (if (and (not ignore-existing) (file-exists-p (concat dir file-name)))
-       (setq file-name
-             (read-file-name "File exist. Enter a new name: " dir 
-                             (concat dir file-name) nil file-name))
-      (setq file-name (concat dir file-name)))
-    (rename-file from-file-name file-name t)))
-    
-(defun gnus-uu-read-directory (prompt &optional default)
-  (let (dir ok create)
-    (while (not ok)
-      (setq ok t)
-      (setq dir (if default default
-                 (read-file-name prompt gnus-uu-current-save-dir 
-                                 gnus-uu-current-save-dir)))
-      (while (string-match "/$" dir)
-       (setq dir (substring dir 0 (match-beginning 0))))
-      (if (file-exists-p dir)
-         (if (not (file-directory-p dir))
-             (progn
-               (setq ok nil)
-               (message "%s is a file" dir)
-               (sit-for 2)))
-       (setq create ?o)
-       (while (not (or (= create ?y) (= create ?n)))
-         (message "%s: No such directory. Do you want to create it? (y/n)" 
-                  dir)
-         (setq create (read-char)))
-       (if (= create ?y) (make-directory dir))))
-    (setq gnus-uu-current-save-dir (concat dir "/"))))
-
-; Unpacks an archive and views all the files in it. Returns t if
-; viewing one or more files is successful.
 (defun gnus-uu-treat-archive (file-path)
+  ;; Unpacks an archive. Returns t if unpacking is successful.
   (let ((did-unpack t)
        action command files file file-name dir)
     (setq action (gnus-uu-choose-action 
@@ -1874,7 +1067,7 @@ what files."
     (setq file-name (substring file-path (1+ (match-beginning 0))))
     (setq dir (substring file-path 0 (match-beginning 0)))
 
-    (if (gnus-uu-string-in-list action gnus-uu-destructive-archivers)
+    (if (member action gnus-uu-destructive-archivers)
        (copy-file file-path (concat file-path "~") t))
 
     (setq command (format "cd %s ; %s" dir (gnus-uu-command action file-path)))
@@ -1889,57 +1082,14 @@ what files."
                           (get-buffer-create gnus-uu-output-buffer-name)
                           nil "-c" command))
        (message "")
-      (if (not gnus-uu-use-interactive-view)
-         (progn
-           (message "Error during unpacking of archive")
-           (sleep-for 2)))
+      (message "Error during unpacking of archive")
       (setq did-unpack nil))
 
-    (if (gnus-uu-string-in-list action gnus-uu-destructive-archivers)
+    (if (member action gnus-uu-destructive-archivers)
        (rename-file (concat file-path "~") file-path t))
 
     did-unpack))
 
-; Tries to view all the files in the given directory. Returns t if
-; viewing one or more files is successful.
-(defun gnus-uu-view-directory (dir &optional dont-delete-files not-top)
-  (let ((first t)
-       files file did-view ignore-files)
-    (setq files (gnus-uu-directory-files dir t))
-    (gnus-uu-add-file files)
-    (setq ignore-files files)
-    
-    (while (gnus-uu-unpack-archives 
-           files (if not-top (list ".")
-                   (if first () ignore-files)))
-      (setq first nil)
-      (gnus-uu-add-file 
-       (setq files (gnus-uu-directory-files dir t))))
-
-    (gnus-uu-add-file (gnus-uu-directory-files dir t))
-      
-    (while files
-      (setq file (car files))
-      (setq files (cdr files))
-      (if (not (string= (or (gnus-uu-get-action file) "") "gnus-uu-archive"))
-         (progn
-           (set-file-modes file 448)
-           (if (file-directory-p file)
-               (setq did-view (or (gnus-uu-view-directory file 
-                                                          dont-delete-files 
-                                                          t) 
-                                  did-view))
-             (setq did-view (or (gnus-uu-view-file file t) did-view)))))
-      (if (and (not dont-delete-files) (not gnus-uu-asynchronous) 
-              (file-exists-p file))
-         (delete-file file)))
-
-    (if (and (not gnus-uu-asynchronous) (not dont-delete-files))
-       (if (string-match "/$" dir)
-           (delete-directory (substring dir 0 (match-beginning 0)))
-         (delete-directory dir)))
-    did-view))
-
 (defun gnus-uu-dir-files (dir)
   (let ((dirs (directory-files dir t "[^/][^\\.][^\\.]?$"))
        files file)
@@ -1950,124 +1100,56 @@ what files."
       (setq dirs (cdr dirs)))
     files))
 
-(defun gnus-uu-directory-files-old (dir)
-  (let ((files (directory-files dir t)) f)
-    (setq f files)
-    (while (cdr f)
-      (if (string-match "/\\.\\.?$" (car (cdr f)))
-         (setcdr f (cdr (cdr f)))
-       (setq f (cdr f))))
-    (if (string-match "/\\.\\.?$" (car files)) (cdr files)
-      files)))
-
-(defun gnus-uu-unpack-archives (files &optional ignore)
-  (let (path did-unpack)
+(defun gnus-uu-unpack-files (files &optional ignore)
+  ;; Go through FILES and look for files to unpack. 
+  (let* ((totfiles (gnus-uu-ls-r gnus-uu-work-dir))
+        (ofiles files)
+        file did-unpack)
     (while files
-      (setq path (car files))
-      (setq files (cdr files))
-      (if (not (gnus-uu-string-in-list path ignore))
-         (if (string= (or (gnus-uu-get-action 
-                           (gnus-uu-name-from-path path)) "") 
-                      "gnus-uu-archive")
-             (progn
-               (if (and (not (setq did-unpack (gnus-uu-treat-archive path)))
-                        gnus-uu-use-interactive-view)
-                   (gnus-uu-enter-interactive-file 
-                    "# error during unpacking of" path))
-               (if ignore (delete-file path))))))
-    did-unpack))
-
-
-;; Manual marking
-
-(defun gnus-uu-mark-by-regexp ()
-  "Asks for a regular expression and marks all articles that match."
-  (interactive)
-  (let (exp)
-    (setq exp (read-from-minibuffer "Mark (regexp): "))
-    (setq gnus-newsgroup-processable 
-         (nconc gnus-newsgroup-processable
-                 (nreverse (gnus-uu-get-list-of-articles exp t))))
-    (message "")))
+      (setq file (cdr (assq 'name (car files))))
+      (if (and (not (member file ignore))
+              (equal (gnus-uu-get-action (file-name-nondirectory file))
+                     "gnus-uu-archive"))
+         (progn
+           (setq did-unpack (cons file did-unpack))
+           (or (gnus-uu-treat-archive file)
+               (message "Error during unpacking of %s" file))
+           (let* ((newfiles (gnus-uu-ls-r gnus-uu-work-dir))
+                  (nfiles newfiles))
+             (while nfiles
+               (or (member (car nfiles) totfiles)
+                   (setq ofiles (cons (list (cons 'name (car nfiles))
+                                            (cons 'original file))
+                                      ofiles)))
+               (setq nfiles (cdr nfiles)))
+             (setq totfiles newfiles))))
+      (setq files (cdr files)))
+    (if did-unpack 
+       (gnus-uu-unpack-files ofiles (append did-unpack ignore))
+      ofiles)))
 
-(defun gnus-uu-mark-region (beg end)
-  "Marks all articles between point and mark."
-  (interactive "r")
-  (let ((mark-even-if-inactive t)
-       (opoint 0)
-       tmp)
-    (save-excursion
-      (cond 
-       ((= beg end)
-       (error "Empty region."))
-       (t
-       (if (< end beg)
-           (progn 
-             (setq tmp beg)
-             (setq beg end)
-             (setq end tmp)))
-       (goto-char beg)
-       (while (and (< (point) end)
-                   (not (= (point) opoint)))
-         (setq opoint (point))
-         (gnus-summary-set-process-mark (gnus-summary-article-number))))))))
-      
-(defun gnus-uu-mark-thread ()
-  "Marks all articles downwards in this thread."
-  (interactive)
-  (beginning-of-line)
-  (let (level)
-    (if (not (search-forward ":" nil t))
-       ()
-      (setq level (current-column))
-      (gnus-summary-set-process-mark (gnus-summary-article-number))
-      (gnus-summary-search-forward)
-      (while (< level (current-column))
-       (gnus-summary-set-process-mark (gnus-summary-article-number))
-       (gnus-summary-search-forward))
-      (gnus-summary-search-backward))))
-
-(defun gnus-uu-marked-universal-argument ()
-  "Perform any operation on all marked articles.
-If you type `\\<gnus-summary-mode-map>\\[gnus-uu-decode-and-view]' and then, for instance, `u', 
-gnus-uu will perform the operation bound to `u' on all 
-marked articles."
-  (interactive)
-  (let ((articles (setq gnus-newsgroup-processable 
-                       (nreverse gnus-newsgroup-processable)))
-       key func)
-    (gnus-summary-unmark-all-processable)
-    (if (not articles)
-       (error "No articles marked"))
-    (if (not (setq func (key-binding (read-key-sequence "C-c C-v C-u"))))
-       (error "Undefined key"))
-    (while articles
-      (gnus-summary-goto-subject (car articles))
-      (command-execute func)
-      (setq articles (cdr articles)))))
-  
+(defun gnus-uu-ls-r (dir)
+  (let* ((files (gnus-uu-directory-files dir t))
+        (ofiles files))
+    (while files
+      (if (file-directory-p (car files))
+         (progn
+           (setq ofiles (delete (car files) ofiles))
+           (setq ofiles (append ofiles (gnus-uu-ls-r (car files))))))
+      (setq files (cdr files)))
+    ofiles))
 
 ;; Various stuff
 
-(defun gnus-uu-string-in-list (string list)
-  (while (and list
-             (not (string= (car list) string))
-             (setq list (cdr list))))
-  list)
-
-(defun gnus-uu-name-from-path (path)
-  (string-match "/[^/]*$" path)
-  (substring path (1+ (match-beginning 0))))
-
 (defun gnus-uu-directory-files (dir &optional full)
   (let (files out file)
     (setq files (directory-files dir full))
     (while files
       (setq file (car files))
       (setq files (cdr files))
-      (if (not (string-match "/\\.\\.?$" file))
+      (or (string-match "/\\.\\.?$" file)
          (setq out (cons file out))))
-    (setq out (reverse out))
+    (setq out (nreverse out))
     out))
 
 (defun gnus-uu-check-correct-stripped-uucode (start end)
@@ -2117,23 +1199,21 @@ marked articles."
   (gnus-uu-add-file gnus-uu-work-dir)
   (if (not (file-directory-p gnus-uu-work-dir)) 
       (make-directory gnus-uu-work-dir))
-  (setq gnus-uu-work-dir (concat gnus-uu-work-dir "/"))
-  (setq gnus-uu-interactive-file-list nil))
+  (setq gnus-uu-work-dir (concat gnus-uu-work-dir "/")))
 
-; Kills the temporary uu buffers, kills any processes, etc.
+;; Kills the temporary uu buffers, kills any processes, etc.
 (defun gnus-uu-clean-up ()
   (let (buf pst)
     (and gnus-uu-uudecode-process
         (setq pst (process-status (or gnus-uu-uudecode-process "nevair")))
         (if (or (eq pst 'stop) (eq pst 'run))
             (delete-process gnus-uu-uudecode-process)))
-    (and (not gnus-uu-asynchronous) 
-        (setq buf (get-buffer gnus-uu-output-buffer-name))
+    (and (setq buf (get-buffer gnus-uu-output-buffer-name))
         (kill-buffer buf))))
 
-; `gnus-uu-check-for-generated-files' deletes any generated files that
-; hasn't been deleted, if, for instance, the user terminated decoding
-; with `C-g'.
+;; `gnus-uu-check-for-generated-files' deletes any generated files that
+;; hasn't been deleted, if, for instance, the user terminated decoding
+;; with `C-g'.
 (defun gnus-uu-check-for-generated-files ()
   (let (file dirs)
     (while gnus-uu-generated-file-list
@@ -2154,8 +1234,8 @@ marked articles."
              (delete-directory (substring file 0 (match-beginning 0)))
            (delete-directory file))))))
 
-; Add a file (or a list of files) to be checked (and deleted if it/they
-; still exists upon exiting the newsgroup).
+;; Add a file (or a list of files) to be checked (and deleted if it/they
+;; still exists upon exiting the newsgroup).
 (defun gnus-uu-add-file (file)
   (if (stringp file)
       (setq gnus-uu-generated-file-list 
@@ -2163,27 +1243,8 @@ marked articles."
     (setq gnus-uu-generated-file-list 
          (append file gnus-uu-generated-file-list))))
 
-; Go to the next unread subject. If there is no further unread
-; subjects, go to the last subject in the buffer.
-(defun gnus-uu-summary-next-subject ()
-  (let (opi)
-    (if (not (gnus-summary-search-forward t))
-       (progn
-         (goto-char 1)
-         (sit-for 0)
-         (gnus-summary-goto-subject gnus-uu-highest-article-number)))
-
-    ; You may well find all this a bit puzzling - so do I, but I seem
-    ; to have to do something like this to move to the next unread article,
-    ; as `sit-for' seems to do some rather strange things here. Might
-    ; be a bug in my head, probably.
-    (setq opi (point))
-    (sit-for 0)
-    (goto-char opi)
-    (gnus-summary-recenter)))
-
-; Inputs an action and a file and returns a full command, putting
-; ticks round the file name and escaping any ticks in the file name.
+;; Inputs an action and a file and returns a full command, putting
+;; ticks round the file name and escaping any ticks in the file name.
 (defun gnus-uu-command (action file)
   (let ((ofile ""))
     (while (string-match "`\\|\"\\|\\$\\|\\\\" file)
@@ -2199,236 +1260,9 @@ marked articles."
 
 
 ;; Initializing
-(add-hook 'gnus-exit-group-hook
-      '(lambda ()
-        (gnus-uu-clean-up)
-        (gnus-uu-check-for-generated-files)))
-
-
-;; Interactive exec mode
-
-(defvar gnus-uu-output-window nil)
-(defvar gnus-uu-mode-hook nil)
-
-(defvar gnus-uu-mode-map nil)
-(if gnus-uu-mode-map
-    ()
-  (setq gnus-uu-mode-map (make-sparse-keymap))
-  (define-key gnus-uu-mode-map "\C-c\C-x" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-c\C-v" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-m" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-c\C-c" 'gnus-uu-interactive-end)
-  (define-key gnus-uu-mode-map "\C-cs" 
-    'gnus-uu-interactive-save-current-file)
-  (define-key gnus-uu-mode-map "\C-c\C-s"
-    'gnus-uu-interactive-save-current-file-silent)
-  (define-key gnus-uu-mode-map "\C-c\C-w" 'gnus-uu-interactive-save-all-files)
-  (define-key gnus-uu-mode-map "\C-c\C-o" 'gnus-uu-interactive-save-original-file)
-  (define-key gnus-uu-mode-map "\C-c\C-r" 'gnus-uu-interactive-rescan-directory)
-  (define-key gnus-uu-mode-map "\C-cr" 'gnus-uu-interactive-scan-directory)
-  )
-
-(defun gnus-uu-interactive-set-up-windows ()
-  (let (int-buf out-buf height)
-    (gnus-configure-windows 'article)
-    (set-buffer 
-     (setq int-buf (get-buffer-create gnus-uu-interactive-buffer-name)))
-    (if (not (get-buffer-window int-buf))
-       (progn
-         (select-window (get-buffer-window gnus-article-buffer))
-         (switch-to-buffer int-buf)))
-    (setq out-buf (get-buffer-create gnus-uu-output-buffer-name))
-    (if (not (get-buffer-window out-buf))
-       (progn
-         (if (> 2 (setq height (- (window-height) 
-                                  gnus-uu-output-window-height)))
-             (setq height (/ (window-height) 2)))
-         (if (> height 2)
-             (progn
-               (setq gnus-uu-output-window (split-window nil height))
-               (set-window-buffer gnus-uu-output-window out-buf)))))))
-
-(defun gnus-uu-do-interactive (&optional dont-do-windows)
-  (if (not gnus-uu-interactive-file-list) 
-      (gnus-uu-enter-interactive-file "#" ""))
-  (if (not dont-do-windows) (gnus-uu-interactive-set-up-windows))
-  (save-excursion 
-    (set-buffer (get-buffer-create gnus-uu-output-buffer-name)) 
-    (erase-buffer))
-  (set-buffer (get-buffer-create gnus-uu-interactive-buffer-name))
-  (goto-char 1)
-  (forward-line 3)
-  (run-hooks 'gnus-uu-mode-hook))
-
-(defun gnus-uu-enter-interactive-file (action file)
-  (let (command)
-    (save-excursion
-      (set-buffer (get-buffer-create gnus-uu-interactive-buffer-name))
-      (if (not gnus-uu-interactive-file-list)
-         (progn
-           (erase-buffer)
-           (gnus-uu-mode)
-           (insert 
-            "# Press return to execute a command.
-# Press `C-c C-c' to exit interactive view.
-
-")))   
-      (setq gnus-uu-interactive-file-list
-           (cons file gnus-uu-interactive-file-list))
-;      (if (string-match (concat "^" gnus-uu-work-dir) file)
-;        (setq file (substring file (match-end 0))))
-      (setq command (gnus-uu-command action file))
-      (goto-char (point-max))
-      (insert (format "%s\n" command)))))
-
-(defun gnus-uu-interactive-execute ()
-  "Executes the command on the current line in interactive mode."
-  (interactive)
-  (let (beg out-buf command)
-    (beginning-of-line)
-    (setq beg (point))
-    (end-of-line)
-    (setq command (buffer-substring beg (point)))
-    (setq out-buf (get-buffer-create gnus-uu-output-buffer-name))
-    (save-excursion
-      (set-buffer out-buf)
-      (erase-buffer)
-      (insert (format "$ %s \n\n" command)))
-    (setq command (format "cd %s ; %s" gnus-uu-work-dir command))
-    (message "Executing...")
-    (if gnus-uu-asynchronous
-       (start-process "gnus-uu-view" out-buf "sh" "-c" command)
-      (call-process "sh" nil out-buf nil "-c" command)
-      (message ""))
-    (end-of-line)
-    (if (= (forward-line 1) 1)
-       (progn
-         (end-of-line)
-         (insert "\n")))
-    (beginning-of-line)))
-
-(defun gnus-uu-interactive-end ()
-  "This function exits interactive view mode and returns to summary mode."
-  (interactive)
-  (let (buf)
-    (if (windowp gnus-uu-output-window) (delete-window gnus-uu-output-window))
-    (gnus-configure-windows 'article)
-    (gnus-uu-clean-up)
-    (if (not gnus-uu-asynchronous) (gnus-uu-check-for-generated-files))
-    (setq buf (get-buffer gnus-uu-interactive-buffer-name))
-    (if gnus-article-buffer (switch-to-buffer gnus-article-buffer))
-    (if buf (kill-buffer buf))
-    (pop-to-buffer gnus-summary-buffer)))
-
-
-(defun gnus-uu-interactive-scan-directory (dir)
-  "Read any directory and view the files.
-When used in interactive mode, the files and commands will be displayed,
-as usual, in the interactive mode buffer."
-  (interactive "DDirectory: ")
-  (setq gnus-uu-interactive-file-list nil)
-  (gnus-uu-view-directory dir gnus-uu-use-interactive-view)
-  (gnus-uu-do-interactive t))
-  
-(defun gnus-uu-interactive-rescan-directory ()
-  "Reread the directory and view the files.
-When used in interactive mode, the files and commands will be displayed,
-as usual, in the interactive mode buffer."
-  (interactive)
-  (gnus-uu-interactive-scan-directory gnus-uu-work-dir))
-
-(defun gnus-uu-interactive-save-original-file ()
-  "Saves the file from whence the file on the current line came from."
-  (interactive)
-  (let ((files gnus-uu-list-of-files-decoded)
-       (filestr "")
-       file did dir)
-    (while files
-      (setq file (car files))
-      (setq files (cdr files))
-      (if (file-exists-p file)
-         (progn
-           (if (not did)
-               (progn
-                 (setq dir (gnus-uu-read-directory 
-                            (format "Where do you want the file%s? " 
-                                    (if (> (length files) 1) "s" ""))))
-                 (setq did t)))
-           (setq filestr (concat filestr (gnus-uu-name-from-path file) " "))
-           (gnus-uu-save-file file dir t)))
-      (if did 
-         (message "Saved %s" filestr)
-       (message "Already saved.")))))
-
-(defun gnus-uu-interactive-save-current-file-silent ()
-  "Saves the file referred to on the current line in the current directory."
-  (interactive)
-  (gnus-uu-interactive-save-current-file t))
 
-(defun gnus-uu-interactive-save-current-file (&optional dont-ask silent)
-  "Saves the file referred to on the current line."
-  (interactive)
-  (let (files beg line file)
-    (setq files (copy-sequence gnus-uu-interactive-file-list))
-    (beginning-of-line)
-    (setq beg (point))
-    (end-of-line)
-    (setq line (buffer-substring beg (point)))
-    (while (and files
-               (not (string-match 
-                     (concat "" (regexp-quote (setq file (car files))) "")
-                     line)))
-      (setq files (cdr files)))
-    (beginning-of-line)
-    (forward-line 1)
-    (if (not files)
-       (if (not silent)
-           (progn (message "Could not find file") (sit-for 2)))
-      (gnus-uu-save-file file (if dont-ask gnus-uu-current-save-dir nil) silent)
-      (delete-region beg (point)))))
-
-(defun gnus-uu-interactive-save-all-files ()
-  "Saves all files referred to in the interactive buffer."
-  (interactive)
-  (let (dir)
-    (goto-char 1)
-    (setq dir (gnus-uu-read-directory "Where do you want the files? "))
-    (while (not (eobp))
-      (gnus-uu-interactive-save-current-file t t))))
-
-(defun gnus-uu-mode ()
-  "Major mode for editing view commands in gnus-uu.
-
-Commands:
-\\<gnus-uu-mode-map>Return, C-c C-v, C-c C-x        Execute the current command
-\\[gnus-uu-interactive-end]\tEnd interactive mode
-\\[gnus-uu-interactive-save-current-file]\tSave the current file
-\\[gnus-uu-interactive-save-current-file-silent]\tSave the current file without asking 
-\twhere to put it
-\\[gnus-uu-interactive-save-all-files]\tSave all files
-\\[gnus-uu-interactive-save-original-file]\tSave the original file: If the files
-\toriginated in an archive, the archive 
-\tfile is saved.
-\\[gnus-uu-interactive-rescan-directory]\tRescan the directory
-\\[gnus-uu-interactive-scan-directory]\tScan any directory
-"
-  (interactive)
-  (kill-all-local-variables)
-  (use-local-map gnus-uu-mode-map)   
-  (setq mode-name "gnus-uu")         
-  (setq major-mode 'gnus-uu-mode)    
-)
-
-  (define-key gnus-uu-mode-map "\C-c\C-x" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-c\C-v" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-m" 'gnus-uu-interactive-execute)
-  (define-key gnus-uu-mode-map "\C-c\C-c" 'gnus-uu-interactive-end)
-  (define-key gnus-uu-mode-map "\C-cs" 
-    'gnus-uu-interactive-save-current-file)
-  (define-key gnus-uu-mode-map "\C-c\C-s"
-    'gnus-uu-interactive-save-current-file-silent)
-  (define-key gnus-uu-mode-map "\C-c\C-a" 'gnus-uu-interactive-save-all-files)
-  (define-key gnus-uu-mode-map "\C-c\C-o" 'gnus-uu-interactive-save-original-file)
+(add-hook 'gnus-exit-group-hook 'gnus-uu-clean-up)
+(add-hook 'gnus-exit-group-hook        'gnus-uu-check-for-generated-files)
 
 
 ;; Major mode for posting encoded articles.
@@ -2436,10 +1270,10 @@ Commands:
 (require 'sendmail)
 (require 'rnews)
 
-; Any function that is to be used as and encoding method will take two
-; parameters: PATH-NAME and FILE-NAME. (E.g. "/home/gaga/spiral.jpg"
-; and "spiral.jpg", respectively.) The function should return nil if
-; the encoding wasn't successful.
+;; Any function that is to be used as and encoding method will take two
+;; parameters: PATH-NAME and FILE-NAME. (E.g. "/home/gaga/spiral.jpg"
+;; and "spiral.jpg", respectively.) The function should return nil if
+;; the encoding wasn't successful.
 (defvar gnus-uu-post-encode-method 'gnus-uu-post-encode-uuencode
   "Function used for encoding binary files.
 There are three functions supplied with gnus-uu for encoding files:
@@ -2477,41 +1311,41 @@ is t.")
 (defvar gnus-uu-post-inserted-file-name nil)
 (defvar gnus-uu-winconf-post-news nil)
 
-; The following map and mode was taken from rnewspost.el and edited
-; somewhat.
-(defvar gnus-uu-post-reply-mode-map () "Mode map used by gnus-uu-post-reply.")
-(or gnus-uu-post-reply-mode-map
-    (progn
-      (setq gnus-uu-post-reply-mode-map (make-keymap))
-      (define-key gnus-uu-post-reply-mode-map "\C-c?" 'describe-mode)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-d" 
-       'news-reply-distribution)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-k" 
-       'news-reply-keywords)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-n" 
-       'news-reply-newsgroups)
+;; The following map and mode was taken from rnewspost.el and edited
+;; somewhat.
+(defvar gnus-uu-post-reply-mode-map nil)
+(if gnus-uu-post-reply-mode-map
+    ()
+  (setq gnus-uu-post-reply-mode-map (make-keymap))
+  (define-key gnus-uu-post-reply-mode-map "\C-c?" 'describe-mode)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-d" 
+    'news-reply-distribution)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-k" 
+    'news-reply-keywords)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-n" 
+    'news-reply-newsgroups)
       
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-f" 
-       'news-reply-followup-to)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-s" 'mail-subject)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-a" 
-       'gnus-uu-post-reply-summary)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-r" 
-       'news-caesar-buffer-body)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-w" 'news-reply-signature)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-y" 
-       'news-reply-yank-original)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-q" 
-       'mail-fill-yanked-message)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-c" 
-       'gnus-uu-post-news-inews)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-s" 
-       'gnus-uu-post-news-inews)
-      (define-key gnus-uu-post-reply-mode-map "\C-c\C-i" 
-       'gnus-uu-post-insert-binary-in-article)
-      ))
-
-; This mode was taken from rnewspost.el and modified slightly.
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-f" 
+    'news-reply-followup-to)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-s" 'mail-subject)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-f\C-a" 
+    'gnus-uu-post-reply-summary)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-r" 
+    'news-caesar-buffer-body)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-w" 'news-reply-signature)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-y" 
+    'news-reply-yank-original)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-q" 
+    'mail-fill-yanked-message)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-c" 
+    'gnus-uu-post-news-inews)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-s" 
+    'gnus-uu-post-news-inews)
+  (define-key gnus-uu-post-reply-mode-map "\C-c\C-i" 
+    'gnus-uu-post-insert-binary-in-article)
+  )
+
+;; This mode was taken from rnewspost.el and modified slightly.
 (defun gnus-uu-post-reply-mode ()
   "Major mode for editing binary news to be posted on USENET.
 First-time posters are asked to please read the articles in newsgroup:
@@ -2610,7 +1444,7 @@ The user will be asked for a file name."
   (save-excursion 
     (setq gnus-uu-post-inserted-file-name (gnus-uu-post-insert-binary))))
 
-; Encodes with uuencode and substitutes all spaces with backticks.
+;; Encodes with uuencode and substitutes all spaces with backticks.
 (defun gnus-uu-post-encode-uuencode (path file-name)
   (if (gnus-uu-post-encode-file "uuencode" path file-name)
       (progn
@@ -2620,21 +1454,21 @@ The user will be asked for a file name."
          (replace-match "`"))
        t)))
 
-; Encodes with uuencode and adds MIME headers.
+;; Encodes with uuencode and adds MIME headers.
 (defun gnus-uu-post-encode-mime-uuencode (path file-name)
   (if (gnus-uu-post-encode-uuencode path file-name)
       (progn
        (gnus-uu-post-make-mime file-name "x-uue")
        t)))
 
-; Encodes with base64 and adds MIME headers
+;; Encodes with base64 and adds MIME headers
 (defun gnus-uu-post-encode-mime (path file-name)
   (if (gnus-uu-post-encode-file "mmencode" path file-name)
       (progn
        (gnus-uu-post-make-mime file-name "base64")
        t)))
 
-; Adds MIME headers.
+;; Adds MIME headers.
 (defun gnus-uu-post-make-mime (file-name encoding)
   (goto-char 1)
   (insert (format "Content-Type: %s; name=\"%s\"\n" 
@@ -2654,8 +1488,8 @@ The user will be asked for a file name."
          (insert "MIME-Version: 1.0\n")))
     (widen)))
 
-; Encodes a file PATH with COMMAND, leaving the result in the
-; current buffer.
+;; Encodes a file PATH with COMMAND, leaving the result in the
+;; current buffer.
 (defun gnus-uu-post-encode-file (command path file-name)
   (= 0 (call-process "sh" nil t nil "-c" 
                     (format "%s %s %s" command path file-name))))
@@ -2700,8 +1534,8 @@ If no file has been included, the user will be asked for a file."
   (and gnus-uu-winconf-post-news
        (set-window-configuration gnus-uu-winconf-post-news)))
       
-; Asks for a file to encode, encodes it and inserts the result in
-; the current buffer. Returns the file name the user gave.
+;; Asks for a file to encode, encodes it and inserts the result in
+;; the current buffer. Returns the file name the user gave.
 (defun gnus-uu-post-insert-binary ()
   (let ((uuencode-buffer-name "*uuencode buffer*")
        file-path post-buf uubuf file-name)
@@ -2731,7 +1565,7 @@ If no file has been included, the user will be asked for a file."
       (kill-buffer uubuf))
     file-name))
 
-; Posts the article and all of the encoded file.
+;; Posts the article and all of the encoded file.
 (defun gnus-uu-post-encoded (file-name &optional threaded)
   (let ((send-buffer-name "*uuencode send buffer*")
        (encoded-buffer-name "*encoded buffer*")
index 9ada039..c75197d 100644 (file)
   "Face used for highlighting the selected article in the Summary buffer.")
 
 (defvar gnus-visual-summary-highlight
-  (list (cons (list '> '(gnus-summary-interest) gnus-summary-default-interest)
-             'bold)
-       (cons (list '< '(gnus-summary-interest) gnus-summary-default-interest)
-             'italic))
+  '(((> score default) . bold)
+    ((< score default) . italic))
   "Alist of (FORM . FACE).
 Summary lines are highlighted with the FACE for the first FORM which
-evaluate to non-nil.")
+evaluate to non-nil.  
+
+When FORM is evaluated point will be at the beginning of the line, and
+the following free variable can be used for convenience:
+
+score:   (gnus-summary-interest)
+default: gnus-summary-default-interest
+below:   gnus-summary-mark-below
+
+To check for marks, e.g. to underline replied articles, use `looking-at':
+
+   ((looking-at \".R\") . underline)
+
+This will match all lines where the second character is `R'.  
+The `.' will match any character.")
 
 ;; Newsgroup buffer
 
@@ -70,6 +82,7 @@ evaluate to non-nil.")
      ["Jump to group" gnus-group-jump-to-group t]
      ["List subscribed groups" gnus-group-list-groups t]
      ["List all groups" gnus-group-list-all-groups t]
+     ["List groups matching..." gnus-group-list-matching t]
      ["Subscribe to random group" gnus-group-unsubscribe-group t]
      ["Describe all groups" gnus-group-describe-all-groups t]
      ["Group apropos" gnus-group-apropos t]
@@ -80,6 +93,7 @@ evaluate to non-nil.")
      ["Kill all zombie groups" gnus-group-kill-all-zombies t]
      ["List killed groups" gnus-group-list-killed t]
      ["List zombie groups" gnus-group-list-zombies t]
+     ["Edit global KILL file" gnus-group-edit-global-kill t]
      ))
 
   (easy-menu-define
@@ -138,9 +152,9 @@ evaluate to non-nil.")
      ["Remove expirable mark" gnus-summary-unmark-as-expirable t]
      ["Set bookmark" gnus-summary-set-bookmark t]
      ["Remove bookmark" gnus-summary-remove-bookmark t]
-     ["Raise score" gnus-summary-raise-interest t]
-     ["Lower score" gnus-summary-lower-interest t]
-     ["Set score" gnus-summary-set-interest t]
+     ["Raise score" gnus-summary-raise-score t]
+     ["Lower score" gnus-summary-lower-score t]
+     ["Set score" gnus-summary-set-score t]
      ))
 
   (easy-menu-define
@@ -203,11 +217,16 @@ evaluate to non-nil.")
    gnus-summary-mode-map
    ""
    '("Misc"
+     ["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]
      ["Filter articles" gnus-summary-execute-command t]
      ["Mark all articles as read and exit" gnus-summary-catchup-and-exit t]
      ["Toggle line truncation" gnus-summary-toggle-truncation t]
      ["Expire expirable articles" gnus-summary-expire-articles t]
      ["Delete a mail article" gnus-summary-delete-article t]
+     ["Show all dormant articles" gnus-summary-show-all-dormant t]
      ["Show all expunged articles" gnus-summary-show-all-expunged t]
      ["Reselect group" gnus-summary-reselect-current-group t]
      ["Rescan group" gnus-summary-rescan-group t]
@@ -216,17 +235,6 @@ evaluate to non-nil.")
      ["Exit group without updating" gnus-summary-quit t]
      ))
 
-  (easy-menu-define
-   gnus-summary-sort-menu
-   gnus-summary-mode-map
-   ""
-   '("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]
-     ))
-
   (easy-menu-define
    gnus-summary-post-menu
    gnus-summary-mode-map
@@ -259,42 +267,78 @@ evaluate to non-nil.")
       gnus-summary-temporarily-raise-by-author t]
      ["Raise score with current thread" 
       gnus-summary-temporarily-raise-by-thread t]
-     ["Raise score with current xref
+     ["Raise score with current crossposting
       gnus-summary-temporarily-raise-by-xref t]
      ["Permanently raise score with current subject"
       gnus-summary-raise-by-subject t]
      ["Permanently raise score with current author" 
       gnus-summary-raise-by-author t]
-     ["Permanently raise score with current thread"
-      gnus-summary-raise-by-thread t]
-     ["Permanently raise score with current xref" 
+     ["Permanently raise score with current crossposting" 
       gnus-summary-raise-by-xref t]
+     ["Permanently raise score for followups to current author"
+      gnus-summary-raise-followups-to-author t]
      ["Lower score with current subject" 
       gnus-summary-temporarily-lower-by-subject t]
      ["Lower score with current author" 
       gnus-summary-temporarily-lower-by-author t]
      ["Lower score with current thread" 
       gnus-summary-temporarily-lower-by-thread t]
-     ["Lower score with current xref
+     ["Lower score with current crossposting
       gnus-summary-temporarily-lower-by-xref t]
      ["Permanently lower score with current subject"
       gnus-summary-lower-by-subject t]
      ["Permanently lower score with current author" 
       gnus-summary-lower-by-author t]
-     ["Permanently lower score with current thread"
-      gnus-summary-lower-by-thread t]
-     ["Permanently lower score with current xref" 
+     ["Permanently lower score with current crossposting" 
       gnus-summary-lower-by-xref t]
+     ["Permanently lower score for followups to current author"
+      gnus-summary-lower-followups-to-author t]
      ))
   )
+;; Article buffer
+(defun gnus-article-make-menu-bar ()
+
+ (easy-menu-define
+   gnus-article-mode-menu
+   gnus-article-mode-map
+   ""
+   '("Article"
+     ["Scroll forwards" gnus-article-next-page t]
+     ["Scroll backwards" gnus-article-prev-page t]
+     ["Show summary" gnus-article-show-summary t]
+     ["Fetch Message-ID at point" gnus-article-refer-article t]
+     ["Mail to address at point" gnus-article-mail t]
+     ["Mail to address at point and include original"
+      gnus-article-mail-with-original t]
+     ))
+
+ (easy-menu-define
+   gnus-article-mode-menu
+   gnus-article-mode-map
+   ""
+   '("Treatment"
+     ["Hide headers" gnus-article-hide-headers t]
+     ["Hide signature" gnus-article-hide-signature t]
+     ["Hide citation" gnus-article-hide-citation t]
+     ["Treat overstrike" gnus-article-treat-overstrike t]
+     ["Remove carriage return" gnus-article-remove-cr t]
+     ["Remove quoted-unreadble" gnus-article-de-quoted-unreadable t]
+     ))
+ )
 
 (defun gnus-visual-highlight-selected-summary ()
   ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
   ;; Highlight selected article in summary buffer
   (if gnus-summary-selected-face
       (save-excursion
-       (let ((from (progn (beginning-of-line 1) (point)))
-             (to (progn (end-of-line 1) (point))))
+       (let* ((beg (progn (beginning-of-line) (point)))
+              (end (progn (end-of-line) (point)))
+              (from (or
+                     (next-single-property-change beg 'mouse-face nil end)
+                     beg))
+              (to (or (next-single-property-change from 'mouse-face nil end)
+                      end)))
          (if gnus-newsgroup-selected-overlay
              (move-overlay gnus-newsgroup-selected-overlay 
                            from to (current-buffer))
@@ -304,21 +348,21 @@ evaluate to non-nil.")
 
 (defun gnus-visual-summary-highlight-line ()
   "Highlight current line according to `gnus-visual-summary-highlight'."
-  (if (not gnus-visual)
-      ()
-    (let ((list gnus-visual-summary-highlight)
-         (inhibit-read-only t))
-      (while (and list (not (eval (car (car list)))))
-       (setq list (cdr list)))
-      (let ((face (and list (cdr (car list)))))
-       (save-excursion
-         (beginning-of-line 1)
-         (if (eq face (get-text-property (point) 'face))
-             ()
-           (put-text-property (point) (save-excursion (end-of-line 1) (point))
-                              'face face)))))))
-
+  (let ((list gnus-visual-summary-highlight)
+       (inhibit-read-only t))
+    (while (and list (not (eval (car (car list)))))
+      (setq list (cdr list)))
+    (let ((face (and list (cdr (car list)))))
+      (save-excursion
+       ;; BUG! For some reason the text properties of the first
+       ;; characters get mangled. 
+       (forward-char 10)
+       (if (eq face (get-text-property (point) 'face))
+           ()
+         (put-text-property (save-excursion (beginning-of-line 1) (point))
+                            (save-excursion (end-of-line 1) (point))
+                            'face face))))))
 
 (provide 'gnus-visual)
 
-;;; gnus-visual.el ends here
\ No newline at end of file
+;;; gnus-visual.el ends here
index 3aa6b16..6909b8c 100644 (file)
 ;;; Code:
 
 (require 'mail-utils)
+(require 'timezone)
 (require 'rnews)
 (require 'rmail)
-(require 'timezone)
 
 (require 'nnheader)
-(require 'nnmail)
 
 ;; Customization variables
 
@@ -77,15 +76,20 @@ the like, only in \"real\" newsgroups.
 The value must be a valid method as discussed in the documentation of
 `gnus-select-method'.")
 
+(defvar gnus-secondary-select-methods nil
+  "A list of secondary methods that will be used for reading news.")
+
 (defvar gnus-default-nntp-server nil
   "Specify a default NNTP server.
-This variable should be defined in paths.el.")
+This variable should be defined in paths.el, and should never be set
+by the user.
+If you want to change servers, you should use `gnus-select-method'.
+See the documentation to that variable.")
 
 (defvar gnus-secondary-servers nil
   "List of NNTP servers that the user can choose between interactively.
-The list should contain lists, where each list contains the name of
-the server. To make Gnus query you for a server, you have to give
-`gnus' a non-numeric prefix - `C-u M-x gnus', in short.")
+To make Gnus query you for a server, you have to give `gnus' a
+non-numeric prefix - `C-u M-x gnus', in short.")
 
 (defvar gnus-nntp-server nil
   "*The name of the host running the NNTP server.
@@ -104,7 +108,18 @@ used to 899, you would say something along these lines:
   "Your `.newsrc' file.  Use `.newsrc-SERVER' instead if it exists.")
 
 (defvar gnus-signature-file "~/.signature"
-  "Your `.signature' file.")
+  "Your signature file.
+If the variable is a string that doesn't correspond to a file, the
+string itself is inserted.")
+
+(defvar gnus-signature-function nil
+  "A function that should return a signature file name.
+The function will be called with the name of the newsgroup being
+posted to.
+If the function returns a string that doesn't correspond to a file, the
+string itself is inserted.
+If the function returns nil, the `gnus-signature-file' variable will
+be used instead.")
 
 (defvar gnus-init-file "~/.gnus"
   "Your Gnus elisp startup file.
@@ -118,7 +133,7 @@ If it is `t', Gnus will not do anything special the first time it is
 started; it'll just use the normal newsgroups subscription methods.")
 
 (defconst gnus-backup-default-subscribed-newsgroups 
-  '("news.announce.newusers" "news.groups.questions")
+  '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
   "Default default new newsgroups the first time Gnus is run.")
 
 (defvar gnus-post-prepare-function nil
@@ -134,15 +149,15 @@ If nil, ignore cross references.  If t, mark articles as read in
 all newsgroups.")
 
 (defvar gnus-use-followup-to 'use
-  "Specifies what to do with Followup-To field.
-If nil, ignore the field. If it is t, use its value, but ignore 
+  "Specifies what to do with Followup-To header.
+If nil, ignore the header. If it is t, use its value, but ignore 
 `poster'. If it is neither nil nor t, always use the value.")
 
 (defvar gnus-followup-to-function nil
   "A variable that contains a function that returns a followup address.
 The function will be called in the buffer of the article that is being
 followed up. The buffer will be narrowed to the headers of the
-article. To pick header fields, one might use `mail-fetch-field'.  The
+article. To pick header headers, one might use `mail-fetch-field'.  The
 function will be called with the name of the current newsgroup as the
 argument.
 
@@ -168,7 +183,7 @@ If the number of articles in a newsgroup is greater than the value,
 confirmation is required for selecting the newsgroup.")
 
 (defvar gnus-author-copy (getenv "AUTHORCOPY")
-  "Name of the file the article will be saved before it is posted using the FCC: field.
+  "Name of the file the article will be saved before it is posted using the FCC header.
 Initialized from the AUTHORCOPY environment variable.
 
 Articles are saved using a function specified by the the variable
@@ -179,6 +194,11 @@ possible to save an article in an MH folder as follows:
 
 \(setq gnus-author-copy \"|/usr/local/lib/mh/rcvstore +Article\")")
 
+(defvar gnus-mail-self-blind nil
+  "Non-nil means insert BCC to self in messages to be sent.
+This is done when the message is initialized,
+so you can remove or alter the BCC header to override the default.")
+
 (defvar gnus-author-copy-saver (function rmail-output)
   "A function called with a file name to save an author copy to.
 The default function is `rmail-output' which saves in Unix mailbox format.")
@@ -187,11 +207,11 @@ The default function is `rmail-output' which saves in Unix mailbox format.")
   "Non-nil means that the default name of a file to save articles in is the newsgroup name.
 If it's nil, the directory form of the newsgroup name is used instead.")
 
-(defvar gnus-article-save-directory (getenv "SAVEDIR")
+(defvar gnus-article-save-directory (or (getenv "SAVEDIR") "~/News/")
   "Name of the directory articles will be saved in (default \"~/News\").
 Initialized from the SAVEDIR environment variable.")
 
-(defvar gnus-kill-files-directory (getenv "SAVEDIR")
+(defvar gnus-kill-files-directory (or (getenv "SAVEDIR") "~/News/")
   "Name of the directory where kill files will be stored (default \"~/News\").
 Initialized from the SAVEDIR environment variable.")
 
@@ -229,10 +249,20 @@ The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
 (defvar gnus-kill-file-name "KILL"
   "Suffix of the kill files.")
 
+(defvar gnus-fetch-old-headers nil
+  "Non-nil means that Gnus will try to build threads by grabbing old headers.
+If an unread article in the group refers to an older, already read (or
+just marked as read) article, the old article will not normally be
+displayed in the Summary buffer. If this variable is non-nil, Gnus
+will attempt to grab the headers to the old articles, and thereby
+build complete threads. `gnus-nov-is-evil' has to be nil if this is
+to work.  If it has the value `some', only enough headers to connect
+otherwise loose threads will be displayed.")
+
 (defvar gnus-visual t
   "*If non-nil, will do various highlighting.
 If nil, no mouse highlight (or any other) will be performed. This
-might speed up Gnus some when generating large Newsgroup and Summary
+might speed up Gnus some when generating large group and summary
 buffers.")
 
 (defvar gnus-novice-user t
@@ -248,41 +278,49 @@ And that means *anything*.")
   "Non-nil means that the next newsgroup after the current will be on the same level.
 When you type, for instance, `n' after reading the last article in the
 current newsgroup, you will go to the next newsgroup. If this variable
-is nil, the next newsgroup will be the next from the Newsgroup
+is nil, the next newsgroup will be the next from the group
 buffer. If this variable is non-nil, Gnus will either put you in the
 next newsgroup with the same level, or, if no such newsgroup is
 available, the next newsgroup with the lowest possible level higher
 than the current level.")
 
-(defvar gnus-gather-loose-threads t
-  "Non-nil means sub-threads from a common thread will be gathered.
+(defvar gnus-summary-make-false-root 'adopt
+  "nil means that Gnus won't gather loose threads.
 If the root of a thread has expired or been read in a previous
 session, the information necessary to build a complete thread has been
 lost. Instead of having many small sub-threads from this original thread
-scattered all over the Summary buffer, Gnus will gather them. If the
-`gnus-summary-make-false-root' variable is non-nil, Gnus will also
-present them as one thread with a new root.")
+scattered all over the summary buffer, Gnus can gather them. 
 
-(defvar gnus-summary-make-false-root 'adopt
-  "nil means that Gnus won't print dummy roots of threads in the summary buffer.
-If `gnus-gather-loose-threads' is non-nil, Gnus will try to gather all
-loose sub-threads from an original thread into one large thread. If
-this variable is nil, these sub-threads will not get a common root,
-but will just be presented after one another. If this variable is
-`dummy', Gnus will create a dummy root that will have all the
-sub-threads as children.
+If non-nil, Gnus will try to gather all loose sub-threads from an
+original thread into one large thread.
+
+If this variable is non-nil, it should be one of `none', `adopt',
+`dummy' or `empty'.
+
+If this variable is `none', Gnus will not make a false root, but just
+present the sub-threads after another.
+If this variable is `dummy', Gnus will create a dummy root that will
+have all the sub-threads as children.
 If this variable is `adopt', Gnus will make one of the \"children\"
 the parent and mark all the step-children as such.
 If this variable is `empty', the \"children\" are printed with empty
 subject fields.")
 
+(defvar gnus-summary-gather-subject-limit nil
+  "*Maximum length of subject to compare when gathering loose threads.
+Use nil to compare the whole subject.")
+
 (defvar gnus-check-new-newsgroups t
   "Non-nil means that Gnus will add new newsgroups at startup.
+If this variable is `ask-server', Gnus will ask the server for new
+groups since the last time it checked. This means that the killed list
+is no longer necessary, so you could set `gnus-save-killed-list' to
+nil. 
 If this variable is nil, then you have to tell Gnus explicitly to
 check for new newsgroups with \\<gnus-group-mode-map>\\[gnus-find-new-newsgroups].")
 
 (defvar gnus-check-bogus-newsgroups nil
-  "Non-nil means that Gnus will check and delete bogus newsgroup at startup.
+  "Non-nil means that Gnus will check and remove bogus newsgroup at startup.
 If this variable is nil, then you have to tell Gnus explicitly to
 check for bogus newsgroups with \\<gnus-group-mode-map>\\[gnus-group-check-bogus-groups].")
 
@@ -321,24 +359,27 @@ subscription methods become meaningless. You should always set
   "Require your confirmation when catching up a newsgroup if non-nil.")
 
 (defvar gnus-interactive-post t
-  "Newsgroup and subject will be asked for if non-nil.")
+  "Group and subject will be asked for if non-nil.")
 
 (defvar gnus-interactive-exit t
   "Require your confirmation when exiting Gnus if non-nil.")
 
-(defvar gnus-kill-killed t
-  "If non-nil, Gnus will apply kill files to already \"killed\" articles.
+(defvar gnus-kill-killed nil
+  "If non-nil, Gnus will apply kill files to already killd articles.
 If it is nil, Gnus will never apply kill files to articles that have
-already been through the kill process, which might very well save lots
+already been through the scoring process, which might very well save lots
 of time.")
 
 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
 (defvar gnus-summary-same-subject ""
   "String indicating that the current article has the same subject as the previous.")
 
-(defvar gnus-summary-default-interest nil
-  "Default article interest level.
-If this variable is nil, interest levels will not be used.")
+(defvar gnus-score-interactive-default-score 1000
+  "Scoring commands will raise/lower with this number as the default.")
+
+(defvar gnus-summary-default-score 0
+  "Default article score level.
+If this variable is nil, score levels will not be used.")
 
 (defvar gnus-user-login-name nil
   "The login name of the user.
@@ -352,7 +393,7 @@ Got from the NAME environment variable if undefined.")
   "*Show MIME message if non-nil.")
 
 (defvar gnus-show-threads t
-  "*Show conversation threads in Summary Mode if non-nil.")
+  "*Show conversation threads in summary mode if non-nil.")
 
 (defvar gnus-thread-hide-subtree nil
   "Non-nil means hide thread subtrees initially.
@@ -375,9 +416,9 @@ If it is non-nil, some commands work with subjects do not work properly.")
 ;; toxic.
 (defvar gnus-ignored-newsgroups
   (purecopy (mapconcat 'identity
-                      '("^to\\."               ; not "real" groups
-                        "^[0-9. \t]+ "         ; all digits in name
-                        "[][\"#'();\\]"        ; bogus characters
+                      '("^to\\."       ; not "real" groups
+                        "^[0-9. \t]+ " ; all digits in name
+                        "[][\"#'()     ;\\]"   ; bogus characters
                         )
                       "\\|"))
   "A regexp to match uninteresting newsgroups in the active file.
@@ -387,19 +428,19 @@ thus making them effectively non-existant.")
 
 (defvar gnus-ignored-headers
   "^Path:\\|^Posting-Version:\\|^Article-I.D.:\\|^Expires:\\|^Date-Received:\\|^References:\\|^Control:\\|^Xref:\\|^Lines:\\|^Posted:\\|^Relay-Version:\\|^Message-ID:\\|^Nf-ID:\\|^Nf-From:\\|^Approved:\\|^Sender:\\|^Received:\\|^Mail-from:"
-  "All header lines that match this regexp will be hidden.
+  "All headers that match this regexp will be hidden.
 Also see `gnus-visible-headers'.")
 
 (defvar gnus-visible-headers "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:"
-  "All header lines that do not match this regexp will be hidden.
+  "All headers that do not match this regexp will be hidden.
 Also see `gnus-ignored-headers'.")
 
 (defvar gnus-sorted-header-list
   '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:" 
     "^Date:" "^Organization:")
   "This variable is a list of regular expressions.
-If it is non-nil, header lines that match the regular expressions will
-be placed first in the Article buffer in the sequence specified by
+If it is non-nil, headers that match the regular expressions will
+be placed first in the article buffer in the sequence specified by
 this list.")
 
 (defvar gnus-required-headers
@@ -407,10 +448,10 @@ this list.")
   ;; changed by jwz because it's not so nice to do "Lines: 0" by default.
   ;; and to remove Path, since it's incorrect for Gnus to try
   ;; and generate that - it is the responsibility of inews or nntpd.
-  "All required fields for articles you post.
+  "All required headers for articles you post.
 RFC977 and RFC1036 require From, Date, Newsgroups, Subject, Message-ID
-and Path fields.  Organization, Lines and X-Newsreader are optional.
-If you want Gnus not to insert some field, remove it from this
+and Path headers.  Organization, Lines and X-Newsreader are optional.
+If you want Gnus not to insert some header, remove it from this
 variable.")
 
 (defvar gnus-show-all-headers nil
@@ -434,7 +475,7 @@ or `gnus-apply-kill-hook'.")
 (defvar gnus-auto-select-next t
   "Select the next newsgroup automagically if non-nil.
 If the value is t and the next newsgroup is empty, Gnus will exit
-Summary mode and go back to Group mode.  If the value is neither nil
+summary mode and go back to group mode.  If the value is neither nil
 nor t, Gnus will select the following unread newsgroup.  Especially, if
 the value is the symbol `quietly', the next unread newsgroup will be
 selected without any confirmations.")
@@ -443,7 +484,7 @@ selected without any confirmations.")
   "Select the next article with the same subject automagically if non-nil.")
 
 (defvar gnus-auto-center-summary t
-  "*Always center the current summary in Gnus Summary window if non-nil.")
+  "*Always center the current summary in Gnus summary window if non-nil.")
 
 (defvar gnus-auto-mail-to-author nil
   "Insert `To: author' of the article when following up if non-nil.
@@ -472,7 +513,7 @@ Page delimiter is specified by the variable `gnus-page-delimiter'.")
     (article (0 3 10)))
   "Specify window configurations for each action.
 The format of the variable is either a list of (ACTION (G S A)), where
-G, S, and A are the relative height of Group, Summary, and Article
+G, S, and A are the relative height of group, summary, and article
 windows, respectively, or a list of (ACTION FUNCTION), where FUNCTION
 is a function that will be called with ACTION as an argument. ACTION
 can be `summary', `newsgroups', or `article'.")
@@ -503,7 +544,7 @@ mail program.  You can use yet another program by customizing this variable.")
 
 (defvar gnus-mail-send-method send-mail-function
   "Function to mail a message too which is being posted as an article.
-The message must have To: or Cc: field.  The default is copied from
+The message must have To or Cc header.  The default is copied from
 the variable `send-mail-function'.")
 
 (defvar gnus-subscribe-newsgroup-method
@@ -531,38 +572,47 @@ the subscription method in this variable.")
 
 ;; Mark variables suggested by Thomas Michanek
 ;; <Thomas.Michanek@telelogic.se>. 
-(defvar gnus-unread-mark " "
+(defvar gnus-unread-mark 
   "Mark used for unread articles.")
-
-(defvar gnus-read-mark "D"
-  "Mark used for read articles.")
-
-(defvar gnus-ticked-mark "-"
+(defvar gnus-ticked-mark ?!
   "Mark used for ticked articles.")
-
-(defvar gnus-dormant-mark "+"
+(defvar gnus-dormant-mark ??
   "Mark used for dormant articles.")
-
-(defvar gnus-killed-mark "K"
+(defvar gnus-read-mark ?D
+  "Mark used for read articles.")
+(defvar gnus-expirable-mark ?E
+  "Mark used for expirable articles.")
+(defvar gnus-killed-mark ?K
   "Mark used for killed articles.")
-
-(defvar gnus-kill-file-mark "X"
+(defvar gnus-kill-file-mark ?X
   "Mark used for articles killed by kill files.")
-
-(defvar gnus-catchup-mark "C"
+(defvar gnus-low-score-mark ?Y
+  "Mark used for articles with a low score.")
+(defvar gnus-catchup-mark ?C
   "Mark used for articles that are caught up.")
+(defvar gnus-replied-mark ?R
+  "Mark used for articles that have been replied to.")
+(defvar gnus-process-mark ?#
+  "Mark used for marking articles as processable.")
+(defvar gnus-ancient-mark ?A
+  "Mark used for ancient articles.")
+(defvar gnus-canceled-mark ?%
+  "Mark used for cancelled articles.")
+
+(defvar gnus-view-pseudo-asynchronously nil
+  "*If non-nil, Gnus will view pseudo-articles asynchronously.")
 
 (defvar gnus-group-mode-hook nil
-  "A hook for Gnus Group Mode.")
+  "A hook for Gnus group mode.")
 
 (defvar gnus-summary-mode-hook nil
-  "A hook for Gnus Summary Mode.")
+  "A hook for Gnus summary mode.")
 
 (defvar gnus-article-mode-hook nil
-  "A hook for Gnus Article Mode.")
+  "A hook for Gnus article mode.")
 
 (defvar gnus-kill-file-mode-hook nil
-  "A hook for Gnus KILL File Mode.")
+  "A hook for Gnus KILL File mode.")
 
 (defvar gnus-open-server-hook nil
   "A hook called just before opening connection to news server.")
@@ -574,47 +624,29 @@ is possible to change the behavior of Gnus according to the selected
 NNTP server.")
 
 (defvar gnus-group-prepare-hook nil
-  "A hook called after the newsgroup list is created in the Newsgroup buffer.
-If you want to modify the Newsgroup buffer, you can use this hook.")
+  "A hook called after the newsgroup list is created in the group buffer.
+If you want to modify the group buffer, you can use this hook.")
 
 (defvar gnus-summary-prepare-hook nil
-  "A hook called after summary list is created in the Summary buffer.
-If you want to modify the Summary buffer, you can use this hook.")
+  "A hook called after summary list is created in the summary buffer.
+If you want to modify the summary buffer, you can use this hook.")
 
 (defvar gnus-article-prepare-hook nil
-  "A hook called after an article is prepared in the Article buffer.
+  "A hook called after an article is prepared in the article buffer.
 If you want to run a special decoding program like nkf, use this hook.")
 
 (defvar gnus-article-display-hook nil
-  "A hook called after the article is displayed in the Article buffer.
-The hook is designed to change the contents of the Article
+  "A hook called after the article is displayed in the article buffer.
+The hook is designed to change the contents of the article
 buffer. Typical functions that this hook may contain are
 `gnus-article-hide-headers' (hide selected headers),
 `gnus-article-hide-signature' (hide signature) and
 `gnus-article-treat-overstrike' (turn \"^H_\" into bold characters).")
 (add-hook 'gnus-article-display-hook 'gnus-article-hide-headers-if-wanted)
+(add-hook 'gnus-article-display-hook 'gnus-article-treat-overstrike)
 
 (defvar gnus-select-group-hook nil
   "A hook called when a newsgroup is selected.
-If you want to sort Summary buffer by date and then by subject, you
-can use the following hook:
-
- (setq gnus-select-group-hook
-      (list
-       (lambda ()
-         ;; First of all, sort by date.
-         (gnus-keysort-headers
-          (function string-lessp)
-           (lambda (a)
-             (gnus-sortable-date (header-date a))))
-         ;; Then sort by subject string ignoring `Re:'.
-         ;; If case-fold-search is non-nil, case of letters is ignored.
-         (gnus-keysort-headers
-          (function string-lessp)
-           (lambda (a)
-             (if case-fold-search
-                 (downcase (gnus-simplify-subject (header-subject a) t))
-               (gnus-simplify-subject (header-subject a) t)))))))
 
 If you'd like to simplify subjects like the
 `gnus-summary-next-same-subject' command does, you can use the
@@ -654,12 +686,12 @@ use the following hook:
 
 (defvar gnus-select-digest-hook
   (list
-    (lambda ()
-      ;; Reply-To: is required by `undigestify-rmail-message'.
-      (or (mail-position-on-field "Reply-to" t)
-         (progn
-           (mail-position-on-field "Reply-to")
-           (insert (gnus-fetch-field "From"))))))
+   (lambda ()
+     ;; Reply-To: is required by `undigestify-rmail-message'.
+     (or (mail-position-on-field "Reply-to" t)
+        (progn
+          (mail-position-on-field "Reply-to")
+          (insert (gnus-fetch-field "From"))))))
   "A hook called when reading digest messages using Rmail.
 This hook can be used to modify incomplete digest articles as follows
 \(this is the default):
@@ -679,12 +711,12 @@ This hook is intended to customize Rmail mode for reading digest articles.")
 
 (defvar gnus-apply-kill-hook '(gnus-apply-kill-file)
   "A hook called when a newsgroup is selected and summary list is prepared.
-This hook is intended to apply a KILL file to the selected newsgroup.
+This hook is intended to apply a kill file to the selected newsgroup.
 The function `gnus-apply-kill-file' is called by default.
 
-Since a general KILL file is too heavy to use only for a few
+Since a general kill file is too heavy to use only for a few
 newsgroups, I recommend you to use a lighter hook function. For
-example, if you'd like to apply a KILL file to articles which contains
+example, if you'd like to apply a kill file to articles which contains
 a string `rmgroup' in subject in newsgroup `control', you can use the
 following hook:
 
@@ -695,13 +727,14 @@ following hook:
                 (gnus-kill \"Subject\" \"rmgroup\")
                 (gnus-expunge \"X\"))))))")
 
-(defvar gnus-visual-mark-article-hook 'gnus-visual-highlight-selected-summary
-  "Hook run after selecting an article in the Summary buffer.
+(defvar gnus-visual-mark-article-hook 
+  (list 'gnus-visual-highlight-selected-summary)
+  "Hook run after selecting an article in the summary buffer.
 It is meant to be used for highlighting the article in some way. It is
 not run if `gnus-visual' is nil.")
 
 (defvar gnus-prepare-article-hook (list (function gnus-inews-insert-signature))
-  "A hook called after preparing body, but before preparing header fields.
+  "A hook called after preparing body, but before preparing header headers.
 The default hook (`gnus-inews-insert-signature') inserts a signature
 file specified by the variable `gnus-signature-file'.")
 
@@ -711,8 +744,8 @@ The default hook (`gnus-inews-do-fcc') does FCC processing (save article
 to a file).")
 
 (defvar gnus-exit-group-hook nil
-  "A hook called when exiting (not quitting) Summary mode.
-If your machine is so slow that exiting from Summary mode takes very
+  "A hook called when exiting (not quitting) summary mode.
+If your machine is so slow that exiting from summary mode takes very
 long time, set the variable `gnus-use-cross-reference' to nil. This
 inhibits marking articles as read using cross-reference information.")
 
@@ -739,8 +772,8 @@ If the user pressed `d', Gnus will descend the hierarchy, `y' will
 subscribe to all newsgroups in the hierarchy and `s' will skip this
 hierarchy in its entirety.")
 
-(defvar gnus-group-line-format "%M%S%5y: %G %z\n"
-  "Format of Newsgroups lines.
+(defvar gnus-group-line-format "%M%S%5y: %(%g%)\n"
+  "Format of groups lines.
 It works along the same lines as a normal formatting string,
 with some simple extrensions.
 
@@ -755,12 +788,22 @@ with some simple extrensions.
 %t    Total number of articles (integer)
 %y    Number of unread, unticked articles (integer)
 %G    Group name (string)
-%D    Newsgroup description (string)
+%g    Qualified group name (string)
+%D    Group description (string)
 %s    Select method (string)
 %o    Moderated group (char, \"m\")
 %O    Moderated group (string, \"(m)\" or \"\")
 %n    Select from where (string)
 %z    A string that look like `<%s:%n>' if a foreign select method is used
+%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 move inside the area.  There can only be one such area.
 
 Note that this format specification is not always respected. For
 reasons of efficiency, when listing killed groups, this specification
@@ -774,9 +817,9 @@ Also note that if you change the format specification to include any
 of these specs, you must probably re-start Gnus to see them go into
 effect.") 
 
-(defvar gnus-summary-line-format "%U%R%X%i %I%[%4L: %-20,20n%] %s\n"
-  "The format specification of the lines in the Summary buffer.
-The first specification must always be \"%U%R%X\", at least in this
+(defvar gnus-summary-line-format "%U%R %I%(%[%4L: %-20,20n%]%) %s\n"
+  "The format specification of the lines in the summary buffer.
+The first specification must always be \"%U%R\", at least in this
 version of Gnus.
 
 It works along the same lines as a normal formatting string,
@@ -788,34 +831,44 @@ with some simple extensions.
 %n   Name of the poster (string)
 %A   Address of the poster (string)
 %L   Number of lines in the article (integer)
+%c   Number of characters in the article (integer)
 %D   Date of the article (string)
 %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
-%C   This is the current article (character, \"+\" or \" \")
 %U   Status of this article (character, \"D\", \"K\", \"-\" or \" \") 
-%[   Opening bracket (character, \"[\" or \"=\")
-%]   Closing bracket (character, \"]\" or \"=\")
+%[   Opening bracket (character, \"[\" or \"<\")
+%]   Closing bracket (character, \"]\" or \">\")
 %>   Spaces of length thread-level (string)
 %<   Spaces of length (- 20 thread-level) (string)
-%i   Article interest (integer, 0-9)
-")
+%i   Article score (number)
+%z   Article zcore (character)
+%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.")
 
 (defconst gnus-summary-dummy-line-format "*   :                          : %S\n"
-  "The format specification for the dummy roots in the Summary buffer.
+  "The format specification for the dummy roots in the summary buffer.
 It works along the same lines as a normal formatting string,
 with some simple extensions.
 
 %S  The subject")
 
 (defvar gnus-summary-mode-line-format "(ding) %G/%A %Z"
-  "The format specification for the Summary mode line.")
+  "The format specification for the summary mode line.")
 
 (defvar gnus-article-mode-line-format "(ding) %G/%A %S"
-  "The format specification for the Article mode line.")
+  "The format specification for the article mode line.")
 
-(defconst gnus-group-mode-line-format "(ding) List of Newsgroups   {%M:%S}"
-  "The format specification for the Newsgroup mode line.")
+(defconst gnus-group-mode-line-format "(ding) List of groups   {%M:%S}"
+  "The format specification for the group mode line.")
 
 
 \f
@@ -833,33 +886,41 @@ For backwards compatibility, it may also be a string like \"JST\",
 but strings are obsolescent: you should use numeric offsets instead.")
 
 (defvar gnus-local-domain nil
-  "Local domain name without a host name like: \"stars.flab.Fujitsu.CO.JP\"
-The `DOMAINNAME' environment variable is used instead if defined.  If
-the function (system-name) returns the full internet name, there is no
-need to define the name.")
+  "Local domain name without a host name.
+The DOMAINNAME environment variable is used instead if it is defined.
+If the `system-name' function returns the full Internet name, there is
+no need to set this variable.")
 
 (defvar gnus-local-organization nil
-  "Local organization like: \"Fujitsu Laboratories Ltd., Kawasaki, Japan.\"
-The `ORGANIZATION' environment variable is used instead if defined.")
+  "String with a description of what organization (if any) the user belongs to.
+The ORGANIZATION environment variable is used instead if it is defined.
+If this variable contains a function, this function will be called
+with the current newsgroup name as the argument. The function should
+return a string.
+In any case, if the string (either in the variable, in the environment
+variable, or returned by the function) is a file name, the contents of
+this file will be used as the organization.")
 
 (defvar gnus-use-generic-from nil
-  "If nil, prepend local host name to the defined domain in the From:
-field; if stringp, use this; if non-nil, strip of the local host name.")
+  "If nil, the full host name will be the system name prepended to the domain name.
+If this is a string, the full host name will be this string.
+If this is non-nil, non-string, the domain name will be used as the
+full host name.")
 
 (defvar gnus-use-generic-path nil
-  "If nil, use the NNTP server name in the Path: field; if stringp,
-use this; if non-nil, use no host name (user name only)")
+  "If nil, use the NNTP server name in the Path header.
+If stringp, use this; if non-nil, use no host name (user name only).")
 
 (defvar gnus-valid-select-methods
-  '(("nntp" post) ("nnspool" post) ("nnvirtual" none) 
-    ("nnmail" mail respool) ("nnml" mail respool)
-    ("nnmh" mail respool))
+  '(("nntp" post address) ("nnspool" post) ("nnvirtual" none) 
+    ("nnmbox" mail respool) ("nnml" mail respool)
+    ("nnmh" mail respool) ("nndir" none))
   "A list of valid select methods.
 Each element in this list should be a list. The first element of these
 lists should be a string with the name of the select method. The
 other elements may be be the category of this method (ie. `post',
 `mail', `none' or whatever) or other properties that this method has
-(like being respoolable). 
+ (like being respoolable). 
 If you implement a new select method, all you should have to change is
 this variable. I think.")
 
@@ -878,11 +939,58 @@ No mouse highlights will be done if `gnus-visual' is nil.")
 (defvar gnus-visual-summary-update-hook 
   (list 'gnus-visual-summary-highlight-line)
   "A hook called when a summary line is changed.
-The cursor will be positioned at the summary line.
+The hook will not be called if `gnus-visual' is nil.
+
+Point will be at the beginning of the line, and the following free
+variables can be used for convenience:
+
+score:   (gnus-summary-article-score)
+default: gnus-summary-default-score
+below:   gnus-summary-mark-below
 
 The default hook `gnus-visual-summary-highlight-line' will highlight the line
 according to the `gnus-visual-summary-highlight' variable.")
 
+(defvar gnus-summary-mark-below nil
+  "Score below which articles automatically become marked.
+This variable is local to each summary buffer and usually set in the
+score file.")  
+
+(defvar gnus-thread-sort-functions '(gnus-thread-sort-by-number)
+  "List of functions used for thread roots in the summary buffer.
+
+Each function takes two threads and return non-nil if the first thread
+should be sorted before the other.  If you use more than one function,
+list the function you want to act as the primary sort key last.
+
+Functions you can use are:
+- gnus-thread-sort-by-number
+- gnus-thread-sort-by-author
+- gnus-thread-sort-by-subject
+- gnus-thread-sort-by-date
+- gnus-thread-sort-by-score
+- gnus-thread-sort-by-total-score (see `gnus-thread-score-function').
+
+The two later only works on articles that have already been scored prior
+to entering the newsgroup.")
+
+(defvar gnus-thread-score-function '+
+  "Function used for calculating the total score of a thread.
+
+The function is called with the scores of the article and each
+subthread and should then return the score of the thread.
+
+Some functions you can use are `+', `max', or `min'.")
+
+(defvar gnus-score-hierarchical t
+  "If non-nil, a SCORE file for a group also applies to subgroups.")
+
+(defvar gnus-score-find-score-files-function nil
+  "If non-nil, it should be a function that returns a list of score files.
+The function will be called with the name of the group that is to be
+scored. This function does not have to make sure that the file names
+returned actually exist.")
+
 \f
 ;; Internal variables
 
@@ -892,10 +1000,34 @@ according to the `gnus-visual-summary-highlight' variable.")
 (defvar caesar-translate-table nil)
 
 (defvar gnus-dribble-buffer nil)
+(defvar gnus-headers-retrieved-by nil)
 
 (defvar gnus-article-reply nil)
 (defvar gnus-article-check-size nil)
 
+(defvar gnus-score-file-list nil)
+(defvar gnus-score-alist nil
+  "Alist containing score information.
+The keys can be symbols or strings.  The following symbols are defined. 
+
+touched: If this alist has been modified.
+mark:    Automatically mark articles below this.
+expunge: Automatically expunge articles below this.
+files:   List of other SCORE files to load when loading this one.
+eval:    Sexp to be evaluated when the score file is loaded.
+
+String entries have the form (HEADER (MATCH TYPE SCORE DATE) ...) 
+where HEADER is the header being scored, MATCH is the string we are
+looking for, TYPE is a flag indicating whether it should use regexp or
+substring matching, SCORE is the score to add and DATE is the date
+of the last succesful match.")
+
+(defvar gnus-score-cache nil)
+;; Alist containing the content of all loaded SCORE files.
+
+(defvar gnus-header-index nil)
+(defvar gnus-score-index nil)
+
 (defvar gnus-newsgroup-dependencies nil)
 
 (defconst gnus-group-edit-buffer "*Gnus edit newsgroup*")
@@ -920,13 +1052,15 @@ according to the `gnus-visual-summary-highlight' variable.")
        (list ?t 'number-total ?d)
        (list ?y 'number-of-unread-unticked ?s)
        (list ?i 'number-of-ticked-and-dormant ?d)
-       (list ?G 'group ?s)
+       (list ?g 'group ?s)
+       (list ?G 'qualified-group ?s)
        (list ?D 'newsgroup-description ?s)
        (list ?o 'moderated ?c)
        (list ?O 'moderated-string ?s)
        (list ?s 'news-server ?s)
        (list ?n 'news-method ?s)
-       (list ?z 'news-method-string ?s)))
+       (list ?z 'news-method-string ?s)
+       (list ?u 'user-defined ?s)))
 
 (defconst gnus-summary-line-format-alist 
   (list (list ?N 'number ?d)
@@ -939,19 +1073,19 @@ according to the `gnus-visual-summary-highlight' variable.")
        (list ?D (macroexpand '(header-date header)) ?s)
        (list ?M (macroexpand '(header-id header)) ?s)
        (list ?r (macroexpand '(header-references header)) ?s)
+       (list ?c (macroexpand '(header-chars header)) ?d)
        (list ?L 'lines ?d)
        (list ?I 'indentation ?s)
-       (list ?T '(thread-space (if (< level 1) "" (make-string (frame-width) ? ))) 
-             ?s)
-       (list ?C '(if current ?+ ? ) ?c)
+       (list ?T '(if (< level 1) "" (make-string (frame-width) ? )) ?s)
        (list ?R 'replied ?c)
-       (list ?X 'expirable ?c)
        (list ?\[ 'opening-bracket ?c)
        (list ?\] 'closing-bracket ?c)
        (list ?\> '(make-string level ? ) ?s)
        (list ?\< '(make-string (max 0 (- 20 level)) ? ) ?s)
-       (list ?i 'interest ?s)
-       (list ?U 'unread ?c))
+       (list ?i 'score ?s)
+       (list ?z 'score-char ?c)
+       (list ?U 'unread ?c)
+       (list ?u 'user-defined ?s))
   "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).")
@@ -975,22 +1109,20 @@ variable (string, integer, character, etc).")
 
 (defvar gnus-have-read-active-file nil)
 
-(defconst gnus-foreign-group-prefix "foreign.")
-
 (defconst gnus-maintainer "Lars Magne Ingebrigtsen <larsi@ifi.uio.no>"
   "The mail address of the Gnus maintainer.")
 
-(defconst gnus-version "(ding) Gnus v0.10"
-  "Version numbers of this version of Gnus.")
+(defconst gnus-version "(ding) Gnus v0.20"
+  "Version number for this version of Gnus.")
 
 (defvar gnus-info-nodes
-  '((gnus-group-mode           "(gnus)Newsgroup Commands")
+  '((gnus-group-mode           "(gnus)Group Commands")
     (gnus-summary-mode         "(gnus)Summary Commands")
     (gnus-article-mode         "(gnus)Article Commands")
     (gnus-kill-file-mode       "(gnus)Kill File"))
   "Assoc list of major modes and related Info nodes.")
 
-(defvar gnus-group-buffer "*Newsgroup*")
+(defvar gnus-group-buffer "*Group*")
 (defvar gnus-summary-buffer "*Summary*")
 (defvar gnus-article-buffer "*Article*")
 (defvar gnus-digest-buffer "Gnus Digest")
@@ -1000,8 +1132,9 @@ variable (string, integer, character, etc).")
   "Gnus buffers that should be killed when exiting.")
 
 (defvar gnus-variable-list
-  '(gnus-newsrc-options
+  '(gnus-newsrc-options 
     gnus-newsrc-options-n-yes gnus-newsrc-options-n-no
+    gnus-newsrc-last-checked-date
     gnus-newsrc-assoc gnus-killed-list gnus-zombie-list)
   "Gnus variables saved in the quick startup file.")
 
@@ -1020,6 +1153,9 @@ It is a list of `(original overload &optional file)'.")
 (defvar gnus-newsrc-options-n-no nil
   "Regexp representing unsubscribed newsgroups.")
 
+(defvar gnus-newsrc-last-checked-date nil
+  "Date Gnus last asked server for new newsgroups.")
+
 (defvar gnus-newsrc-assoc nil
   "Assoc list of read articles.
 gnus-newsrc-hashtb should be kept so that both hold the same information.")
@@ -1037,7 +1173,7 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
   "List of almost dead newsgroups.")
 
 (defvar gnus-description-hashtb nil
-  "Descriptions of newsgroups (from the file 'newsgroups').")
+  "Descriptions of newsgroups.")
 
 (defvar gnus-list-of-killed-groups nil
   "List of newsgroups that have recently been killed by the user.")
@@ -1089,7 +1225,9 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
   "List of ticked articles in the current newsgroup (a subset of unread art).")
 
 (defvar gnus-newsgroup-killed nil
-  "List of ranges of articles that have been through the kill process.")
+  "List of ranges of articles that have been through the scoring process.")
+
+(defvar gnus-newsgroup-kill-headers nil)
 
 (defvar gnus-newsgroup-replied nil
   "List of articles that have been replied to in the current newsgroup.")
@@ -1106,10 +1244,16 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-newsgroup-dormant nil
   "List of dormant articles in the current newsgroup.")
 
+(defvar gnus-newsgroup-scored nil
+  "List of scored articles in the current newsgroup.")
+
 (defvar gnus-newsgroup-headers nil
   "List of article headers in the current newsgroup.")
 (defvar gnus-newsgroup-headers-hashtb-by-number nil)
 
+(defvar gnus-newsgroup-ancient nil
+  "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
+
 (defvar gnus-current-article nil)
 (defvar gnus-article-current nil)
 (defvar gnus-current-headers nil)
@@ -1117,13 +1261,12 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-last-article nil)
 (defvar gnus-current-kill-article nil)
 (defvar gnus-newsgroup-dormant-subjects nil)
-(defvar gnus-newsgroup-expunged-lines nil)
+(defvar gnus-newsgroup-expunged-buffer nil)
 
 ;; Save window configuration.
 (defvar gnus-winconf-kill-file nil)
 
 (defconst gnus-group-mode-map nil)
-(defvar gnus-summary-mode-map nil)
 (defvar gnus-article-mode-map nil)
 (defvar gnus-kill-file-mode-map nil)
 
@@ -1134,14 +1277,15 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-summary-mode-line-format-spec nil)
 (defvar gnus-article-mode-line-format-spec nil)
 (defvar gnus-group-mode-line-format-spec nil)
-
+(defvar gnus-summary-expunge-below nil)
 (defvar gnus-reffed-article-number nil)
 
 (defvar rmail-default-file (expand-file-name "~/XMBOX"))
 (defvar rmail-default-rmail-file (expand-file-name "~/XNEWS"))
 
 (defconst gnus-summary-local-variables 
-  '(gnus-newsgroup-name gnus-newsgroup-begin gnus-newsgroup-end 
+  '(gnus-newsgroup-name 
+    gnus-newsgroup-begin gnus-newsgroup-end 
     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail 
     gnus-newsgroup-last-folder gnus-newsgroup-last-file 
     gnus-newsgroup-auto-expire gnus-newsgroup-unreads 
@@ -1149,18 +1293,22 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
     gnus-newsgroup-replied gnus-newsgroup-expirable
     gnus-newsgroup-processable gnus-newsgroup-killed
     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
-    gnus-newsgroup-dormant-subjects gnus-newsgroup-expunged-lines
+    gnus-newsgroup-dormant-subjects gnus-newsgroup-expunged-buffer
     gnus-newsgroup-headers gnus-newsgroup-headers-hashtb-by-number
     gnus-current-article gnus-current-headers gnus-have-all-headers
     gnus-last-article gnus-article-internal-prepare-hook
-    gnus-newsgroup-selected-overlay)
-  "Variables that are buffer-local to the Summary buffers.")
+    gnus-newsgroup-selected-overlay gnus-newsgroup-dependencies
+    gnus-newsgroup-scored gnus-newsgroup-kill-headers
+    gnus-score-alist gnus-summary-expunge-below 
+    gnus-summary-mark-below gnus-newsgroup-ancient)
+  "Variables that are buffer-local to the summary buffers.")
 
 (defvar gnus-mark-article-hook
   (list
    (lambda ()
      (or (memq gnus-current-article gnus-newsgroup-marked)
         (memq gnus-current-article gnus-newsgroup-dormant)
+        (memq gnus-current-article gnus-newsgroup-expirable)
         (gnus-summary-mark-as-read gnus-current-article))))
   "A hook called when an article is selected at the first time.
 The hook is intended to mark an article as read (or unread)
@@ -1197,15 +1345,33 @@ If you'd like to tick articles instead, use the following hook:
   
   (autoload 'gnus-group-make-menu-bar "gnus-visual")
   (autoload 'gnus-summary-make-menu-bar "gnus-visual")
+  (autoload 'gnus-article-make-menu-bar "gnus-visual")
   (autoload 'gnus-visual-highlight-selected-summary "gnus-visual")
   (autoload 'gnus-visual-summary-highlight-line "gnus-visual")
+
+  (autoload 'gnus-uu-decode-map "gnus-uu" nil nil 'keymap)
+  (autoload 'gnus-uu-mark-by-regexp "gnus-uu")
+  (autoload 'gnus-uu-mark-region "gnus-uu")
+  (autoload 'gnus-uu-mark-thread "gnus-uu")
+  (autoload 'gnus-uu-mark-sparse "gnus-uu")
+  (autoload 'gnus-uu-post-news "gnus-uu")
+  (autoload 'gnus-uu-digest-and-forward "gnus-uu")
+  (autoload 'gnus-uu-decode-uu "gnus-uu")
+  (autoload 'gnus-uu-decode-uu-and-save "gnus-uu")
+  (autoload 'gnus-uu-decode-unshar "gnus-uu")
+  (autoload 'gnus-uu-decode-unshar-and-save "gnus-uu")
+  (autoload 'gnus-uu-decode-save "gnus-uu")
+  (autoload 'gnus-uu-decode-save "gnus-uu")
+  (autoload 'gnus-uu-decode-binhex "gnus-uu")
+  (autoload 'gnus-uu-decode-binhex "gnus-uu")
+
+  (autoload 'pp "pp")
   )
 
 (put 'gnus-group-mode 'mode-class 'special)
 (put 'gnus-summary-mode 'mode-class 'special)
 (put 'gnus-article-mode 'mode-class 'special)
 
-(autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap)
 \f
 
 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
@@ -1239,7 +1405,7 @@ Optional argument HASHSIZE specifies the table size."
 (defmacro gnus-sethash (string value hashtable)
   "Set hash value. Arguments are STRING, VALUE, and HASHTABLE."
   ;; We cannot use define-abbrev since it only accepts string as value.
-;  (set (intern string hashtable) value))
+                                       ;  (set (intern string hashtable) value))
   (` (set (intern (, string) (, hashtable)) (, value))))
 
 (defsubst gnus-buffer-substring (beg end)
@@ -1252,6 +1418,9 @@ Optional argument HASHSIZE specifies the table size."
        (substring subject (match-end 0))
       subject)))
 
+(defsubst gnus-goto-char (point)
+  (and point (goto-char point)))
+
 \f
 ;;;
 ;;; Gnus Utility Functions
@@ -1262,10 +1431,11 @@ Optional argument HASHSIZE specifies the table size."
     (if (string-match "([^)]+)" from)
        (setq name (substring from (1+ (match-beginning 0)) 
                              (1- (match-end 0)))))
-    (if (string-match "\\b[^@ \t<>]+@[^@ \t<>]+\\b" from)
+    ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+    (if (string-match "\\b[^@ \t<>]+[!@][^@ \t<>]+\\b" from)
        (setq address (substring from (match-beginning 0) (match-end 0))))
     (if (and (not name) address)
-       (if (string-match (concat "<" address ">") from)
+       (if (string-match (concat "<" (regexp-quote address) ">") from)
            (setq name (substring from 0 (1- (match-beginning 0))))))
     (list (or name from) (or address from))))
 
@@ -1301,11 +1471,11 @@ Optional argument HASHSIZE specifies the table size."
   (setq gnus-summary-dummy-line-format-spec 
        (gnus-parse-format gnus-summary-dummy-line-format 
                           gnus-summary-dummy-line-format-alist))
-  (if (and (memq 'newsgroup-description
-                (cdr (cdr (setq gnus-group-line-format-spec 
-                                (gnus-parse-format 
-                                 gnus-group-line-format 
-                                 gnus-group-line-format-alist)))))
+  (setq gnus-group-line-format-spec
+       (gnus-parse-format 
+        gnus-group-line-format 
+        gnus-group-line-format-alist))
+  (if (and (string-match "%D" gnus-group-line-format)
           (not gnus-description-hashtb))
       (gnus-read-descriptions-file))
   (setq gnus-summary-mode-line-format-spec 
@@ -1324,12 +1494,39 @@ Optional argument HASHSIZE specifies the table size."
        (format "%s" (substring result 0 length))
       (format "%s" result))))
 
+(defun gnus-set-mouse-face (string)
+  ;; Set mouse face property on STRING.
+  (put-text-property 0 (length string) 'mouse-face gnus-mouse-face string)
+  string)
+
 (defun gnus-parse-format (format spec-alist)
-;; This function parses the FORMAT string with the help of the
-;; SPEC-ALIST and returns a list that can be eval'ed to return the
-;; string. The list will consist of the symbol `format', a format
-;; specification string, and a list of forms depending on the
-;; SPEC-ALIST.
+  ;; This function parses the FORMAT string with the help of the
+  ;; SPEC-ALIST and returns a list that can be eval'ed to return the
+  ;; string.  If the FORMAT string contains the specifiers %( and %)
+  ;; the text between them will have the mouse-face text property.
+  (if (string-match "\\`\\(.*\\)%(\\(.*\\)%)\\(.*\n?\\)\\'" format)
+      (if (and gnus-visual gnus-mouse-face)
+         (let ((pre (substring format (match-beginning 1) (match-end 1)))
+               (button (substring format (match-beginning 2) (match-end 2)))
+               (post (substring format (match-beginning 3) (match-end 3))))
+           (list 'concat
+                 (gnus-parse-simple-format pre spec-alist)
+                 (list 'gnus-set-mouse-face
+                       (gnus-parse-simple-format button spec-alist))
+                 (gnus-parse-simple-format post spec-alist)))
+       (gnus-parse-simple-format
+        (concat (substring format (match-beginning 1) (match-end 1))
+                (substring format (match-beginning 2) (match-end 2))
+                (substring format (match-beginning 3) (match-end 3)))
+        spec-alist))
+    (gnus-parse-simple-format format spec-alist)))
+
+(defun gnus-parse-simple-format (format spec-alist)
+  ;; This function parses the FORMAT string with the help of the
+  ;; SPEC-ALIST and returns a list that can be eval'ed to return the
+  ;; string. The list will consist of the symbol `format', a format
+  ;; specification string, and a list of forms depending on the
+  ;; SPEC-ALIST.
   (let ((max-width 0)
        spec flist fstring b newspec max-width elem beg)
     (save-excursion
@@ -1339,7 +1536,7 @@ Optional argument HASHSIZE specifies the table size."
       (erase-buffer)
       (insert format)
       (goto-char 1)
-      (while (re-search-forward "%[-0-9]*\\(,[0-9]*\\)*\\(.\\)" nil t)
+      (while (re-search-forward "%[-0-9]*\\(,[0-9]*\\)*\\(.\\)\\(.\\)?" nil t)
        (setq spec (string-to-char (buffer-substring (match-beginning 2)
                                                     (match-end 2))))
        ;; First check if there are any specs that look anything like
@@ -1354,7 +1551,18 @@ Optional argument HASHSIZE specifies the table size."
        ;; Find the specification from `spec-alist'.
        (if (not (setq elem (cdr (assq spec spec-alist))))
            (setq elem '("*" ?s)))
-       (if (not (= max-width 0))
+       ;; Treat user defined format specifiers specially
+       (and (eq (car elem) 'user-defined)
+            (setq elem
+                  (list 
+                   (list (intern (concat "gnus-user-format-function-"
+                                         (buffer-substring
+                                          (match-beginning 3)
+                                          (match-end 3))))
+                         'header)
+                   ?s))
+            (delete-region (match-beginning 3) (match-end 3)))
+       (if (not (zerop max-width))
            (progn
              (setq flist (cons (list 'gnus-format-max-width 
                                      (car elem) max-width) flist))
@@ -1372,9 +1580,11 @@ Optional argument HASHSIZE specifies the table size."
 
 ;; Suggested by Brian Edmonds <edmonds@cs.ubc.ca>.
 (defun gnus-read-init-file ()
-  (if (and gnus-init-file
-          (file-exists-p gnus-init-file))
-      (load gnus-init-file nil t)))
+  (and gnus-init-file
+       (or (file-exists-p gnus-init-file)
+          (file-exists-p (concat gnus-init-file ".el"))
+          (file-exists-p (concat gnus-init-file ".elc")))
+       (load gnus-init-file nil t)))
 
 ;; Article file names when saving.
 
@@ -1455,7 +1665,7 @@ Otherwise, it is like ~/News/news/group/news."
                 (string-match prefix (car (cdr groups))))
            (progn
              (setq prefixes (cons prefix prefixes))
-             (message "Descend hierarchy %s'? ([y]nsq): " 
+             (message "Descend hierarchy %s? ([y]nsq): " 
                       (substring prefix 1 (1- (length prefix))))
              (setq ans (read-char))
              (cond ((= ans ?n)
@@ -1472,8 +1682,7 @@ Otherwise, it is like ~/News/news/group/news."
                                 (string-match prefix 
                                               (setq group (car groups))))
                       (gnus-sethash group group gnus-killed-hashtb)
-                      (funcall gnus-subscribe-newsgroup-method 
-                               (car groups))
+                      (gnus-subscribe-alphabetically (car groups))
                       (setq groups (cdr groups)))
                     (setq starts (cdr starts)))
                    ((= ans ?q)
@@ -1483,10 +1692,11 @@ Otherwise, it is like ~/News/news/group/news."
                       (gnus-sethash group group gnus-killed-hashtb)
                       (setq groups (cdr groups))))
                    (t nil)))
-         (message "Subscribe '%s'? ([n]yq)" (car groups))
+         (message "Subscribe %s? ([n]yq)" (car groups))
          (setq ans (read-char))
+         (setq group (car groups))
          (cond ((= ans ?y)
-                (funcall gnus-subscribe-newsgroup-method (car groups))
+                (gnus-subscribe-alphabetically (car groups))
                 (gnus-sethash group group gnus-killed-hashtb))
                ((= ans ?q)
                 (while groups
@@ -1574,38 +1784,25 @@ the first newsgroup."
     newsgroup
     ))
 
-(defun gnus-make-directory (directory)
+(defun gnus-make-directory (dir)
   "Make DIRECTORY recursively."
-  (let ((directory (expand-file-name directory default-directory)))
-    (or (file-exists-p directory)
-       (gnus-make-directory-1 "" directory))
-    ))
-
-(defun gnus-make-directory-1 (head tail)
-  (cond ((string-match "^/\\([^/]+\\)" tail)
-        ;; ange-ftp interferes with calling match-* after
-        ;; calling file-name-as-directory.
-        (let ((beg (match-beginning 1))
-              (end (match-end 1)))
-          (setq head (concat (file-name-as-directory head)
-                             (substring tail beg end)))
-          (or (file-exists-p head)
-              (call-process "mkdir" nil nil nil head))
-          (gnus-make-directory-1 head (substring tail end))))
-       ((string-equal tail "") t)
-       ))
+  (let* ((dir (expand-file-name dir default-directory))
+        dirs)
+    (if (string-match "/$" dir)
+       (setq dir (substring dir 0 (match-beginning 0))))
+    (while (not (file-exists-p dir))
+      (setq dirs (cons dir dirs))
+      (string-match "/[^/]+$" dir)
+      (setq dir (substring dir 0 (match-beginning 0))))
+    (while dirs
+      (make-directory (car dirs))
+      (setq dirs (cdr dirs)))))
 
 (defun gnus-capitalize-newsgroup (newsgroup)
-  "Capitalize NEWSGROUP name with treating '.' and '-' as part of words."
-  ;; Suggested by "Jonathan I. Kamens" <jik@pit-manager.MIT.EDU>.
-  (let ((current-syntax-table (syntax-table)))
-    (unwind-protect
-       (progn
-         (set-syntax-table (copy-syntax-table current-syntax-table))
-         (modify-syntax-entry ?- "w")
-         (modify-syntax-entry ?. "w")
-         (capitalize newsgroup))
-      (set-syntax-table current-syntax-table))))
+  "Capitalize NEWSGROUP name."
+  (and (not (zerop (length newsgroup)))
+       (concat (char-to-string (upcase (aref newsgroup 0)))
+              (substring newsgroup 1))))
 
 ;; Var
 
@@ -1689,6 +1886,9 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
        (kill-buffer (get-file-buffer gnus-current-startup-file)))
   (setq gnus-current-startup-file nil)
   (gnus-dribble-clear)
+  ;; Kill global KILL file buffer.
+  (if (get-file-buffer (gnus-newsgroup-kill-file nil))
+      (kill-buffer (get-file-buffer (gnus-newsgroup-kill-file nil))))
   ;; Kill Gnus buffers.
   (while gnus-buffer-list
     (if (and (get-buffer (car gnus-buffer-list))
@@ -1715,7 +1915,10 @@ or not."
         (height nil)
         (grpheight 0)
         (subheight 0)
-        (artheight 0))
+        (artheight 0)
+
+        ;; Make split-window-vertically leave focus in upper window.
+        (split-window-keep-point t))
     (if (and (symbolp windows) (fboundp windows))
        (funcall windows action)
       (if (and (not force)
@@ -1738,8 +1941,8 @@ or not."
               (setq height (+ (if grpwin (window-height grpwin) 0)
                               (if subwin (window-height subwin) 0)
                               (if artwin (window-height artwin) 0)))))
-       ;; The Newsgroup buffer exits always. So, use it to extend the
-       ;; Group window so as to get enough window space.
+       ;; The group buffer exits always. So, use it to extend the
+       ;; group window so as to get enough window space.
        (switch-to-buffer gnus-group-buffer 'norecord)
        (and (get-buffer gnus-summary-buffer)
             (delete-windows-on gnus-summary-buffer))
@@ -1767,27 +1970,31 @@ or not."
             (not (zerop subheight))
             (split-window-vertically grpheight))
        ;; Then select buffers in each window.
-       (and (not (zerop grpheight))
-            (progn
-              (switch-to-buffer gnus-group-buffer 'norecord)
-              (other-window 1)))
-       (and (not (zerop subheight))
-            (progn
-              (switch-to-buffer gnus-summary-buffer 'norecord)
-              (other-window 1)))
-       (and (not (zerop artheight))
-            (progn
-              ;; If Article buffer does not exist, it will be created
-              ;; and initialized.
-              (gnus-article-setup-buffer)
-              (switch-to-buffer gnus-article-buffer 'norecord)))))
-    ))
+       (or (zerop grpheight)
+           (progn
+             (switch-to-buffer gnus-group-buffer 'norecord)
+             (other-window 1)))
+       (or (zerop subheight)
+           (progn
+             (switch-to-buffer gnus-summary-buffer 'norecord)
+             (other-window 1)))
+       (or (zerop artheight)
+           (progn
+             ;; If article buffer does not exist, it will be created
+             ;; and initialized.
+             (gnus-article-setup-buffer)
+             (switch-to-buffer gnus-article-buffer 'norecord)
+             (bury-buffer gnus-summary-buffer)
+             (bury-buffer gnus-group-buffer)))
+       (or (zerop subheight)
+           (pop-to-buffer gnus-summary-buffer))
+       ))))
 
 (defun gnus-window-configuration-split (action)
   (switch-to-buffer gnus-group-buffer t)
   (delete-other-windows)
   (split-window-horizontally)
-  (cond ((or (eq action 'newsgroup) (eq action 'summary))
+  (cond ((or (eq action 'newsgroups) (eq action 'summary))
         (if (and (get-buffer gnus-summary-buffer)
                  (buffer-name gnus-summary-buffer))
             (switch-to-buffer-other-window gnus-summary-buffer)))
@@ -1837,8 +2044,44 @@ or not."
   (search-forward mail-header-separator)
   (forward-line 1)
   (insert (format "%s\n%s\n\n" (gnus-version) (emacs-version)))
+  (gnus-debug)
+  (mail-mode)
   (message ""))
 
+(defun gnus-debug ()
+  "Attemps to go through the Gnus source file and report what variables have been changed.
+The source file has to be in the Emacs load path."
+  (interactive)
+  (let ((dirs load-path)
+       file expr olist)
+    (while dirs
+      (if (file-exists-p (setq file (concat (car dirs) "/gnus.el")))
+         (save-excursion
+           (setq dirs nil)
+           (set-buffer (get-buffer-create "*gnus bug info*"))
+           (buffer-disable-undo)
+           (erase-buffer)
+           (insert-file-contents file)
+           (goto-char (point-min))
+           (or (search-forward "\n;; Internal variables" nil t)
+               (error "Malformed sources"))
+           (narrow-to-region (point-min) (point))
+           (goto-char (point-min))
+           (while (setq expr (condition-case () 
+                                 (read (current-buffer)) (error nil)))
+             (and (eq (car expr) 'defvar)
+                  (stringp (nth 3 expr))
+                  (not (equal (eval (nth 2 expr))
+                              (symbol-value (nth 1 expr))))
+                  (setq olist (cons (nth 1 expr) olist))))
+           (kill-buffer (current-buffer)))
+       (setq dirs (cdr dirs))))
+    (while olist
+      (insert (symbol-name (car olist)) ": " 
+             (prin1-to-string (symbol-value (car olist))) "\n")
+      (setq olist (cdr olist)))
+    (insert "\n\n")))
+
 (defun gnus-overload-functions (&optional overloads)
   "Overload functions specified by optional argument OVERLOADS.
 If nothing is specified, use the variable gnus-overload-functions."
@@ -1855,6 +2098,35 @@ If nothing is specified, use the variable gnus-overload-functions."
       (fset (car defs) (car (cdr defs)))
       )))
 
+(defun gnus-replace-chars-in-string (string from to)
+  "Replace characters in STRING from FROM to TO."
+  (let ((string (substring string 0))  ;Copy string.
+       (len (length string))
+       (idx 0))
+    ;; Replace all occurrences of FROM with TO.
+    (while (< idx len)
+      (if (= (aref string idx) from)
+         (aset string idx to))
+      (setq idx (1+ idx)))
+    string))
+
+(defun gnus-days-between (date1 date2)
+  ;; Return the number of days between date1 and date2.
+  (let ((d1 (mapcar (lambda (s) (and s (string-to-int s)) )
+                   (timezone-parse-date date1)))
+       (d2 (mapcar (lambda (s) (and s (string-to-int s)) )
+                   (timezone-parse-date date2))))
+    (- (timezone-absolute-from-gregorian 
+       (nth 1 d1) (nth 2 d1) (car d1))
+       (timezone-absolute-from-gregorian 
+       (nth 1 d2) (nth 2 d2) (car d2)))))
+
+(defun gnus-file-newer-than (file date)
+  (let ((fdate (nth 5 (file-attributes file))))
+    (or (> (car fdate) (car date))
+       (and (= (car fdate) (car date))
+            (> (nth 1 fdate) (nth 1 date))))))
+
 ;; List and range functions
 
 (defun gnus-last-element (list)
@@ -1931,33 +2203,47 @@ these ranges."
 Note: LIST has to be sorted over `<'."
   (let* ((ranges (if (and ranges (atom (car ranges))) (list ranges) ranges))
         (inrange ranges)
+        did-one
         range nranges first last)
-    (if (not ranges)
-       (gnus-compress-sequence list t)
-      (while (and ranges list)
-       (setq range (car ranges))
-       (while (and list (<= (car list) (cdr range)))
-         (setq list (cdr list)))
-       (while (and list (= (1- (car list)) (cdr range)))
-         (setcdr range (car list))
-         (setq list (cdr list)))
-       (if (and list (and (> (car list) (cdr range)) (cdr ranges)
-                          (< (car list) (car (car (cdr ranges))))))
-           (setcdr ranges (cons (cons (car list) (car list)) (cdr ranges))))
-       (setq ranges (cdr ranges)))
-      (if (and list (not ranges))
-         (setq inrange (nconc inrange (gnus-compress-sequence list t))))
-      (setq ranges inrange)
-      (while ranges
-       (if (and (cdr ranges) (>= (1+ (cdr (car ranges)))
-                                 (car (car (cdr ranges)))))
-           (progn
-             (setcdr (car ranges) (cdr (car (cdr ranges))))
-             (setcdr ranges (cdr (cdr ranges))))
-         (setq ranges (cdr ranges))))
-      (if (not (cdr inrange))
-         (car inrange)
-       inrange))))
+    (if (not list)
+       ranges
+      (if (not ranges)
+         (gnus-compress-sequence list t)
+       (and ranges 
+            (> (car (car ranges)) 1)
+            (progn
+              (setq did-one t)
+              (setq inrange (setq ranges (cons (cons 1 1) ranges)))))
+       (while (and ranges list)
+         (setq range (car ranges))
+         (while (and list (>= (car list) (car range))
+                     (<= (car list) (cdr range)))
+           (setq list (cdr list)))
+         (while (and list (= (1- (car list)) (cdr range)))
+           (setcdr range (car list))
+           (setq list (cdr list)))
+         (if (and list (and (> (car list) (cdr range)) 
+                            (cdr ranges)
+                            (< (car list) (car (car (cdr ranges))))))
+             (setcdr ranges (cons (cons (car list) (car list)) (cdr ranges))))
+         (setq ranges (cdr ranges)))
+       (if (and list (not ranges))
+           (setq inrange (nconc inrange (gnus-compress-sequence list t))))
+       (if did-one
+           (if (eq (cdr (car inrange)) 1)
+               (setq inrange (cdr inrange))
+             (setcar (car inrange) 2)))
+       (setq ranges inrange)
+       (while ranges
+         (if (and (cdr ranges) (>= (1+ (cdr (car ranges)))
+                                   (car (car (cdr ranges)))))
+             (progn
+               (setcdr (car ranges) (cdr (car (cdr ranges))))
+               (setcdr ranges (cdr (cdr ranges))))
+           (setq ranges (cdr ranges))))
+       (if (not (cdr inrange))
+           (car inrange)
+         inrange)))))
 
 (defun gnus-remove-from-range (ranges list)
   "Return a list of ranges that has all articles from LIST removed from RANGES.
@@ -1978,7 +2264,7 @@ Note: LIST has to be sorted over `<'."
 
 \f
 ;;;
-;;; Gnus Group Mode
+;;; Gnus group mode
 ;;;
 
 (if gnus-group-mode-map
@@ -2014,9 +2300,10 @@ Note: LIST has to be sorted over `<'."
   (define-key gnus-group-mode-map "\M-d" 'gnus-group-describe-all-groups)
   (define-key gnus-group-mode-map "\C-c\C-a" 'gnus-group-apropos)
   (define-key gnus-group-mode-map "\C-c\M-C-a" 'gnus-group-description-apropos)
+  (define-key gnus-group-mode-map "d" 'gnus-group-make-directory-group)
   (define-key gnus-group-mode-map "a" 'gnus-group-post-news)
-  (define-key gnus-group-mode-map "\M-a" 'gnus-group-add-newsgroup)
-  (define-key gnus-group-mode-map "\M-e" 'gnus-group-edit-newsgroup)
+  (define-key gnus-group-mode-map "\M-a" 'gnus-group-add-group)
+  (define-key gnus-group-mode-map "\M-e" 'gnus-group-edit-group)
   (define-key gnus-group-mode-map "\ek" 'gnus-group-edit-local-kill)
   (define-key gnus-group-mode-map "\eK" 'gnus-group-edit-global-kill)
   (define-key gnus-group-mode-map "\C-k" 'gnus-group-kill-group)
@@ -2039,7 +2326,7 @@ Note: LIST has to be sorted over `<'."
   (define-key gnus-group-mode-map "?" 'gnus-group-describe-briefly)
   (define-key gnus-group-mode-map "\C-c\C-i" 'gnus-info-find-node)
   (define-key gnus-group-mode-map [mouse-2] 'gnus-mouse-pick-group)
-  (gnus-group-make-menu-bar))
+  (if gnus-visual (gnus-group-make-menu-bar)))
 
 (defun gnus-group-mode ()
   "Major mode for reading news.
@@ -2068,13 +2355,14 @@ The following commands are available:
 \\[gnus-group-restart]\t Restart Gnus
 \\[gnus-group-save-newsrc]\t Save the startup file(s)
 \\[gnus-group-browse-foreign-server]\t Browse a foreign (NNTP) server
-\\[gnus-group-check-bogus-groups]\t Check for and delete bogus newsgroups
+\\[gnus-group-check-bogus-groups]\t Check for and remove bogus newsgroups
 \\[gnus-find-new-newsgroups]\t Find new newsgroups
 \\[gnus-group-describe-group]\t Describe the current newsgroup
 \\[gnus-group-describe-all-groups]\t Describe all newsgroups
 \\[gnus-group-post-news]\t Post an article to some newsgroup
-\\[gnus-group-add-newsgroup]\t Add a newsgroup entry
-\\[gnus-group-edit-newsgroup]\t Edit a newsgroup entry
+\\[gnus-group-add-group]\t Add a newsgroup entry
+\\[gnus-group-edit-group]\t Edit a newsgroup entry
+\\[gnus-group-make-directory-group]\t Read a directory as a newsgroups
 \\[gnus-group-edit-local-kill]\t Edit a local kill file
 \\[gnus-group-edit-global-kill]\t Edit the global kill file
 \\[gnus-group-kill-group]\t Kill the current newsgroup
@@ -2097,9 +2385,13 @@ The following commands are available:
 "
   (interactive)
   (kill-all-local-variables)
-  (setq mode-line-modified "--- ")
+  (setq mode-line-modified "-- ")
+  (make-local-variable 'mode-line-format)
+  (setq mode-line-format (copy-sequence mode-line-format))
+  (and (equal (nth 3 mode-line-format) "   ")
+       (setcar (nthcdr 3 mode-line-format) ""))
   (setq major-mode 'gnus-group-mode)
-  (setq mode-name "Newsgroup")
+  (setq mode-name "Group")
   (gnus-group-set-mode-line)
   (setq mode-line-process nil)
   (use-local-map gnus-group-mode-map)
@@ -2116,12 +2408,13 @@ The following commands are available:
 ;;;###autoload
 (defun gnus-no-server (&optional arg)
   "Read network news.
-If ARG is non-nil and a positive number, Gnus will use that as the
-startup level. If ARG is non-nil and not a positive number, Gnus will
+If ARG is a positive number, Gnus will use that as the
+startup level. If ARG is nil, Gnus will be started at level 2. 
+If ARG is non-nil and not a positive number, Gnus will
 prompt the user for the name of an NNTP server to use.
 As opposed to `gnus', this command will not connect to the local server."
   (interactive "P")
-  (gnus arg t))
+  (gnus (or arg 2) t))
 
 (defalias '\(ding\) 'gnus)
 
@@ -2132,35 +2425,37 @@ If ARG is non-nil and a positive number, Gnus will use that as the
 startup level. If ARG is non-nil and not a positive number, Gnus will
 prompt the user for the name of an NNTP server to use."
   (interactive "P")
-  (gnus-clear-system)
-  (gnus-read-init-file)
-  (if (and gnus-signature-file mail-signature)
-      (setq gnus-signature-file nil))
-  (let ((level (and arg (numberp arg) (> arg 0) arg)))
-    (unwind-protect
-       (progn
-         (switch-to-buffer (get-buffer-create gnus-group-buffer))
-         (gnus-add-current-to-buffer-list)
-         (gnus-group-mode)
-         (or dont-connect (gnus-start-news-server (and arg (not level)))))
-      (if (and (not dont-connect) 
-              (not (gnus-server-opened gnus-select-method)))
-         (gnus-group-quit)
-       ;; NNTP server is successfully open. 
-       (gnus-update-format-specifications)
-       (let ((buffer-read-only nil))
-         (erase-buffer)
-         (if (not gnus-inhibit-startup-message)
-             (progn
-               (gnus-group-startup-message)
-               (sit-for 0))))
-       (run-hooks 'gnus-startup-hook)
-       (gnus-setup-news nil level)
-       (gnus-dribble-open)
-       (or (not gnus-novice-user)
-           gnus-expert-user
-           (gnus-group-describe-briefly)) ;Show brief help message.
-       (gnus-group-list-groups (or level 5))))))
+  (if (get-buffer gnus-group-buffer)
+      (progn
+       (switch-to-buffer gnus-group-buffer)
+       (gnus-group-get-new-news))
+    (gnus-clear-system)
+    (gnus-read-init-file)
+    (let ((level (and arg (numberp arg) (> arg 0) arg)))
+      (unwind-protect
+         (progn
+           (switch-to-buffer (get-buffer-create gnus-group-buffer))
+           (gnus-add-current-to-buffer-list)
+           (gnus-group-mode)
+           (or dont-connect (gnus-start-news-server (and arg (not level)))))
+       (if (and (not dont-connect) 
+                (not (gnus-server-opened gnus-select-method)))
+           (gnus-group-quit)
+         ;; NNTP server is successfully open. 
+         (gnus-update-format-specifications)
+         (let ((buffer-read-only nil))
+           (erase-buffer)
+           (if (not gnus-inhibit-startup-message)
+               (progn
+                 (gnus-group-startup-message)
+                 (sit-for 0))))
+         (run-hooks 'gnus-startup-hook)
+         (gnus-setup-news nil level)
+         (gnus-dribble-open)
+         (or (not gnus-novice-user)
+             gnus-expert-user
+             (gnus-group-describe-briefly)) ;Show brief help message.
+         (gnus-group-list-groups (or level 5)))))))
 
 (defun gnus-group-startup-message (&optional x y)
   "Insert startup message in current buffer."
@@ -2183,7 +2478,7 @@ Lars Ingebrigtsen
   ;; And then hack it.
   ;; 18 is the longest line.
   (indent-rigidly (point-min) (point-max) 
-                 (/ (max (- (window-width) (or x 28)) 0) 2))
+                 (/ (max (- (window-width) (or x 22)) 0) 2))
   (goto-char (point-min))
   ;; +4 is fuzzy factor.
   (insert-char ?\n (/ (max (- (window-height) (or y 12)) 0) 2)))
@@ -2196,24 +2491,28 @@ If argument UNREAD is non-nil, groups with no unread articles are also listed."
   (setq level (or level 5))
   (let ((case-fold-search nil)
        (group (gnus-group-group-name)))
-    (set-buffer gnus-group-buffer)     ;May call from out of Group buffer
+    (set-buffer gnus-group-buffer)     ;May call from out of group buffer
     (gnus-group-prepare level unread)
     (if (zerop (buffer-size))
        ;; Suggested by Andrew Eskilsson <pi92ae@lelle.pt.hk-r.se>.
        (message "No news is horrible news")
       (goto-char (point-min))
       (if (not group)
-         ()
+         ;; Go to the first group with unread articles.
+         (gnus-group-search-forward nil nil nil t)
        ;; Find the right group to put point on. If the current group
        ;; has disapeared in the new listing, try to find the next
        ;; one. If no next one can be found, just leave point at the
        ;; first newsgroup in the buffer.
-       (if (not (re-search-forward (gnus-group-make-regexp group) nil t))
+       (if (not (gnus-goto-char
+                 (text-property-any (point-min) (point-max) 
+                                    'gnus-group (intern group))))
            (let ((newsrc (nthcdr 3 (gnus-gethash group gnus-newsrc-hashtb))))
              (while (and newsrc
-                         (not (re-search-forward 
-                               (gnus-group-make-regexp (car (car newsrc))) 
-                               nil t)))
+                         (not (gnus-goto-char 
+                               (text-property-any 
+                                (point-min) (point-max) 'gnus-group 
+                                (intern group)))))
                (setq newsrc (cdr newsrc))))))
       ;; Adjust cursor point.
       (gnus-group-position-cursor))))
@@ -2254,13 +2553,15 @@ If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
     ;; suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>. It does
     ;; this by ignoring the group format specification altogether.
     (let ((lists (list 'gnus-zombie-list 'gnus-killed-list))
-         mark beg)
+         mark beg lev)
       (while lists
        (if (or (and (eq (car lists) 'gnus-zombie-list)
                     (progn (setq mark ?Z)
+                           (setq lev 8)
                            (and (>= level 8) (<= lowest 8))))
                (and (eq (car lists) 'gnus-killed-list)
                     (progn (setq mark ?K)
+                           (setq lev 9)
                            (and (>= level 9) (<= lowest 9)))))
            (progn
              (setq newsrc (set (car lists)
@@ -2269,12 +2570,13 @@ If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
              (while newsrc
                (setq group (car newsrc)
                      newsrc (cdr newsrc))
-               (insert (format " %c    *: %s" mark group))
                (setq beg (point))
-               (insert (format " %s  %d\n" group 
-                               (if (= mark ?Z) 8 9)))
-               (set-text-properties beg (1- (point))
-                                    '(invisible t)))))
+               (insert (format " %c    *: %s\n" mark group))
+               (add-text-properties 
+                beg (1+ beg) 
+                (list 'gnus-group (intern group)
+                      'gnus-unread t
+                      'gnus-level lev)))))
        (setq lists (cdr lists))))
 
     (gnus-group-set-mode-line)
@@ -2283,10 +2585,37 @@ If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
 
 (defun gnus-group-real-name (group)
   "Find the real name of a foreign newsgroup."
-  (if (string-match (concat "^" gnus-foreign-group-prefix) group)
+  (if (string-match "^[^:]+:" group)
       (substring group (match-end 0))
     group))
 
+(defun gnus-group-prefixed-name (group method)
+  "Return the whole name from GROUP and METHOD."
+  (concat (format "%s" (car method))
+         (if (assoc (format "%s" (car method)) (gnus-methods-using 'address))
+             (concat "+" (nth 1 method)))
+         ":" group))
+
+(defun gnus-group-real-prefix (group)
+  "Return the prefix of the current group name."
+  (if (string-match "^[^:]+:" group)
+      (substring group 0 (match-end 0))
+    ""))
+
+(defun gnus-group-method-name (group)
+  "Return the method used for selecting GROUP."
+  (let ((prefix (gnus-group-real-prefix group)))
+    (if (equal prefix "")
+       gnus-select-method
+      (if (string-match "^[^\\+]+\\+" prefix)
+         (list (intern (substring prefix 0 (1- (match-end 0))))
+               (substring prefix (match-end 0) (1- (length prefix))))
+       (list (intern (substring prefix 0 (1- (length prefix)))) "")))))
+
+(defun gnus-group-foreign-p (group)
+  "Return nil if GROUP is native, non-nil if it is foreign."
+  (string-match ":" group))
+
 (defun gnus-group-set-info (info)
   (let ((entry (gnus-gethash (car info) gnus-newsrc-hashtb)))
     (if entry
@@ -2301,13 +2630,13 @@ If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
 (defun gnus-group-update-group-line ()
   "This function updates the current line in the newsgroup buffer and
 moves the point to the colon."
-  (let ((group (gnus-group-group-name))
-       (buffer-read-only nil))
-    (let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
-      (if entry
-         (gnus-dribble-enter 
-          (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
-                  ")"))))
+  (let* ((buffer-read-only nil)
+        (group (gnus-group-group-name))
+        (entry (and group (gnus-gethash group gnus-newsrc-hashtb))))
+    (if entry
+       (gnus-dribble-enter 
+        (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
+                ")")))
     (beginning-of-line)
     (delete-region (point) (save-excursion (forward-line 1) (point)))
     (gnus-group-insert-group-line-info group)
@@ -2336,17 +2665,18 @@ moves the point to the colon."
         (number-of-ticked-and-dormant
          (+ number-of-ticked number-of-dormant))
         (number-of-unread-unticked 
-         (if (numberp number) (- number number-of-ticked number-of-dormant)
+         (if (numberp number) 
+             (max 0 (- number number-of-ticked number-of-dormant))
            "*"))
         (number-of-read
          (if (numberp number)
-             (- number-total number)
+             (max 0 (- number-total number))
            "*"))
         (subscribed (cond ((< level 6) ? )
                           ((< level 8) ?U)
                           ((= level 8) ?Z)
                           (t ?K)))
-        (buffer-read-only nil)
+        (qualified-group (gnus-group-real-name group))
         (newsgroup-description 
          (if gnus-description-hashtb
              (or (gnus-gethash group gnus-description-hashtb) "")
@@ -2365,79 +2695,69 @@ moves the point to the colon."
                             (length (cdr (assq 'dormant marked)))) number)
                      (> (length (cdr (assq 'tick marked))) 0))
                     ?* ? ))
+        (buffer-read-only nil)
         b)
     (beginning-of-line)
     (setq b (point))
-    (let ((group (if method (gnus-group-real-name group) group)))
-      ;; Insert the visible text.
-      (insert-before-markers (eval gformat)))
-    (forward-char -1)
-    (if (and gnus-visual gnus-mouse-face)
-       (overlay-put (make-overlay b (point)) 'mouse-face gnus-mouse-face))
-    ;; Insert the invisible info on the end of the line.
-    (set-text-properties 
-     (prog1 
-        (point)
-       ;; The info is GROUP UNREAD MARKED LEVEL.
-       (insert (format 
-               " %s%c%c%d" group (if (or (stringp number) (> number 0)) ?+ ? )
-               marked level)))
-     (point) '(invisible t))
-    (forward-char 1)))
+    ;; Insert the visible text.
+    (insert-before-markers (eval gformat))
+    (add-text-properties 
+     b (1+ b) (list 'gnus-group (intern group)
+                   'gnus-unread (if (numberp number-of-unread-unticked)
+                                    number-of-unread-unticked t)
+                   'gnus-marked marked
+                   'gnus-level level))))
 
 (defun gnus-group-update-group (group &optional visible-only)
   "Update newsgroup info of GROUP.
 If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't already."
-  (let ((buffer-read-only nil)
-       (case-fold-search nil)
-       (regexp (gnus-group-make-regexp group))
-       (visible nil))
-    (let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
-      (if entry
-         (gnus-dribble-enter 
-          (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
-                  ")"))))
-    ;; Buffer may be narrowed.
-    (save-restriction
-      (widen)
-      ;; Search a line to modify.  If the buffer is large, the search
-      ;; takes long time.  In most cases, current point is on the line
-      ;; we are looking for.  So, first of all, check current line. 
-      ;; And then if current point is in the first half, search from
-      ;; the beginning.  Otherwise, search from the end.
-      (if (cond ((progn
-                  (beginning-of-line)
-                  (looking-at regexp)))
-               ((and (> (/ (buffer-size) 2) (point)) ;In the first half.
-                     (progn
-                       (goto-char (point-min))
-                       (re-search-forward regexp nil t))))
-               ((progn
-                  (goto-char (point-max))
-                  (re-search-backward regexp nil t))))
-         ;; GROUP is listed in current buffer. So, delete old line.
-         (progn
-           (setq visible t)
-           (beginning-of-line)
-           (delete-region (point) (progn (forward-line 1) (point))))
-       ;; No such line in the buffer, find out where it's supposed to
-       ;; go, and insert it there (or at the end of the buffer).
-       ;; Fix by Per Abrahamsen <amanda@iesd.auc.dk>.
-       (or visible-only
-           (let ((entry (cdr (gnus-gethash group gnus-newsrc-hashtb))))
-             (goto-char (point-min))
-             (while (and entry
-                         (not (re-search-forward (gnus-group-make-regexp
-                                                  (car (car entry))) nil t)))
-               (setq entry (cdr entry)))
-             (if (not entry)
-                 (goto-char (point-max))))))
-      (if (or visible (not visible-only))
-         (progn
-           (gnus-group-insert-group-line-info group)
-           (forward-line -1)           ; Move point back to the inserted line.
-           ))))
-  (gnus-group-set-mode-line))
+  (save-excursion
+    (set-buffer gnus-group-buffer)
+    (let ((buffer-read-only nil)
+         (visible nil))
+      (let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
+       (if entry
+           (gnus-dribble-enter 
+            (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
+                    ")"))))
+      ;; Buffer may be narrowed.
+      (save-restriction
+       (widen)
+       ;; Search a line to modify.  If the buffer is large, the search
+       ;; takes long time.  In most cases, current point is on the line
+       ;; we are looking for.  So, first of all, check current line. 
+       (if (or (progn
+                 (beginning-of-line)
+                 (eq (get-text-property (point) 'gnus-group)
+                     (intern group)))
+               (progn
+                 (gnus-goto-char 
+                  (text-property-any 
+                   (point-min) (point-max) 'gnus-group (intern group)))))
+           ;; GROUP is listed in current buffer. So, delete old line.
+           (progn
+             (setq visible t)
+             (beginning-of-line)
+             (delete-region (point) (progn (forward-line 1) (point))))
+         ;; No such line in the buffer, find out where it's supposed to
+         ;; go, and insert it there (or at the end of the buffer).
+         ;; Fix by Per Abrahamsen <amanda@iesd.auc.dk>.
+         (or visible-only
+             (let ((entry (cdr (gnus-gethash group gnus-newsrc-hashtb))))
+               (while (and entry
+                           (not
+                            (gnus-goto-char
+                             (text-property-any
+                              (point-min) (point-max) 
+                              'gnus-group (intern (car (car entry)))))))
+                 (setq entry (cdr entry)))
+               (or entry (goto-char (point-max))))))
+       (if (or visible (not visible-only))
+           (progn
+             (gnus-group-insert-group-line-info group)
+             (forward-line -1)         ; Move point back to the inserted line.
+             ))))
+    (gnus-group-set-mode-line)))
 
 (defun gnus-group-set-mode-line ()
   (if (memq 'group gnus-updated-mode-lines)
@@ -2457,60 +2777,50 @@ If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't already."
 
 (defun gnus-group-group-name ()
   "Get the name of the newsgroup on the current line."
-  (save-excursion
-    (let ((buffer-read-only nil))
-      (beginning-of-line)
-      (if (re-search-forward " \\([^ ]*\\)...$" nil t)
-         (prog2
-             (set-text-properties (match-beginning 1) (match-end 1) nil)
-             (buffer-substring (match-beginning 1) (match-end 1))
-           (set-text-properties (match-beginning 1) (match-end 1) 
-                                '(invisible t)))))))
+  (let ((group (get-text-property 
+               (save-excursion (beginning-of-line) (point)) 'gnus-group)))
+    (and group (symbol-name group))))
 
 (defun gnus-group-group-level ()
   "Get the level of the newsgroup on the current line."
-  (save-excursion
-    (end-of-line)
-    (forward-char -1)
-    (let ((c (following-char)))
-      (if (and (>= c ?1) (<= c ?9))
-         (1+ (- c ?1))))))
-
-(defun gnus-group-make-regexp (newsgroup)
-  "Return regexp that will match the line that NEWSGROUP is on."
-  (concat " " (regexp-quote newsgroup) "...$"))
+  (get-text-property (save-excursion (beginning-of-line) (point)) 'gnus-level))
 
-(defun gnus-group-search-forward (&optional backward all level)
+(defun gnus-group-search-forward (&optional backward all level first-too)
   "Find the next newsgroup with unread articles.
 If BACKWARD is non-nil, find the previous newsgroup instead.
 If ALL is non-nil, just find any newsgroup.
 If LEVEL is non-nil, find group with level LEVEL, or higher if no such
-group exists."
-  (if (not level)
-      (let ((regexp (if all "...$" "\\+.[1-5]$")))
-       (prog1
-           (if backward
-               (progn
-                 (beginning-of-line)
-                 (re-search-backward regexp nil t))
-             (end-of-line)
-             (re-search-forward regexp nil t))
-         (gnus-group-position-cursor)))
-    (let ((beg (point)))
-      (while (and (< level 10)
-                 (goto-char beg)
-                 (let ((regexp (format "%s.%d$" (if all "." "\\+") level)))
-                   (not            
-                    (if backward
-                        (progn
-                          (beginning-of-line)
-                          (re-search-backward regexp nil t))
-                      (end-of-line)
-                      (re-search-forward regexp nil t)))))
-       (setq level (1+ level)))
-      (< level 10))))
+group exists.
+If FIRST-TOO, the current line is also eligeble as a target."
+  (let ((way (if backward -1 1))
+       (low 10)
+       (beg (point))
+       pos found)
+    (or first-too (forward-line way))
+    (while (and 
+           (not (eobp))
+           (not (setq 
+                 found 
+                 (and (or (not all)
+                          (let ((unread 
+                                 (get-text-property (point) 'gnus-unread)))
+                            (or (eq unread t) (and unread (> unread 0)))))
+                      (or (not level)
+                          (let ((lev (get-text-property (point) 'gnus-level)))
+                            (if (<= lev level)
+                                t
+                              (if (< lev low)
+                                  (progn
+                                    (setq low lev)
+                                    (setq pos (point))))
+                              nil))))))
+           (zerop (forward-line way))))
+    (if found 
+       (progn (gnus-group-position-cursor) t)
+      (if pos (goto-char pos) (goto-char beg))
+      nil)))
 
-;; Gnus Group mode command
+;; Gnus group mode commands
 
 (defun gnus-group-read-group (all &optional no-article)
   "Read news in this newsgroup.
@@ -2542,15 +2852,18 @@ If argument ALL is non-nil, already read articles become readable."
   "Jump to newsgroup GROUP."
   (interactive
    (list 
-    (completing-read "Newsgroup: " gnus-active-hashtb nil t)))
-  (let ((case-fold-search nil))
-    (goto-char (point-min))
+    (completing-read "Group: " gnus-active-hashtb nil t)))
+  (let (b)
     ;; Either go to the line in the group buffer...
-    (or (re-search-forward (gnus-group-make-regexp group) nil t)
+    (or (and (setq b (text-property-any (point-min) (point-max) 
+                                       'gnus-group (intern group)))
+            (goto-char b))
        ;; ... or insert the line.
-       (gnus-group-update-group group))
-    ;; Adjust cursor point.
-    (gnus-group-position-cursor)))
+       (progn (gnus-group-update-group group)
+              (goto-char (text-property-any (point-min) (point-max) 
+                                            'gnus-group (intern group))))))
+  ;; Adjust cursor point.
+  (gnus-group-position-cursor))
 
 (defun gnus-group-next-group (n)
   "Go to next N'th newsgroup.
@@ -2572,12 +2885,12 @@ done."
   (interactive "p")
   (let ((backward (< n 0))
        (n (abs n)))
-  (while (and (> n 0)
-             (gnus-group-search-forward backward all level))
-    (setq n (1- n)))
-  (if (/= 0 n) (message "No more%s newsgroups%s" (if all "" " unread")
-                       (if level " on this level or higher" "")))
-  n))
+    (while (and (> n 0)
+               (gnus-group-search-forward backward all level))
+      (setq n (1- n)))
+    (if (/= 0 n) (message "No more%s newsgroups%s" (if all "" " unread")
+                         (if level " on this level or higher" "")))
+    n))
 
 (defun gnus-group-prev-group (n)
   "Go to previous N'th newsgroup.
@@ -2610,29 +2923,26 @@ done."
   (gnus-group-next-unread-group (- n) t (gnus-group-group-level))
   (gnus-group-position-cursor))
 
-(defun gnus-group-add-newsgroup (&optional name how where)
+(defun gnus-group-add-group (&optional name how where)
   "Add a new newsgroup."
   (interactive)
   (let ((methods gnus-valid-select-methods)
        nname)
     (if (not name)
-       (setq name (read-string "Newsgroup name: ")))
-    (setq nname (concat gnus-foreign-group-prefix name))
-    (while (gnus-gethash nname gnus-newsrc-hashtb)
-      (setq name (read-string "Name already in use. Newsgroup name: "))
-      (setq nname (concat gnus-foreign-group-prefix name)))
+       (setq name (read-string "Group name: ")))
     (if (not how)
        (setq how (completing-read (format "%s method: " name) methods nil t)))
     (if (not where)
        (setq where (read-string 
                     (format "Get %s by method %s from: " name how))))
+    (setq nname (gnus-group-prefixed-name name (list (intern how) where)))
     (gnus-group-change-level 
      (list t nname 3 nil nil (list (intern how) where))
      3 9 (gnus-gethash (gnus-group-group-name) gnus-newsrc-hashtb)
      t)
     (gnus-group-insert-group-line-info nname)))
 
-(defun gnus-group-edit-newsgroup ()
+(defun gnus-group-edit-group ()
   (interactive)
   (let ((group (gnus-group-group-name))
        info)
@@ -2641,12 +2951,14 @@ done."
     (switch-to-buffer (get-buffer-create gnus-group-edit-buffer))
     (gnus-add-current-to-buffer-list)
     (emacs-lisp-mode)
+    ;; Suggested by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+    (use-local-map (copy-keymap emacs-lisp-mode-map))
+    (local-set-key "\C-c\C-c" 'gnus-group-edit-group-done)
     (erase-buffer)
     (insert ";; Type `C-c C-c' after you have edited the newsgroup entry.\n\n")
-    (insert (format "(gnus-group-set-info\n  '%S)\n" info))
-    (local-set-key "\C-c\C-c" 'gnus-group-edit-newsgroup-done)))
+    (insert (format "(gnus-group-set-info\n  '%S)\n" info))))
 
-(defun gnus-group-edit-newsgroup-done ()
+(defun gnus-group-edit-group-done ()
   (interactive)
   (set-buffer (get-buffer-create gnus-group-edit-buffer))
   (eval-current-buffer)
@@ -2655,32 +2967,22 @@ done."
   (gnus-group-update-group (gnus-group-group-name))
   (gnus-group-position-cursor))
 
-(defun gnus-group-make-mail-groups (method)
-  ;; Suggested by Brian Edmonds <bedmonds@prodigy.bc.ca>.
+(defun gnus-group-make-directory-group (dir)
+  "Create an nndir group.
+The user will be prompted for a directory. The contents of this
+directory will be used as a newsgroup. The directory should contain
+mail messages or news articles in files that have numeric names."
   (interactive
-   (list
-    (intern
-     (completing-read
-      "Mail method: " 
-      (gnus-methods-using 'mail) nil t "nnmail"))))
-  (let ((groups nnmail-split-methods)
-       group)
-    (while groups
-      (setq group (concat gnus-foreign-group-prefix (car (car groups))))
-      (if (not (gnus-gethash group gnus-newsrc-hashtb))
-         (progn
-           (gnus-group-change-level 
-            (list t group 1 nil nil (list method ""))
-            1 9 (gnus-gethash (gnus-group-group-name) gnus-newsrc-hashtb)
-            t)
-           (gnus-group-insert-group-line-info group)))
-      (setq groups (cdr groups)))))
+   (list (read-file-name "Create group from directory: ")))
+  (or (file-exists-p dir) (error "No such directory"))
+  (or (file-directory-p dir) (error "Not a directory"))
+  (gnus-group-add-group dir "nndir" dir))
 
 (defun gnus-group-catchup-current (n &optional all)
   "Mark all articles not marked as unread in current newsgroup as read.
 If prefix argument N is numeric, the ARG next newsgroups will be
 caught up. If ALL is non-nil, marked articles will also be marked as
-read. Cross references (Xref: field) of articles are ignored.
+read. Cross references (Xref: header) of articles are ignored.
 The difference between N and actual number of newsgroups that were
 caught up is returned."
   (interactive "p")
@@ -2698,12 +3000,12 @@ caught up is returned."
                   (gnus-group-catchup (gnus-group-group-name) all)
                   (gnus-group-update-group-line)
                   t)
-                (= 0 (gnus-group-next-unread-group 1))))))
+                (zerop (gnus-group-next-unread-group 1))))))
     n)
 
 (defun gnus-group-catchup-current-all (n)
   "Mark all articles in current newsgroup as read.
-Cross references (Xref: field) of articles are ignored."
+Cross references (Xref: header) of articles are ignored."
   (interactive "p")
   (gnus-group-catchup-current n 'all))
 
@@ -2714,12 +3016,16 @@ The return value is the number of articles that were marked as read,
 or nil if no action could be taken."
   (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
         (num (car entry))
+        (marked (nth 3 (nth 2 entry)))
         ticked)
     ;; Do the updating only if the newsgroup isn't killed
     (if entry
        (progn
-         (setq ticked (if all nil (cdr (assq 'tick (nth 3 (nth 2 entry))))))
-         (gnus-update-read-articles group ticked nil ticked)))
+         (setq ticked (if all nil (cdr (assq 'tick marked))))
+         (gnus-update-read-articles group ticked nil ticked)
+         (if (and all marked)
+             (setcar (nthcdr 3 (nth 2 entry)) 
+                     (delq (assq 'dormant marked) marked)))))
     num))
 
 (defun gnus-group-expire-articles (newsgroup)
@@ -2737,10 +3043,12 @@ or nil if no action could be taken."
 (defun gnus-group-expire-all-groups ()
   "Expire all expirable articles in all newsgroups."
   (interactive)
+  (message "Expiring...")
   (let ((newsrc (cdr gnus-newsrc-assoc)))
     (while newsrc
       (gnus-group-expire-articles (car (car newsrc)))
-      (setq newsrc (cdr newsrc)))))
+      (setq newsrc (cdr newsrc))))
+  (message "Expiring...done"))
 
 (defun gnus-group-set-current-level (n)
   "Set the level of the current group to the numeric prefix."
@@ -2748,7 +3056,7 @@ or nil if no action could be taken."
   (setq n (or n (string-to-int 
                 (completing-read 
                  "Level: " 
-                 '(("1") ("2") ("3") ("4") ("5") ("6") ("7") ("8") ("9"))
+                 (mapcar (lambda (n) (list (char-to-string n))) "123456789")
                  nil t))))
   (let ((group (gnus-group-group-name)))
     (if (not group) (error "No newsgroup on current line.")
@@ -2765,21 +3073,22 @@ or nil if no action could be taken."
     (if group
        (progn
          (if (not arg) 
-             (setq arg (if (<= (gnus-group-group-level) 5) 7 3)))
+             (setq arg (if (<= (gnus-group-group-level) 5) 6 3)))
          (gnus-group-unsubscribe-group group arg)
-         (gnus-group-next-group 1))
+;        (gnus-group-next-group 1)
+         )
       (message "No newsgroup on current line"))))
 
 (defun gnus-group-unsubscribe-group (group &optional level)
   "Toggle subscribe from/to unsubscribe GROUP.
 New newsgroup is added to .newsrc automatically."
   (interactive
-   (list (completing-read "Newsgroup: " gnus-active-hashtb nil t)))
+   (list (completing-read "Group: " gnus-active-hashtb nil t)))
   (let ((newsrc (gnus-gethash group gnus-newsrc-hashtb)))
     (cond (newsrc
           ;; Toggle subscription flag.
           (gnus-group-change-level 
-           newsrc (if level level (if (< (nth 1 (nth 2 newsrc)) 6) 7 4)))
+           newsrc (if level level (if (< (nth 1 (nth 2 newsrc)) 6) 6 4)))
           (gnus-group-update-group group))
          ((and (stringp group)
                (gnus-gethash group gnus-active-hashtb))
@@ -2845,7 +3154,7 @@ The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
     (gnus-group-kill-group lines)))
 
 (defun gnus-group-kill-group (n)
-  "Kill newsgroup on current line, repeated prefix argument N times.
+  "The the next N groups.
 The killed newsgroups can be yanked by using \\[gnus-group-yank-group].
 However, only groups that were alive can be yanked; already killed 
 groups or zombie groups can't be yanked.
@@ -2859,8 +3168,7 @@ The return value is the name of the (last) newsgroup that was killed."
          (signal 'end-of-buffer nil))
       (setq level (gnus-group-group-level))
       (beginning-of-line)
-      (delete-region (point)
-                    (progn (forward-line 1) (point)))
+      (delete-region (point) (progn (forward-line 1) (point)))
       (if (setq entry (gnus-gethash group gnus-newsrc-hashtb))
          (setq gnus-list-of-killed-groups 
                (cons (cons (car entry) (nth 2 entry)) 
@@ -2890,7 +3198,7 @@ newsgroup yanked is returned."
       ;; other newsgroups in this buffer, just make this newsgroup the
       ;; first newsgroup.
       (while (and (not (setq prev (gnus-group-group-name)))
-                 (= 0 (forward-line -1))))
+                 (zerop (forward-line -1))))
       (if (not prev)
          (setq prev (car (car gnus-newsrc-assoc))))
       (gnus-group-change-level 
@@ -2906,20 +3214,20 @@ newsgroup yanked is returned."
       
 (defun gnus-group-list-all-groups (arg)
   "List all newsgroups with level ARG or lower.
-Default is 7, which lists all subscribed and unsubscribed groups."
+Default is 7, which lists all subscribed and most unsubscribed groups."
   (interactive "P")
   (setq arg (or arg 7))
   (gnus-group-list-groups arg t))
 
 (defun gnus-group-list-killed ()
-  "List all killed newsgroups in the Newsgroup buffer."
+  "List all killed newsgroups in the group buffer."
   (interactive)
   (gnus-group-prepare 9 t 9)
   (goto-char (point-min))
   (gnus-group-position-cursor))
 
 (defun gnus-group-list-zombies ()
-  "List all zombie newsgroups in the Newsgroup buffer."
+  "List all zombie newsgroups in the group buffer."
   (interactive)
   (gnus-group-prepare 8 t 8)
   (goto-char (point-min))
@@ -2931,11 +3239,11 @@ If ARG is non-nil, it should be a number between one and nine to
 specify which levels you are interested in re-scanning."
   (interactive "P")
   (if (and gnus-read-active-file (not arg))
-      (gnus-read-active-file))
-  (if arg
-      (let ((gnus-read-active-file nil))
-       (gnus-get-unread-articles arg))
-    (gnus-get-unread-articles 7))
+      (progn
+       (gnus-read-active-file)
+       (gnus-get-unread-articles (or arg 6)))
+    (let ((gnus-read-active-file nil))
+      (gnus-get-unread-articles (or arg 6))))
   (gnus-group-list-groups 5 gnus-have-all-newsgroups))
 
 (defun gnus-group-get-new-news-this-group (n)
@@ -2948,24 +3256,24 @@ If N is negative, this group and the N-1 previous groups will be checked."
        (w-p (window-start))
        group)
     (while (and (> n 0)
-               (progn
-                 (and (setq group (gnus-group-group-name))
-                      (gnus-activate-newsgroup 
-                       group (gnus-group-real-name group))
-                      (progn
-                        (gnus-get-unread-articles-in-group 
-                         (nth 2 (gnus-gethash group gnus-newsrc-hashtb))
-                         (gnus-gethash group gnus-active-hashtb))
-                        (gnus-group-update-group-line)))
-                 t)
-               (= 0 (gnus-group-next-group way)))
+               (gnus-get-new-news-in-group (gnus-group-group-name))
+               (zerop (gnus-group-next-group way)))
       (setq n (1- n)))
     (if (/= 0 n) (message "No more newsgroups"))
     ;; !!! I don't know why the buffer scrolls forward when updating
-    ;; the first line in the Group buffer, but it does. So we set the
+    ;; the first line in the group buffer, but it does. So we set the
     ;; window start forcibly.
     (set-window-start (get-buffer-window (current-buffer)) w-p)
     n))
+
+(defun gnus-get-new-news-in-group (group)
+  (if (and group (gnus-activate-newsgroup group))
+      (progn
+       (gnus-get-unread-articles-in-group 
+        (nth 2 (gnus-gethash group gnus-newsrc-hashtb))
+        (gnus-gethash group gnus-active-hashtb))
+       (gnus-group-update-group-line)))
+  t)
   
 (defun gnus-group-describe-group (&optional group)
   "Display a description of the current newsgroup."
@@ -2987,15 +3295,16 @@ If N is negative, this group and the N-1 previous groups will be checked."
               (gnus-read-descriptions-file)))
       (error "Couldn't request descriptions file"))
   (let ((buffer-read-only nil)
-       beg)
+       b)
     (erase-buffer)
     (mapatoms
      (lambda (group)
        (insert (format "      *: %-20s %s" (symbol-name group)
                       (symbol-value group)))
-       (setq beg (point))
-       (insert (format " %s  6\n" group))
-       (set-text-properties beg (1- (point)) '(invisible t)))
+       (setq b (point))
+       (add-text-properties 
+       b (1+ b) (list 'gnus-group (intern group)
+                      'gnus-unread t 'gnus-marked nil 'gnus-level 6)))
      gnus-description-hashtb)
     (goto-char (point-min))
     (gnus-group-position-cursor)))
@@ -3050,6 +3359,60 @@ If N is negative, this group and the N-1 previous groups will be checked."
       (error "Couldn't request descriptions file"))
   (gnus-group-apropos regexp t))
 
+;; Written by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun gnus-group-list-matching (regexp) 
+  "List all newsgroups with unread articles that match REGEXP."
+  (interactive "sList newsgroups matching: ")
+  (set-buffer gnus-group-buffer)
+  (let ((buffer-read-only nil)
+       (newsrc (cdr gnus-newsrc-assoc))
+       (zombie gnus-zombie-list)
+       (killed gnus-killed-list)
+       info unread active group)
+    (erase-buffer)
+
+    ;; List alive newsgroups.
+    (while newsrc
+      (setq info (car newsrc)
+           group (car info)
+           newsrc (cdr newsrc)
+           unread (car (gnus-gethash group gnus-newsrc-hashtb)))
+      (if (and unread ; This group might be bogus
+              (string-match regexp group))
+         (gnus-group-insert-group-line 
+          nil group (car (cdr info)) (nth 3 info) unread
+          (nth 4 info))))
+
+    ;; List zombies and killed lists.
+    (let ((lists (list 'gnus-zombie-list 'gnus-killed-list))
+         mark b)
+      (while lists
+       (if (eq (car lists) 'gnus-zombie-list)
+           (setq mark ?Z)
+         (setq mark ?K))
+       (setq newsrc (set (car lists)
+                         (sort (symbol-value (car lists)) 
+                               (function string<))))
+       (while newsrc
+         (setq group (car newsrc)
+               newsrc (cdr newsrc))
+         (if (not (string-match regexp group))
+             ()
+           (setq b (point))
+           (insert (format " %c    *: %s" mark group))
+           (add-text-properties 
+            b (1+ b) 
+            (list 'gnus-group (intern group)
+                  'gnus-unread t
+                  'gnus-level (if (= mark ?Z) 8 9)))))
+       (setq lists (cdr lists))))
+
+    (gnus-group-set-mode-line)
+    (setq gnus-have-all-newsgroups t)
+    (run-hooks 'gnus-group-prepare-hook))
+  (goto-char (point-min))
+  (gnus-group-position-cursor))
+
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
 (defun gnus-group-save-newsrc ()
   "Save the Gnus startup files."
@@ -3080,22 +3443,22 @@ If N is negative, this group and the N-1 previous groups will be checked."
   (mail))
 
 (defun gnus-group-edit-global-kill ()
-  "Edit a global KILL file."
+  "Edit a global kill file."
   (interactive)
   (setq gnus-current-kill-article nil) ;No articles selected.
   (gnus-kill-file-edit-file nil)       ;Nil stands for global KILL file.
   (message
    (substitute-command-keys
-    "Editing a global KILL file (Type \\[gnus-kill-file-exit] to exit)")))
+    "Editing a global kill file (Type \\[gnus-kill-file-exit] to exit)")))
 
 (defun gnus-group-edit-local-kill ()
-  "Edit a local KILL file."
+  "Edit a local kill file."
   (interactive)
   (setq gnus-current-kill-article nil) ;No articles selected.
   (gnus-kill-file-edit-file (gnus-group-group-name))
   (message
    (substitute-command-keys
-    "Editing a local KILL file (Type \\[gnus-kill-file-exit] to exit)")))
+    "Editing a local kill file (Type \\[gnus-kill-file-exit] to exit)")))
 
 (defun gnus-group-force-update ()
   "Update `.newsrc' file."
@@ -3104,11 +3467,11 @@ If N is negative, this group and the N-1 previous groups will be checked."
 
 (defun gnus-group-suspend ()
   "Suspend the current Gnus session.
-In fact, cleanup buffers except for Group Mode buffer.
+In fact, cleanup buffers except for group mode buffer.
 The hook gnus-suspend-gnus-hook is called before actually suspending."
   (interactive)
   (run-hooks 'gnus-suspend-gnus-hook)
-  ;; Kill Gnus buffers except for Group Mode buffer.
+  ;; Kill Gnus buffers except for group mode buffer.
   (let ((group-buf (get-buffer gnus-group-buffer)))
     (while gnus-buffer-list
       (and (not (eq (car gnus-buffer-list) group-buf))
@@ -3149,6 +3512,7 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
          (zerop (buffer-size))
          (not (gnus-server-opened gnus-select-method))
          gnus-expert-user
+         (not gnus-current-startup-file)
          (yes-or-no-p
           (format "Quit reading news without saving %s? "
                   (file-name-nondirectory gnus-current-startup-file))))
@@ -3159,10 +3523,10 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
        (gnus-clear-system))))
 
 (defun gnus-group-describe-briefly ()
-  "Give a one line description of the Group mode commands."
+  "Give a one line description of the group mode commands."
   (interactive)
   (message
-   (substitute-command-keys "\\[gnus-group-read-group]:Select  \\[gnus-group-next-unread-group]:Forward  \\[gnus-group-prev-unread-group]:Backward  \\[gnus-group-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-group-describe-briefly]:This help")))
+   (substitute-command-keys "\\<gnus-group-mode-map>\\[gnus-group-read-group]:Select  \\[gnus-group-next-unread-group]:Forward  \\[gnus-group-prev-unread-group]:Backward  \\[gnus-group-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-group-describe-briefly]:This help")))
 
 (defun gnus-group-browse-foreign-server (method)
   "Browse a foreign news server.
@@ -3171,9 +3535,9 @@ If called interactively, this function will ask for a select method
 If not, METHOD should be a list where the first element is the method
 and the second element is the address."
   (interactive
-   (list (list (completing-read "Select method: "
-                               gnus-valid-select-methods
-                               nil t "nntp")
+   (list (list (intern (completing-read 
+                       "Select method: "
+                       gnus-valid-select-methods nil t "nntp"))
               ;; Suggested by mapjph@bath.ac.uk.
               (completing-read 
                "Server name: " 
@@ -3195,16 +3559,14 @@ and the second element is the address."
   (suppress-keymap gnus-browse-server-mode-map)
   (define-key gnus-browse-server-mode-map " " 'gnus-browse-read-group)
   (define-key gnus-browse-server-mode-map "=" 'gnus-browse-read-group)
-  (define-key gnus-browse-server-mode-map "n" 'gnus-group-next-group)
-  (define-key gnus-browse-server-mode-map "p" 'gnus-group-prev-group)
-  (define-key gnus-browse-server-mode-map [del] 'gnus-group-prev-group)
-  (define-key gnus-browse-server-mode-map "N" 'gnus-group-next-group)
+  (define-key gnus-browse-server-mode-map "n" 'gnus-browse-next-group)
+  (define-key gnus-browse-server-mode-map "p" 'gnus-browse-prev-group)
+  (define-key gnus-browse-server-mode-map [del] 'gnus-browse-prev-group)
+  (define-key gnus-browse-server-mode-map "N" 'gnus-browse-next-group)
   (define-key gnus-browse-server-mode-map "P" 'gnus-group-prev-group)
-  (define-key gnus-browse-server-mode-map "\M-n" 'gnus-group-next-group)
-  (define-key gnus-browse-server-mode-map "\M-p" 'gnus-group-prev-group)
-  (define-key gnus-browse-server-mode-map [down] 'gnus-group-next-group)
-  (define-key gnus-browse-server-mode-map [up] 'gnus-group-prev-group)
-  (define-key gnus-browse-server-mode-map "\r" 'gnus-group-next-group)
+  (define-key gnus-browse-server-mode-map "\M-n" 'gnus-browse-next-group)
+  (define-key gnus-browse-server-mode-map "\M-p" 'gnus-browse-prev-group)
+  (define-key gnus-browse-server-mode-map "\r" 'gnus-browse-read-group)
   (define-key gnus-browse-server-mode-map "u" 'gnus-browse-unsubscribe-current-group)
   (define-key gnus-browse-server-mode-map "q" 'gnus-browse-exit)
   (define-key gnus-browse-server-mode-map "Q" 'gnus-browse-exit)
@@ -3259,7 +3621,11 @@ and the second element is the address."
   "Major mode for reading network news."
   (interactive)
   (kill-all-local-variables)
-  (setq mode-line-modified "--- ")
+  (setq mode-line-modified "-- ")
+  (make-local-variable 'mode-line-format)
+  (setq mode-line-format (copy-sequence mode-line-format))
+  (and (equal (nth 3 mode-line-format) "   ")
+       (setcar (nthcdr 3 mode-line-format) ""))
   (setq major-mode 'gnus-browse-server-mode)
   (setq mode-name "Browse Server")
   (setq mode-line-process nil)
@@ -3274,14 +3640,29 @@ and the second element is the address."
   (interactive)
   (error "You can't read while browsing"))
 
+(defun gnus-browse-next-group (n)
+  "Go to the next group."
+  (interactive "p")
+  (prog1
+      (forward-line n)
+    (gnus-group-position-cursor)))
+
+(defun gnus-browse-prev-group (n)
+  "Go to the next group."
+  (interactive "p")
+  (gnus-browse-next-group (- n)))
+
 (defun gnus-browse-unsubscribe-current-group (arg)
   "(Un)subscribe to the next ARG groups."
   (interactive "p")
+  (and (eobp)
+       (error "No group at current line."))
   (let ((ward (if (< arg 0) -1 1))
        (arg (abs arg)))
     (while (and (> arg 0)
+               (not (eobp))
                (gnus-browse-unsubscribe-group)
-               (= (gnus-group-next-group ward) 0))
+               (zerop (gnus-browse-next-group ward)))
       (setq arg (1- arg)))
     (gnus-group-position-cursor)
     (if (/= 0 arg) (message "No more newsgroups" ))
@@ -3295,9 +3676,9 @@ and the second element is the address."
       (beginning-of-line)
       (if (= (following-char) ?K) (setq sub t))
       (re-search-forward ": \\(.*\\)$" nil t)
-      (setq group 
-           (concat gnus-foreign-group-prefix 
-                   (buffer-substring (match-beginning 1) (match-end 1))))
+      (setq group (gnus-group-prefixed-name 
+                  (buffer-substring (match-beginning 1) (match-end 1))
+                  gnus-browse-current-method))
       (beginning-of-line)
       (delete-char 1)
       (if sub
@@ -3312,7 +3693,7 @@ and the second element is the address."
     t))
 
 (defun gnus-browse-exit ()
-  "Quit browsing and return to the Newsgroup buffer."
+  "Quit browsing and return to the group buffer."
   (interactive)
   (if (eq major-mode 'gnus-browse-server-mode)
       (kill-buffer (current-buffer)))
@@ -3320,158 +3701,408 @@ and the second element is the address."
   (gnus-group-list-groups 5))
 
 (defun gnus-browse-describe-briefly ()
-  "Give a one line description of the Group mode commands."
+  "Give a one line description of the group mode commands."
   (interactive)
   (message
-   (substitute-command-keys "\\[gnus-group-next-group]:Forward  \\[gnus-group-prev-group]:Backward  \\[gnus-browse-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-browse-describe-briefly]:This help")))
+   (substitute-command-keys "\\<gnus-browse-server-mode-map>\\[gnus-group-next-group]:Forward  \\[gnus-group-prev-group]:Backward  \\[gnus-browse-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-browse-describe-briefly]:This help")))
       
 \f
 ;;;
-;;; Gnus Summary Mode
+;;; Gnus summary mode
 ;;;
 
-(defmacro gnus-summary-add (key func)
-  (` (define-key gnus-summary-mode-map (, key) (, func))))
-
-(defvar gnus-summary-raise-map nil)
-(define-prefix-command 'gnus-summary-raise-map)
-
+(defvar gnus-summary-mode-map nil)
+(defvar gnus-summary-mark-map nil)
+(defvar gnus-summary-send-map nil)
+(defvar gnus-summary-extract-map nil)
+(defvar gnus-summary-article-map nil)
+(defvar gnus-summary-thread-map nil)
+(defvar gnus-summary-goto-map nil)
+(defvar gnus-summary-exit-map nil)
+(defvar gnus-summary-various-map nil)
+(defvar gnus-summary-interest-map nil)
+(defvar gnus-summary-process-map nil)
+(defvar gnus-summary-sort-map nil)
+(defvar gnus-summary-mgroup-map nil)
+(defvar gnus-summary-vkill-map nil)
+(defvar gnus-summary-increase-map nil)
+(defvar gnus-summary-inc-subject-map nil)
+(defvar gnus-summary-inc-author-map nil)
+(defvar gnus-summary-inc-xref-map nil)
+(defvar gnus-summary-inc-thread-map nil)
+(defvar gnus-summary-inc-fol-map nil)
 (defvar gnus-summary-lower-map nil)
-(define-prefix-command 'gnus-summary-lower-map)
+(defvar gnus-summary-low-subject-map nil)
+(defvar gnus-summary-low-author-map nil)
+(defvar gnus-summary-low-xref-map nil)
+(defvar gnus-summary-low-thread-map nil)
+(defvar gnus-summary-low-fol-map nil)
 
 (if gnus-summary-mode-map
     nil
   (setq gnus-summary-mode-map (make-keymap))
   (suppress-keymap gnus-summary-mode-map)
-  (gnus-summary-add "\C-c\C-i" gnus-summary-raise-map)
-  (gnus-summary-add "\C-c\C-k" gnus-summary-lower-map)
-  (gnus-summary-add "\C-c\C-v" 'gnus-uu-ctl-map)
-  (gnus-summary-add "@" 'gnus-summary-kill-below)
-  (gnus-summary-add "\C-c " 'gnus-summary-clear-above)
-  (gnus-summary-add "\C-c-" 'gnus-summary-tick-above)
-  (gnus-summary-add "#" 'gnus-summary-mark-as-processable)
-  (gnus-summary-add "\M-#" 'gnus-summary-unmark-as-processable)
-  (gnus-summary-add "\C-c\M-#" 'gnus-summary-unmark-all-processable)
-  (gnus-summary-add " " 'gnus-summary-next-page)
-  (gnus-summary-add "\177" 'gnus-summary-prev-page)
-  (gnus-summary-add "\r" 'gnus-summary-scroll-up)
-  (gnus-summary-add "n" 'gnus-summary-next-unread-article)
-  (gnus-summary-add "p" 'gnus-summary-prev-unread-article)
-  (gnus-summary-add "N" 'gnus-summary-next-article)
-  (gnus-summary-add "P" 'gnus-summary-prev-article)
-  (gnus-summary-add "\M-\C-n" 'gnus-summary-next-same-subject)
-  (gnus-summary-add "\M-\C-p" 'gnus-summary-prev-same-subject)
-  (gnus-summary-add "\C-c\C-n" 'gnus-summary-next-digest)
-  (gnus-summary-add "\C-c\C-p" 'gnus-summary-prev-digest)
-  (gnus-summary-add "\M-n" 'gnus-summary-next-unread-subject)
-  (gnus-summary-add "\M-p" 'gnus-summary-prev-unread-subject)
-  (gnus-summary-add "." 'gnus-summary-first-unread-article)
-  (gnus-summary-add "s" 'gnus-summary-isearch-article)
-  (gnus-summary-add "\M-s" 'gnus-summary-search-article-forward)
-  (gnus-summary-add "\M-r" 'gnus-summary-search-article-backward)
-  (gnus-summary-add "<" 'gnus-summary-beginning-of-article)
-  (gnus-summary-add ">" 'gnus-summary-end-of-article)
-  (gnus-summary-add "j" 'gnus-summary-goto-subject)
-  (gnus-summary-add "l" 'gnus-summary-goto-last-article)
-  (gnus-summary-add "^" 'gnus-summary-refer-parent-article)
-  (gnus-summary-add "\M-^" 'gnus-summary-refer-article)
-  (gnus-summary-add "u" 'gnus-summary-tick-article-forward)
-  (gnus-summary-add "-" 'gnus-summary-tick-article-forward)
-  (gnus-summary-add "U" 'gnus-summary-tick-article-backward)
-  (gnus-summary-add "d" 'gnus-summary-mark-as-read-forward)
-  (gnus-summary-add "D" 'gnus-summary-mark-as-read-backward)
-  (gnus-summary-add "\M-u" 'gnus-summary-clear-mark-forward)
-  (gnus-summary-add "\M-U" 'gnus-summary-clear-mark-backward)
-  (gnus-summary-add "k" 'gnus-summary-kill-same-subject-and-select)
-  (gnus-summary-add "\C-k" 'gnus-summary-kill-same-subject)
-  (gnus-summary-add "\M-\C-t" 'gnus-summary-toggle-threads)
-  (gnus-summary-add "\M-\C-s" 'gnus-summary-show-thread)
-  (gnus-summary-add "\M-\C-h" 'gnus-summary-hide-thread)
-  (gnus-summary-add "\M-\C-f" 'gnus-summary-next-thread)
-  (gnus-summary-add "\M-\C-b" 'gnus-summary-prev-thread)
-  (gnus-summary-add "\M-\C-u" 'gnus-summary-up-thread)
-  (gnus-summary-add "\M-\C-d" 'gnus-summary-down-thread)
-  (gnus-summary-add "\M-\C-k" 'gnus-summary-kill-thread)
-  (gnus-summary-add "&" 'gnus-summary-execute-command)
-  (gnus-summary-add "c" 'gnus-summary-catchup-and-exit)
-  (gnus-summary-add "\C-t" 'gnus-summary-toggle-truncation)
-  (gnus-summary-add "\M-d" 'gnus-summary-delete-marked-as-read)
-  (gnus-summary-add "\C-c\M-\C-d" 'gnus-summary-delete-marked-with)
-  (gnus-summary-add "x" 'gnus-summary-mark-as-expirable)
-  (gnus-summary-add "X" 'gnus-summary-unmark-as-expirable)
-  (gnus-summary-add "\M-\C-x" 'gnus-summary-expire-articles)
-  (gnus-summary-add [M-DEL] 'gnus-summary-delete-article)
-  (gnus-summary-add "b" 'gnus-summary-set-bookmark)
-  (gnus-summary-add "B" 'gnus-summary-remove-bookmark)
-  (gnus-summary-add "+" 'gnus-summary-mark-as-dormant)
-  (gnus-summary-add "\M-+" 'gnus-summary-show-all-dormant)
-  (gnus-summary-add "\C-c\M-\C-s" 'gnus-summary-show-all-expunged)
-  (gnus-summary-add "\C-c\C-sn" 'gnus-summary-sort-by-number)
-  (gnus-summary-add "\C-c\C-sa" 'gnus-summary-sort-by-author)
-  (gnus-summary-add "\C-c\C-ss" 'gnus-summary-sort-by-subject)
-  (gnus-summary-add "\C-c\C-sd" 'gnus-summary-sort-by-date)
-  (gnus-summary-add "\C-c\C-s\C-n" 'gnus-summary-sort-by-number)
-  (gnus-summary-add "\C-c\C-s\C-a" 'gnus-summary-sort-by-author)
-  (gnus-summary-add "\C-c\C-s\C-s" 'gnus-summary-sort-by-subject)
-  (gnus-summary-add "\C-c\C-s\C-d" 'gnus-summary-sort-by-date)
-  (gnus-summary-add "=" 'gnus-summary-expand-window)
-  (gnus-summary-add "\C-x\C-s" 'gnus-summary-reselect-current-group)
-  (gnus-summary-add "\M-g" 'gnus-summary-rescan-group)
-  (gnus-summary-add "w" 'gnus-summary-stop-page-breaking)
-  (gnus-summary-add "\C-c\C-r" 'gnus-summary-caesar-message)
-  (gnus-summary-add "g" 'gnus-summary-show-article)
-  (gnus-summary-add "t" 'gnus-summary-toggle-header)
-  (gnus-summary-add "\M-t" 'gnus-summary-toggle-mime)
-  (gnus-summary-add "\C-d" 'gnus-summary-rmail-digest)
-  (gnus-summary-add "a" 'gnus-summary-post-news)
-  (gnus-summary-add "f" 'gnus-summary-followup)
-  (gnus-summary-add "F" 'gnus-summary-followup-with-original)
-  (gnus-summary-add "C" 'gnus-summary-cancel-article)
-  (gnus-summary-add "S" 'gnus-summary-supersede-article)
-  (gnus-summary-add "r" 'gnus-summary-reply)
-  (gnus-summary-add "R" 'gnus-summary-reply-with-original)
-  (gnus-summary-add "\C-c\C-f" 'gnus-summary-mail-forward)
-  (gnus-summary-add "m" 'gnus-summary-mail-other-window)
-  (gnus-summary-add "o" 'gnus-summary-save-article)
-  (gnus-summary-add "\C-o" 'gnus-summary-save-article-rmail)
-  (gnus-summary-add "|" 'gnus-summary-pipe-output)
-  (gnus-summary-add "\M-m" 'gnus-summary-move-article)
-  (gnus-summary-add "\M-\C-m" 'gnus-summary-respool-article)
-  (gnus-summary-add "\M-k" 'gnus-summary-edit-local-kill)
-  (gnus-summary-add "\M-K" 'gnus-summary-edit-global-kill)
-  (gnus-summary-add "V" 'gnus-version)
-  (gnus-summary-add "\C-c\C-d" 'gnus-summary-describe-group)
-  (gnus-summary-add "q" 'gnus-summary-exit)
-  (gnus-summary-add "Q" 'gnus-summary-quit)
-  (gnus-summary-add "?" 'gnus-summary-describe-briefly)
-  ;;(gnus-summary-add "\C-c\C-i" 'gnus-info-find-node)
-  (gnus-summary-add [mouse-2] 'gnus-mouse-pick-article)
-  (gnus-summary-add "\C-c\C-x" 'gnus-kill-file-set-expunge-below)
-  (gnus-summary-add "\C-c\C-m" 'gnus-kill-file-set-mark-below)
-  (define-key gnus-summary-raise-map "\C-s" 
-    'gnus-summary-temporarily-raise-by-subject)
-  (define-key gnus-summary-raise-map "\C-a" 
-    'gnus-summary-temporarily-raise-by-author)
-  (define-key gnus-summary-raise-map "\C-t" 
-    'gnus-summary-temporarily-raise-by-thread)
-  (define-key gnus-summary-raise-map "\C-x" 
-    'gnus-summary-temporarily-raise-by-xref)
-  (define-key gnus-summary-raise-map "s" 'gnus-summary-raise-by-subject)
-  (define-key gnus-summary-raise-map "a" 'gnus-summary-raise-by-author)
-  (define-key gnus-summary-raise-map "x" 'gnus-summary-raise-by-xref)
-  (define-key gnus-summary-raise-map "f" 'gnus-summary-raise-followups-to-author)
-  (define-key gnus-summary-lower-map "\C-s" 'gnus-summary-temporarily-lower-by-subject)
-  (define-key gnus-summary-lower-map "\C-a" 'gnus-summary-temporarily-lower-by-author)
-  (define-key gnus-summary-lower-map "\C-t" 'gnus-summary-temporarily-lower-by-thread)
-  (define-key gnus-summary-lower-map "\C-x" 'gnus-summary-temporarily-lower-by-xref)
-  (define-key gnus-summary-lower-map "s" 'gnus-summary-lower-by-subject)
-  (define-key gnus-summary-lower-map "a" 'gnus-summary-lower-by-author)
-  (define-key gnus-summary-lower-map "x" 'gnus-summary-lower-by-xref)
-  (define-key gnus-summary-lower-map "f" 'gnus-summary-lower-followups-to-author)
-  (gnus-summary-add "(" 'gnus-summary-lower-interest)
-  (gnus-summary-add ")" 'gnus-summary-raise-interest)
-  (gnus-summary-add "I" 'gnus-summary-set-interest)
-  (gnus-summary-make-menu-bar))
+
+  ;;Non-orthogonal keys
+
+  (define-key gnus-summary-mode-map " " 'gnus-summary-next-page)
+  (define-key gnus-summary-mode-map "\177" 'gnus-summary-prev-page)
+  (define-key gnus-summary-mode-map "\r" 'gnus-summary-scroll-up)
+  (define-key gnus-summary-mode-map "n" 'gnus-summary-next-unread-article)
+  (define-key gnus-summary-mode-map "p" 'gnus-summary-prev-unread-article)
+  (define-key gnus-summary-mode-map "N" 'gnus-summary-next-article)
+  (define-key gnus-summary-mode-map "P" 'gnus-summary-prev-article)
+  (define-key gnus-summary-mode-map "\M-\C-n" 'gnus-summary-next-same-subject)
+  (define-key gnus-summary-mode-map "\M-\C-p" 'gnus-summary-prev-same-subject)
+  (define-key gnus-summary-mode-map "\C-c\C-n" 'gnus-summary-next-digest)
+  (define-key gnus-summary-mode-map "\C-c\C-p" 'gnus-summary-prev-digest)
+  (define-key gnus-summary-mode-map "\M-n" 'gnus-summary-next-unread-subject)
+  (define-key gnus-summary-mode-map "\M-p" 'gnus-summary-prev-unread-subject)
+  (define-key gnus-summary-mode-map "." 'gnus-summary-first-unread-article)
+  (define-key gnus-summary-mode-map "," 'gnus-summary-best-unread-article)
+  (define-key gnus-summary-mode-map "\M-s" 'gnus-summary-search-article-forward)
+  (define-key gnus-summary-mode-map "\M-r" 'gnus-summary-search-article-backward)
+  (define-key gnus-summary-mode-map "<" 'gnus-summary-beginning-of-article)
+  (define-key gnus-summary-mode-map ">" 'gnus-summary-end-of-article)
+  (define-key gnus-summary-mode-map "j" 'gnus-summary-goto-subject)
+  (define-key gnus-summary-mode-map "^" 'gnus-summary-refer-parent-article)
+  (define-key gnus-summary-mode-map "\M-^" 'gnus-summary-refer-article)
+  (define-key gnus-summary-mode-map "u" 'gnus-summary-tick-article-forward)
+  (define-key gnus-summary-mode-map "!" 'gnus-summary-tick-article-forward)
+  (define-key gnus-summary-mode-map "U" 'gnus-summary-tick-article-backward)
+  (define-key gnus-summary-mode-map "d" 'gnus-summary-mark-as-read-forward)
+  (define-key gnus-summary-mode-map "D" 'gnus-summary-mark-as-read-backward)
+  (define-key gnus-summary-mode-map "\M-u" 'gnus-summary-clear-mark-forward)
+  (define-key gnus-summary-mode-map "\M-U" 'gnus-summary-clear-mark-backward)
+  (define-key gnus-summary-mode-map "k" 'gnus-summary-kill-same-subject-and-select)
+  (define-key gnus-summary-mode-map "\C-k" 'gnus-summary-kill-same-subject)
+  (define-key gnus-summary-mode-map "\M-\C-k" 'gnus-summary-kill-thread)
+  (define-key gnus-summary-mode-map "#" 'gnus-summary-mark-as-processable)
+  (define-key gnus-summary-mode-map "\M-#" 'gnus-summary-unmark-as-processable)
+  (define-key gnus-summary-mode-map "\M-\C-t" 'gnus-summary-toggle-threads)
+  (define-key gnus-summary-mode-map "\M-\C-s" 'gnus-summary-show-thread)
+  (define-key gnus-summary-mode-map "\M-\C-h" 'gnus-summary-hide-thread)
+  (define-key gnus-summary-mode-map "\M-\C-f" 'gnus-summary-next-thread)
+  (define-key gnus-summary-mode-map "\M-\C-b" 'gnus-summary-prev-thread)
+  (define-key gnus-summary-mode-map "\M-\C-u" 'gnus-summary-up-thread)
+  (define-key gnus-summary-mode-map "\M-\C-d" 'gnus-summary-down-thread)
+  (define-key gnus-summary-mode-map "&" 'gnus-summary-execute-command)
+  (define-key gnus-summary-mode-map "c" 'gnus-summary-catchup-and-exit)
+  (define-key gnus-summary-mode-map "\C-t" 'gnus-summary-toggle-truncation)
+  (define-key gnus-summary-mode-map "\M-d" 'gnus-summary-remove-lines-marked-as-read)
+  (define-key gnus-summary-mode-map "\C-c\M-\C-d" 'gnus-summary-remove-lines-marked-with)
+  (define-key gnus-summary-mode-map "?" 'gnus-summary-mark-as-dormant)
+  (define-key gnus-summary-mode-map "\C-c\M-\C-s" 'gnus-summary-show-all-expunged)
+  (define-key gnus-summary-mode-map "\C-c\C-s\C-n" 'gnus-summary-sort-by-number)
+  (define-key gnus-summary-mode-map "\C-c\C-s\C-a" 'gnus-summary-sort-by-author)
+  (define-key gnus-summary-mode-map "\C-c\C-s\C-s" 'gnus-summary-sort-by-subject)
+  (define-key gnus-summary-mode-map "\C-c\C-s\C-d" 'gnus-summary-sort-by-date)
+  (define-key gnus-summary-mode-map "\C-c\C-s\C-i" 'gnus-summary-sort-by-score)
+  (define-key gnus-summary-mode-map "=" 'gnus-summary-expand-window)
+  (define-key gnus-summary-mode-map "\C-x\C-s" 'gnus-summary-reselect-current-group)
+  (define-key gnus-summary-mode-map "\M-g" 'gnus-summary-rescan-group)
+  (define-key gnus-summary-mode-map "w" 'gnus-summary-stop-page-breaking)
+  (define-key gnus-summary-mode-map "\C-c\C-r" 'gnus-summary-caesar-message)
+  (define-key gnus-summary-mode-map "\M-t" 'gnus-summary-toggle-mime)
+  (define-key gnus-summary-mode-map "\C-d" 'gnus-summary-rmail-digest)
+  (define-key gnus-summary-mode-map "f" 'gnus-summary-followup)
+  (define-key gnus-summary-mode-map "F" 'gnus-summary-followup-with-original)
+  (define-key gnus-summary-mode-map "C" 'gnus-summary-cancel-article)
+  (define-key gnus-summary-mode-map "r" 'gnus-summary-reply)
+  (define-key gnus-summary-mode-map "R" 'gnus-summary-reply-with-original)
+  (define-key gnus-summary-mode-map "\C-c\C-f" 'gnus-summary-mail-forward)
+  (define-key gnus-summary-mode-map "o" 'gnus-summary-save-article)
+  (define-key gnus-summary-mode-map "\C-o" 'gnus-summary-save-article-mail)
+  (define-key gnus-summary-mode-map "|" 'gnus-summary-pipe-output)
+  (define-key gnus-summary-mode-map "\M-k" 'gnus-summary-edit-local-kill)
+  (define-key gnus-summary-mode-map "\M-K" 'gnus-summary-edit-global-kill)
+  (define-key gnus-summary-mode-map "V" 'gnus-version)
+  (define-key gnus-summary-mode-map "\C-c\C-d" 'gnus-summary-describe-group)
+  (define-key gnus-summary-mode-map "q" 'gnus-summary-exit)
+  (define-key gnus-summary-mode-map "Q" 'gnus-summary-quit)
+  (define-key gnus-summary-mode-map "\C-c\C-i" 'gnus-info-find-node)
+  (define-key gnus-summary-mode-map [mouse-2] 'gnus-mouse-pick-article)
+  (define-key gnus-summary-mode-map "m" 'gnus-summary-mail-other-window)
+  (define-key gnus-summary-mode-map "a" 'gnus-summary-post-news)
+  (define-key gnus-summary-mode-map "x" 'gnus-summary-delete-marked-as-read)
+  (define-key gnus-summary-mode-map "s" 'gnus-summary-isearch-article)
+  (define-key gnus-summary-mode-map "t" 'gnus-summary-toggle-header)
+  (define-key gnus-summary-mode-map "g" 'gnus-summary-show-article)
+;  (define-key gnus-summary-mode-map "?" 'gnus-summary-describe-briefly)
+  (define-key gnus-summary-mode-map "l" 'gnus-summary-goto-last-article)
+
+
+  ;; Orthogonal keymap
+  (define-prefix-command 'gnus-summary-mark-map)
+  (define-key gnus-summary-mode-map "M" 'gnus-summary-mark-map)
+  (define-key gnus-summary-mark-map "t" 'gnus-summary-tick-article-forward)
+  (define-key gnus-summary-mark-map "!" 'gnus-summary-tick-article-forward)
+  (define-key gnus-summary-mark-map "d" 'gnus-summary-mark-as-read-forward)
+  (define-key gnus-summary-mark-map "r" 'gnus-summary-mark-as-read-forward)
+  (define-key gnus-summary-mark-map "c" 'gnus-summary-clear-mark-forward)
+  (define-key gnus-summary-mark-map " " 'gnus-summary-clear-mark-forward)
+  (define-key gnus-summary-mark-map "e" 'gnus-summary-mark-as-expirable)
+  (define-key gnus-summary-mark-map "x" 'gnus-summary-mark-as-expirable)
+  (define-key gnus-summary-mark-map "?" 'gnus-summary-mark-as-dormant)
+  (define-key gnus-summary-mark-map "b" 'gnus-summary-set-bookmark)
+  (define-key gnus-summary-mark-map "B" 'gnus-summary-remove-bookmark)
+  (define-key gnus-summary-mark-map "#" 'gnus-summary-mark-as-processable)
+  (define-key gnus-summary-mark-map "\M-#" 'gnus-summary-unmark-as-processable)
+  (define-key gnus-summary-mark-map "\M-r" 'gnus-summary-remove-lines-marked-as-read)
+  (define-key gnus-summary-mark-map "\M-\C-r" 'gnus-summary-remove-lines-marked-with)
+  (define-key gnus-summary-mark-map "\C-d" 'gnus-summary-show-all-dormant)
+  (define-key gnus-summary-mark-map "\C-s" 'gnus-summary-show-all-expunged)
+  (define-key gnus-summary-mark-map "C" 'gnus-summary-catchup)
+  (define-key gnus-summary-mark-map "\C-c" 'gnus-summary-catchup-all)
+  (define-key gnus-summary-mark-map "a" 'gnus-summary-clear-above)
+  (define-key gnus-summary-mark-map "A" 'gnus-summary-tick-above)
+
+  (define-prefix-command 'gnus-summary-process-map)
+  (define-key gnus-summary-mark-map "p" 'gnus-summary-process-map)
+  (define-key gnus-summary-process-map "p" 'gnus-summary-mark-as-processable)
+  (define-key gnus-summary-process-map "u" 'gnus-summary-unmark-as-processable)
+  (define-key gnus-summary-process-map "U" 'gnus-summary-unmark-all-processable)
+  (define-key gnus-summary-process-map "s" 'gnus-uu-mark-by-regexp)
+  (define-key gnus-summary-process-map "r" 'gnus-uu-mark-region)
+  (define-key gnus-summary-process-map "t" 'gnus-uu-mark-thread)
+  (define-key gnus-summary-process-map "a" 'gnus-uu-mark-sparse)
+  
+
+  (define-prefix-command 'gnus-summary-send-map)
+  (define-key gnus-summary-mode-map "S" 'gnus-summary-send-map)
+  (define-key gnus-summary-send-map "p" 'gnus-summary-post-news)
+  (define-key gnus-summary-send-map "f" 'gnus-summary-followup)
+  (define-key gnus-summary-send-map "F" 'gnus-summary-followup-with-original)
+  (define-key gnus-summary-send-map "c" 'gnus-summary-cancel-article)
+  (define-key gnus-summary-send-map "s" 'gnus-summary-supersede-article)
+  (define-key gnus-summary-send-map "r" 'gnus-summary-reply)
+  (define-key gnus-summary-send-map "R" 'gnus-summary-reply-with-original)
+  (define-key gnus-summary-send-map "\C-f" 'gnus-summary-mail-forward)
+  (define-key gnus-summary-send-map "m" 'gnus-summary-mail-other-window)
+  (define-key gnus-summary-send-map "u" 'gnus-uu-post-news)
+  (define-key gnus-summary-send-map "\M-f" 'gnus-uu-digest-and-forward)
+
+  
+  (define-prefix-command 'gnus-summary-goto-map)
+  (define-key gnus-summary-mode-map "G" 'gnus-summary-goto-map)
+  (define-key gnus-summary-goto-map "n" 'gnus-summary-next-unread-article)
+  (define-key gnus-summary-goto-map "p" 'gnus-summary-prev-unread-article)
+  (define-key gnus-summary-goto-map "N" 'gnus-summary-next-article)
+  (define-key gnus-summary-goto-map "P" 'gnus-summary-prev-article)
+  (define-key gnus-summary-goto-map "\C-n" 'gnus-summary-next-same-subject)
+  (define-key gnus-summary-goto-map "\C-p" 'gnus-summary-prev-same-subject)
+  (define-key gnus-summary-goto-map "\M-n" 'gnus-summary-next-unread-subject)
+  (define-key gnus-summary-goto-map "\M-p" 'gnus-summary-prev-unread-subject)
+  (define-key gnus-summary-goto-map "f" 'gnus-summary-first-unread-article)
+  (define-key gnus-summary-goto-map "b" 'gnus-summary-best-unread-article)
+  (define-key gnus-summary-goto-map "g" 'gnus-summary-goto-subject)
+  (define-key gnus-summary-goto-map "l" 'gnus-summary-goto-last-article)
+
+
+  (define-prefix-command 'gnus-summary-thread-map)
+  (define-key gnus-summary-mode-map "T" 'gnus-summary-thread-map)
+  (define-key gnus-summary-thread-map "k" 'gnus-summary-kill-thread)
+  (define-key gnus-summary-thread-map "l" 'gnus-summary-lower-thread)
+  (define-key gnus-summary-thread-map "r" 'gnus-summary-raise-thread)
+  (define-key gnus-summary-thread-map "T" 'gnus-summary-toggle-threads)
+  (define-key gnus-summary-thread-map "s" 'gnus-summary-show-thread)
+  (define-key gnus-summary-thread-map "h" 'gnus-summary-hide-thread)
+  (define-key gnus-summary-thread-map "n" 'gnus-summary-next-thread)
+  (define-key gnus-summary-thread-map "p" 'gnus-summary-prev-thread)
+  (define-key gnus-summary-thread-map "u" 'gnus-summary-up-thread)
+  (define-key gnus-summary-thread-map "d" 'gnus-summary-down-thread)
+  (define-key gnus-summary-thread-map "#" 'gnus-uu-mark-thread)
+
+  
+  (define-prefix-command 'gnus-summary-exit-map)
+  (define-key gnus-summary-mode-map "E" 'gnus-summary-exit-map)
+  (define-key gnus-summary-exit-map "c" 'gnus-summary-catchup-and-exit)
+  (define-key gnus-summary-exit-map "\C-c" 'gnus-summary-catchup-all-and-exit)
+  (define-key gnus-summary-exit-map "q" 'gnus-summary-exit)
+  (define-key gnus-summary-exit-map "e" 'gnus-summary-exit)
+  (define-key gnus-summary-exit-map "Q" 'gnus-summary-quit)
+  (define-key gnus-summary-exit-map "E" 'gnus-summary-quit)
+
+
+  (define-prefix-command 'gnus-summary-article-map)
+  (define-key gnus-summary-mode-map "A" 'gnus-summary-article-map)
+  (define-key gnus-summary-article-map " " 'gnus-summary-next-page)
+  (define-key gnus-summary-article-map "n" 'gnus-summary-next-page)
+  (define-key gnus-summary-article-map "\177" 'gnus-summary-prev-page)
+  (define-key gnus-summary-article-map "p" 'gnus-summary-prev-page)
+  (define-key gnus-summary-article-map "\r" 'gnus-summary-scroll-up)
+  (define-key gnus-summary-article-map "<" 'gnus-summary-beginning-of-article)
+  (define-key gnus-summary-article-map ">" 'gnus-summary-end-of-article)
+  (define-key gnus-summary-article-map "b" 'gnus-summary-beginning-of-article)
+  (define-key gnus-summary-article-map "e" 'gnus-summary-end-of-article)
+  (define-key gnus-summary-article-map "^" 'gnus-summary-refer-parent-article)
+  (define-key gnus-summary-article-map "r" 'gnus-summary-refer-parent-article)
+  (define-key gnus-summary-article-map "w" 'gnus-summary-stop-page-breaking)
+  (define-key gnus-summary-article-map "c" 'gnus-summary-caesar-message)
+  (define-key gnus-summary-article-map "g" 'gnus-summary-show-article)
+  (define-key gnus-summary-article-map "t" 'gnus-summary-toggle-header)
+  (define-key gnus-summary-article-map "m" 'gnus-summary-toggle-mime)
+  (define-key gnus-summary-article-map "s" 'gnus-summary-isearch-article)
+
+
+  (define-prefix-command 'gnus-summary-extract-map)
+  (define-key gnus-summary-mode-map "X" 'gnus-summary-extract-map)
+;  (define-key gnus-summary-extract-map "x" 'gnus-summary-extract-any)
+;  (define-key gnus-summary-extract-map "m" 'gnus-summary-extract-mime)
+;  (define-key gnus-summary-extract-map "d" 'gnus-summary-extract-digest)
+
+  (define-key gnus-summary-extract-map "u" 'gnus-uu-decode-uu)
+  (define-key gnus-summary-extract-map "U" 'gnus-uu-decode-uu-and-save)
+  (define-key gnus-summary-extract-map "s" 'gnus-uu-decode-unshar)
+  (define-key gnus-summary-extract-map "S" 'gnus-uu-decode-unshar-and-save)
+  (define-key gnus-summary-extract-map "o" 'gnus-uu-decode-save)
+  (define-key gnus-summary-extract-map "O" 'gnus-uu-decode-save)
+  (define-key gnus-summary-extract-map "b" 'gnus-uu-decode-binhex)
+  (define-key gnus-summary-extract-map "B" 'gnus-uu-decode-binhex)
+
+  
+  (define-prefix-command 'gnus-summary-various-map)
+  (define-key gnus-summary-mode-map "V" 'gnus-summary-various-map)
+  (define-key gnus-summary-various-map "u" 'gnus-summary-universal-argument)
+  (define-key gnus-summary-various-map "\M-s" 'gnus-summary-search-article-forward)
+  (define-key gnus-summary-various-map "\M-r" 'gnus-summary-search-article-backward)
+  (define-key gnus-summary-various-map "r" 'gnus-summary-refer-article)
+  (define-key gnus-summary-various-map "&" 'gnus-summary-execute-command)
+  (define-key gnus-summary-various-map "\C-t" 'gnus-summary-toggle-truncation)
+  (define-key gnus-summary-various-map "=" 'gnus-summary-expand-window)
+  (define-key gnus-summary-various-map "\C-s" 'gnus-summary-reselect-current-group)
+  (define-key gnus-summary-various-map "g" 'gnus-summary-rescan-group)
+  (define-key gnus-summary-various-map "o" 'gnus-summary-save-article)
+  (define-key gnus-summary-various-map "\C-o" 'gnus-summary-save-article-mail)
+  (define-key gnus-summary-various-map "|" 'gnus-summary-pipe-output)
+  (define-key gnus-summary-various-map "V" 'gnus-version)
+  (define-key gnus-summary-various-map "d" 'gnus-summary-describe-group)
+  (define-key gnus-summary-various-map "?" 'gnus-summary-describe-briefly)
+  (define-key gnus-summary-various-map "i" 'gnus-info-find-node)
+  (define-key gnus-summary-various-map "S" 'gnus-summary-set-score)
+  (define-key gnus-summary-various-map "b" 'gnus-summary-set-mark-below)
+
+  (define-prefix-command 'gnus-summary-sort-map)
+  (define-key gnus-summary-various-map "s" 'gnus-summary-sort-map)
+  (define-key gnus-summary-sort-map "n" 'gnus-summary-sort-by-number)
+  (define-key gnus-summary-sort-map "a" 'gnus-summary-sort-by-author)
+  (define-key gnus-summary-sort-map "s" 'gnus-summary-sort-by-subject)
+  (define-key gnus-summary-sort-map "d" 'gnus-summary-sort-by-date)
+  (define-key gnus-summary-sort-map "i" 'gnus-summary-sort-by-score)
+
+  (define-prefix-command 'gnus-summary-mgroup-map)
+  (define-key gnus-summary-various-map "m" 'gnus-summary-mgroup-map)
+  (define-key gnus-summary-mgroup-map "e" 'gnus-summary-expire-articles)
+  (define-key gnus-summary-mgroup-map "\177" 'gnus-summary-delete-article)
+  (define-key gnus-summary-mgroup-map "m" 'gnus-summary-move-article)
+  (define-key gnus-summary-mgroup-map "r" 'gnus-summary-respool-article)
+
+  (define-prefix-command 'gnus-summary-vkill-map)
+  (define-key gnus-summary-various-map "k" 'gnus-summary-vkill-map)
+  (define-key gnus-summary-vkill-map "k" 'gnus-summary-kill-same-subject-and-select)
+  (define-key gnus-summary-vkill-map "K" 'gnus-summary-kill-same-subject)
+  (define-key gnus-summary-vkill-map "\M-k" 'gnus-summary-edit-local-kill)
+  (define-key gnus-summary-vkill-map "\M-K" 'gnus-summary-edit-global-kill)
+  (define-key gnus-summary-vkill-map "x" 'gnus-kill-file-set-expunge-below)
+  (define-key gnus-summary-vkill-map "m" 'gnus-kill-file-set-mark-below)
+
+
+
+  (define-prefix-command 'gnus-summary-increase-map)
+  (define-key gnus-summary-mode-map "I" 'gnus-summary-increase-map)
+  (define-key gnus-summary-increase-map "i" 'gnus-summary-raise-same-subject-and-select)
+  (define-key gnus-summary-increase-map "I" 'gnus-summary-raise-same-subject)
+  (define-key gnus-summary-increase-map "\C-i" 'gnus-summary-raise-score)
+
+  (define-prefix-command 'gnus-summary-inc-subject-map)
+  (define-key gnus-summary-increase-map "s" 'gnus-summary-inc-subject-map)
+  (define-key gnus-summary-increase-map "S" 'gnus-summary-temporarily-raise-by-subject)
+  (define-key gnus-summary-inc-subject-map "s" 'gnus-summary-temporarily-raise-by-subject)
+  (define-key gnus-summary-inc-subject-map "S" 'gnus-summary-raise-by-subject)
+  (define-key gnus-summary-inc-subject-map "t" 'gnus-summary-temporarily-raise-by-subject)
+  (define-key gnus-summary-inc-subject-map "p" 'gnus-summary-raise-by-subject)
+
+  (define-prefix-command 'gnus-summary-inc-author-map)
+  (define-key gnus-summary-increase-map "a" 'gnus-summary-inc-author-map)
+  (define-key gnus-summary-increase-map "A" 'gnus-summary-temporarily-raise-by-author)
+  (define-key gnus-summary-inc-author-map "a" 'gnus-summary-temporarily-raise-by-author)
+  (define-key gnus-summary-inc-author-map "A" 'gnus-summary-raise-by-author)
+  (define-key gnus-summary-inc-author-map "t" 'gnus-summary-temporarily-raise-by-author)
+  (define-key gnus-summary-inc-author-map "p" 'gnus-summary-raise-by-author)
+
+  (define-prefix-command 'gnus-summary-inc-thread-map)
+  (define-key gnus-summary-increase-map "t" 'gnus-summary-inc-thread-map)
+  (define-key gnus-summary-increase-map "T" 'gnus-summary-temporarily-raise-by-thread)
+  (define-key gnus-summary-inc-thread-map "t" 'gnus-summary-temporarily-raise-by-thread)
+  (define-key gnus-summary-inc-thread-map "T" 'gnus-summary-raise-by-thread)
+  (define-key gnus-summary-inc-thread-map "t" 'gnus-summary-temporarily-raise-by-thread)
+  (define-key gnus-summary-inc-thread-map "p" 'gnus-summary-raise-by-thread)
+
+  (define-prefix-command 'gnus-summary-inc-xref-map)
+  (define-key gnus-summary-increase-map "x" 'gnus-summary-inc-xref-map)
+  (define-key gnus-summary-increase-map "X" 'gnus-summary-temporarily-raise-by-xref)
+  (define-key gnus-summary-inc-xref-map "x" 'gnus-summary-temporarily-raise-by-xref)
+  (define-key gnus-summary-inc-xref-map "X" 'gnus-summary-raise-by-xref)
+  (define-key gnus-summary-inc-xref-map "t" 'gnus-summary-temporarily-raise-by-xref)
+  (define-key gnus-summary-inc-xref-map "p" 'gnus-summary-raise-by-xref)
+
+  (define-prefix-command 'gnus-summary-inc-fol-map)
+  (define-key gnus-summary-increase-map "f" 'gnus-summary-inc-fol-map)
+  (define-key gnus-summary-increase-map "F" 'gnus-summary-temporarily-raise-followups-to-author)
+  (define-key gnus-summary-inc-fol-map "f" 'gnus-summary-temporarily-raise-followups-to-author)
+  (define-key gnus-summary-inc-fol-map "F" 'gnus-summary-raise-followups-to-author)
+  (define-key gnus-summary-inc-fol-map "t" 'gnus-summary-temporarily-raise-followups-to-author)
+  (define-key gnus-summary-inc-fol-map "p" 'gnus-summary-raise-followups-to-author)
+
+  (define-prefix-command 'gnus-summary-lower-map)
+  (define-key gnus-summary-mode-map "L" 'gnus-summary-lower-map)
+  (define-key gnus-summary-lower-map "l" 'gnus-summary-lower-same-subject-and-select)
+  (define-key gnus-summary-lower-map "L" 'gnus-summary-lower-same-subject)
+  (define-key gnus-summary-lower-map "\C-l" 'gnus-summary-lower-score)
+
+  (define-prefix-command 'gnus-summary-low-subject-map)
+  (define-key gnus-summary-lower-map "s" 'gnus-summary-low-subject-map)
+  (define-key gnus-summary-lower-map "S" 'gnus-summary-temporarily-lower-by-subject)
+  (define-key gnus-summary-low-subject-map "s" 'gnus-summary-temporarily-lower-by-subject)
+  (define-key gnus-summary-low-subject-map "S" 'gnus-summary-lower-by-subject)
+  (define-key gnus-summary-low-subject-map "t" 'gnus-summary-temporarily-lower-by-subject)
+  (define-key gnus-summary-low-subject-map "p" 'gnus-summary-lower-by-subject)
+
+  (define-prefix-command 'gnus-summary-low-author-map)
+  (define-key gnus-summary-lower-map "a" 'gnus-summary-low-author-map)
+  (define-key gnus-summary-lower-map "A" 'gnus-summary-temporarily-lower-by-author)
+  (define-key gnus-summary-low-author-map "a" 'gnus-summary-temporarily-lower-by-author)
+  (define-key gnus-summary-low-author-map "A" 'gnus-summary-lower-by-author)
+  (define-key gnus-summary-low-author-map "t" 'gnus-summary-temporarily-lower-by-author)
+  (define-key gnus-summary-low-author-map "p" 'gnus-summary-lower-by-author)
+
+  (define-prefix-command 'gnus-summary-low-thread-map)
+  (define-key gnus-summary-lower-map "t" 'gnus-summary-low-thread-map)
+  (define-key gnus-summary-lower-map "T" 'gnus-summary-temporarily-lower-by-thread)
+  (define-key gnus-summary-low-thread-map "t" 'gnus-summary-temporarily-lower-by-thread)
+  (define-key gnus-summary-low-thread-map "T" 'gnus-summary-lower-by-thread)
+  (define-key gnus-summary-low-thread-map "t" 'gnus-summary-temporarily-lower-by-thread)
+  (define-key gnus-summary-low-thread-map "p" 'gnus-summary-lower-by-thread)
+
+  (define-prefix-command 'gnus-summary-low-xref-map)
+  (define-key gnus-summary-lower-map "x" 'gnus-summary-low-xref-map)
+  (define-key gnus-summary-lower-map "X" 'gnus-summary-temporarily-lower-by-xref)
+  (define-key gnus-summary-low-xref-map "x" 'gnus-summary-temporarily-lower-by-xref)
+  (define-key gnus-summary-low-xref-map "X" 'gnus-summary-lower-by-xref)
+  (define-key gnus-summary-low-xref-map "t" 'gnus-summary-temporarily-lower-by-xref)
+  (define-key gnus-summary-low-xref-map "p" 'gnus-summary-lower-by-xref)
+
+  (define-prefix-command 'gnus-summary-low-fol-map)
+  (define-key gnus-summary-lower-map "f" 'gnus-summary-low-fol-map)
+  (define-key gnus-summary-lower-map "F" 'gnus-summary-temporarily-lower-followups-to-author)
+  (define-key gnus-summary-low-fol-map "f" 'gnus-summary-temporarily-lower-followups-to-author)
+  (define-key gnus-summary-low-fol-map "F" 'gnus-summary-lower-followups-to-author)
+  (define-key gnus-summary-low-fol-map "t" 'gnus-summary-temporarily-lower-followups-to-author)
+  (define-key gnus-summary-low-fol-map "p" 'gnus-summary-lower-followups-to-author)
+
+  (if gnus-visual (gnus-summary-make-menu-bar)))
+
+
 \f
 
 (defun gnus-summary-mode ()
@@ -3496,6 +4127,7 @@ The following commands are available:
 \\[gnus-summary-next-unread-subject]\t Go to the next unread summary line
 \\[gnus-summary-prev-unread-subject]\t Go to the previous unread summary line
 \\[gnus-summary-first-unread-article]\t Go to the first unread article
+\\[gnus-summary-best-unread-article]\t Go to the unread article with the highest score
 \\[gnus-summary-goto-subject]\t Go to some subject
 \\[gnus-summary-goto-last-article]\t Go to the previous article
 
@@ -3519,8 +4151,10 @@ The following commands are available:
 \\[gnus-summary-unmark-as-processable]\t Remove the process mark from the current article
 \\[gnus-summary-unmark-all-processable]\t Remove the process mark from all articles
 
-\\[gnus-summary-kill-same-subject-and-select]\t Kill all articles with the current subject and select the next article
-\\[gnus-summary-kill-same-subject]\t Kill all articles with the current subject
+\\[gnus-summary-raise-same-subject-and-select]\t Raise all articles with the current subject and select the next article
+\\[gnus-summary-raise-same-subject]\t Raise all articles with the current subject
+\\[gnus-summary-lower-same-subject-and-select]\t Lower all articles with the current subject and select the next article
+\\[gnus-summary-lower-same-subject]\t Lower all articles with the current subject
 
 \\[gnus-summary-toggle-threads]\t Toggle thread display
 \\[gnus-summary-show-thread]\t Show the current thread
@@ -3529,21 +4163,22 @@ The following commands are available:
 \\[gnus-summary-prev-thread]\t Go to the previous thread
 \\[gnus-summary-up-thread]\t Go up the current thread
 \\[gnus-summary-down-thread]\t Descend the current thread
-\\[gnus-summary-kill-thread]\t Kill the current thread
+\\[gnus-summary-raise-thread]\t Raise the current thread
+\\[gnus-summary-lower-thread]\t Lower the current thread
 \\[gnus-summary-mark-as-expirable]\t Mark the current artivles as expirable
-\\[gnus-summary-unmark-as-expirable]\t Remove the expirable mark from the current article
-\\[gnus-summary-delete-marked-as-read]\t Delete all articles that are marked as read
-\\[gnus-summary-delete-marked-with]\t Delete all articles that have some mark
+\\[gnus-summary-remove-lines-marked-as-read]\t Remove all articles that are marked as read
+\\[gnus-summary-remove-lines-marked-with]\t Remove all articles that have some mark
 
 \\[gnus-summary-execute-command]\t Execute a command
 \\[gnus-summary-catchup-and-exit]\t Mark all unread articles as read and exit
 \\[gnus-summary-toggle-truncation]\t Toggle truncation of summary lines
 \\[gnus-summary-expand-window]\t Expand the summary window
+\\[gnus-summary-universal-argument]\t Run a command on all articles with the process mark
 
-\\[gnus-summary-sort-by-number]\t Sort the Summary buffer by article number
-\\[gnus-summary-sort-by-author]\t Sort the Summary buffer by author
-\\[gnus-summary-sort-by-subject]\t Sort the Summary buffer by subject
-\\[gnus-summary-sort-by-date]\t Sort the Summary buffer by date
+\\[gnus-summary-sort-by-number]\t Sort the summary buffer by article number
+\\[gnus-summary-sort-by-author]\t Sort the summary buffer by author
+\\[gnus-summary-sort-by-subject]\t Sort the summary buffer by subject
+\\[gnus-summary-sort-by-date]\t Sort the summary buffer by date
 
 \\[gnus-summary-reselect-current-group]\t Exit and reselect the current group
 \\[gnus-summary-rescan-group]\t Exit, get new articles and reselect the group
@@ -3563,15 +4198,15 @@ The following commands are available:
 \\[gnus-summary-mail-forward]\t Forward the current article
 \\[gnus-summary-mail-other-window]\t Mail in the other window
 \\[gnus-summary-save-article]\t Save the current article
-\\[gnus-summary-save-article-rmail]\t Save the current article in rmail format
+\\[gnus-summary-save-article-mail]\t Save the current article in rmail format
 \\[gnus-summary-pipe-output]\t Pipe the current article to a process
 \\[gnus-summary-move-article]\t Move the article to a different newsgroup
 \\[gnus-summary-respool-article]\t Respool the article
 \\[gnus-summary-edit-local-kill]\t Edit the local kill file
 \\[gnus-summary-edit-global-kill]\t Edit the global kill file
 \\[gnus-version]\t Display the current Gnus version
-\\[gnus-summary-exit]\t Exit the Summary buffer 
-\\[gnus-summary-quit]\t Exit the Summary buffer without saving any changes
+\\[gnus-summary-exit]\t Exit the summary buffer 
+\\[gnus-summary-quit]\t Exit the summary buffer without saving any changes
 \\[gnus-summary-describe-group]\t Describe the current newsgroup
 \\[gnus-summary-describe-briefly]\t Give a brief key overview
 \\[gnus-info-find-node]\t Go to the Gnus info node
@@ -3599,17 +4234,25 @@ The following commands are available:
   (kill-all-local-variables)
   (let ((locals gnus-summary-local-variables))
     (while locals
-      (make-local-variable (car locals))
-      (set (car locals) nil)
+      (if (consp (car locals))
+         (progn
+           (make-local-variable (car (car locals)))
+           (set (car (car locals)) (eval (cdr (car locals)))))
+       (make-local-variable (car locals))
+       (set (car locals) nil))
       (setq locals (cdr locals))))
   (gnus-update-format-specifications)
-  (setq mode-line-modified "--- ")
+  (setq mode-line-modified "-- ")
+  (make-local-variable 'mode-line-format)
+  (setq mode-line-format (copy-sequence mode-line-format))
+  (and (equal (nth 3 mode-line-format) "   ")
+       (setcar (nthcdr 3 mode-line-format) ""))
   (setq major-mode 'gnus-summary-mode)
   (setq mode-name "Summary")
   (make-local-variable 'minor-mode-alist)
-  (or (assq 'gnus-show-threads minor-mode-alist)
-      (setq minor-mode-alist
-           (cons (list 'gnus-show-threads " Thread") minor-mode-alist)))
+;  (or (assq 'gnus-show-threads minor-mode-alist)
+;      (setq minor-mode-alist
+;          (cons (list 'gnus-show-threads " Thread") minor-mode-alist)))
   (gnus-set-mode-line 'summary)
   (use-local-map gnus-summary-mode-map)
   (buffer-disable-undo (current-buffer))
@@ -3625,36 +4268,54 @@ The following commands are available:
   (gnus-summary-next-page nil t))
 
 (defun gnus-summary-setup-buffer (group)
-  "Initialize Summary buffer."
+  "Initialize summary buffer."
   (let ((buffer (concat "*Summary " group "*")))
     ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>
     (setq gnus-summary-buffer (set-buffer (get-buffer-create buffer)))
     (gnus-add-current-to-buffer-list)
     (gnus-summary-mode)))
 
+(defun gnus-set-global-variables ()
+  ;; Set the global equivalents of the summary buffer-local variables
+  ;; to the latest values they had. These reflect the summary buffer
+  ;; that was in action when the last article was fetched.
+  (let ((name gnus-newsgroup-name)
+       (marked gnus-newsgroup-marked)
+       (unread gnus-newsgroup-unreads)
+       (headers gnus-current-headers))
+    (save-excursion
+      (set-buffer gnus-group-buffer)
+      (setq gnus-newsgroup-name name)
+      (setq gnus-newsgroup-marked marked)
+      (setq gnus-newsgroup-unreads unread)
+      (setq gnus-current-headers headers))))
+
 (defun gnus-summary-insert-dummy-line (sformat subject number)
   (if (not sformat) 
       (setq sformat gnus-summary-dummy-line-format-spec))
   (let (b)
     (beginning-of-line)
-    (insert (eval sformat))
-    (forward-char -1)
     (setq b (point))
-    (insert (format "%s Z %d 0" subject number))
-    (set-text-properties b (point) '(invisible t))
-    (forward-char 1)))
+    (insert (eval sformat))
+    (add-text-properties
+     b (1+ b)
+     (list 'gnus-subject (gnus-simplify-subject-re subject)
+          'gnus-number number
+          'gnus-mark ?Z
+          'gnus-thread 0))))
 
 (defun gnus-summary-insert-line 
   (sformat header level current unread replied expirable subject-or-nil
-          &optional dummy)
+          &optional dummy score)
   (if (not sformat) 
       (setq sformat gnus-summary-line-format-spec))
   (let* ((indentation 
          (make-string (* level gnus-thread-indent-level) ? ))
         (lines (or (header-lines header) 0))
-        (interest (or gnus-summary-default-interest " "))
-        (replied (if replied ?R ? ))
-        (expirable (if expirable ?X ? ))
+        (score (or score gnus-summary-default-score 0))
+        (score-char (if (= score gnus-summary-default-score) ? 
+                      (if (< score gnus-summary-default-score) ?- ?+)))
+        (replied (if replied gnus-replied-mark ? ))
         (from (header-from header))
         (name-address (gnus-extract-address-components from))
         (address (car (cdr name-address)))
@@ -3670,18 +4331,30 @@ The following commands are available:
     (beginning-of-line)
     (setq b (point))
     (insert-before-markers (eval sformat))
-    (forward-char -1)
-    (if (and gnus-visual gnus-mouse-face)
-       (overlay-put (make-overlay b (point)) 'mouse-face gnus-mouse-face))
-    ;; Info format SUBJECT INTEREST UNREAD NUMBER LEVEL
-    (set-text-properties
-     (prog1
-        (point)
-       (insert (format "%s %d %c %d %d" (gnus-simplify-subject-re subject)
-                      (or gnus-summary-default-interest 5)
-                      unread number level)))
-     (point) '(invisible t))
-    (forward-char 1)))
+    (add-text-properties
+     b (1+ b)
+     (list 'gnus-subject (gnus-simplify-subject-re subject)
+          'gnus-number number
+          'gnus-mark unread
+          'gnus-thread level))))
+
+(defun gnus-summary-update-line ()
+  ;; Update summary line after change.
+  (or (not gnus-summary-default-score)
+      gnus-summary-inhibit-highlight
+      (save-excursion
+       (beginning-of-line 1)
+       (let ((score (gnus-summary-article-score))
+             (default gnus-summary-default-score)
+             (below gnus-summary-mark-below))
+         (save-excursion
+           (if (< score below)
+               (if (eq (following-char) gnus-unread-mark)
+                   (gnus-summary-mark-article nil gnus-low-score-mark))
+             (if (eq (following-char) gnus-low-score-mark)
+                 (gnus-summary-mark-article nil gnus-unread-mark))))
+         (if  gnus-visual
+             (run-hooks 'gnus-visual-summary-update-hook))))))
 
 (defun gnus-summary-update-lines ()
   ;; Rehighlight summary buffer according to `gnus-summary-highlight'.
@@ -3690,37 +4363,30 @@ The following commands are available:
        (set-buffer gnus-summary-buffer)
        (goto-char (point-min))
        (while (not (eobp))
-         (run-hooks 'gnus-summary-update-hook)
+         (gnus-summary-update-line)
          (forward-line 1)))))
 
-;; Suggested by Daniel Quinlan <quinlan@best.com>.  
-  
-
 (defun gnus-summary-read-group (group &optional show-all no-article kill-buffer)
   "Start reading news in newsgroup GROUP.
 If SHOW-ALL is non-nil, already read articles are also listed.
 If NO-ARTICLE is non-nil, no article is selected initially."
-  (message "Retrieving newsgroup: %s..." (gnus-group-real-name group))
+  (message "Retrieving newsgroup: %s..." group)
   (gnus-summary-setup-buffer group)
   (if (gnus-select-newsgroup group show-all)
       (progn
-       ;; You can change the order of subjects in this hook.
+       ;; You can change the subjects in this hook.
        (run-hooks 'gnus-select-group-hook)
+       ;; Do Score Processing.
+       (gnus-score-headers)
+       ;; Update the format specifiers.
+       (gnus-update-format-specifications)
        (gnus-summary-prepare)
        (if (and (zerop (buffer-size))
                 gnus-newsgroup-dormant)
            (gnus-summary-show-all-dormant))
-       (let ((killed 
-              (gnus-add-to-range 
-               gnus-newsgroup-killed 
-               (setq gnus-newsgroup-unreads
-                     (sort gnus-newsgroup-unreads (function <)))))
-             (gnus-newsgroup-killed 
-              (if gnus-kill-killed nil gnus-newsgroup-killed)))
-         (if (not (consp (car killed))) (setq killed (list killed)))
-         ;; Function `gnus-apply-kill-file' must be called in this hook.
-         (run-hooks 'gnus-apply-kill-hook)
-         (setq gnus-newsgroup-killed killed))
+       (gnus-set-global-variables)
+       ;; Function `gnus-apply-kill-file' must be called in this hook.
+       (run-hooks 'gnus-apply-kill-hook)
        (if (zerop (buffer-size))
            (progn
              ;; This newsgroup is empty.
@@ -3753,27 +4419,29 @@ If NO-ARTICLE is non-nil, no article is selected initially."
              (kill-buffer kill-buffer))))
     ;; Cannot select newsgroup GROUP.
     (message "Couldn't select newsgroup")
+    (and (eq major-mode 'gnus-summary-mode)
+        (kill-buffer (current-buffer)))
     (set-buffer gnus-group-buffer)
     (gnus-summary-position-cursor)))
 
 (defun gnus-summary-prepare ()
-  "Prepare summary list of current newsgroup in Summary buffer."
+  "Prepare summary list of current newsgroup in summary buffer."
   (let ((buffer-read-only nil))
     (erase-buffer)
     (gnus-summary-prepare-threads 
-         (if gnus-show-threads
-             (gnus-gather-threads (gnus-make-threads))
-           gnus-newsgroup-headers)
-         0)
-    (gnus-summary-delete-dormant)
+     (if gnus-show-threads
+        (gnus-gather-threads (gnus-sort-threads (gnus-make-threads)))
+       gnus-newsgroup-headers)
+     0)
+    (gnus-summary-remove-dormant-lines)
     ;; Erase header retrieval message.
     (message "")
-    ;; Call hooks for modifying Summary buffer.
+    ;; Call hooks for modifying summary buffer.
     ;; Suggested by sven@tde.LTH.Se (Sven Mattisson).
     (goto-char (point-min))
     (run-hooks 'gnus-summary-prepare-hook)))
 
-(defun gnus-summary-delete-dormant ()
+(defun gnus-summary-remove-dormant-lines ()
   (let ((int gnus-newsgroup-dormant)
        (buffer-read-only nil)
        beg cur-level)
@@ -3797,7 +4465,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
 
 (defun gnus-gather-threads (threads)
   "Gather threads that have lost their roots."
-  (if (not gnus-gather-loose-threads)
+  (if (not gnus-summary-make-false-root)
       threads 
     (let ((hashtb (gnus-make-hashtable 1023))
          (prev threads)
@@ -3805,15 +4473,19 @@ If NO-ARTICLE is non-nil, no article is selected initially."
          thread subject hthread unre-subject)
       (while threads
        (setq subject (header-subject (car (car threads))))
-       (if (setq hthread (gnus-gethash 
-                          (setq unre-subject 
-                                (gnus-simplify-subject-re subject))
-                          hashtb))
+       (and gnus-summary-gather-subject-limit
+            (> (length subject) gnus-summary-gather-subject-limit)
+            (setq subject
+                  (substring subject 0 gnus-summary-gather-subject-limit)))
+       (if (setq hthread 
+                 (gnus-gethash 
+                  (setq unre-subject (gnus-simplify-subject-re subject))
+                  hashtb))
            (progn
-             (if (not (stringp (car (car hthread))))
+             (or (stringp (car (car hthread)))
                  (setcar hthread (list subject (car hthread))))
-             (setcar hthread
-                     (append (car hthread) (cons (car threads) nil)))
+             (setcdr (car hthread) (nconc (cdr (car hthread)) 
+                                          (list (car threads))))
              (setcdr prev (cdr threads))
              (setq threads prev))
          (gnus-sethash unre-subject threads hashtb))
@@ -3822,15 +4494,17 @@ If NO-ARTICLE is non-nil, no article is selected initially."
       result)))
 
 (defun gnus-make-threads ()
-  ;; This function takes the dependencies already made by
+  ;; This function takes the dependencies already made by 
   ;; `gnus-get-newsgroup-headers' and builds the trees. First we go
   ;; through the dependecies in the hash table and finds all the
-  ;; roots. Roots do not refer back to any valid articles. 
-  (let (roots mroots)
+  ;; roots. Roots do not refer back to any valid articles.
+  (let (roots)
+    (and gnus-fetch-old-headers (eq gnus-headers-retrieved-by 'nov)
+        (gnus-build-old-threads))
     (mapatoms
      (lambda (refs)
        (if (not (car (symbol-value refs)))
-          (setq mroots (append (cdr (symbol-value refs)) mroots))
+          (setq roots (append (cdr (symbol-value refs)) roots))
         ;; Ok, these refer back to valid articles, but if
         ;; `gnus-thread-ignore-subject' is nil, we have to check that
         ;; the root has the same subject as its children. The children
@@ -3846,41 +4520,170 @@ If NO-ARTICLE is non-nil, no article is selected initially."
                                   (gnus-simplify-subject-re 
                                    (header-subject (car headers)))))
                     (progn
-                      (setq mroots (cons (car headers) mroots))
+                      (setq roots (cons (car headers) roots))
                       (setcdr prev (cdr headers)))
                   (setq prev headers))
                 (setq headers (cdr headers)))))))
      gnus-newsgroup-dependencies)
 
-    ;; We sort the roots according to article number. (This has to be
-    ;; done because all sequencing information was lost when we built
-    ;; the dependecies hash table.)
-    (setq roots
-         (sort
-          mroots
-          (lambda (h1 h2)
-            (< (header-number h1) (header-number h2)))))
-    ;; Now we have all the roots, so we go through all them all and
-    ;; build the trees. 
-    (mapcar (lambda (root) (gnus-make-sub-thread root)) roots)))
+    (mapcar (lambda (root) (gnus-trim-thread (gnus-make-sub-thread root)))
+           roots)))
+
+(defun gnus-trim-thread (thread)
+  (if (and (eq gnus-fetch-old-headers 'some)
+          (memq (header-number (car thread)) gnus-newsgroup-ancient)
+          (= (length thread) 2))
+      (gnus-trim-thread (nth 1 thread))
+    thread))
 
 (defun gnus-make-sub-thread (root)
   ;; This function makes a sub-tree for a node in the tree.
   (let ((children (reverse (cdr (gnus-gethash (downcase (header-id root))
                                              gnus-newsgroup-dependencies)))))
-    (if (not children)
-       (list root)
-      (cons root (mapcar 
-                 (lambda (top) (gnus-make-sub-thread top)) children)))))
+    (cons root (mapcar 'gnus-make-sub-thread children))))
+
+(defun gnus-build-old-threads ()
+  ;; Look at all the articles that refer back to old articles, and
+  ;; fetch the headers for the articles that aren't there. This will
+  ;; build complete threads - if the roots haven't been expired by the
+  ;; server, that is.
+  (let (id heads)
+    (mapatoms
+     (lambda (refs)
+       (if (not (car (symbol-value refs)))
+          (progn
+            (setq heads (cdr (symbol-value refs)))
+            (while heads
+              (if (not (memq (header-number (car heads))
+                             gnus-newsgroup-dormant))
+                  (progn
+                    (setq id (symbol-name refs))
+                    (while (and (setq id (gnus-build-get-header id))
+                                (not (car (gnus-gethash 
+                                           id gnus-newsgroup-dependencies)))))
+                    (setq heads nil))
+                (setq heads (cdr heads)))))))
+     gnus-newsgroup-dependencies)))
+
+(defun gnus-build-get-header (id)
+  ;; Look through the buffer of NOV lines and find the header to
+  ;; ID. Enter this line into the dependencies hash table, and return
+  ;; the id of the parent article (if any).
+  (let ((deps gnus-newsgroup-dependencies)
+       found header)
+    (prog1
+       (save-excursion
+         (set-buffer nntp-server-buffer)
+         (goto-char (point-min))
+         (while (and (not found) (search-forward id nil t))
+           (beginning-of-line)
+           (setq found (looking-at (format "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t%s"
+                                           (regexp-quote id))))
+           (or found (beginning-of-line 2)))
+         (if found
+             (let (ref)
+               (beginning-of-line)
+               (and
+                (setq header (gnus-nov-parse-line 
+                              (read (current-buffer)) deps))
+                (setq ref (header-references header))
+                (string-match "\\(<[^>]+>\\) *$" ref)
+                (substring ref (match-beginning 1) (match-end 1))))))
+      (and header
+          (setq gnus-newsgroup-headers (cons header gnus-newsgroup-headers)
+                gnus-newsgroup-ancient (cons (header-number header)
+                                             gnus-newsgroup-ancient))))))
+
+(defun gnus-sort-threads (threads)
+  ;; Sort threads as specified in `gnus-thread-sort-functions'.
+  (let ((fun gnus-thread-sort-functions))
+    (while fun
+      (setq threads (sort threads (car fun))
+           fun (cdr fun))))
+  threads)
+
+(defun gnus-thread-header (thread)
+  ;; Return header of first article in THREAD.
+  (if (consp thread)
+      (if (stringp (car thread))
+         (car (car (cdr thread)))
+       (car thread))
+    thread))
+
+(defun gnus-thread-sort-by-number (h1 h2)
+  "Sort threads by root article number."
+  (let ((h1 (gnus-thread-header h1))
+       (h2 (gnus-thread-header h2)))
+    (< (header-number h1) (header-number h2))))
+
+(defun gnus-thread-sort-by-author (h1 h2)
+  "Sort threads by root author."
+  (let ((h1 (gnus-thread-header h1))
+       (h2 (gnus-thread-header h2)))
+    (string-lessp
+     (let ((extract (gnus-extract-address-components (header-from h1))))
+       (or (car extract) (cdr extract)))
+     (let ((extract (gnus-extract-address-components (header-from h2))))
+       (or (car extract) (cdr extract))))))
+
+(defun gnus-thread-sort-by-subject (h1 h2)
+  "Sort threads by root subject."
+  (let ((h1 (gnus-thread-header h1))
+       (h2 (gnus-thread-header h2)))
+    (string-lessp
+     (downcase (gnus-simplify-subject (header-subject h1)))
+     (downcase (gnus-simplify-subject (header-subject h2))))))
+
+(defun gnus-thread-sort-by-date (h1 h2)
+  "Sort threads by root article date."
+  (let ((h1 (gnus-thread-header h1))
+       (h2 (gnus-thread-header h2)))
+    (string-lessp
+     (gnus-sortable-date (header-date h1))
+     (gnus-sortable-date (header-date h2)))))
+
+(defun gnus-thread-sort-by-score (h1 h2)
+  "Sort threads by root article score.
+Unscored articles will be counted as havin a score of zero."
+  (let ((h1 (gnus-thread-header h1))
+       (h2 (gnus-thread-header h2)))
+    (let ((s1 (assq (header-number h1) gnus-newsgroup-scored))
+         (s2 (assq (header-number h2) gnus-newsgroup-scored)))
+      (> (or (cdr s1) gnus-summary-default-score 0)
+        (or (cdr s2) gnus-summary-default-score 0)))))
+
+(defun gnus-thread-sort-by-total-score (h1 h2)
+  "Sort threads by the sum of all scores in the thread.
+Unscored articles will be counted as havin a score of zero."
+  (> (gnus-thread-total-score h1) (gnus-thread-total-score h2)))
+
+(defun gnus-thread-total-score (thread)
+  ;;  This function find the total score of  THREAD.
+  (if (consp thread)
+      (if (stringp (car thread))
+         (apply gnus-thread-score-function 0
+                (mapcar 'gnus-thread-total-score-1 (cdr thread)))
+       (gnus-thread-total-score-1 thread))
+    (gnus-thread-total-score-1 (list thread))))
+
+(defun gnus-thread-total-score-1 (root)
+  ;; This function find the total score of the thread below ROOT.
+  (setq root (car root))
+  (apply gnus-thread-score-function
+        (or (cdr (assq (header-number root) gnus-newsgroup-scored))
+            gnus-summary-default-score 0)
+        (mapcar 'gnus-thread-total-score
+                (cdr (gnus-gethash (downcase (header-id root))
+                                   gnus-newsgroup-dependencies)))))
 
 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
 (defvar gnus-tmp-prev-subject "")
+(defvar gnus-tmp-prev-dormant nil)
 
-;; Basic ideas by Paul Dworkin <paul@media-lab.media.mit.edu>
-;; Subject bug fix by jbw@bigbird.bu.edu (Joe Wells)
+;; Basic ideas by Paul Dworkin <paul@media-lab.media.mit.edu>.
 (defun gnus-summary-prepare-threads 
   (threads level &optional not-child no-subject)
-  "Prepare Summary buffer from THREADS and indentation LEVEL.  
+  "Prepare summary buffer from THREADS and indentation LEVEL.  
 THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'  
 or a straight list of headers."
   (let (thread header number subject clevel)
@@ -3912,7 +4715,8 @@ or a straight list of headers."
                   (gnus-summary-prepare-threads (list (car (cdr thread))) 0)
                   (setq thread (cdr (cdr thread)))
                   (while thread
-                    (gnus-summary-prepare-threads (list (car thread)) 0 nil t)
+                    (gnus-summary-prepare-threads (list (car thread)) 0 nil
+                                                  (not gnus-tmp-prev-dormant))
                     (setq thread (cdr thread))))
                  (t
                   ;; We do not make a root for the gathered
@@ -3924,13 +4728,14 @@ or a straight list of headers."
        ;; The header is a real article.
        (setq number (header-number header)
              subject (header-subject header)
-             gnus-tmp-prev-subject subject)
+             gnus-tmp-prev-dormant (memq number gnus-newsgroup-dormant))
        (gnus-summary-insert-line
         nil header level nil 
-        (cond ((memq number gnus-newsgroup-marked) ?-)
-              ((memq number gnus-newsgroup-dormant) ?+)
-              ((memq number gnus-newsgroup-unreads) ? )
-              (t ?D))
+        (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 gnus-ancient-mark))
         (memq number gnus-newsgroup-replied)
         (memq number gnus-newsgroup-expirable)
         (if no-subject gnus-summary-same-subject
@@ -3941,148 +4746,165 @@ or a straight list of headers."
                              (gnus-simplify-subject-re subject)))))
               subject
             gnus-summary-same-subject))
-        not-child)
+        not-child
+        (cdr (assq number gnus-newsgroup-scored)))
+       (setq gnus-tmp-prev-subject subject)
        ;; Recursively print subthreads.
        (and (consp thread) (cdr thread)
             (gnus-summary-prepare-threads (cdr thread) (1+ level)))))))
 
-(defun gnus-select-newsgroup (group &optional show-all)
+(defun gnus-select-newsgroup (group &optional read-all)
   "Select newsgroup GROUP.
-If SHOW-ALL is non-nil, all articles in the group are selected."
+If READ-ALL is non-nil, all articles in the group are selected."
   (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
-        (real-group (gnus-group-real-name group))
         (info (nth 2 entry))
         articles header-marks)
-
-    (if (eq (car entry) t)
-       (or (if (nth 4 info) 
-               (gnus-activate-foreign-newsgroup info)
-             (gnus-activate-newsgroup (car info)))
-           (error "Couldn't request newsgroup %s" group)))
-    (setq gnus-current-select-method (or (nth 4 info)
-                                        gnus-select-method))
+    (and (eq (car entry) t)
+        (or (gnus-activate-newsgroup (car info))
+            (error "Couldn't request newsgroup %s" group)))
+    (setq gnus-current-select-method (or (nth 4 info) gnus-select-method))
     (gnus-check-news-server (nth 4 info))
     (if (not (gnus-request-group group t))
        (error "Couldn't request newsgroup %s" group))
 
+    ;; Initialize the buffer that holds lines that have been removed
+    ;; from the summary buffer.
+    (setq gnus-newsgroup-expunged-buffer 
+         (get-buffer-create (format " *gnus expunge %s*" group)))
+    (save-excursion
+      (set-buffer gnus-newsgroup-expunged-buffer)
+      (buffer-disable-undo (current-buffer))
+      (erase-buffer)
+      (gnus-add-current-to-buffer-list))
+    
     (setq gnus-newsgroup-name group)
     (setq gnus-newsgroup-unselected nil)
     (setq gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
-    (cond 
-     ((or show-all
-         ;; Check whether there are only dormant articles in this newsgroup. 
-         (= (length gnus-newsgroup-unreads)
-            (length (cdr (assq 'dormant (nth 3 info))))))
-      ;; Select all active articles.
-      (setq articles (gnus-uncompress-sequence 
-                     (gnus-gethash group gnus-active-hashtb))))
-     (t
-      ;; Select unread articles only.
-      (setq articles gnus-newsgroup-unreads)))
-    ;; Require confirmation if selecting large newsgroup.
-    (if (not (numberp gnus-large-newsgroup))
+
+    (and info
+        (progn
+          (gnus-adjust-marked-articles info)
+          (setq gnus-newsgroup-marked (cdr (assq 'tick (nth 3 info))))
+          (setq gnus-newsgroup-replied (cdr (assq 'reply (nth 3 info))))
+          (setq gnus-newsgroup-expirable (cdr (assq 'expire (nth 3 info))))
+          (setq gnus-newsgroup-killed (cdr (assq 'killed (nth 3 info))))
+          (setq gnus-newsgroup-bookmarks (cdr (assq 'bookmark (nth 3 info))))
+          (setq gnus-newsgroup-dormant (cdr (assq 'dormant (nth 3 info))))
+          (setq gnus-newsgroup-scored (cdr (assq 'score (nth 3 info))))
+          (setq gnus-newsgroup-processable nil)))
+
+    (if (not (setq articles (gnus-articles-to-read group read-all)))
        nil
-      (let ((number (length articles))
-           selected break)
-       (if (> number gnus-large-newsgroup)
-           (progn
-             (condition-case ()
-                 (let ((input
-                        (read-string
-                         (format
-                          "How many articles from %s (default %d): "
-                          gnus-newsgroup-name number))))
-                   (setq selected
-                         (if (string-equal input "")
-                             number (string-to-int input))))
-               (quit
-                (setq selected 0)))
-             (if (< (abs selected) number)
-                 (progn
-                   (cond 
-                    ((< selected 0) 
-                     ;; Select the N oldest articles.
-                     (setq articles (copy-sequence articles))
-                     (setq break (nthcdr (1- (abs selected)) articles))
-                     (setq gnus-newsgroup-unselected 
-                           (gnus-intersection
-                            (cdr break)
-                            gnus-newsgroup-unreads))
-                     (setcdr break nil))
-                    ((> selected 0)
-                     ;; Select the N most recent articles.
-                     (setq gnus-newsgroup-unselected  
-                           (copy-sequence articles))
-                     (setq break (nthcdr (- number (1+ selected))
-                                         gnus-newsgroup-unselected))
-                     (setq articles (cdr break))
-                     (setcdr break nil)
-                     (setq gnus-newsgroup-unselected
-                           (gnus-intersection
-                            gnus-newsgroup-unselected
-                            gnus-newsgroup-unreads)))
-                    
-                    (t
-                     ;; Select no articles.
-                     (setq gnus-newsgroup-unselected articles)
-                     (setq articles nil)))))))
-       ))
-    (if (not articles)
-       nil
-      ;; Create the list of headers from the headers.
+      ;; Init the dependencies hash table.
+      (setq gnus-newsgroup-dependencies 
+           (gnus-make-hashtable (length gnus-newsgroup-unreads)))
+      ;; Retrieve the headers and read them in.
       (setq gnus-newsgroup-headers 
-           (if (eq (gnus-retrieve-headers articles gnus-newsgroup-name) 'nov)
+           (if (eq 'nov (setq gnus-headers-retrieved-by
+                              (gnus-retrieve-headers 
+                               (if gnus-fetch-old-headers 
+                                   (cons 1 articles) articles) 
+                               gnus-newsgroup-name)))
                (progn
                  (gnus-get-newsgroup-headers-xover articles))
              (gnus-get-newsgroup-headers)))
+      ;; If we were to fetch old headers, but the backend didn't
+      ;; support XOVER, then it is possible we fetched one article
+      ;; that we shouldn't have. If that's the case, we pop it off the
+      ;; list of headers.
+      (and (not (eq gnus-headers-retrieved-by 'nov))
+          gnus-fetch-old-headers
+          gnus-newsgroup-headers
+          (/= (header-number (car gnus-newsgroup-headers)) (car articles))
+          (setq gnus-newsgroup-headers (cdr gnus-newsgroup-headers)))
       ;; Remove cancelled articles from the list of unread articles.
       (setq gnus-newsgroup-unreads
-           (gnus-intersection gnus-newsgroup-unreads
-                              (mapcar
-                               (lambda (headers)
-                                 (header-number headers))
-                               gnus-newsgroup-headers)))
-      ;; Ticked articles must be a subset of unread articles.
-      (if info
-         (progn
-           (gnus-adjust-marked-articles info)
-           (setq gnus-newsgroup-marked (cdr (assq 'tick (nth 3 info))))
-           (setq gnus-newsgroup-replied (cdr (assq 'reply (nth 3 info))))
-           (setq gnus-newsgroup-expirable (cdr (assq 'expire (nth 3 info))))
-           (setq gnus-newsgroup-killed (cdr (assq 'killed (nth 3 info))))
-           (setq gnus-newsgroup-bookmarks (cdr (assq 'bookmark (nth 3 info))))
-           (setq gnus-newsgroup-dormant (cdr (assq 'dormant (nth 3 info))))
-           (setq gnus-newsgroup-processable nil)))
+           (gnus-intersection 
+            gnus-newsgroup-unreads
+            (mapcar (lambda (headers) (header-number headers))
+                    gnus-newsgroup-headers)))
       ;; Check whether auto-expire is to be done in this group.
       (setq gnus-newsgroup-auto-expire
            (and (stringp gnus-auto-expirable-newsgroups)
-                (string-match gnus-auto-expirable-newsgroups real-group)))
+                (string-match gnus-auto-expirable-newsgroups 
+                              (gnus-group-real-name group))))
       ;; First and last article in this newsgroup.
-      (setq gnus-newsgroup-begin
-           (if gnus-newsgroup-headers
-               (header-number (car gnus-newsgroup-headers))
-             0))
-      (setq gnus-newsgroup-end
-           (if gnus-newsgroup-headers
-               (header-number (gnus-last-element gnus-newsgroup-headers))
-             0))
-      ;; File name of the last saved article.
-      (setq gnus-newsgroup-last-rmail nil)
-      (setq gnus-newsgroup-last-mail nil)
-      (setq gnus-newsgroup-last-folder nil)
-      (setq gnus-newsgroup-last-file nil)
-      ;; Reset article pointers etc.
-      (setq gnus-current-article nil)
-      (setq gnus-current-headers nil)
-      (setq gnus-have-all-headers nil)
-      (setq gnus-last-article nil)
+      (and gnus-newsgroup-headers
+          (setq gnus-newsgroup-begin 
+                (header-number (car gnus-newsgroup-headers)))
+          (setq gnus-newsgroup-end
+                (header-number (gnus-last-element gnus-newsgroup-headers))))
       (setq gnus-xref-hashtb nil)
       (setq gnus-reffed-article-number -1)
-      (setq gnus-newsgroup-headers-hashtb-by-number nil)
-      ;; Update the format specifiers.
-      (gnus-update-format-specifications)
       ;; GROUP is successfully selected.
-      t)))
+      (or gnus-newsgroup-headers t))))
+
+(defun gnus-articles-to-read (group read-all)
+  ;; Find out what articles the user wants to read.
+  (let* ((articles
+         ;; Select all articles if `read-all' is non-nil, or if all the
+         ;; unread articles are dormant articles.
+         (if (or read-all
+                 (= (length gnus-newsgroup-unreads) 
+                    (length gnus-newsgroup-scored)))
+             (gnus-uncompress-sequence 
+              (gnus-gethash group gnus-active-hashtb))
+           gnus-newsgroup-unreads))
+        (scored-list (gnus-killed-articles gnus-newsgroup-killed articles))
+        (scored (length scored-list))
+        (number (length articles))
+        (marked (+ (length gnus-newsgroup-marked)
+                   (length gnus-newsgroup-dormant)))
+        (select
+         (condition-case ()
+             (cond ((and (or (<= scored marked)
+                             (= scored number))
+                         (numberp gnus-large-newsgroup)
+                         (> number gnus-large-newsgroup))
+                    (let ((input
+                           (read-string
+                            (format
+                             "How many articles from %s (default %d): "
+                             gnus-newsgroup-name number))))
+                      (if (string-equal input "")
+                          number input)))
+                   ((and (> scored marked) (< scored number))
+                    (let ((input
+                           (read-string
+                            (format 
+                             "%s %s (%d scored, %d total, %d default): "
+                             "How many articles from"
+                             group scored number scored))))
+                      (if (string-equal input "")
+                          scored input)))
+                   (t number))
+           (quit 0))))
+    (setq select (if (numberp select) select (string-to-number select)))
+    (if (zerop select)
+       ()
+      (if (and (not (zerop scored)) (<= (abs select) scored))
+         (progn
+           (setq articles (sort scored-list '<))
+           (setq number (length articles)))
+       (setq articles (copy-sequence articles)))
+
+      (if (< (abs select) number)
+         (if (< select 0) 
+             ;; Select the N oldest articles.
+             (setcdr (nthcdr (1- (abs select)) articles) nil)
+           ;; Select the N most recent articles.
+           (setq articles (nthcdr (- number select) articles))))
+      (setq gnus-newsgroup-unselected
+           (gnus-set-difference gnus-newsgroup-unreads articles))
+      articles)))
+
+(defun gnus-killed-articles (killed articles)
+  (let (out)
+    (while articles
+      (if (inline (gnus-member-of-range (car articles) killed))
+         (setq out (cons (car articles) out)))
+      (setq articles (cdr articles)))
+    out))
 
 (defun gnus-adjust-marked-articles (info)
   "Remove all marked articles that are no longer legal."
@@ -4102,6 +4924,15 @@ If SHOW-ALL is non-nil, all articles in the group are selected."
                   (setq prev m)
                 (setcdr prev (cdr m)))
               (setq m (cdr m))))
+           ((eq 'score (car prev))
+            ;; Scored articles should be a subset of
+            ;; unread/unselected articles. 
+            (while m
+              (if (or (memq (car (car m)) gnus-newsgroup-unreads)
+                      (memq (car (car m)) gnus-newsgroup-unreads))
+                  (setq prev m)
+                (setcdr prev (cdr m)))
+              (setq m (cdr m))))
            ((eq 'bookmark (car prev))
             ;; Bookmarks should be a subset of active articles.
             (while m
@@ -4113,7 +4944,8 @@ If SHOW-ALL is non-nil, all articles in the group are selected."
             ;; Articles that have been through the kill process are
             ;; to be a subset of active articles.
             (while (and m (< (cdr (car m)) (car active)))
-              (setcdr prev (cdr m)))
+              (setcdr prev (cdr m))
+              (setq m (cdr m)))
             (if (and m (< (car (car m)) (car active))) 
                 (setcar (car m) (car active))))
            ((or (eq 'reply (car marked)) (eq 'expire (car marked)))
@@ -4146,21 +4978,18 @@ If SHOW-ALL is non-nil, all articles in the group are selected."
   info)
 
 (defun gnus-set-marked-articles 
-  (info ticked replied expirable killed dormant bookmark) 
+  (info ticked replied expirable killed dormant bookmark score
   "Enter the various lists of marked articles into the newsgroup info list."
   (let (newmarked)
-    (if ticked
-       (setq newmarked (cons (cons 'tick ticked) nil)))
-    (if replied 
-       (setq newmarked (cons (cons 'reply replied) newmarked)))
-    (if expirable 
-       (setq newmarked (cons (cons 'expire expirable) newmarked)))
-    (if killed
-       (setq newmarked (cons (cons 'killed killed) newmarked)))
-    (if dormant
-       (setq newmarked (cons (cons 'dormant dormant) newmarked)))
-    (if bookmark
-       (setq newmarked (cons (cons 'bookmark bookmark) newmarked)))
+    (and ticked (setq newmarked (cons (cons 'tick ticked) nil)))
+    (and replied (setq newmarked (cons (cons 'reply replied) newmarked)))
+    (and expirable (setq newmarked (cons (cons 'expire expirable) 
+                                        newmarked)))
+    (and killed (setq newmarked (cons (cons 'killed killed) newmarked)))
+    (and dormant (setq newmarked (cons (cons 'dormant dormant) newmarked)))
+    (and bookmark (setq newmarked (cons (cons 'bookmark bookmark) 
+                                       newmarked)))
+    (and score (setq newmarked (cons (cons 'score score) newmarked)))
     (if (nthcdr 3 info)
        (if newmarked
            (setcar (nthcdr 3 info) newmarked)
@@ -4170,8 +4999,23 @@ If SHOW-ALL is non-nil, all articles in the group are selected."
       (if newmarked
          (setcdr (nthcdr 2 info) (cons newmarked nil))))))
 
+(defun gnus-add-marked-articles (group type articles &optional info)
+  ;; Add ARTICLES of TYPE to the info of GROUP.
+  ;; If INFO is non-nil, use that info.
+  (let ((info (or info (nth 2 (gnus-gethash group gnus-newsrc-hashtb))))
+       marked m)
+    (or (not info)
+       (and (not (setq marked (nthcdr 3 info)))
+            (setcdr (nthcdr 2 info) (list (list (cons type articles)))))
+       (and (not (setq m (assq type (car marked))))
+            (setcar marked (cons (cons type articles) (car marked))))
+       (while articles
+         (or (memq (car articles) m) (setcdr m (cons (car articles)
+                                                     (cdr m))))
+         (setq articles (cdr articles))))))
+        
 (defun gnus-set-mode-line (where)
-  "This function sets the mode line of the Article or Summary buffers.
+  "This function sets the mode line of the article or summary buffers.
 If WHERE is `summary', the summary mode line format will be used."
   (if (memq where gnus-updated-mode-lines)
       (let (mode-string)
@@ -4192,34 +5036,36 @@ If WHERE is `summary', the summary mode line format will be used."
                 (subject
                  (if gnus-current-headers
                      (header-subject gnus-current-headers) ""))
-                (max-len (if (eq where 'summary) 45 52)))
+                (max-len (if (eq where 'summary) 59 59)))
            (setq mode-string (eval mformat))
            (if (> (length mode-string) max-len) 
                (setq mode-string 
-                     (concat (substring mode-string 0 (- max-len 4)) "...")))
-           (setq mode-string (format (format "%%-%ds" max-len) mode-string))))
+                     (concat (substring mode-string 0 (- max-len 3)) "...")))
+           (setq mode-string (format (format "%%-%ds" max-len 5)
+                                     mode-string))))
        (setq mode-line-buffer-identification mode-string)
        (set-buffer-modified-p t))))
 
 (defun gnus-create-xref-hashtb (from-newsgroup headers unreads)
   "Go through the HEADERS list and add all Xrefs to a hash table.
 The resulting hash table is returned, or nil if no Xrefs were found."
-  (let ((prefix (if (and 
-                    (string-match gnus-foreign-group-prefix from-newsgroup)
-                    (not (eq 'nnvirtual (car gnus-current-select-method))))
-                   gnus-foreign-group-prefix))
-       (xref-hashtb (make-vector 63 0))
-       start group entry number xrefs header)
+  (let* ((from-method (gnus-find-method-for-group from-newsgroup))
+        (prefix (if (and 
+                     (gnus-group-foreign-p from-newsgroup)
+                     (not (eq 'nnvirtual (car from-method))))
+                    (gnus-group-real-prefix from-newsgroup)))
+        (xref-hashtb (make-vector 63 0))
+        start group entry number xrefs header)
     (while headers
       (setq header (car headers))
       (if (and (setq xrefs (header-xref header))
               (not (memq (header-number header) unreads)))
          (progn
            (setq start 0)
-           (while (string-match "\\([^ :]+\\):\\([0-9]+\\)" xrefs start)
+           (while (string-match "\\([^ ]+\\):\\([0-9]+\\)" xrefs start)
              (setq start (match-end 0))
              (setq group (concat prefix (substring xrefs (match-beginning 1) 
-                                           (match-end 1))))
+                                                   (match-end 1))))
              (setq number 
                    (string-to-int (substring xrefs (match-beginning 2) 
                                              (match-end 2))))
@@ -4229,9 +5075,9 @@ The resulting hash table is returned, or nil if no Xrefs were found."
       (setq headers (cdr headers)))
     (if start xref-hashtb nil)))
 
-(defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
+(defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads expirable)
   "Look through all the headers and mark the Xrefs as read."
-  (let (name entry read info xref-hashtb idlist active num range)
+  (let (name entry read info xref-hashtb idlist active num range exps)
     (set-buffer gnus-group-buffer)
     (if (setq xref-hashtb 
              (gnus-create-xref-hashtb from-newsgroup headers unreads))
@@ -4245,23 +5091,35 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                      ;; Only do the xrefs if the group has the same
                      ;; select method as the group we have just read.
                      (or (and (not (nth 4 (setq info (nth 2 entry))))
-                              (eq gnus-current-select-method
+                              (eq (gnus-find-method-for-group from-newsgroup)
                                   gnus-select-method))
-                         (eq (car gnus-current-select-method) 'nnvirtual)
+                         (eq (car (gnus-find-method-for-group 
+                                   from-newsgroup)) 'nnvirtual)
                          (equal (nth 4 info) 
-                                gnus-current-select-method)))
+                                (gnus-find-method-for-group from-newsgroup))))
                 (progn
                   (setq num 0)
                   ;; Set the new list of read articles in this group.
                   (setq active (gnus-gethash name gnus-active-hashtb))
                   ;; First peel off all illegal article numbers.
                   (if active
-                      (let ((id idlist))
-                        (while id
-                          (if (or (> (car id) (cdr active))
-                                  (< (car id) (car active)))
-                              (setq idlist (delq (car id) idlist)))
-                          (setq id (cdr id)))))
+                      (let ((ids idlist)
+                            (ticked (cdr (memq 'tick (nth 3 info))))
+                            (dormant (cdr (memq 'dormant (nth 3 info))))
+                            id)
+                        (setq exps nil)
+                        (while ids
+                          (setq id (car ids))
+                          (if (or (> id (cdr active))
+                                  (< id (car active))
+                                  (memq id ticked)
+                                  (memq id dormant))
+                              (setq idlist (delq id idlist)))
+                          (and (memq id expirable)
+                               (setq exps (cons id exps)))
+                          (setq ids (cdr ids)))))
+                  ;; Update expirable articles.
+                  (gnus-add-marked-articles nil 'expirable exps info)
                   (setcar (nthcdr 2 info)
                           (setq range
                                 (gnus-add-to-range 
@@ -4283,103 +5141,118 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                           (setq num (- (cdr active) num)))
                         ;; Update the number of unread articles.
                         (setcar entry (max 0 num))
-                        ;; Update the Newsgroup buffer.
+                        ;; Update the group buffer.
                         (gnus-group-update-group name t)))))))
         xref-hashtb))))
 
 (defsubst gnus-header-value ()
   (buffer-substring (match-end 0) (save-excursion (end-of-line) (point))))
 
-;; Felix Lee function with jwz rewrites (and some lmi rewrites to boot).
-;; Goes through the newsgroups headers and returns a list of arrays:
 (defun gnus-get-newsgroup-headers ()
   (setq gnus-article-internal-prepare-hook nil)
-  (save-excursion
-    (let ((cur nntp-server-buffer)
-         (dependencies (gnus-make-hashtable (length gnus-newsgroup-unreads)))
-         (none-id 0)
-         headers header subject from char c article unreads in-reply-to
-         references end-header id dep ref end)
+  (let ((cur nntp-server-buffer)
+       (dependencies gnus-newsgroup-dependencies)
+       (none-id 0)
+       headers char article id dep end)
+    (save-excursion
       (set-buffer nntp-server-buffer)
       (goto-char 1)
-      (while (re-search-forward "^[23][0-9]+ \\([0-9]+\\)" nil t)
-       (setq from nil
-             subject nil
-             in-reply-to nil
-             references nil
-             ref nil
-             header (make-vector 9 nil)
-             c (following-char))
-       (goto-char (match-beginning 1))
-       (header-set-number 
-        header (setq article (read cur)))
-       (setq end-header (save-excursion (search-forward "\n.\n" nil t)))
-       (while (re-search-forward "^\\(from\\|subject\\|message-id\\|date\\|lines\\|xref\\|references\\|in-reply-to\\): "
-                                  end-header t)
-         (beginning-of-line)
-         (setq char (downcase (following-char))) 
-         (cond
-          ((eq char ?s)
-           (header-set-subject header 
-                               (setq subject (gnus-header-value))))
-          ((eq char ?f)
-           (header-set-from header (setq from (gnus-header-value))))
-          ((eq char ?x)
-           (header-set-xref header (gnus-header-value)))
-          ((eq char ?l)
-           (header-set-lines header 
-                                  (string-to-int (gnus-header-value))))
-          ((eq char ?d)
-           (header-set-date header (gnus-header-value)))
-          ((eq char ?m)
-           (header-set-id header (setq id (gnus-header-value))))
-          ((eq char ?r)
-           (setq references (gnus-header-value))
-           (setq end (match-end 0))
-           (save-excursion
-             (setq ref 
-                   (downcase
-                    (buffer-substring
-                     (progn 
-                       (end-of-line)
-                       (search-backward ">" end t)
-                       (1+ (point)))
-                     (progn
-                       (search-backward "<" end t)
-                       (point)))))))
-          ((eq char ?i)
-           (setq in-reply-to (gnus-header-value))))
-         (forward-line 1))
-       (if references
-           (header-set-references header references)
-         (and in-reply-to
-              (string-match "<[^>]+>" in-reply-to)
-              (header-set-references 
-               header
-               (setq ref (downcase (substring in-reply-to (match-beginning 0)
-                                              (match-end 0)))))))
-       (or subject (header-set-subject header "(none)"))
-       (or from (header-set-from header "(nobody)"))
-       ;; We build the thread tree.
-       (if (boundp 
-            (setq dep 
-                  (intern 
-                   (downcase
-                    (or id
-                        (concat "none+" (int-to-string 
-                                         (setq none-id (1+ none-id))))))
-                   dependencies)))
-           (setcar (symbol-value dep) header)
-         (set dep (list header)))
-       (if (boundp (setq dep (intern (or ref "none") dependencies)))
-           (setcdr (symbol-value dep) 
-                   (cons header (cdr (symbol-value dep))))
-         (set dep (list nil header)))
-       (setq headers (cons header headers))
-       (forward-line -1)
-       (search-forward "\n.\n" nil t))
-      (setq gnus-newsgroup-dependencies dependencies)
-      (nreverse headers))))
+      ;; Search to the beginning of the next header. Error messages
+      ;; do not begin with 2 or 3.
+      (while (re-search-forward "^[23][0-9]+ " nil t)
+       (let ((header (make-vector 9 nil))
+             (c (following-char))
+             (case-fold-search t)
+             (p (point))
+             from subject in-reply-to references ref)
+         (setq id nil
+               ref nil
+               references nil
+               subject nil
+               from nil)
+         (header-set-number header (setq article (read cur)))
+         ;; This implementation of this function, with nine
+         ;; search-forwards instead of the one re-search-forward and
+         ;; a case (which basically was the old function) is actually
+         ;; about twice as fast, even though it looks messier. You
+         ;; can't have everything, I guess. Speed and elegance
+         ;; doesn't always come hand in hand.
+         (save-restriction
+           (narrow-to-region (point) (save-excursion 
+                                       (search-forward "\n.\n" nil t)))
+           (if (search-forward "\nfrom: " nil t)
+               (header-set-from header (gnus-header-value))
+             (header-set-from header "(nobody)"))
+           (goto-char p)
+           (if (search-forward "\nsubject: " nil t)
+               (header-set-subject header (gnus-header-value))
+             (header-set-subject header "(none)"))
+           (goto-char p)
+           (and (search-forward "\nxref: " nil t)
+                (header-set-xref header (gnus-header-value)))
+           (goto-char p)
+           (and (search-forward "\nlines: " nil t)
+                (header-set-lines header (read cur)))
+           (goto-char p)
+           (and (search-forward "\ndate: " nil t)
+                (header-set-date header (gnus-header-value)))
+           (goto-char p)
+           (if (search-forward "\nmessage-id: " nil t)
+               (header-set-id header (setq id (gnus-header-value)))
+             ;; If there was no message-id, we just fake one to make
+             ;; subsequent routines simpler.
+             (header-set-id 
+              header 
+              (setq id (concat "none+" (int-to-string 
+                                        (setq none-id (1+ none-id)))))))
+           (goto-char p)
+           (if (search-forward "\nreferences: " nil t)
+               (progn
+                 (header-set-references header (gnus-header-value))
+                 (setq end (match-end 0))
+                 (save-excursion
+                   (setq ref 
+                         (downcase
+                          (buffer-substring
+                           (progn 
+                             (end-of-line)
+                             (search-backward ">" end t)
+                             (1+ (point)))
+                           (progn
+                             (search-backward "<" end t)
+                             (point)))))))
+             ;; Get the references from the in-reply-to header if there
+             ;; was no references, and the in-reply-to header looks
+             ;; promising. 
+             (if (and (search-forward "\nin-reply-to: " nil t)
+                      (setq in-reply-to (gnus-header-value))
+                      (string-match "<[^>]+>" in-reply-to))
+                 (progn
+                   (header-set-references 
+                    header 
+                    (setq ref (substring in-reply-to (match-beginning 0)
+                                         (match-end 0))))
+                   (setq ref (downcase ref)))
+               (setq ref "none")))
+           ;; We do some threading while we read the headers. The
+           ;; message-id and the last reference are both entered into
+           ;; the same hash table. Some tippy-toeing around has to be
+           ;; done in case an article has arrived before the article
+           ;; which it refers to.
+           (if (boundp (setq dep (intern (downcase id) dependencies)))
+               (if (car (symbol-value dep))
+                   (setq header nil)
+                 (setcar (symbol-value dep) header))
+             (set dep (list header)))
+           (if header
+               (progn
+                 (if (boundp (setq dep (intern ref dependencies)))
+                     (setcdr (symbol-value dep) 
+                             (cons header (cdr (symbol-value dep))))
+                   (set dep (list nil header)))
+                 (setq headers (cons header headers))))
+           (goto-char (point-max))))))
+    (nreverse headers)))
 
 ;; The following macros and functions were written by Felix Lee
 ;; <flee@cse.psu.edu>. 
@@ -4409,12 +5282,12 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
   ;; Get the Xref when the users reads the articles since most/some
   ;; NNTP servers do not include Xrefs when using XOVER.
   (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (let ((cur (current-buffer))
-         (dependencies (gnus-make-hashtable (length gnus-newsgroup-unreads)))
-         (none 0)
-         number header headers eol header id ref dep)
+  (let ((cur nntp-server-buffer)
+       (dependencies gnus-newsgroup-dependencies)
+       (none 0)
+       number headers header)
+    (save-excursion
+      (set-buffer nntp-server-buffer)
       (goto-char (point-min))
       (while (and sequence (not (eobp)))
        (setq number (read cur))
@@ -4424,59 +5297,71 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
             (eq number (car sequence))
             (progn
               (setq sequence (cdr sequence))
-              (save-excursion
-                (end-of-line)
-                (setq eol (point)))
-              (forward-char)
-              ;; overview: [num subject from date id refs chars lines misc]
-              (setq header
-                    (vector 
-                     number           ; number
-                     (gnus-nov-field) ; subject
-                     (gnus-nov-field) ; from
-                     (gnus-nov-field) ; date
-                     (setq id (gnus-nov-field)) ; id
-                     (progn
-                       (save-excursion
-                         (let ((beg (point)))
-                         (search-forward "\t" eol)
-                         (if (search-backward ">" beg t)
-                             (setq ref 
-                                   (downcase 
-                                    (buffer-substring 
-                                     (1+ (point))
-                                     (progn
-                                       (search-backward "<" beg t)
-                                       (point)))))
-                           (setq ref nil))))
-                       (gnus-nov-field)) ; refs
-                     (read cur)       ; chars
-                     (read cur)       ; lines
-                     (if (/= (following-char) ?\t)
-                         nil
-                       (forward-char 1)
-                       (gnus-nov-field)) ; misc
-                     ))
-              ;; We build the thread tree.
-              (if (boundp 
-                   (setq dep 
-                         (intern 
-                          (downcase 
-                           (or id (concat "none+"
-                                          (int-to-string 
-                                           (setq none (1+ none))))))
-                          dependencies)))
-                  (setcar (symbol-value dep) header)
-                (set dep (list header)))
-              (if (boundp (setq dep (intern (or ref "none") dependencies)))
-                  (setcdr (symbol-value dep) 
-                          (cons header (cdr (symbol-value dep))))
-                (set dep (list nil header)))
-              (setq headers (cons header headers))))
+              (if (setq header 
+                        (inline (gnus-nov-parse-line number dependencies)))
+                  (setq headers (cons header headers)))))
        (forward-line 1))
-      (setq headers (nreverse headers))
-      (setq gnus-newsgroup-dependencies dependencies)
-      headers)))
+      (setq headers (nreverse headers)))
+    headers))
+
+(defun gnus-nov-parse-line (number dependencies)
+  "Point has to be after the number on the beginning of the line."
+  (let ((none 0)
+       header eol ref id dep)
+    (save-excursion
+      (end-of-line)
+      (setq eol (point)))
+    (forward-char)
+    ;; overview: [num subject from date id refs chars lines misc]
+    (setq header
+         (vector 
+          number                       ; number
+          (gnus-nov-field)             ; subject
+          (gnus-nov-field)             ; from
+          (gnus-nov-field)             ; date
+          (setq id (gnus-nov-field))   ; id
+          (progn
+            (save-excursion
+              (let ((beg (point)))
+                (search-forward "\t" eol)
+                (if (search-backward ">" beg t)
+                    (setq ref 
+                          (downcase 
+                           (buffer-substring 
+                            (1+ (point))
+                            (progn
+                              (search-backward "<" beg t)
+                              (point)))))
+                  (setq ref nil))))
+            (gnus-nov-field))          ; refs
+          (read (current-buffer))      ; chars
+          (read (current-buffer))      ; lines
+          (if (/= (following-char) ?\t)
+              nil
+            (forward-char 1)
+            (gnus-nov-field))          ; misc
+          ))
+    ;; We build the thread tree.
+    (if (boundp 
+        (setq dep 
+              (intern 
+               (downcase 
+                (or id (concat "none+"
+                               (int-to-string 
+                                (setq none (1+ none))))))
+               dependencies)))
+       (if (car (symbol-value dep))
+           (setq header nil)
+         (setcar (symbol-value dep) header))
+      (set dep (list header)))
+    (if header
+       (progn
+         (if (boundp (setq dep (intern (or ref "none") 
+                                       dependencies)))
+             (setcdr (symbol-value dep) 
+                     (cons header (cdr (symbol-value dep))))
+           (set dep (list nil header)))))
+    header))
 
 (defun gnus-article-get-xrefs ()
   "Fill in the Xref value in `gnus-current-headers', if necessary.
@@ -4503,23 +5388,26 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
 
 ;; Return a header specified by a NUMBER.
 (defun gnus-get-header-by-number (number)
-  (or gnus-newsgroup-headers-hashtb-by-number
-      (gnus-make-headers-hashtable-by-number))
-  (gnus-gethash (int-to-string number)
-               gnus-newsgroup-headers-hashtb-by-number))
+  (save-excursion
+    (set-buffer gnus-summary-buffer)
+    (or gnus-newsgroup-headers-hashtb-by-number
+       (gnus-make-headers-hashtable-by-number))
+    (gnus-gethash (int-to-string number)
+                 gnus-newsgroup-headers-hashtb-by-number)))
 
 (defun gnus-make-headers-hashtable-by-number ()
   "Make hashtable for the variable gnus-newsgroup-headers by number."
-  (let ((header nil)
-       (headers gnus-newsgroup-headers))
-    (setq gnus-newsgroup-headers-hashtb-by-number
-         (gnus-make-hashtable (length headers)))
-    (while headers
-      (setq header (car headers))
-      (gnus-sethash (int-to-string (header-number header))
-                   header gnus-newsgroup-headers-hashtb-by-number)
-      (setq headers (cdr headers))
-      )))
+  (save-excursion
+    (set-buffer gnus-summary-buffer)
+    (let ((headers gnus-newsgroup-headers)
+         header)
+      (setq gnus-newsgroup-headers-hashtb-by-number
+           (gnus-make-hashtable (length headers)))
+      (while headers
+       (setq header (car headers))
+       (gnus-sethash (int-to-string (header-number header))
+                     header gnus-newsgroup-headers-hashtb-by-number)
+       (setq headers (cdr headers))))))
 
 (defun gnus-more-header-backward ()
   "Find new header backward."
@@ -4564,9 +5452,9 @@ If optional argument BACKWARD is non-nil, search backward instead."
   (save-excursion
     (set-buffer gnus-group-buffer)
     (save-excursion
-      ;; We don't want to alter current point of Group mode buffer.
+      ;; We don't want to alter current point of group mode buffer.
       (if (gnus-group-search-forward 
-          backward nil 
+          backward t 
           (if use-level (gnus-group-group-level) nil))
          (gnus-group-group-name))
       )))
@@ -4577,27 +5465,33 @@ If BACKWARD is non-nil, search backward.
 If UNREAD is non-nil, only unread articles are selected.
 If SUBJECT is non-nil, the article which has the same subject will be
 searched for." 
-  (let ((func
-        (if backward
-            (function re-search-backward) (function re-search-forward)))
-       ;; We have to take care of hidden lines.
-       (regexp 
-        (if subject 
-            (format "%s [-0-9]+ %s \\([-0-9 ]+\\) [0-9]+[\n\r]"
-                    (regexp-quote (gnus-simplify-subject-re subject))
-                    (if unread gnus-unread-mark "."))
-          (if unread (concat "^[" gnus-unread-mark "]") "^."))))
-    (if backward
-       (beginning-of-line)
-      (end-of-line))
-    (prog1
-       (if (funcall func regexp nil t)
-           (progn
-             (goto-char (match-beginning 0))
-             (gnus-summary-article-number))
-         nil)
-      ;; Adjust cursor point.
-      (gnus-summary-position-cursor))))
+  (let ((func (if backward 'previous-single-property-change
+               'next-single-property-change))
+       (beg (point))
+       (did t)
+       pos)
+    (beginning-of-line)
+    (forward-char (if backward (if (bobp) 0 -1) (if (eobp) 0 1)))
+    (while (and (setq pos (funcall func (point) 'gnus-number))
+               (goto-char (if backward (1- pos) pos))
+               (setq did
+                     (not (and (or (not unread)
+                                   (= (get-text-property (point) 'gnus-mark) 
+                                      gnus-unread-mark))
+                               (or (not subject)
+                                   (string= (gnus-simplify-subject-re 
+                                             subject)
+                                            (gnus-simplify-subject-re
+                                             (get-text-property 
+                                              (point) 
+                                              'gnus-subject)))))))
+               (if backward (if (bobp) nil (forward-char -1) t)
+                 (if (eobp) nil (forward-char 1) t))))
+    (if did
+       (progn (goto-char beg) nil)
+      (prog1
+         (get-text-property (point) 'gnus-number)
+       (gnus-summary-position-cursor)))))
 
 (defun gnus-summary-search-forward (&optional unread subject backward)
   "Search for article forward.
@@ -4618,75 +5512,56 @@ the same subject will be searched for."
   "The article number of the article on the current line.
 If there isn's an article number here, then we return the current
 article number."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward " [-0-9]+ [0-9]+[\n\r]" nil t)
-       (progn
-         ;; jwz: this is faster than string-to-int/buffer-substring
-         (goto-char (match-beginning 0))
-         (read (current-buffer)))
-       ;; We return the current if we couldn't find anything.
-       (if number-or-nil nil gnus-current-article))))
+  (let ((number (get-text-property (save-excursion (beginning-of-line) (point))
+                                  'gnus-number)))
+    (if number-or-nil number (or number gnus-current-article))))
 
 (defun gnus-summary-thread-level ()
   "The thread level of the article on the current line."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward " [0-9]+[\n\r]" nil t)
-       (progn
-         (goto-char (match-beginning 0))
-         (read (current-buffer)))
-      ;; We return zero if we couldn't find anything.
-      0)))
+  (or (get-text-property (save-excursion (beginning-of-line) (point))
+                        'gnus-thread)
+      0))
+
+(defun gnus-summary-pseudo-article ()
+  "The thread level of the article on the current line."
+  (get-text-property (save-excursion (beginning-of-line) (point)) 
+                    'gnus-pseudo))
 
 (defun gnus-summary-article-mark ()
   "The mark on the current line."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward ". [-0-9]+ [0-9]+[\n\r]" nil t)
-       (char-after (match-beginning 0)))))
+  (get-text-property (save-excursion (beginning-of-line) (point))
+                    'gnus-mark))
 
 (defun gnus-summary-subject-string ()
   "Return current subject string or nil if nothing."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward " [-0-9]+ . [-0-9]+ [0-9]+[\n\r]" nil t)
-       (let ((beg (previous-property-change (match-beginning 0)))
-             (end (match-beginning 0))
-             (buffer-read-only nil))
-         (set-text-properties beg end nil)
-         (prog1
-             (buffer-substring beg end)
-           (set-text-properties beg end '(invisible t))))
-      nil)))
+  (get-text-property (save-excursion (beginning-of-line) (point))
+                    'gnus-subject))
 
-(defun gnus-summary-interest ()
-  "Return current article interest."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward " [-0-9]+ . [-0-9]+ [0-9]+[\n\r]" nil t)
-       (progn
-         (goto-char (match-beginning 0))
-         (read (current-buffer)))
-      ;; We return zero if we couldn't find anything.
-      0)))
+(defalias 'gnus-summary-score 'gnus-summary-article-score)
+(make-obsolete 'gnus-summary-score 'gnus-summary-article-score)
+(defun gnus-summary-article-score ()
+  "Return current article score."
+  (or (cdr (assq (gnus-summary-article-number) gnus-newsgroup-scored))
+      gnus-summary-default-score))
 
 (defun gnus-summary-recenter ()
-  "Center point in Summary window."
-  ;; Scroll window so as to cursor comes center of Summary window
-  ;;  only when article is displayed.
+  "Center point in summary window."
   ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
-  ;; Recenter only when requested.
-  ;; Subbested by popovich@park.cs.columbia.edu
-  (and gnus-auto-center-summary
-       (get-buffer-window gnus-article-buffer)
-       (< (/ (- (window-height) 1) 2)
-         (count-lines (point) (point-max)))
-       (recenter (/ (- (window-height) 2) 2))))
+  ;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu.
+  (let ((half (/ (- (window-height) 2) 2)))
+    (and 
+     ;; It has to be wanted,
+     gnus-auto-center-summary 
+     ;; the article buffer must be displayed,
+     (get-buffer-window gnus-article-buffer)
+     ;; there must be lines left to scroll forward,
+     (zerop (save-excursion (forward-line (1+ half))))
+     ;; so we recenter.
+     (recenter half))))
 
 (defun gnus-summary-jump-to-group (newsgroup)
-  "Move point to NEWSGROUP in Group mode buffer."
-  ;; Keep update point of Group mode buffer if visible.
+  "Move point to NEWSGROUP in group mode buffer."
+  ;; Keep update point of group mode buffer if visible.
   (if (eq (current-buffer)
          (get-buffer gnus-group-buffer))
       (save-window-excursion
@@ -4733,11 +5608,22 @@ article number."
     ;; Return the list of unread articles.
     (nreverse unread)))
 
-
-;; Gnus Summary mode commands.
-
 ;; Various summary commands
 
+(defun gnus-summary-universal-argument ()
+  "Perform any operation on all articles marked with the process mark."
+  (interactive)
+  (let ((articles (reverse gnus-newsgroup-processable))
+       key func)
+    (or articles (error "No articles marked"))
+    (or (setq func (key-binding (read-key-sequence "C-c C-u")))
+       (error "Undefined key"))
+    (while articles
+      (gnus-summary-goto-subject (car articles))
+      (command-execute func)
+      (gnus-summary-remove-process-mark (car articles))
+      (setq articles (cdr articles)))))
+
 (defun gnus-summary-toggle-truncation (arg)
   "Toggle truncation of summary lines.
 With arg, turn line truncation on iff arg is positive."
@@ -4753,7 +5639,7 @@ Prefix argument SHOW-ALL means to select all articles."
   (interactive "P")
   (let ((current-subject (gnus-summary-article-number)))
     (gnus-summary-exit t)
-    ;; We have to adjust the point of Group mode buffer because the
+    ;; We have to adjust the point of group mode buffer because the
     ;; current point was moved to the next unread newsgroup by
     ;; exiting.
     (gnus-summary-jump-to-group gnus-newsgroup-name)
@@ -4782,53 +5668,70 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
   (let ((group gnus-newsgroup-name)
        (mode major-mode)
        (buf (current-buffer)))
+    (if gnus-newsgroup-kill-headers
+       (setq gnus-newsgroup-killed
+             (gnus-compress-sequence
+              (nconc
+               (gnus-intersection
+                (gnus-uncompress-sequence gnus-newsgroup-killed)
+                (setq gnus-newsgroup-unselected
+                      (sort gnus-newsgroup-unselected '<)))
+               (setq gnus-newsgroup-unreads
+                     (sort gnus-newsgroup-unreads '<))))))
+    (or (listp (cdr gnus-newsgroup-killed))
+       (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
     (let ((updated nil)
          (headers gnus-newsgroup-headers)
          (unreads gnus-newsgroup-unreads)
-         (unselected (setq gnus-newsgroup-unselected
-                           (sort gnus-newsgroup-unselected '<)))
+         (unselected gnus-newsgroup-unselected)
          (ticked gnus-newsgroup-marked))
+      (gnus-close-group group)
       ;; Important internal variables are saved, so we can reenter
-      ;; the Summary buffer even if the hook changes them.
+      ;; the summary buffer even if the hook changes them.
       (run-hooks 'gnus-exit-group-hook)
-      (gnus-update-read-articles group unreads unselected ticked
-                                t gnus-newsgroup-replied
-                                gnus-newsgroup-expirable
-                                gnus-newsgroup-killed
-                                gnus-newsgroup-dormant
-                                gnus-newsgroup-bookmarks)
+      (gnus-score-save)
+      (gnus-update-read-articles 
+       group unreads unselected ticked
+       t gnus-newsgroup-replied gnus-newsgroup-expirable
+       gnus-newsgroup-killed gnus-newsgroup-dormant
+       gnus-newsgroup-bookmarks gnus-newsgroup-scored)
       ;; t means ignore unsubscribed newsgroups.
-      (if gnus-use-cross-reference
-         (gnus-mark-xrefs-as-read group headers unreads))
+      (and gnus-use-cross-reference
+          (gnus-mark-xrefs-as-read 
+           group headers unreads gnus-newsgroup-expirable))
       ;; Do not switch windows but change the buffer to work.
       (set-buffer gnus-group-buffer)
       (gnus-group-update-group group))
     ;; Make sure where I was, and go to next newsgroup.
     (gnus-group-jump-to-group group)
-;    (gnus-group-next-unread-group 1)
+    (gnus-group-next-unread-group 1)
     (if temporary
-       ;; If exiting temporary, caller should adjust Group mode
+       ;; If exiting temporary, caller should adjust group mode
        ;; buffer point by itself.
        nil                             ;Nothing to do.
-      ;; Return to Group mode buffer.
+      ;; Return to group mode buffer. 
       (if (and (get-buffer buf) 
               (eq mode 'gnus-summary-mode))
          (kill-buffer buf))
       (if (get-buffer gnus-article-buffer)
          (bury-buffer gnus-article-buffer))
       (setq gnus-current-select-method gnus-select-method)
+      (and gnus-newsgroup-expunged-buffer
+          (buffer-name gnus-newsgroup-expunged-buffer)
+          (kill-buffer gnus-newsgroup-expunged-buffer))
       (gnus-configure-windows 'newsgroups t)
       (pop-to-buffer gnus-group-buffer))))
 
-(defun gnus-summary-quit ()
+(defun gnus-summary-quit (&optional no-questions)
   "Quit reading current newsgroup without updating read article info."
   (interactive)
-  (if (y-or-n-p "Do you really wanna quit reading this group? ")
+  (if (or no-questions
+         (y-or-n-p "Do you really wanna quit reading this group? "))
       (progn
        (message "")                    ;Erase "Yes or No" question.
-       ;; Return to Group selection mode.
+       ;; Return to group selection mode.
        (if (get-buffer gnus-summary-buffer)
-           (bury-buffer gnus-summary-buffer))
+           (kill-buffer gnus-summary-buffer))
        (if (get-buffer gnus-article-buffer)
            (bury-buffer gnus-article-buffer))
        (gnus-configure-windows 'newsgroups)
@@ -4843,12 +5746,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
   (gnus-group-describe-group gnus-newsgroup-name))
 
 (defun gnus-summary-describe-briefly ()
-  "Describe Summary mode commands briefly."
+  "Describe summary mode commands briefly."
   (interactive)
   (message
-    (substitute-command-keys "\\[gnus-summary-next-page]:Select  \\[gnus-summary-next-unread-article]:Forward  \\[gnus-summary-prev-unread-article]:Backward  \\[gnus-summary-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-summary-describe-briefly]:This help")))
+    (substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select  \\[gnus-summary-next-unread-article]:Forward  \\[gnus-summary-prev-unread-article]:Backward  \\[gnus-summary-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-summary-describe-briefly]:This help")))
 
-;; Walking around Group mode buffer from Summary mode.
+;; Walking around group mode buffer from summary mode.
 
 (defun gnus-summary-next-group (&optional no-article group)
   "Exit current newsgroup and then select next unread newsgroup.
@@ -4860,18 +5763,21 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
     (let ((group (or group (gnus-summary-search-group)))
          (buf gnus-summary-buffer))
       (if (null group)
-         (gnus-summary-quit)
+         (gnus-summary-quit t)
        (message "Selecting %s..." group)
-       ;; We are now in Group mode buffer.
-       ;; Make sure Group mode buffer point is on GROUP.
+       ;; We are now in group mode buffer.
+       ;; Make sure group mode buffer point is on GROUP.
        (gnus-group-jump-to-group group)
-       (gnus-summary-read-group group nil no-article buf)))))
+       (unwind-protect
+           (gnus-summary-read-group group nil no-article buf)
+         (and (string= gnus-newsgroup-name ingroup)
+              (gnus-summary-quit t)))))))
 
 (defun gnus-summary-prev-group (no-article)
   "Exit current newsgroup and then select previous unread newsgroup.
 If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
   (interactive "P")
-  ;; Make sure Group mode buffer point is on current newsgroup.
+  ;; Make sure group mode buffer point is on current newsgroup.
   (gnus-summary-jump-to-group gnus-newsgroup-name)
   (let ((group (gnus-summary-search-group t)))
     (if (null group)
@@ -4880,9 +5786,9 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
          (gnus-summary-exit)
          (message ""))
       (message "Selecting %s..." group)
-      (gnus-summary-exit t)            ;Exit Summary mode temporary.
-      ;; We are now in Group mode buffer.
-      ;; We have to adjust point of Group mode buffer because current
+      (gnus-summary-exit t)            ;Exit summary mode temporary.
+      ;; We are now in group mode buffer.
+      ;; We have to adjust point of group mode buffer because current
       ;; point is moved to next unread newsgroup by exiting.
       (gnus-summary-jump-to-group group)
       (gnus-summary-read-group group nil no-article)
@@ -4891,7 +5797,7 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
          (eq gnus-auto-select-next t)
          ;; Expected newsgroup has nothing to read since the articles
          ;; are marked as read by cross-referencing. So, try next
-         ;; newsgroup. (Make sure we are in Group mode buffer now.)
+         ;; newsgroup. (Make sure we are in group mode buffer now.)
          (and (eq (current-buffer)
                   (get-buffer gnus-group-buffer))
               (gnus-summary-search-group t)
@@ -4907,18 +5813,17 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
 If UNREAD is non-nil, go to the first unread article.
 Returns nil if there are no unread articles."
   (let ((begin (point)))
-    (goto-char 1)
-    (if (re-search-forward 
-        (concat (if unread " " ".") " [-0-9]+ [0-9]+[\n\r]") nil t)
-       (progn
-         (forward-char -1)
-         ;; Fix by Per Abrahamsen <amanda@iesd.auc.dk>.
-         (gnus-summary-position-cursor)
+    (if unread
+       (if (not (gnus-goto-char 
+                 (text-property-any (point-min) (point-max)
+                                    'gnus-mark gnus-unread-mark)))
+           (progn
+             ;; If there is no unread articles, stay where you are.
+             (goto-char begin)
+             (message "No more unread articles")
+             nil)
          t)
-      ;; If there is no unread articles, stay where you are.
-      (goto-char begin)
-      (message "No more unread articles")
-      nil)))
+      (goto-char (point-min)))))
 
 (defun gnus-summary-next-subject (n &optional unread)
   "Go to next N'th summary line.
@@ -4965,51 +5870,46 @@ If optional argument UNREAD is non-nil, only unread article is selected."
                          (int-to-string (header-number headers))))
                       gnus-newsgroup-headers)
                      nil 'require-match))))
-  (if (not article)
-      (error "No article number"))
+  (or article (error "No article number"))
   (if (or (eq article (gnus-summary-article-number t))
-         (let ((org (point)))
-           (goto-char 1)
-           (if (re-search-forward 
-                (format "[^Z] %d [0-9]+[\n\r]" article) nil t)
-               (goto-char (match-beginning 0))
-             (goto-char org)
-             nil)))
-      (progn
-       (gnus-summary-position-cursor)
-       article)))
+         (gnus-goto-char
+          (text-property-any
+           (point-min) (point-max) 'gnus-number article)))
+      article))
 
 ;; Walking around summary lines with displaying articles.
 
 (defun gnus-summary-expand-window ()
-  "Expand Summary window to show headers full window."
+  "Expand summary window to show headers full window."
   (interactive)
   (gnus-configure-windows 'summary)
   (pop-to-buffer gnus-summary-buffer))
 
 (defun gnus-summary-display-article (article &optional all-header)
-  "Display ARTICLE in Article buffer."
+  "Display ARTICLE in article buffer."
   (setq gnus-summary-buffer (current-buffer))
   (if (null article)
       nil
-    (gnus-configure-windows 'article)
-    (pop-to-buffer gnus-summary-buffer)
     (gnus-article-prepare article all-header)
     (if (= (gnus-summary-article-mark) ?Z) 
        (progn
          (forward-line 1)
          (gnus-summary-position-cursor)))
     (gnus-summary-recenter)
-    (gnus-set-mode-line 'summary)
     (run-hooks 'gnus-select-article-hook)
+    (gnus-summary-goto-subject article)
+    (gnus-configure-windows 'article)
     ;; Successfully display article.
     t))
 
-(defun gnus-summary-select-article (&optional all-headers force)
+(defun gnus-summary-select-article (&optional all-headers force pseudo)
   "Select the current article.
-Optional first argument ALL-HEADERS is non-nil, show all header fields.
-Optional second argument FORCE is nil, the article is only selected
-again when current header does not match with ALL-HEADERS option."
+If ALL-HEADERS is non-nil, show all header fields.  If FORCE is
+non-nil, the article will be re-fetched even if it already present in
+the article buffer.  If PSEUDO is non-nil, pseudo-articles will also
+be displayed."
+  (and (not pseudo) (gnus-summary-pseudo-article)
+       (error "This is a pseudo-article."))
   (let ((article (gnus-summary-article-number))
        (all-headers (not (not all-headers)))) ;Must be T or NIL.
     (if (or (null gnus-current-article)
@@ -5018,11 +5918,13 @@ again when current header does not match with ALL-HEADERS option."
            (not (equal (car gnus-article-current) gnus-newsgroup-name))
            force)
        ;; The requested article is different from the current article.
-       (gnus-summary-display-article article all-headers)
-      (if all-headers
-         (gnus-article-show-all-headers))
+       (progn
+         (gnus-summary-display-article article all-headers)
+         article)
+      (if all-headers (gnus-article-show-all-headers))
       (gnus-configure-windows 'article)
-      (pop-to-buffer gnus-summary-buffer))))
+      (pop-to-buffer gnus-summary-buffer)
+      nil)))
 
 (defun gnus-summary-set-current-mark (&optional current-mark)
   "Obsolete function."
@@ -5141,8 +6043,8 @@ If UNREAD is non-nil, only unread articles are selected."
   (gnus-summary-position-cursor))
 
 (defun gnus-summary-prev-article (unread &optional subject)
-  "Select article before current one.
-If argument UNREAD is non-nil, only unread article is selected."
+  "Select the article after the current one.
+If UNREAD is non-nil, only unread articles are selected."
   (interactive "P")
   (let ((header nil))
     (cond ((gnus-summary-display-article
@@ -5154,28 +6056,78 @@ If argument UNREAD is non-nil, only unread article is selected."
                                             gnus-newsgroup-dormant))
                (memq this-command
                      '(gnus-summary-prev-unread-article
-                       ;;gnus-summary-prev-page
-                       ;;gnus-summary-prev-article
-                       ;;gnus-summary-prev-same-subject
-                       ;;gnus-summary-prev-unread-same-subject
-                       )))
-          ;; Ignore given SUBJECT, and try again.
-          (gnus-summary-prev-article unread nil))
-         (unread
-          (message "No more unread articles"))
+                       gnus-summary-prev-page)))
+          ;; Wrap article pointer if there are unread articles.
+          ;; Hook function, such as gnus-summary-rmail-digest, may
+          ;; change current buffer, so need check.
+          (let ((buffer (current-buffer))
+                (last-point (point)))
+            ;; No more articles with same subject, so jump to the first
+            ;; unread article.
+            (gnus-summary-first-unread-article)
+            (and (eq buffer (current-buffer))
+                 (< (point) last-point)
+                 (message "Wrapped"))
+            ))
          ((and gnus-auto-extend-newsgroup
+               (not unread)            ;Not unread only
                (not subject)           ;Only if subject is not specified.
                (setq header (gnus-more-header-backward)))
-          ;; Extend to previous article if possible.
+          ;; Extend to next article if possible.
           ;; Basic ideas by himacdonald@watdragon.waterloo.edu
           (gnus-extend-newsgroup header t)
+          ;; Threads feature must be turned off.
           (let ((buffer-read-only nil))
             (goto-char (point-min))
             (gnus-summary-prepare-threads (list header) 0))
-          (gnus-summary-goto-article gnus-newsgroup-begin)
-          (gnus-summary-position-cursor))
+          (gnus-summary-goto-article gnus-newsgroup-begin))
          (t
-          (message "No more articles"))
+          ;; Select prev newsgroup automatically if requested.
+          (gnus-summary-jump-to-group gnus-newsgroup-name)
+          (let ((cmd (aref (this-command-keys) 0))
+                (group (gnus-summary-search-group t gnus-keep-same-level))
+                (auto-select
+                 (and gnus-auto-select-next
+                      (memq this-command
+                            '(gnus-summary-prev-unread-article
+                              gnus-summary-prev-article
+                              gnus-summary-prev-page))
+                      ;; Ignore characters typed ahead.
+                      (not (input-pending-p)))))
+            ;; Keep just the event type of CMD.
+            (if (listp cmd)
+                (setq cmd (car cmd)))
+            (message "No more%s articles%s"
+                     (if unread " unread" "")
+                     (if (and auto-select
+                              (not (eq gnus-auto-select-next 'quietly)))
+                         (if group
+                             (format " (Type %s for %s [%s])"
+                                     (single-key-description cmd)
+                                     group
+                                     (car (gnus-gethash 
+                                           group gnus-newsrc-hashtb)))
+                           (format " (Type %s to exit %s)"
+                                   (single-key-description cmd)
+                                   gnus-newsgroup-name))
+                       ""))
+            ;; Select next unread newsgroup automagically.
+            (cond ((and auto-select
+                        (eq gnus-auto-select-next 'quietly))
+                   ;; Select quietly.
+                   (gnus-summary-prev-group 1))
+                  (auto-select
+                   ;; Confirm auto selection.
+                   (let* ((event (read-event))
+                          (type
+                           (if (listp event)
+                               (car event)
+                             event)))
+                     (if (and (eq event type) (eq event cmd))
+                         (gnus-summary-prev-group 1)
+                       (setq unread-command-events (list event)))))
+                  )
+            ))
          )))
 
 (defun gnus-summary-prev-unread-article ()
@@ -5200,11 +6152,12 @@ current article."
            (/= article (cdr gnus-article-current))
            (not (equal (car gnus-article-current) gnus-newsgroup-name)))
        ;; Selected subject is different from current article's.
-         (gnus-summary-display-article article)
+       (gnus-summary-display-article article)
       (gnus-configure-windows 'article)
       (pop-to-buffer gnus-summary-buffer)
-      (gnus-eval-in-buffer-window gnus-article-buffer
-       (setq endp (gnus-article-next-page lines)))
+      (gnus-eval-in-buffer-window
+       gnus-article-buffer
+       (setq endp (gnus-article-next-page lines)))
       (if endp
          (cond (circular
                 (gnus-summary-beginning-of-article))
@@ -5235,14 +6188,15 @@ Argument LINES specifies lines to be scrolled down."
   "Scroll up (or down) one line current article.
 Argument LINES specifies lines to be scrolled up (or down if negative)."
   (interactive "p")
-  (gnus-summary-select-article)
-  (gnus-eval-in-buffer-window gnus-article-buffer
-    (cond ((> lines 0)
-          (if (gnus-article-next-page lines)
-              (message "End of message")))
-         ((< lines 0)
-          (gnus-article-prev-page (- 0 lines))))
-    ))
+  (or (gnus-summary-select-article nil nil 'pseudo)
+      (gnus-eval-in-buffer-window 
+       gnus-article-buffer
+       (cond ((> lines 0)
+             (if (gnus-article-next-page lines)
+                 (message "End of message")))
+            ((< lines 0)
+             (gnus-article-prev-page (- lines))))))
+  (gnus-summary-position-cursor))
 
 (defun gnus-summary-next-same-subject ()
   "Select next article which has the same subject as current one."
@@ -5271,76 +6225,92 @@ Return nil if there are no unread articles."
   (if (gnus-summary-first-subject t)
       (gnus-summary-display-article (gnus-summary-article-number))))
 
+(defun gnus-summary-best-unread-article ()
+  "Select the unread article with the highest score."
+  (interactive)
+  (let ((scored gnus-newsgroup-scored)
+       (best -1000000)
+       article art)
+    (while scored
+      (or (> best (cdr (car scored)))
+         (and (memq (setq art (car (car scored))) gnus-newsgroup-unreads)
+              (not (memq art gnus-newsgroup-marked))
+              (not (memq art gnus-newsgroup-dormant))
+              (if (= best (cdr (car scored)))
+                  (setq article (min art article))
+                (setq article art)
+                (setq best (cdr (car scored))))))
+      (setq scored (cdr scored)))
+    (if article 
+       (gnus-summary-goto-article article)
+      (gnus-summary-first-unread-article))))
+
 (defun gnus-summary-goto-article (article &optional all-headers)
   "Fetch ARTICLE and display it if it exists.
 If ALL-HEADERS is non-nil, no header lines are hidden."
   (interactive
    (list
     (string-to-int
-     (completing-read "Article number: "
-                     (mapcar
-                      (lambda (headers)
-                        (list
-                         (int-to-string (header-number headers))))
-                      gnus-newsgroup-headers)
-                     nil 'require-match))))
+     (completing-read 
+      "Article number: "
+      (mapcar (lambda (headers) (list (int-to-string (header-number headers))))
+             gnus-newsgroup-headers) 
+      nil 'require-match))))
   (if (gnus-summary-goto-subject article)
       (gnus-summary-display-article article all-headers)))
 
 (defun gnus-summary-goto-last-article ()
-  "Go to last subject line."
+  "Go to the last article."
   (interactive)
   (if gnus-last-article
       (gnus-summary-goto-article gnus-last-article)))
 
-
 ;; Summary article oriented commands
 
-(defun gnus-summary-refer-parent-article ()
-  "Refer parent article of current article."
-  (interactive)
-  (let ((ref (header-references (gnus-get-header-by-number
-                                (gnus-summary-article-number))))
-       parent)
-    (if (or (not ref) (equal ref ""))
-       (error "No references in this article"))
-    (and (string-match "<[^<>]*>[ \t]*$" ref)
-        (setq parent 
-              (substring ref (match-beginning 0) (match-end 0))))
-    (if (stringp parent)
-       (gnus-summary-refer-article parent)
-      (error "Possibly malformed references"))))
-
+(defun gnus-summary-refer-parent-article (n)
+  "Refer parent article N times.
+The difference between N and the number of articles fetched is returned."
+  (interactive "p")
+  (while 
+      (and 
+       (> n 0)
+       (let ((ref (header-references (gnus-get-header-by-number
+                                     (gnus-summary-article-number)))))
+        (if (and ref (not (equal ref ""))
+                 (string-match "<[^<>]*>[ \t]*$" ref))
+            (gnus-summary-refer-article 
+             (substring ref (match-beginning 0) (match-end 0))))))
+    (setq n (1- n)))
+  (or (zerop n) (message "No references in article or expired article."))
+  n)
+    
 (defun gnus-summary-refer-article (message-id)
   "Refer article specified by MESSAGE-ID.
 NOTE: This command only works with newsgroup that use NNTP."
   (interactive "sMessage-ID: ")
-  ;; Make sure that this command depends on the fact that article
-  ;; related information is not updated when an article is retrieved
-  ;; by Message-ID.
-  (gnus-summary-select-article t)      ;Request all headers.
-  (if (and (stringp message-id)
-          (> (length message-id) 0))
-      (let ((current (header-id gnus-current-headers)))
-       (gnus-eval-in-buffer-window 
-        gnus-article-buffer
-        ;; Construct the correct Message-ID if necessary.
-        ;; Suggested by tale@pawl.rpi.edu.
-        (or (string-match "^<" message-id)
-            (setq message-id (concat "<" message-id)))
-        (or (string-match ">$" message-id)
-            (setq message-id (concat message-id ">"))))))
-  (if (and (stringp message-id)
-          (gnus-article-prepare message-id nil (gnus-read-header message-id)))
-      (progn
-       (gnus-summary-insert-line 
-        nil gnus-current-headers 0 nil ?D nil nil 
-        (header-subject gnus-current-headers))
-       (forward-line -1)
-       (gnus-summary-position-cursor)
-       (run-hooks 'gnus-summary-update-hook)
-       message-id)
-    (error "No such references")))
+  (if (or (not (stringp message-id))
+         (zerop (length message-id)))
+      ()
+    ;; Construct the correct Message-ID if necessary.
+    ;; Suggested by tale@pawl.rpi.edu.
+    (or (string-match "^<" message-id)
+       (setq message-id (concat "<" message-id)))
+    (or (string-match ">$" message-id)
+       (setq message-id (concat message-id ">")))
+    (let ((header (car (gnus-gethash message-id gnus-newsgroup-dependencies))))
+      (if header
+         (gnus-summary-goto-article (header-number header))
+       (if (gnus-article-prepare message-id nil (gnus-read-header message-id))
+           (progn
+             (gnus-summary-insert-line 
+              nil gnus-current-headers 0 nil gnus-read-mark nil nil 
+              (header-subject gnus-current-headers))
+             (forward-line -1)
+             (gnus-summary-position-cursor)
+             (gnus-summary-update-line)
+             message-id)
+         (message "No such references")
+         nil)))))
 
 (defun gnus-summary-next-digest (nth)
   "Move to head of NTH next digested message."
@@ -5415,7 +6385,7 @@ is non-nil. The hook is intended to customize Rmail mode."
          ;; Take all windows safely.
          (gnus-configure-windows '(1 0 0))
          (pop-to-buffer gnus-group-buffer)
-         ;; Use Summary Article windows for Digest summary and
+         ;; Use summary article windows for Digest summary and
          ;; Digest buffers.
          (if gnus-digest-show-summary
              (let ((gnus-summary-buffer gnus-digest-summary-buffer)
@@ -5584,7 +6554,7 @@ If optional (prefix) argument BACKWARD is non-nil, do backward instead."
 (defun gnus-summary-show-article ()
   "Force re-fetching of the current article."
   (interactive)
-  (gnus-summary-select-article gnus-have-all-headers t))
+  (gnus-summary-select-article gnus-have-all-headers t t))
 
 (defun gnus-summary-toggle-header (arg)
   "Show the headers if they are hidden, or hide them if they are shown.
@@ -5688,15 +6658,22 @@ and `request-accept' functions. (Ie. mail newsgroups at present.)"
       (if (setq art-group
                (gnus-request-move-article 
                 (car articles)
-                gnus-newsgroup-name (nth 1 gnus-current-select-method)
+                gnus-newsgroup-name 
+                (nth 1 (gnus-find-method-for-group gnus-newsgroup-name))
                 (list 'gnus-request-accept-article 
-                      (or select-method to-newsgroup))))
+                      (if select-method
+                          (quote select-method)
+                        to-newsgroup))))
          (let* ((buffer-read-only nil)
-                (entry (or
-                        (gnus-gethash (car art-group) gnus-newsrc-hashtb)
-                        (gnus-gethash (concat gnus-foreign-group-prefix
-                                              (car art-group) )
-                                      gnus-newsrc-hashtb)))
+                (entry 
+                 (or
+                  (gnus-gethash (car art-group) gnus-newsrc-hashtb)
+                  (gnus-gethash 
+                   (gnus-group-prefixed-name 
+                    (car art-group) 
+                    (if select-method (list select-method "")
+                      (gnus-find-method-for-group to-newsgroup)))
+                   gnus-newsrc-hashtb)))
                 (info (nth 2 entry))
                 (article (car articles))
                 (marked (nth 3 info)))
@@ -5731,55 +6708,100 @@ and `request-accept' functions. (Ie. mail newsgroups at present.)"
            (completing-read
             "What method do you want to use when respooling? "
             (gnus-methods-using 'respool) nil t)))
-  (gnus-summary-move-article n nil respool-method))
+  (gnus-summary-move-article n nil (intern respool-method)))
 
-;; Summary interest commands.
+;; Summary score commands.
 
 ;; Suggested by boubaker@cenatls.cena.dgac.fr.
 
-(defun gnus-summary-raise-interest (n)
-  "Raise the interest of the current article by N."
+(defun gnus-summary-raise-score (n)
+  "Raise the score of the current article by N."
   (interactive "p")
-  (gnus-summary-set-interest (+ (gnus-summary-interest) n)))
+  (gnus-summary-set-score (+ (gnus-summary-article-score) n)))
 
-(defun gnus-summary-lower-interest (n)
-  "Lower the interest of the current article by N."
+(defun gnus-summary-lower-score (n)
+  "Lower the score of the current article by N."
   (interactive "p")
-  (gnus-summary-raise-interest (- n)))
+  (gnus-summary-raise-score (- n)))
 
-(defun gnus-summary-set-interest (n)
-  "Set the interest of the current article to N."
+(defun gnus-summary-set-score (n)
+  "Set the score of the current article to N."
   (interactive "p")
   ;; Skip dummy header line.
   (save-excursion
     (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
-    (let ((buffer-read-only nil)
-         beg)
-      ;; Set visible interest.
+    (let ((buffer-read-only nil))
+      ;; Set score.
       (beginning-of-line)
-      (forward-char 3)
+      (forward-char 2)
       (delete-char 1)
-      (insert (int-to-string (max 1 (min 9 n))))
-      ;; Set invisible interest.
-      (re-search-forward " [-0-9]+ . [-0-9]+ [0-9]+[\n\r]")
-      (goto-char (1+ (match-beginning 0)))
-      (delete-region (setq beg (point)) (progn (search-forward " ") 
-                                              (forward-char -1)
-                                              (point)))
-      (insert (int-to-string n))
-      (set-text-properties beg (point) '(invisible t)))
-    (run-hooks 'gnus-summary-update-hook)))
+      (insert (if (= n gnus-summary-default-score) ? 
+               (if (< n gnus-summary-default-score) ?- ?+))))
+    (let* ((article (gnus-summary-article-number))
+          (score (assq article gnus-newsgroup-scored)))
+      (if score (setcdr score n)
+       (setq gnus-newsgroup-scored 
+             (cons (cons article n) gnus-newsgroup-scored))))
+    (gnus-summary-update-line)))
 
 (defmacro gnus-raise (field expression level)
   (` (gnus-kill (, field) (, expression)
-               (function (gnus-summary-raise-interest (, level))) t)))
+               (function (gnus-summary-raise-score (, level))) t)))
 
 (defmacro gnus-lower (field expression level)
   (` (gnus-kill (, field) (, expression)
-            (function (gnus-summary-raise-interest (- (, level)))) t)))
+               (function (gnus-summary-raise-score (- (, level)))) t)))
 
 ;; Summary marking commands.
 
+(defun gnus-summary-raise-same-subject-and-select (score)
+  "Raise articles which has the same subject with SCORE and select the next."
+  (interactive "p")
+  (let ((subject (gnus-summary-subject-string)))
+    (gnus-summary-raise-score score)
+    (while (gnus-summary-search-subject nil nil subject)
+      (gnus-summary-raise-score score))
+    (gnus-summary-next-article t)))
+
+(defun gnus-summary-raise-same-subject (score)
+  "Raise articles which has the same subject with SCORE."
+  (interactive "p")
+  (let ((subject (gnus-summary-subject-string)))
+    (gnus-summary-raise-score score)
+    (while (gnus-summary-search-subject nil nil subject)
+      (gnus-summary-raise-score score))
+    (gnus-summary-next-subject 1 t)))
+
+(defun gnus-summary-raise-thread (score)
+  "Raise articles under current thread with SCORE."
+  (interactive "p")
+  (let (e)
+    (save-excursion
+      (let ((level (gnus-summary-thread-level)))
+       (gnus-summary-raise-score score)
+       (while (and (zerop (gnus-summary-next-subject 1))
+                   (> (gnus-summary-thread-level) level))
+         (gnus-summary-raise-score score))
+       (setq e (point))))
+    (or (zerop (gnus-summary-next-subject 1 t))
+       (goto-char e)))
+  (gnus-summary-position-cursor))
+
+(defun gnus-summary-lower-same-subject-and-select (score)
+  "Raise articles which has the same subject with SCORE and select the next."
+  (interactive "p")
+  (gnus-summary-raise-same-subject-and-select (- score)))
+
+(defun gnus-summary-lower-same-subject (score)
+  "Raise articles which has the same subject with SCORE."
+  (interactive "p")
+  (gnus-summary-raise-same-subject (- score)))
+
+(defun gnus-summary-lower-thread (score)
+  "Raise articles under current thread with SCORE."
+  (interactive "p")
+  (gnus-summary-raise-thread (- score)))
+
 (defun gnus-summary-kill-same-subject-and-select (unmark)
   "Mark articles which has the same subject as read, and then select the next.
 If UNMARK is positive, remove any kind of mark.
@@ -5854,13 +6876,12 @@ number of articles marked is returned."
   (interactive "p")
   (let ((backward (< n 0))
        (n (abs n)))
-  (while (and (> n 0)
-             (if unmark
-                 (gnus-summary-remove-process-mark 
-                  (gnus-summary-article-number))
-               (gnus-summary-set-process-mark 
-                (gnus-summary-article-number)))
-             (= 0 (gnus-summary-next-subject (if backward -1 1))))
+  (while (and 
+         (> n 0)
+         (if unmark
+             (gnus-summary-remove-process-mark (gnus-summary-article-number))
+           (gnus-summary-set-process-mark (gnus-summary-article-number)))
+         (zerop (gnus-summary-next-subject (if backward -1 1))))
     (setq n (1- n)))
   (if (/= 0 n) (message "No more articles"))
   n))
@@ -5880,60 +6901,12 @@ the actual number of articles marked is returned."
       (gnus-summary-remove-process-mark (car gnus-newsgroup-processable))))
   (gnus-summary-position-cursor))
 
-(defun gnus-summary-mark-as-expirable (n &optional unmark)
+(defun gnus-summary-mark-as-expirable (n)
   "Mark N articles forward as expirable.
-If N is negative, mark backward instead.  If UNMARK is non-nil, remove
-the expirably mark instead.  The difference between N and the actual
-number of articles marked is returned."
-  (interactive "p")
-  (let ((backward (< n 0))
-       (n (abs n)))
-  (while (and (> n 0)
-             (if unmark
-                 (gnus-summary-remove-expirable-mark 
-                  (gnus-summary-article-number))
-               (gnus-summary-set-expirable-mark 
-                (gnus-summary-article-number)))
-             (= 0 (gnus-summary-next-subject (if backward -1 1))))
-    (setq n (1- n)))
-  (if (/= 0 n) (message "No more articles"))
-  n))
-
-(defun gnus-summary-unmark-as-expirable (n)
-  "Mark N articles forward as expirable.
-If N is negative, mark backward instead.  The difference between N and
+If N is negative, mark backward instead. The difference between N and
 the actual number of articles marked is returned."
   (interactive "p")
-  (gnus-summary-mark-as-expirable n t))
-
-(defun gnus-summary-set-expirable-mark (article)
-  "Mark the current article as expirable and update the Summary line."
-  (setq gnus-newsgroup-expirable (cons article gnus-newsgroup-expirable))
-  (let ((buffer-read-only nil))
-    (if (gnus-summary-goto-subject article)
-       (progn
-         (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
-         (beginning-of-line)
-         (forward-char 2)
-         (delete-char 1)
-         (insert "X")
-         (run-hooks 'gnus-summary-update-hook)
-         t))))
-
-(defun gnus-summary-remove-expirable-mark (article)
-  "Remove the expirable mark from ARTICLE as expirable and update the Summary line."
-  (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
-  (let ((buffer-read-only nil))
-    (if (gnus-summary-goto-subject article)
-       (progn
-         (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
-         (beginning-of-line)
-         (forward-char 2)
-         (delete-char 1)
-         (insert 
-          (if (memq article gnus-newsgroup-processable) ?# ? ))
-         (run-hooks 'gnus-summary-update-hook)   
-         t))))
+  (gnus-summary-mark-forward n gnus-expirable-mark))
 
 (defun gnus-summary-expire-articles ()
   "Expire all articles that are marked as expirable in the current group."
@@ -5941,9 +6914,17 @@ the actual number of articles marked is returned."
   (if (and gnus-newsgroup-expirable
           (gnus-check-backend-function 
            'gnus-request-expire-articles gnus-newsgroup-name))
-      (setq gnus-newsgroup-expirable 
-           (gnus-request-expire-articles gnus-newsgroup-expirable
-                                         gnus-newsgroup-name))))
+      (let ((expirable gnus-newsgroup-expirable))
+       ;; The list of articles that weren't expired is returned.
+       (setq gnus-newsgroup-expirable 
+             (gnus-request-expire-articles gnus-newsgroup-expirable
+                                           gnus-newsgroup-name))
+       ;; We go through the old list of expirable, and mark all
+       ;; really expired articles as non-existant.
+       (while expirable
+         (or (memq (car expirable) gnus-newsgroup-expirable)
+             (gnus-summary-mark-as-read (car expirable) "%"))
+         (setq expirable (cdr expirable))))))
 
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
 (defun gnus-summary-delete-article (n)
@@ -5985,7 +6966,7 @@ delete these instead."
             articles gnus-newsgroup-name 'force)))))
 
 (defun gnus-summary-mark-article-as-replied (article)
-  "Mark ARTICLE replied and update the Summary line."
+  "Mark ARTICLE replied and update the summary line."
   (setq gnus-newsgroup-replied (cons article gnus-newsgroup-replied))
   (let ((buffer-read-only nil))
     (if (gnus-summary-goto-subject article)
@@ -5993,7 +6974,7 @@ delete these instead."
          (beginning-of-line)
          (forward-char 1)
          (delete-char 1)
-         (insert "R")
+         (insert gnus-replied-mark)
          t))))
 
 (defun gnus-summary-set-bookmark (article)
@@ -6046,122 +7027,122 @@ the actual number of articles marked is returned."
   (gnus-summary-mark-forward n gnus-dormant-mark))
 
 (defun gnus-summary-set-process-mark (article)
-  "Set the process mark on ARTICLE and update the Summary line."
+  "Set the process mark on ARTICLE and update the summary line."
   (setq gnus-newsgroup-processable (cons article gnus-newsgroup-processable))
   (let ((buffer-read-only nil))
     (if (gnus-summary-goto-subject article)
        (progn
          (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
          (beginning-of-line)
-         (forward-char 2)
+         (forward-char 1)
          (delete-char 1)
-         (insert "#")
-         (run-hooks 'gnus-summary-update-hook)
+         (insert gnus-process-mark)
+         (gnus-summary-update-line)
          t))))
 
 (defun gnus-summary-remove-process-mark (article)
-  "Remove the process mark from ARTICLE and update the Summary line."
+  "Remove the process mark from ARTICLE and update the summary line."
   (setq gnus-newsgroup-processable (delq article gnus-newsgroup-processable))
   (let ((buffer-read-only nil))
     (if (gnus-summary-goto-subject article)
        (progn
-         (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
+         (and (= (gnus-summary-article-mark) ?Z) (forward-line 1))
          (beginning-of-line)
-         (forward-char 2)
+         (forward-char 1)
          (delete-char 1)
-         (insert 
-          (if (memq article gnus-newsgroup-expirable) ?X ? ))
-         (run-hooks 'gnus-summary-update-hook)
+         (insert (if (memq article gnus-newsgroup-replied) 
+                     gnus-replied-mark ? ))
+         (gnus-summary-update-line)
          t))))
 
-(defun gnus-summary-mark-forward (n &optional unread)
+(defun gnus-summary-mark-forward (n &optional mark)
   "Mark N articles as read forwards.
 If N is negative, mark backwards instead.
-If UNREAD is non-nil, mark articles as unread. In that case, UNREAD
-must either be \" \", \"-\" or \"I\".
+Mark with MARK. If MARK is ? , ?! or ??, articles will be
+marked as unread. 
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
   (let ((backward (< n 0))
-       (n (abs n)))
+       (n (abs n))
+       (mark (or mark gnus-read-mark)))
   (while (and (> n 0)
-             (gnus-summary-mark-article nil unread)
-             (= 0 (gnus-summary-next-subject (if backward -1 1))))
+             (gnus-summary-mark-article nil mark)
+             (zerop (gnus-summary-next-subject (if backward -1 1))))
     (setq n (1- n)))
-  (if (/= 0 n) (message "No more %sarticles" (if unread "" "unread ")))
+  (if (/= 0 n) (message "No more %sarticles" (if mark "" "unread ")))
   (gnus-set-mode-line 'summary)
   n))
 
 (defun gnus-summary-mark-article (&optional article mark)
   "Mark ARTICLE with MARK.
-MARK can be any string (but it should just be one character long). 
-Four MARK strings are reserved: \" \" (unread), 
-\"-\" (ticked), \"I\" (dormant), \"D\" (read).
-If MARK is nil, then the default string \"D\" is used.
+MARK can be any character.
+Five MARK strings are reserved: ?  (unread), 
+?! (ticked), ?? (dormant), ?D (read), ?E (expirable).
+If MARK is nil, then the default character ?D is used.
 If ARTICLE is nil, then the article on the current line will be
 marked." 
+  ;; If no mark is given, then we check auto-expiring.
+  (and (or (not mark)
+          (and (numberp mark) (= mark gnus-killed-mark)))
+       (and gnus-newsgroup-auto-expire (setq mark gnus-expirable-mark)))
   (let* ((buffer-read-only nil)
-        (mark (or mark "D"))
+        (mark (or (and (stringp mark) (aref mark 0)) mark gnus-read-mark))
         (article (or article (gnus-summary-article-number))))
-    (if (numberp mark) (setq mark (format "%c" mark)))
-    (prog1
-       (if (gnus-summary-goto-subject article)
-           (progn
-             (gnus-summary-show-thread)
-             (beginning-of-line)
-             (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
-             ;; Fix the invisible mark.
-             (re-search-forward ". [-0-9]+ [0-9]+[\n\r]")
-             (goto-char (match-beginning 0))
-             (delete-char 1)
-             (insert mark)
-             (set-text-properties (1- (point)) (point) '(invisible t))
-             ;; Fix the visible mark.
-             (beginning-of-line)
-             (delete-char 1)
-             (insert mark)
-             (run-hooks 'gnus-summary-update-hook)
-             t))
-      (if (or (string= mark gnus-unread-mark) 
-             (string= mark gnus-ticked-mark) 
-             (string= mark gnus-dormant-mark))
-         (gnus-mark-article-as-unread article mark)
-       (gnus-mark-article-as-read article)))))
-
-(defun gnus-mark-article-as-read (article)
-  "Remember that ARTICLE is marked as read."
+    (if (or (= mark gnus-unread-mark) 
+           (= mark gnus-ticked-mark) 
+           (= mark gnus-dormant-mark))
+       (gnus-mark-article-as-unread article mark)
+      (gnus-mark-article-as-read article mark))
+    (if (gnus-summary-goto-subject article)
+       (progn
+         (gnus-summary-show-thread)
+         (beginning-of-line)
+         (if (= (gnus-summary-article-mark) ?Z) (forward-line 1))
+         ;; Fix the mark.
+         (let ((plist (text-properties-at (point))))
+           (delete-char 1)
+           (setcar (cdr (memq 'gnus-mark plist)) mark)
+           (insert mark)
+           (add-text-properties (1- (point)) (point) plist))
+         t))))
+
+(defun gnus-mark-article-as-read (article &optional mark)
+  "Enter ARTICLE in the pertinent lists and remove it from others."
   ;; Make the article expirable.
-  (if gnus-newsgroup-auto-expire
-    (gnus-summary-set-expirable-mark article))
-  ;; Remove from unread and marked list.
-  (setq gnus-newsgroup-unreads
-       (delq article gnus-newsgroup-unreads))
-  (setq gnus-newsgroup-marked
-       (delq article gnus-newsgroup-marked))
-  (setq gnus-newsgroup-dormant
-       (delq article gnus-newsgroup-dormant)))
+  (let ((mark (or (and (stringp mark) (aref mark 0)) mark gnus-read-mark)))
+    (if (= mark gnus-expirable-mark)
+       (setq gnus-newsgroup-expirable (cons article gnus-newsgroup-expirable))
+      (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable)))
+    ;; Remove from unread and marked lists.
+    (setq gnus-newsgroup-unreads
+         (delq article gnus-newsgroup-unreads))
+    (setq gnus-newsgroup-marked
+         (delq article gnus-newsgroup-marked))
+    (setq gnus-newsgroup-dormant
+         (delq article gnus-newsgroup-dormant))))
 
 (defun gnus-mark-article-as-unread (article &optional mark)
-  "Remember that ARTICLE is marked as unread.
-MARK is the mark type: \" \", \"-\" or \"I\"."
-  ;; Add to unread list.
-  (or (memq article gnus-newsgroup-unreads)
-      (setq gnus-newsgroup-unreads
-           (cons article gnus-newsgroup-unreads)))
-  ;; Update the expired list.
-  (gnus-summary-remove-expirable-mark article)
-  ;; If CLEAR-MARK is non-nil, the article must be removed from marked
-  ;; list.  Otherwise, it must be added to the list.
-  (setq gnus-newsgroup-marked
-       (delq article gnus-newsgroup-marked))
-  (setq gnus-newsgroup-dormant
-       (delq article gnus-newsgroup-dormant))
-  (if (equal mark gnus-ticked-mark)
-      (setq gnus-newsgroup-marked 
-           (cons article gnus-newsgroup-marked)))
-  (if (equal mark gnus-dormant-mark)
-      (setq gnus-newsgroup-dormant 
-           (cons article gnus-newsgroup-dormant))))
+  "Enter ARTICLE in the pertinent lists and remove it from others."
+  (let ((mark (or (and (stringp mark) (aref mark 0)) mark gnus-ticked-mark)))
+    ;; Add to unread list.
+    (or (memq article gnus-newsgroup-unreads)
+       (setq gnus-newsgroup-unreads
+             (cons article gnus-newsgroup-unreads)))
+    ;; If CLEAR-MARK is non-nil, the article must be removed from marked
+    ;; list.  Otherwise, it must be added to the list.
+    (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))
+    (if (= mark gnus-ticked-mark)
+       (setq gnus-newsgroup-marked 
+             (cons article gnus-newsgroup-marked)))
+    (if (= mark gnus-dormant-mark)
+       (setq gnus-newsgroup-dormant 
+             (cons article gnus-newsgroup-dormant)))))
 
 (defalias 'gnus-summary-mark-as-unread-forward 
   'gnus-summary-tick-article-forward)
@@ -6227,57 +7208,66 @@ The difference between N and the number of marks cleared is returned."
   (gnus-summary-mark-forward (- n) gnus-unread-mark))
 
 ;; Fix by Per Abrahamsen <amanda@iesd.auc.dk>.
-(defun gnus-summary-delete-marked-as-read ()
-  "Delete lines that are marked as read."
+(defalias 'gnus-summary-delete-marked-as-read 
+  'gnus-summary-remove-lines-marked-as-read)
+(make-obsolete 'gnus-summary-delete-marked-as-read 
+              'gnus-summary-remove-lines-marked-as-read)
+(defun gnus-summary-remove-lines-marked-as-read ()
+  "Remove lines that are marked as read."
   (interactive)
-  (gnus-summary-delete-marked-with 
-   (concat gnus-read-mark gnus-killed-mark gnus-kill-file-mark)))
-
-(defun gnus-summary-delete-marked-with (marks)
-  "Delete lines that are marked with MARKS (e.g. \"DK\")."
+  (gnus-summary-remove-lines-marked-with 
+   (concat (mapconcat
+           (lambda (char) (char-to-string (symbol-value char)))
+           '(gnus-read-mark 
+             gnus-killed-mark gnus-kill-file-mark
+             gnus-low-score-mark gnus-expirable-mark)
+           ""))))
+
+(defalias 'gnus-summary-delete-marked-with 
+  'gnus-summary-remove-lines-marked-with)
+(make-obsolete 'gnus-summary-delete-marked-with 
+              'gnus-summary-remove-lines-marked-with)
+;; Rewrite by Daniel Quinlan <quinlan@best.com>.
+(defun gnus-summary-remove-lines-marked-with (marks)
+  "Remove lines that are marked with MARKS (e.g. \"DK\")."
   (interactive "sMarks: ")
   ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
   (save-excursion
     (set-buffer gnus-summary-buffer)
     (let ((buffer-read-only nil)
-         (marks (concat "[" marks "]"))
-         beg)
+          (marks (concat "^[" marks "]"))
+          beg)
       (goto-char (point-min))
-      (while (not (eobp))
-       (if (looking-at marks)
-           (progn
-             (setq beg (point))
-             (forward-line 1)
-             ;; Fix by Per Abrahamsen <amanda@iesd.auc.dk>.
-              (setq gnus-newsgroup-expunged-lines
-                   (concat (or gnus-newsgroup-expunged-lines "")
-                            (buffer-substring beg (point))))
-             (delete-region beg (point)))
-         (forward-line 1))))
-    ;; Adjust point.
+      (while (search-forward-regexp marks (point-max) t)
+       (progn
+         (move-to-column 0)
+         (setq beg (point))
+         (forward-line 1)
+         ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>
+         (append-to-buffer gnus-newsgroup-expunged-buffer beg (point))
+         (delete-region beg (point)))))
     (or (zerop (buffer-size))
        (if (eobp)
            (gnus-summary-prev-subject 1)
          (gnus-summary-position-cursor)))))
 
 (defun gnus-summary-expunge-below (score)
-  "Delete articles with score less than SCORE."
+  "Remove articles with score less than SCORE."
   (interactive "P")
   (setq score (if score
                  (prefix-numeric-value score)
-               gnus-summary-default-interest))
+               gnus-summary-default-score))
   (save-excursion
     (set-buffer gnus-summary-buffer)
     (goto-char (point-min))
     (let ((buffer-read-only nil)
          beg)
       (while (not (eobp))
-       (if (< (gnus-summary-interest) score)
+       (if (< (gnus-summary-article-score) score)
            (progn
              (setq beg (point))
              (forward-line 1)
-             (setq gnus-newsgroup-expunged-lines 
-                   (buffer-substring beg (point)))
+             (append-to-buffer gnus-newsgroup-expunged-buffer beg (point))
              (delete-region beg (point)))
          (forward-line 1)))
       ;; Adjust point.
@@ -6291,46 +7281,55 @@ The difference between N and the number of marks cleared is returned."
   (interactive "P\ncMark: ")
   (setq score (if score
                  (prefix-numeric-value score)
-               gnus-summary-default-interest))
+               gnus-summary-default-score))
   (save-excursion
     (set-buffer gnus-summary-buffer)
     (goto-char (point-min))
     (while (not (eobp))
-      (if (< (gnus-summary-interest) score)
+      (if (< (gnus-summary-article-score) score)
          (progn
            (gnus-summary-mark-article nil (char-to-string mark))
            (forward-line 1))
        (forward-line 1)))))
 
 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun gnus-summary-set-mark-below (score)
+  "Automatically mark articles with score below SCORE as read."
+  (interactive "P")
+  (setq score (if score
+                 (prefix-numeric-value score)
+               gnus-summary-default-score))
+  (setq gnus-summary-mark-below score)
+  (gnus-summary-update-lines))
+
 (defun gnus-summary-kill-below (score)
-  "Kill articles with score below SCORE."
+  "Mark articles with score below SCORE as read."
   (interactive "P")
-  (gnus-summary-mark-below score ?K))
+  (gnus-summary-mark-below score gnus-killed-mark))
 
 (defun gnus-summary-clear-above (score)
   "Clear all marks from articles with score above SCORE."
   (interactive "P")
-  (gnus-summary-mark-above score ))
+  (gnus-summary-mark-above score gnus-unread-mark))
 
 (defun gnus-summary-tick-above (score)
   "Tick all articles with score above SCORE."
   (interactive "P")
-  (gnus-summary-mark-above score ?-))
+  (gnus-summary-mark-above score gnus-ticked-mark))
 
 (defun gnus-summary-mark-above (score mark)
   "Mark articles with score less than SCORE with MARK."
   (interactive "P\ncMark: ")
   (setq score (if score
                  (prefix-numeric-value score)
-               gnus-summary-default-interest))
+               gnus-summary-default-score))
   (save-excursion
     (set-buffer gnus-summary-buffer)
     (goto-char (point-min))
     (while (not (eobp))
-      (if (> (gnus-summary-interest) score)
+      (if (> (gnus-summary-article-score) score)
          (progn
-           (gnus-summary-mark-article nil (char-to-string mark))
+           (gnus-summary-mark-article nil mark)
            (forward-line 1))
        (forward-line 1)))))
 
@@ -6338,13 +7337,16 @@ The difference between N and the number of marks cleared is returned."
 (defun gnus-summary-show-all-expunged ()
   "Show all previously expunge articles."
   (interactive)
-  (if (not gnus-newsgroup-expunged-lines)
-      (error "No lines expunged."))
   (let ((buffer-read-only nil))
-    (goto-char (point-min))
     (save-excursion
-      (insert gnus-newsgroup-expunged-lines))
-    (setq gnus-newsgroup-expunged-lines nil)))
+      (if (and gnus-newsgroup-expunged-buffer
+              (progn
+                (set-buffer gnus-newsgroup-expunged-buffer)
+                (not (zerop (buffer-size)))))
+         (progn
+           (append-to-buffer gnus-summary-buffer (point-min) (point-max))
+           (erase-buffer))
+       (error "No lines expunged")))))
 
 (defun gnus-summary-show-all-dormant ()
   "Display all the hidden articles that are marked as dormant."
@@ -6374,8 +7376,8 @@ The number of articles marked as read is returned."
          gnus-expert-user
          (y-or-n-p
           (if all
-              "Do you really want to mark everything as read? "
-            "Delete all articles not marked as unread? ")))
+              "Mark absolutely all articles as read? "
+            "Mark all unread articles as read? ")))
       (let ((unreads (length gnus-newsgroup-unreads)))
        (if (gnus-summary-first-subject (not all))
            (while (and (gnus-summary-mark-as-read nil gnus-catchup-mark)
@@ -6463,7 +7465,7 @@ If ARG is positive number, turn showing conversation threads on."
              (end (point)))
          ;; Go forward until either the buffer ends or the subthread
          ;; ends. 
-         (while (and (= 0 (forward-line 1))
+         (while (and (zerop (forward-line 1))
                      (> (gnus-summary-thread-level) level))
            (setq end (point)))
          (subst-char-in-region start end ?\n ?\^M t)))))
@@ -6504,20 +7506,28 @@ done."
   (interactive "p")
   (gnus-summary-next-thread (- n)))
 
-(defun gnus-summary-go-down-thread (&optional up same)
+(defun gnus-summary-go-down-thread (&optional same)
   "Go down one level in the current thread.
-If UP is non-nil, go up instead.
 If SAME is non-nil, also move to articles of the same level."
   (let ((level (gnus-summary-thread-level))
-       (start (point))
-       (level-diff (if up -1 1))
-       l)
-    (if (not (and (= 0 (forward-line level-diff))
-                 (or (= (+ level level-diff) 
-                        (setq l (gnus-summary-thread-level)))
-                     (and same (= level l)))))
-       (goto-char start))
-    (/= start (point))))
+       (start (point)))
+    (if (and (zerop (forward-line 1))
+            (> (gnus-summary-thread-level) level))
+       t
+      (goto-char start)
+      nil)))
+
+(defun gnus-summary-go-up-thread ()
+  "Go up one level in the current thread."
+  (let ((level (gnus-summary-thread-level))
+       (start (point)))
+    (while (and (zerop (forward-line -1))
+               (>= (gnus-summary-thread-level) level)))
+    (if (>= (gnus-summary-thread-level) level)
+       (progn
+         (goto-char start)
+         nil)
+      t)))
 
 (defun gnus-summary-down-thread (n)
   "Go down thread N steps.
@@ -6528,7 +7538,8 @@ taken."
   (let ((up (< n 0))
        (n (abs n)))
   (while (and (> n 0)
-             (gnus-summary-go-down-thread up))
+             (if up (gnus-summary-go-up-thread)
+               (gnus-summary-go-down-thread)))
     (setq n (1- n)))
   (gnus-summary-position-cursor)
   (if (/= 0 n) (message "Can't go further" ))
@@ -6559,7 +7570,7 @@ If the prefix argument is negative, tick articles instead."
              (t (gnus-summary-tick-article)))
        ;; ...and go forward until either the buffer ends or the subtree
        ;; ends. 
-       (if (not (and (= 0 (forward-line 1))
+       (if (not (and (zerop (forward-line 1))
                      (> (gnus-summary-thread-level) level)))
            (setq killing nil))))
     ;; Hide killed subtrees.
@@ -6575,116 +7586,55 @@ If the prefix argument is negative, tick articles instead."
 ;; Summary sorting commands
 
 (defun gnus-summary-sort-by-number (reverse)
-  "Sort Summary buffer by article number.
+  "Sort summary buffer by article number.
 Argument REVERSE means reverse order."
   (interactive "P")
-  (gnus-summary-keysort-summary
-   (function <)
-   (lambda (a)
-     (header-number a))
-   reverse
-   ))
+  (gnus-summary-sort 'gnus-summary-article-number reverse))
 
 (defun gnus-summary-sort-by-author (reverse)
-  "Sort Summary buffer by author name alphabetically.
+  "Sort summary buffer by author name alphabetically.
 If case-fold-search is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
-  (gnus-summary-keysort-summary
-   (function string-lessp)
-   (lambda (a)
-     (if case-fold-search
-        (downcase (header-from a))
-       (header-from a)))
-   reverse
-   ))
+  (gnus-summary-sort
+   (lambda ()
+     (let ((extract (gnus-extract-address-components
+                    (header-from (gnus-get-header-by-number
+                                  (gnus-summary-article-number))))))
+       (or (car extract) (cdr extract))))
+   reverse))
 
 (defun gnus-summary-sort-by-subject (reverse)
-  "Sort Summary buffer by subject alphabetically. `Re:'s are ignored.
+  "Sort summary buffer by subject alphabetically. `Re:'s are ignored.
 If case-fold-search is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
-  (gnus-summary-keysort-summary
-   (function string-lessp)
-   (lambda (a)
-     (if case-fold-search
-        (downcase (gnus-simplify-subject (header-subject a) 're-only))
-       (gnus-simplify-subject (header-subject a) 're-only)))
-   reverse
-   ))
+  (gnus-summary-sort
+   (lambda ()
+     (downcase (gnus-simplify-subject (gnus-summary-subject-string))))
+   reverse))
 
 (defun gnus-summary-sort-by-date (reverse)
-  "Sort Summary buffer by date.
+  "Sort summary buffer by date.
 Argument REVERSE means reverse order."
   (interactive "P")
-  (gnus-summary-keysort-summary
-   (function string-lessp)
-   (lambda (a)
-     (gnus-sortable-date (header-date a)))
-   reverse
-   ))
-
-(defun gnus-summary-keysort-summary (predicate key &optional reverse)
-  "Sort Summary buffer by PREDICATE using a value passed by KEY.
-Optional argument REVERSE means reverse order."
-  (let ((current (gnus-summary-article-number)))
-    (gnus-keysort-headers predicate key reverse)
-    (gnus-summary-prepare)
-    (gnus-summary-goto-subject current)
-    ))
-
-(defun gnus-summary-sort-summary (predicate &optional reverse)
-  "Sort Summary buffer by PREDICATE.
-Optional argument REVERSE means reverse order."
-  (let ((current (gnus-summary-article-number)))
-    (gnus-sort-headers predicate reverse)
-    (gnus-summary-prepare)
-    (gnus-summary-goto-subject current)
-    ))
-
-;; Basic ideas by flee@cs.psu.edu (Felix Lee)
-
-(defun gnus-keysort-headers (predicate key &optional reverse)
-  "Sort current headers by PREDICATE using a value passed by KEY safely.
-*Safely* means C-g quitting is disabled during sort.
-Optional argument REVERSE means reverse order."
-  (let ((inhibit-quit t))
-    (setq gnus-newsgroup-headers
-         (if reverse
-             (nreverse
-              (gnus-keysort (nreverse gnus-newsgroup-headers) predicate key))
-           (gnus-keysort gnus-newsgroup-headers predicate key)))
-    ))
-
-(defun gnus-keysort (list predicate key)
-  "Sort LIST by PREDICATE using a value passed by KEY."
-  (mapcar (function cdr)
-         (sort (mapcar (lambda (a) (cons (funcall key a) a)) list)
-               (lambda (a b)
-                 (funcall predicate (car a) (car b))))))
-
-(defun gnus-sort-headers (predicate &optional reverse)
-  "Sort current headers by PREDICATE safely.
-*Safely* means C-g quitting is disabled during sort.
-Optional argument REVERSE means reverse order."
-  (let ((inhibit-quit t))
-    (setq gnus-newsgroup-headers
-         (if reverse
-             (nreverse (sort (nreverse gnus-newsgroup-headers) predicate))
-           (sort gnus-newsgroup-headers predicate)))
-    ))
+  (gnus-summary-sort
+   (lambda ()
+     (gnus-sortable-date
+      (header-date (gnus-get-header-by-number (gnus-summary-article-number)))))
+   reverse))
 
-(defun gnus-string-lessp (a b)
-  "Return T if first arg string is less than second in lexicographic order.
-If case-fold-search is non-nil, case of letters is ignored."
-  (if case-fold-search
-      (string-lessp (downcase a) (downcase b))
-    (string-lessp a b)))
+(defun gnus-summary-sort-by-score (reverse)
+  "Sort summary buffer by score.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'gnus-summary-article-score (not reverse)))
 
-(defun gnus-date-lessp (date1 date2)
-  "Return T if DATE1 is earlyer than DATE2."
-  (string-lessp (gnus-sortable-date date1)
-               (gnus-sortable-date date2)))
+(defun gnus-summary-sort (predicate reverse)
+  ;; Sort summary buffer by PREDICATE.  REVERSE means reverse order. 
+  (let (buffer-read-only)
+    (goto-char (point-min))
+    (sort-subr reverse 'forward-line 'end-of-line predicate)))
 
 (defun gnus-sortable-date (date)
   "Make sortable string by string-lessp from DATE.
@@ -6727,17 +7677,25 @@ The variable `gnus-default-article-saver' specifies the saver function."
            (setq process t))
        (setq articles (list (gnus-summary-article-number)))))
     (while articles
-      (gnus-summary-display-article (car articles) t)
-      (if (not gnus-save-all-headers)
-         (gnus-article-hide-headers t))
-      (if gnus-default-article-saver
-         (funcall gnus-default-article-saver)
-       (error "No default saver is defined."))
+      (let ((header (gnus-gethash (int-to-string (car articles))
+                                 gnus-newsgroup-headers-hashtb-by-number)))
+       (if (vectorp header)
+           (progn
+             (gnus-summary-display-article (car articles) t)
+             (if (not gnus-save-all-headers)
+                 (gnus-article-hide-headers t))
+             (if gnus-default-article-saver
+                 (funcall gnus-default-article-saver)
+               (error "No default saver is defined.")))
+         (if (assq 'name header)
+             (gnus-copy-file (cdr (assq 'name header)))
+           (message "Article %d is unsaveable" (car articles)))))
       (if process
          (gnus-summary-remove-process-mark (car articles)))
       (setq articles (cdr articles)))
     (if process (setq gnus-newsgroup-processable 
                      (nreverse gnus-newsgroup-processable)))
+    (gnus-summary-position-cursor)
     n))
 
 (defun gnus-summary-pipe-output (arg)
@@ -6750,14 +7708,14 @@ pipe those articles instead."
   (let ((gnus-default-article-saver 'gnus-summary-save-in-pipe))
     (gnus-summary-save-article arg)))
 
-(defun gnus-summary-save-article-rmail (arg)
-  "Append the current article to an Rmail file.
+(defun gnus-summary-save-article-mail (arg)
+  "Append the current article to an mail file.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
-  (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
+  (let ((gnus-default-article-saver 'gnus-summary-save-in-mail))
     (gnus-summary-save-article arg)))
 
 (defun gnus-summary-save-in-rmail (&optional filename)
@@ -6791,6 +7749,7 @@ is initialized from the SAVEDIR environment variable."
 Optional argument FILENAME specifies file name.
 Directory to save to is default to `gnus-article-save-directory' which
 is initialized from the SAVEDIR environment variable."
+  (interactive)
   (let ((default-name
          (funcall gnus-mail-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-mail)))
@@ -6822,6 +7781,7 @@ is initialized from the SAVEDIR environment variable."
 Optional argument FILENAME specifies file name.
 Directory to save to is default to `gnus-article-save-directory' which
 is initialized from the SAVEDIR environment variable."
+  (interactive)
   (let ((default-name
          (funcall gnus-file-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-file)))
@@ -6844,6 +7804,7 @@ is initialized from the SAVEDIR environment variable."
 
 (defun gnus-summary-save-in-pipe (&optional command)
   "Pipe this article to subprocess."
+  (interactive)
   (let ((command (read-string "Shell command on article: "
                              gnus-last-shell-command)))
     (if (string-equal command "")
@@ -6855,81 +7816,200 @@ is initialized from the SAVEDIR environment variable."
        (shell-command-on-region (point-min) (point-max) command nil)))
     (setq gnus-last-shell-command command)))
 
-;; Summary killfile commands
+;; Summary extract commands
+
+(defun gnus-summary-insert-pseudos (pslist)
+  (let ((buffer-read-only nil)
+       (article (gnus-summary-article-number))
+       b)
+    (or (gnus-summary-goto-subject article)
+       (error (format "No such article: %d" article)))
+    (gnus-summary-position-cursor)
+    (save-excursion
+      (forward-line 1)
+      (while pslist
+       (setq b (point))
+       (insert "          " (file-name-nondirectory 
+                             (cdr (assq 'name (car pslist))))
+               ": " (or (cdr (assq 'execute (car pslist))) "") "\n")
+       (add-text-properties 
+        b (1+ b) (list 'gnus-subject (cdr (assq 'name (car pslist)))
+                       'gnus-number gnus-reffed-article-number
+                       'gnus-mark gnus-unread-mark
+                       'gnus-pseudo (car pslist)
+                       'gnus-thread 0))
+       (gnus-sethash (int-to-string gnus-reffed-article-number)
+                     (car pslist) gnus-newsgroup-headers-hashtb-by-number)
+       (setq gnus-reffed-article-number (1- gnus-reffed-article-number))
+       (setq pslist (cdr pslist))))))
+
+(defun gnus-request-pseudo-article (props)
+  (cond ((assq 'execute props)
+        (gnus-execute-command (cdr (assq 'execute props))))
+       ((assq 'digest props)
+        )
+       )
+  (let ((gnus-current-article (gnus-summary-article-number)))
+    (run-hooks 'gnus-mark-article-hook)))
+
+(defun gnus-execute-command (command)
+  (save-excursion
+    (gnus-article-setup-buffer)
+    (set-buffer gnus-article-buffer)
+    (let ((command (read-string "Command: " command))
+         (buffer-read-only nil))
+      (erase-buffer)
+      (insert "$ " command "\n\n")
+      (if gnus-view-pseudo-asynchronously
+         (start-process "gnus-execute" nil "sh" "-c" command)
+       (call-process "sh" nil t nil "-c" command)))))
+
+(defun gnus-copy-file (file &optional to)
+  "Copy FILE to TO."
+  (interactive
+   (list (read-file-name "Copy file: " default-directory)
+        (read-file-name "Copy file to: " default-directory)))
+  (or to (setq to (read-file-name "Copy file to: " default-directory)))
+  (and (file-directory-p to) 
+       (setq to (concat (file-name-as-directory to)
+                       (file-name-nondirectory file))))
+  (copy-file file to))
+
+;; Summary score file commands
 
-;; Much modification of the kill code and some of the functions are
-;; written by Per Abrahamsen <amanda@iesd.auc.dk>.
+;; Much modification of the kill (ahem, score) code and lots of the
+;; functions are written by Per Abrahamsen <amanda@iesd.auc.dk>.
+
+(defun gnus-summary-header (header)
+  ;; Return HEADER for current articles, or error.
+  (let ((article (gnus-summary-article-number)))
+    (if article
+       (aref (gnus-get-header-by-number article)
+             (nth 1 (assoc header gnus-header-index)))
+      (error "No article on current line"))))
+
+(defun gnus-summary-score-entry (header match type score date &optional prompt)
+  "Enter score file entry.
+HEADER is the header being scored.
+MATCH is the string we are looking for.
+TYPE is a flag indicating if it is a regexp or substring.
+SCORE is the score to add.
+DATE is the expire date."
+  (interactive (list (completing-read "Header: "
+                                     gnus-header-index
+                                     (lambda (x) (fboundp (nth 2 x)))
+                                     t)
+                    (read-string "Match: ")
+                    (y-or-n-p "Use regexp match? ")
+                    (prefix-numeric-value current-prefix-arg)
+                    (if (y-or-n-p "Expire kill? ")
+                        (current-time-string)
+                      nil)))
+  (if (not prompt)
+      ()
+    (setq match (read-string "Match: " match)))
+  (let ((score (or score gnus-score-interactive-default-score)))
+    (gnus-summary-score-effect header match type score)
+  
+    (gnus-summary-score-effect header match type score)
+    (gnus-score-set header
+                   (cons (list match type score date) 
+                         (gnus-score-get header)))
+    (gnus-score-set 'touched t)))
+
+(defun gnus-summary-score-effect (header match type score)
+  "Simulate the effect of a score file entry.
+HEADER is the header being scored.
+MATCH is the string we are looking for.
+TYPE is a flag indicating if it is a regexp or substring.
+SCORE is the score to add."
+  (interactive (list (completing-read "Header: "
+                                     gnus-header-index
+                                     (lambda (x) (fboundp (nth 2 x)))
+                                     t)
+                    (read-string "Match: ")
+                    (y-or-n-p "Use regexp match? ")
+                    (prefix-numeric-value current-prefix-arg)))
+  (save-excursion
+    (or (and (stringp match) (> (length match) 0))
+      (error "No match"))
+    (goto-char (point-min))
+    (let ((regexp (if type
+                     match
+                   (concat "\\`.*" (regexp-quote match) ".*\\'"))))
+      (while (not (eobp))
+       (let ((content (gnus-summary-header header))
+             (case-fold-search t))
+         (and content
+              (if (string-match regexp content)
+                  (gnus-summary-raise-score score))))
+       (beginning-of-line 2)))))
+
+(defun gnus-summary-score-crossposting (score date)
+   ;; Enter score file entry for current crossposting.
+   ;; SCORE is the score to add.
+   ;; DATE is the expire date.
+   (let ((xref (gnus-summary-header "xref"))
+        (start 0)
+        group)
+     (or xref (error "This article is not crossposted"))
+     (while (string-match " \\([^ \t]+\\):" xref start)
+       (setq start (match-end 0))
+       (if (not (string= 
+                (setq group 
+                      (substring xref (match-beginning 1) (match-end 1)))
+                gnus-newsgroup-name))
+          (gnus-summary-score-entry
+           "xref" (concat " " group ":") nil score date)))))
 
 (defun gnus-summary-temporarily-lower-by-subject (level)
   "Temporarily lower score by LEVEL for current subject.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-lower-by-subject
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "subject" (gnus-summary-header "subject") nil (- level) (current-time-string)))
 
 (defun gnus-summary-temporarily-lower-by-author (level)
   "Temporarily lower score by LEVEL for current author.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-lower-by-author
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "from" (gnus-summary-header "from") nil (- level) (current-time-string)))
 
 (defun gnus-summary-temporarily-lower-by-xref (level)
   "Temporarily lower score by LEVEL for current xref.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-lower-by-xref
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-crossposting (- level) (current-time-string)))
 
 (defun gnus-summary-temporarily-lower-by-thread (level)
   "Temporarily lower score by LEVEL for current thread.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-lower-by-thread
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "references" (gnus-summary-header "id")
+   nil (- level) (current-time-string)))
 
 (defun gnus-summary-lower-by-subject (level)
   "Lower score by LEVEL for current subject."
-  (interactive "p")
-  (gnus-kill-file-lower-by-subject
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "subject" (gnus-summary-header "subject") nil (- level) nil))
 
 (defun gnus-summary-lower-by-author (level)
   "Lower score by LEVEL for current author."
-  (interactive "p")
-  (gnus-kill-file-lower-by-author
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "from" (gnus-summary-header "from") nil (- level) nil))
 
 (defun gnus-summary-lower-by-xref (level)
   "Lower score by LEVEL for current xref."
-  (interactive "p")
-  (gnus-kill-file-lower-by-xref
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-crossposting (- level) nil))
 
 (defun gnus-summary-lower-followups-to-author (level)
   "Lower score by LEVEL for all followups to the current author."
-  (interactive "p")
+  (interactive "P")
   (gnus-kill-file-lower-followups-to-author
    level
    (let ((article (gnus-summary-article-number)))
@@ -6939,82 +8019,60 @@ See `gnus-kill-expiry-days'."
 (defun gnus-summary-temporarily-raise-by-subject (level)
   "Temporarily raise score by LEVEL for current subject.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-raise-by-subject
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "subject" (gnus-summary-header "subject") nil level (current-time-string)))
 
 (defun gnus-summary-temporarily-raise-by-author (level)
   "Temporarily raise score by LEVEL for current author.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-raise-by-author
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "from" (gnus-summary-header "from") nil level (current-time-string)))
 
 (defun gnus-summary-temporarily-raise-by-xref (level)
   "Temporarily raise score by LEVEL for current xref.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-raise-by-xref
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-crossposting level (current-time-string)))
 
 (defun gnus-summary-temporarily-raise-by-thread (level)
   "Temporarily raise score by LEVEL for current thread.
 See `gnus-kill-expiry-days'."
-  (interactive "p")
-  (gnus-kill-file-temporarily-raise-by-thread
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "references" (gnus-summary-header "id")
+   nil level (current-time-string)))
 
 (defun gnus-summary-raise-by-subject (level)
   "Raise score by LEVEL for current subject."
-  (interactive "p")
-  (gnus-kill-file-raise-by-subject
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "subject" (gnus-summary-header "subject") nil level nil))
 
 (defun gnus-summary-raise-by-author (level)
   "Raise score by LEVEL for current author."
-  (interactive "p")
-  (gnus-kill-file-raise-by-author
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-entry
+   "from" (gnus-summary-header "from") nil level nil t))
 
 (defun gnus-summary-raise-by-xref (level)
   "Raise score by LEVEL for current xref."
-  (interactive "p")
-  (gnus-kill-file-raise-by-xref
-   level
-   (let ((article (gnus-summary-article-number)))
-     (if article (gnus-get-header-by-number article)
-       (error "No article on current line")))))
+  (interactive "P")
+  (gnus-summary-score-crossposting level nil))
 
 (defun gnus-summary-edit-global-kill ()
-  "Edit a global KILL file."
+  "Edit a global score file."
   (interactive)
   (setq gnus-current-kill-article (gnus-summary-article-number))
-  (gnus-kill-file-edit-file nil)       ;Nil stands for global KILL file.
+  (gnus-kill-file-edit-file nil)       ;Nil stands for global score file.
   (message
    (substitute-command-keys
-    "Editing a global KILL file (Type \\[gnus-kill-file-exit] to exit)")))
+    "Editing a global score file (Type \\[gnus-kill-file-exit] to exit)")))
 
 (defun gnus-summary-raise-followups-to-author (level)
   "Raise score by LEVEL for all followups to the current author."
-  (interactive "p")
+  (interactive "P")
   (gnus-kill-file-raise-followups-to-author
    level
    (let ((article (gnus-summary-article-number)))
@@ -7022,18 +8080,18 @@ See `gnus-kill-expiry-days'."
        (error "No article on current line")))))
 
 (defun gnus-summary-edit-local-kill ()
-  "Edit a local KILL file applied to the current newsgroup."
+  "Edit a local score file applied to the current newsgroup."
   (interactive)
   (setq gnus-current-kill-article (gnus-summary-article-number))
   (gnus-kill-file-edit-file gnus-newsgroup-name)
   (message
    (substitute-command-keys
-    "Editing a local KILL file (Type \\[gnus-kill-file-exit] to exit)")))
+    "Editing a local score file (Type \\[gnus-kill-file-exit] to exit)")))
 
 
 \f
 ;;;
-;;; Gnus Article Mode
+;;; Gnus article mode
 ;;;
 
 (if gnus-article-mode-map
@@ -7042,16 +8100,32 @@ See `gnus-kill-expiry-days'."
   (suppress-keymap gnus-article-mode-map)
   (define-key gnus-article-mode-map " " 'gnus-article-next-page)
   (define-key gnus-article-mode-map "\177" 'gnus-article-prev-page)
-  (define-key gnus-article-mode-map "r" 'gnus-article-refer-article)
+  (define-key gnus-article-mode-map "\C-x^" 'gnus-article-refer-article)
   (define-key gnus-article-mode-map "h" 'gnus-article-show-summary)
   (define-key gnus-article-mode-map "s" 'gnus-article-show-summary)
-  (define-key gnus-article-mode-map "m" 'gnus-article-mail)
-  (define-key gnus-article-mode-map "M" 'gnus-article-mail-with-original)
+  (define-key gnus-article-mode-map "\C-xm" 'gnus-article-mail)
+  (define-key gnus-article-mode-map "\C-xM" 'gnus-article-mail-with-original)
   (define-key gnus-article-mode-map "?" 'gnus-article-describe-briefly)
-  (define-key gnus-article-mode-map "\C-c\C-i" 'gnus-info-find-node))
+  
+  ;; Duplicate almost all summary keystrokes in the article mode map.
+  (let ((commands 
+        (list "#" "\M-#" "\C-c\M-#" "\r" "n" "p"
+              "N" "P" "\M-\C-n" "\M-\C-p" "." "\M-s" "\M-r"
+              "<" ">" "l" "j" "^" "\M-^" "-" "u" "U" "d" "D"
+              "\M-u" "\M-U" "k" "\C-k" "\M-\C-k" "c" "x" "X" 
+              "\M-\C-x" "\M-\177" "b" "B" "$" "w" "\C-c\C-r"
+              "t" "\M-t" "a" "f" "F" "C" "S" "r" "R" "\C-c\C-f"
+              "m" "o" "\C-o" "|" "\M-m" "\M-\C-m" "\M-k" "m" "M"
+              "V" "\C-c\C-d" "q" "Q")))
+    (while commands
+      (define-key gnus-article-mode-map (car commands) 
+       'gnus-article-summary-command)
+      (setq commands (cdr commands))))
+
+  (if gnus-visual (gnus-article-make-menu-bar)))
 
 (defun gnus-article-mode ()
-  "Major mode for browsing through an article.
+  "Major mode for reading an article.
 All normal editing commands are switched off.
 The following commands are available:
 
@@ -7059,7 +8133,7 @@ The following commands are available:
 \\[gnus-article-next-page]\t Scroll the article one page forwards
 \\[gnus-article-prev-page]\t Scroll the article one page backwards
 \\[gnus-article-refer-article]\t Go to the article referred to by an article id near point
-\\[gnus-article-show-summary]\t Display the Summary buffer
+\\[gnus-article-show-summary]\t Display the summary buffer
 \\[gnus-article-mail]\t Send a reply to the address near point
 \\[gnus-article-mail-with-original]\t Send a reply to the address near point; include the original article
 \\[gnus-article-describe-briefly]\t Describe the current mode briefly
@@ -7068,9 +8142,13 @@ The following commands are available:
 "
   (interactive)
   (kill-all-local-variables)
-  (setq mode-line-modified "--- ")
-  (setq major-mode 'gnus-article-mode)
+  (setq mode-line-modified "-- ")
+  (make-local-variable 'mode-line-format)
+  (setq mode-line-format (copy-sequence mode-line-format))
+  (and (equal (nth 3 mode-line-format) "   ")
+       (setcar (nthcdr 3 mode-line-format) ""))
   (setq mode-name "Article")
+  (setq major-mode 'gnus-article-mode)
   (make-local-variable 'minor-mode-alist)
   (or (assq 'gnus-show-mime minor-mode-alist)
       (setq minor-mode-alist
@@ -7085,7 +8163,7 @@ The following commands are available:
   (run-hooks 'gnus-article-mode-hook))
 
 (defun gnus-article-setup-buffer ()
-  "Initialize Article mode buffer."
+  "Initialize article mode buffer."
   (or (get-buffer gnus-article-buffer)
       (save-excursion
        (set-buffer (get-buffer-create gnus-article-buffer))
@@ -7095,25 +8173,36 @@ The following commands are available:
 
 (defun gnus-request-article-this-buffer (article &optional group)
   "Get an article and insert it into this buffer."
+  (setq group (or group gnus-newsgroup-name))
   ;; Using `gnus-request-article' directly will insert the article into
   ;; `nntp-server-buffer' - so we'll save some time by not having to
   ;; copy it from the server buffer into the article buffer.
 
   ;; We only request an article by message-id when we do not have the
   ;; headers for it, so we'll have to get those.
-  (if (stringp article) (gnus-read-header article))
+  (and (stringp article) (gnus-read-header article))
+
   ;; If the article number is negative, that means that this article
   ;; doesn't belong in this newsgroup (possibly), so we find its
   ;; message-id and request it by id instead of number.
   (if (and (numberp article) (< article 0))
       (save-excursion
        (set-buffer gnus-summary-buffer)
-       (setq article 
-             (header-id 
-              (gnus-gethash (int-to-string article)
-                            gnus-newsgroup-headers-hashtb-by-number)))))
+       (let ((header (gnus-gethash (int-to-string article)
+                                   gnus-newsgroup-headers-hashtb-by-number)))
+         (if (vectorp header)
+             ;; It's a real article.
+             (setq article (header-id header))
+           ;; It is an extracted pseudo-article.
+           (setq article nil)
+           (gnus-request-pseudo-article header)))))
   ;; Get the article and into the article buffer.
-  (gnus-request-article article group (current-buffer)))
+  (if article
+      (progn
+       (erase-buffer)
+       (and (gnus-request-article article group (current-buffer))
+           'article))
+    'pseudo))
 
 (defun gnus-read-header (id)
   "Read the headers of article ID and enter them into the Gnus system."
@@ -7121,9 +8210,9 @@ The following commands are available:
       (gnus-make-headers-hashtable-by-number))
   (let (header)
     (if (not (setq header 
-                  (car (if (let ((nntp-xover-is-evil t))
-                             (gnus-retrieve-headers (list id) 
-                                                    gnus-newsgroup-name))
+                  (car (if (let ((gnus-nov-is-evil t))
+                             (gnus-retrieve-headers 
+                              (list id) gnus-newsgroup-name))
                            (gnus-get-newsgroup-headers)))))
        nil
       (if (stringp id)
@@ -7137,19 +8226,20 @@ The following commands are available:
       header)))
 
 (defun gnus-article-prepare (article &optional all-headers header)
-  "Prepare ARTICLE in Article mode buffer.
-ARTICLE can be either a article number or Message-ID.
+  "Prepare ARTICLE in article mode buffer.
+ARTICLE should either be an article number or a Message-ID.
 If ARTICLE is an id, HEADER should be the article headers.
 If ALL-HEADERS is non-nil, no headers are hidden."
   (save-excursion
-    ;; Make sure we start are in a Summary buffer.
-    (if (eq major-mode 'gnus-summary-mode)
-       (setq gnus-summary-buffer (current-buffer))
-      (set-buffer gnus-summary-buffer))
+    ;; Make sure we start in a summary buffer.
+    (or (eq major-mode 'gnus-summary-mode)
+       (set-buffer gnus-summary-buffer))
+    (setq gnus-summary-buffer (current-buffer))
     ;; Make sure the connection to the server is alive.
-    (if (not (gnus-server-opened gnus-current-select-method))
+    (or (gnus-server-opened (gnus-find-method-for-group gnus-newsgroup-name))
        (progn
-         (gnus-check-news-server gnus-current-select-method)
+         (gnus-check-news-server 
+          (gnus-find-method-for-group gnus-newsgroup-name))
          (gnus-request-group gnus-newsgroup-name t)))
     (or gnus-newsgroup-headers-hashtb-by-number
        (gnus-make-headers-hashtable-by-number))
@@ -7157,87 +8247,86 @@ If ALL-HEADERS is non-nil, no headers are hidden."
           (summary-buffer (current-buffer))
           (internal-hook gnus-article-internal-prepare-hook)
           (bookmark (cdr (assq article gnus-newsgroup-bookmarks)))
-          (group gnus-newsgroup-name))
+          (group gnus-newsgroup-name)
+          result)
       (save-excursion
+       (gnus-article-setup-buffer)
        (set-buffer gnus-article-buffer)
        (let ((buffer-read-only nil))
-         (erase-buffer)
-         (prog1
-             (if (gnus-request-article-this-buffer article group)
-                 (progn 
-                   ;; gnus-have-all-headers must be either T or NIL.
-                   (setq gnus-have-all-headers
-                         (not (not (or all-headers gnus-show-all-headers))))
-                   (if (and (numberp article)
-                            (not (eq article gnus-current-article)))
-                       ;; Seems like a new article has been selected.
-                       ;; `gnus-current-article' must be an article number.
-                       (save-excursion
-                         (set-buffer summary-buffer)
-                         (setq gnus-last-article gnus-current-article)
-                         (setq gnus-current-article article)
-                         (setq gnus-current-headers
-                               (gnus-get-header-by-number 
-                                gnus-current-article))
-                         (setq gnus-article-current 
-                               (cons gnus-newsgroup-name 
-                                     (header-number gnus-current-headers)))
-                         (run-hooks 'gnus-mark-article-hook)
-                         (and gnus-visual
-                              (run-hooks 'gnus-visual-mark-article-hook))
-                         ;; Set the global newsgroup variables here.
-                         ;; Suggested by Jim Sisolak
-                         ;; <sisolak@trans4.neep.wisc.edu>.
-                         (gnus-set-global-variables)))
-                   ;; Hooks for getting information from the article.
-                   ;; This hook must be called before being narrowed.
-                   (run-hooks 'internal-hook)
-                   (run-hooks 'gnus-article-prepare-hook)
-                   ;; Decode MIME message.
-                   (if (and gnus-show-mime
-                            (gnus-fetch-field "Mime-Version"))
-                       (funcall gnus-show-mime-method))
-                   ;; Perform the article display hooks.
-                   (let ((buffer-read-only nil))
-                     (run-hooks 'gnus-article-display-hook))
-                   ;; Do page break.
-                   (goto-char (point-min))
-                   (if gnus-break-pages
-                       (gnus-narrow-to-page))
-                   (gnus-set-mode-line 'article)
-                   t)
-               ;; There is no such article.
-               (if (numberp article)
-                   (gnus-summary-mark-as-read article))
-               (ding) 
+         (if (not (setq result (gnus-request-article-this-buffer 
+                                article group)))
+             ;; There is no such article.
+             (progn
+               (and (numberp article) 
+                    (gnus-summary-mark-as-read article gnus-canceled-mark))
                (message "No such article (may be canceled)")
+               (ding) 
                nil)
-           (goto-char 1)
-           (if bookmark
+           (if (not (eq result 'article))
                (progn
-                 (message "Moved to bookmark.")
-                 (search-forward "\n\n" nil t)
-                 (forward-line bookmark)))
-           (set-window-start 
-            (get-buffer-window gnus-article-buffer) (point))))))))
-
-(defun gnus-set-global-variables ()
-  ;; Set the global equivalents of the Summary buffer-local variables
-  ;; to the latest values they had. These reflect the Summary buffer
-  ;; that was in action when the last article was fetched.
-  (let ((name gnus-newsgroup-name)
-       (marked gnus-newsgroup-marked)
-       (unread gnus-newsgroup-unreads)
-       (headers gnus-current-headers))
-    (save-excursion
-      (set-buffer gnus-group-buffer)
-      (setq gnus-newsgroup-name name)
-      (setq gnus-newsgroup-marked marked)
-      (setq gnus-newsgroup-unreads unread)
-      (setq gnus-current-headers headers))))
+                 (save-excursion
+                   (set-buffer summary-buffer)
+                   (setq gnus-last-article gnus-current-article
+                         gnus-current-article 0
+                         gnus-current-headers nil
+                         gnus-article-current nil)
+                   (gnus-configure-windows 'article)
+                   (gnus-set-mode-line 'summary)
+                   (gnus-set-global-variables))
+                 (gnus-set-mode-line 'article))
+             ;; The result from the `request' was an actual article -
+             ;; or at least some text that is now displayed in the
+             ;; article buffer.
+             (if (and (numberp article)
+                      (not (eq article gnus-current-article)))
+                 ;; Seems like a new article has been selected.
+                 ;; `gnus-current-article' must be an article number.
+                 (save-excursion
+                   (set-buffer summary-buffer)
+                   (setq gnus-last-article gnus-current-article)
+                   (setq gnus-current-article article)
+                   (setq gnus-current-headers 
+                         (gnus-get-header-by-number gnus-current-article))
+                   (setq gnus-article-current 
+                         (cons gnus-newsgroup-name gnus-current-article))
+                   (gnus-set-mode-line 'summary)
+                   (run-hooks 'gnus-mark-article-hook)
+                   (and gnus-visual 
+                        (run-hooks 'gnus-visual-mark-article-hook))
+                   ;; Set the global newsgroup variables here.
+                   ;; Suggested by Jim Sisolak
+                   ;; <sisolak@trans4.neep.wisc.edu>.
+                   (gnus-set-global-variables)))
+             ;; gnus-have-all-headers must be either T or NIL.
+             (setq gnus-have-all-headers
+                   (not (not (or all-headers gnus-show-all-headers))))
+             ;; Hooks for getting information from the article.
+             ;; This hook must be called before being narrowed.
+             (run-hooks 'internal-hook)
+             (run-hooks 'gnus-article-prepare-hook)
+             ;; Decode MIME message.
+             (if (and gnus-show-mime
+                      (gnus-fetch-field "Mime-Version"))
+                 (funcall gnus-show-mime-method))
+             ;; Perform the article display hooks.
+             (let ((buffer-read-only nil))
+               (run-hooks 'gnus-article-display-hook))
+             ;; Do page break.
+             (goto-char (point-min))
+             (and gnus-break-pages (gnus-narrow-to-page))
+             (gnus-set-mode-line 'article)
+             (goto-char 1)
+             (if bookmark
+                 (progn
+                   (message "Moved to bookmark")
+                   (search-forward "\n\n" nil t)
+                   (forward-line bookmark)))
+             (set-window-start 
+              (get-buffer-window gnus-article-buffer) (point-min))
+             t)))))))
 
 (defun gnus-article-show-all-headers ()
-  "Show all article headers in Article mode buffer."
+  "Show all article headers in article mode buffer."
   (save-excursion 
     (setq gnus-have-all-headers t)
     (gnus-article-setup-buffer)
@@ -7321,10 +8410,11 @@ Provided for backwards compatability."
 
 (defun gnus-article-hide-signature ()
   "Hides the signature in an article.
-It does this by hiding everyting after "^-- *$", which is what all
+It does this by hiding everyting after \"^-- *$\", which is what all
 signatures should be preceded by. Note that this may mean that parts
 of an article may disappear if the article has such a line in the
 middle of the text."
+  (interactive)
   (save-excursion
     (goto-char (point-max))
     (if (re-search-backward "^-- *$" nil t)
@@ -7337,6 +8427,7 @@ This function uses the famous, extremely intelligent \"shoot in foot\"
 algorithm - which is simply deleting all lines that start with
 \">\". Your mileage may vary. If you come up with anything better,
 please do mail it to me."
+  (interactive)
   (save-excursion
     (goto-char 1)
     (search-forward "\n\n" nil t)
@@ -7350,24 +8441,53 @@ please do mail it to me."
 ;; Written by Per Abrahamsen <amanda@iesd.auc.dk>.
 (defun gnus-article-treat-overstrike ()
   ;; Prepare article for overstrike commands.
+  (interactive)
   (save-excursion
-    (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil))
-      (while (search-forward "\b" nil t)
-       (let ((next (following-char))
-             (previous (char-after (- (point) 2))))
-         (cond ((eq next previous)
-                (delete-region (- (point) 2) (point))
-                (put-text-property (point) (1+ (point))
-                                   'face 'bold))
-               ((eq next ?_)
-                (delete-region (1- (point)) (1+ (point)))
-                (put-text-property (1- (point)) (point)
-                                   'face 'underline))
-               ((eq previous ?_)
-                (delete-region (- (point) 2) (point))
-                (put-text-property (point) (1+ (point))
-                                   'face 'underline))))))))
+    (while (search-forward "\b" nil t)
+      (let ((next (following-char))
+           (previous (char-after (- (point) 2))))
+       (cond ((eq next previous)
+              (delete-region (- (point) 2) (point))
+              (put-text-property (point) (1+ (point))
+                                 'face 'bold))
+             ((eq next ?_)
+              (delete-region (1- (point)) (1+ (point)))
+              (put-text-property (1- (point)) (point)
+                                 'face 'underline))
+             ((eq previous ?_)
+              (delete-region (- (point) 2) (point))
+              (put-text-property (point) (1+ (point))
+                                 'face 'underline)))))))
+
+(defun gnus-article-remove-cr ()
+  (interactive)
+  (while (search-forward "\r" nil t)
+    (replace-match "")))
+
+(defun gnus-article-de-quoted-unreadable ()
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (while (re-search-forward "=[0-9A-F][0-9A-F]" nil t)
+       (replace-match 
+        (char-to-string 
+         (+
+          (* 16 (gnus-hex-char-to-integer 
+                 (char-after (1+ (match-beginning 0)))))
+          (gnus-hex-char-to-integer
+           (char-after (1- (match-end 0)))))))))))
+
+;; Taken from hexl.el.
+(defun gnus-hex-char-to-integer (character)
+  "Take a char and return its value as if it was a hex digit."
+  (if (and (>= character ?0) (<= character ?9))
+      (- character ?0)
+    (let ((ch (logior character 32)))
+      (if (and (>= ch ?a) (<= ch ?f))
+         (- ch (- ?a 10))
+       (error (format "Invalid hex digit `%c'." ch))))))
 
 ;; Article savers.
 
@@ -7580,7 +8700,7 @@ Set mark at end of digested message."
        (push-mark)                     ;Set mark at end of digested message.
        (goto-char begin)
        (beginning-of-line)
-       ;; Show From: and Subject: fields.
+       ;; Show From and Subject fields.
        (recenter 1))
     (message "End of message")
     ))
@@ -7644,17 +8764,30 @@ If YANK is non-nil, include the original article."
   (gnus-article-mail 'yank))
 
 (defun gnus-article-show-summary ()
-  "Reconfigure windows to show Summary buffer."
+  "Reconfigure windows to show summary buffer."
   (interactive)
   (gnus-configure-windows 'article)
   (pop-to-buffer gnus-summary-buffer)
   (gnus-summary-goto-subject gnus-current-article))
 
 (defun gnus-article-describe-briefly ()
-  "Describe Article mode commands briefly."
+  "Describe article mode commands briefly."
   (interactive)
   (message
-   (substitute-command-keys "\\[gnus-article-next-page]:Next page  \\[gnus-article-prev-page]:Prev page  \\[gnus-article-show-summary]:Show Summary  \\[gnus-info-find-node]:Run Info  \\[gnus-article-describe-briefly]:This help")))
+   (substitute-command-keys "\\<gnus-article-mode-map>\\[gnus-article-next-page]:Next page  \\[gnus-article-prev-page]:Prev page  \\[gnus-article-show-summary]:Show summary  \\[gnus-info-find-node]:Run Info  \\[gnus-article-describe-briefly]:This help")))
+
+(defun gnus-article-summary-command ()
+  "Execute the last keystroke in the summary buffer."
+  (interactive)
+  (message "                                                                              ")
+  (let ((obuf (current-buffer))
+       (owin (current-window-configuration)))
+    (switch-to-buffer gnus-summary-buffer 'norecord)
+    (execute-kbd-macro (this-command-keys))
+    (set-buffer obuf)
+    (let ((npoint (point)))
+      (set-window-configuration owin)
+      (set-window-start (get-buffer-window (current-buffer)) (point)))))
 
 ;; caesar-region written by phr@prep.ai.mit.edu  Nov 86
 ;; Modified by tower@prep Nov 86
@@ -7711,7 +8844,7 @@ ROT47 will be performed for Japanese text in any case."
 
 \f
 ;;;
-;;; Gnus KILL-File Mode
+;;; Gnus Score File Mode
 ;;;
 
 (if gnus-kill-file-mode-map
@@ -7719,7 +8852,7 @@ ROT47 will be performed for Japanese text in any case."
   (setq gnus-kill-file-mode-map (copy-keymap emacs-lisp-mode-map))
   (define-key gnus-kill-file-mode-map "\C-c\C-x"
     'gnus-kill-file-set-expunge-below)
-  (define-key gnus-kill-file-mode-map "\C-c\C-m"
+  (define-key gnus-kill-file-mode-map "\C-c@"
     'gnus-kill-file-set-mark-below)
   (define-key gnus-kill-file-mode-map "\C-c\C-k\C-s"
     'gnus-kill-file-temporarily-lower-by-subject)
@@ -7759,9 +8892,9 @@ ROT47 will be performed for Japanese text in any case."
   (define-key gnus-kill-file-mode-map "\C-c\C-i" 'gnus-info-find-node))
 
 (defun gnus-kill-file-mode ()
-  "Major mode for editing KILL file.
+  "Major mode for editing score files.
 
-In addition to Emacs-Lisp Mode, the following commands are available:
+In addition to Emacs-Lisp mode, the following commands are available:
 
 \\[gnus-kill-file-set-expunge-below]   Automatically expunge articles below LEVEL.
 \\[gnus-kill-file-set-mark-below]      Automatically mark articles below LEVEL.
@@ -7782,37 +8915,37 @@ In addition to Emacs-Lisp Mode, the following commands are available:
 \\[gnus-kill-file-raise-by-xref]               Insert permanent raise command for current cross-posting.
 \\[gnus-kill-file-apply-buffer]        Apply current buffer to selected newsgroup.
 \\[gnus-kill-file-apply-last-sexp]     Apply sexp before point to selected newsgroup.
-\\[gnus-kill-file-exit]        Save file and exit editing KILL file.
-\\[gnus-info-find-node]        Read Info about KILL file.
+\\[gnus-kill-file-exit]        Save file and exit editing score file.
+\\[gnus-info-find-node]        Read Info about score files.
 
-  A KILL file contains Lisp expressions to be applied to a selected
+  A score file contains Lisp expressions to be applied to a selected
 newsgroup.  The purpose is to mark articles as read on the basis of
-some set of regexps.  A global KILL file is applied to every newsgroup,
-and a local KILL file is applied to a specified newsgroup.  Since a
-global KILL file is applied to every newsgroup, for better performance
-use a local one.
+some set of regexps.  A global score file is applied to every
+newsgroup, and a local score file is applied to a specified newsgroup.
+Since a global score file is applied to every newsgroup, for better
+performance use a local one.
 
-  A KILL file can contain any kind of Emacs Lisp expressions expected
-to be evaluated in the Summary buffer.  Writing Lisp programs for this
+  A score file can contain any kind of Emacs Lisp expressions expected
+to be evaluated in the summary buffer.  Writing Lisp programs for this
 purpose is not so easy because the internal working of Gnus must be
 well-known.  For this reason, Gnus provides a general function which
 does this easily for non-Lisp programmers.
 
-  The `gnus-kill' function executes commands available in Summary Mode
+  The `gnus-kill' function executes commands available in summary mode
 by their key sequences. `gnus-kill' should be called with FIELD,
 REGEXP and optional COMMAND and ALL.  FIELD is a string representing
 the header field or an empty string.  If FIELD is an empty string, the
 entire article body is searched for.  REGEXP is a string which is
 compared with FIELD value. COMMAND is a string representing a valid
-key sequence in Summary mode or Lisp expression. COMMAND defaults to
+key sequence in summary mode or Lisp expression. COMMAND defaults to
 '(gnus-summary-mark-as-read nil \"X\").  Make sure that COMMAND is
-executed in the Summary buffer.  If the second optional argument ALL
+executed in the summary buffer.  If the second optional argument ALL
 is non-nil, the COMMAND is applied to articles which are already
 marked as read or unread.  Articles which are marked are skipped over
 by default.
 
   For example, if you want to mark articles of which subjects contain
-the string `AI' as read, a possible KILL file may look like:
+the string `AI' as read, a possible score file may look like:
 
        (gnus-kill \"Subject\" \"AI\")
 
@@ -7822,16 +8955,16 @@ the following expression:
        (gnus-kill \"Subject\" \"AI\" \"d\")
 
 In this example it is assumed that the command
-`gnus-summary-mark-as-read-forward' is assigned to `d' in Summary Mode.
+`gnus-summary-mark-as-read-forward' is assigned to `d' in summary mode.
 
-  It is possible to delete unnecessary headers which are marked with
-`X' in a KILL file as follows:
+  It is possible to remove unnecessary headers which are marked with
+`X' in a score file as follows:
 
        (gnus-expunge \"X\")
 
-  If the Summary buffer is empty after applying KILL files, Gnus will
+  If the summary buffer is empty after applying score files, Gnus will
 exit the selected newsgroup normally.  If headers which are marked
-with `D' are deleted in a KILL file, it is impossible to read articles
+with `D' are deleted in a score file, it is impossible to read articles
 which are marked as read in the previous Gnus sessions.  Marks other
 than `D' should be used for articles which should really be deleted.
 
@@ -7842,13 +8975,13 @@ gnus-kill-file-mode-hook with no arguments, if that value is non-nil."
   (use-local-map gnus-kill-file-mode-map)
   (set-syntax-table emacs-lisp-mode-syntax-table)
   (setq major-mode 'gnus-kill-file-mode)
-  (setq mode-name "KILL-File")
+  (setq mode-name "score-file")
   (lisp-mode-variables nil)
   (run-hooks 'emacs-lisp-mode-hook 'gnus-kill-file-mode-hook))
 
 (defun gnus-kill-file-edit-file (newsgroup)
-  "Begin editing a KILL file of NEWSGROUP.
-If NEWSGROUP is nil, the global KILL file is selected."
+  "Begin editing a score file for NEWSGROUP.
+If NEWSGROUP is nil, the global score file is selected."
   (interactive "sNewsgroup: ")
   (let ((file (gnus-newsgroup-kill-file newsgroup)))
     (gnus-make-directory (file-name-directory file))
@@ -7863,9 +8996,10 @@ If NEWSGROUP is nil, the global KILL file is selected."
            ((eq major-mode 'gnus-group-mode)
             (gnus-configure-windows '(1 0 0)) ;Take all windows.
             (pop-to-buffer gnus-group-buffer)
+            ;; Fix by sachs@SLINKY.CS.NYU.EDU (Jay Sachs).
             (let ((gnus-summary-buffer buffer))
-              (gnus-configure-windows '(1 1 0)) ;Split into two.
-              (pop-to-buffer buffer)))
+              (gnus-configure-windows '(1 1 0))) ;Split into two.
+            (pop-to-buffer buffer))
            ((eq major-mode 'gnus-summary-mode)
             (gnus-configure-windows 'article)
             (pop-to-buffer gnus-article-buffer)
@@ -7877,12 +9011,13 @@ If NEWSGROUP is nil, the global KILL file is selected."
     (gnus-kill-file-mode)
     ))
 
+;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
 (defun gnus-kill-set-kill-buffer ()
-  (let ((file (gnus-newsgroup-kill-file gnus-newsgroup-name)))
-    (if (get-file-buffer file)
-       (set-buffer (get-file-buffer file))
-      (set-buffer (find-file-noselect file))
-      (bury-buffer))))
+  (let* ((file (gnus-newsgroup-kill-file gnus-newsgroup-name))
+        (buffer (find-file-noselect file)))
+    (set-buffer buffer)
+    (gnus-kill-file-mode)
+    (bury-buffer buffer)))
 
 (defun gnus-kill-save-kill-buffer ()
   (save-excursion
@@ -7890,8 +9025,7 @@ If NEWSGROUP is nil, the global KILL file is selected."
       (if (get-file-buffer file)
          (progn
            (set-buffer (get-file-buffer file))
-           (if (buffer-modified-p)
-               (save-buffer))
+           (and (buffer-modified-p) (save-buffer))
            (kill-buffer (current-buffer)))))))
 
 (defun gnus-article-fetch-field (field)
@@ -7906,35 +9040,36 @@ If NEWSGROUP is nil, the global KILL file is selected."
       (prog1
          (mail-fetch-field field)
        (widen)))))
-
- (defun gnus-kill-file-enter-kill (field regexp level date edit)
-   ;; Enter kill file entry.
-   ;; FIELD: String containing the name of the header field to kill.
-   ;; REGEXP: The string to kill.
-   ;; LEVEL: How much to raise the score by.
-   ;; DATE: A date string for expire kill or nil for permanent kills.
-   ;; EDIT: Allow the user to edit REGEXP iff non-nil.
-    (save-excursion
-      (gnus-kill-set-kill-buffer)
-      (goto-char (point-min))
-     (let ((regexp (if edit
-                     (read-string (concat "Add " level " to articles with "
-                                          (downcase field) " matching: ")
-                                  (cons regexp 1))
-                   regexp)) 
+
+(defun gnus-kill-file-enter-kill (field regexp level date edit)
+  ;; Enter score file entry.
+  ;; FIELD: String containing the name of the header field to score.
+  ;; REGEXP: The string to score.
+  ;; LEVEL: How much to raise the score by.
+  ;; DATE: A date string for expire score or nil for permanent kills.
+  ;; EDIT: Allow the user to edit REGEXP iff non-nil.
+  (save-excursion
+    (gnus-kill-set-kill-buffer)
+    (goto-char (point-min))
+    (let ((regexp 
+          (if edit (read-string 
+                    (format "Add %d to articles with %s matching: " 
+                            level (downcase field))
+                    regexp)
+            regexp))
          entry string kill beg)
-       (setq entry (if date (cons regexp date) regexp)
+      (setq entry (if date (cons regexp date) regexp)
            string (format "(gnus-raise %S (quote %S) %S)\n"
                           field entry level))
-       (while (and (setq beg (point))
+      (while (and (setq beg (point))
                  (condition-case nil
                      (setq kill (read (current-buffer)))
                    (error nil))
                  (or (not (eq (nth 0 kill) 'gnus-raise))
                      (not (string= (downcase (nth 1 kill)) (downcase field)))
                      (not (eq (nth 3 kill) level))))
-        (setq kill nil))
-        (if (not kill)
+       (setq kill nil))
+      (if (not kill)
          (progn
            (goto-char (point-min))
            (insert string))
@@ -7948,52 +9083,61 @@ If NEWSGROUP is nil, the global KILL file is selected."
             (list 'quote (list entry list)))))
        (delete-region beg (point))
        (insert (gnus-pp-gnus-kill kill)))
-       (gnus-kill-file-apply-string string))
-      ;; Added by by Sudish Joseph <joseph@cis.ohio-state.edu>.
-     (or edit 
+      (gnus-kill-file-apply-string string))
+    ;; Added by Sudish Joseph <joseph@cis.ohio-state.edu>.
+    (or edit 
        (message "Added kill file entry %s: %s" (downcase field) regexp))))
     
- (defun gnus-kill-file-set-variable (symbol value)
-   ;; Set SYMBOL to VALUE in the kill file.
-    (save-excursion
-      (gnus-kill-set-kill-buffer)
-      (goto-char (point-min))
+(defun gnus-kill-file-set-variable (symbol value)
+   ;; Set SYMBOL to VALUE in the score file.
+   (save-excursion
+     (gnus-kill-set-kill-buffer)
+     (goto-char (point-min))
      (let ((string (format "(setq %S %S)\n" symbol value))
-         kill beg)
+          kill beg)
        (while (and (setq beg (point))
-                 (condition-case nil
-                     (setq kill (read (current-buffer)))
-                   (error nil))
-                 (or (not (eq (nth 0 kill) 'setq))
-                     (not (eq (nth 1 kill) symbol))))
-       (setq kill nil))
-        (if (not kill)
-         (progn
-           (goto-char (point-min))
-           (insert string))
-       (delete-region beg (point))
-       (insert string)))))
+                  (condition-case nil
+                      (setq kill (read (current-buffer)))
+                    (error nil))
+                  (or (not (eq (nth 0 kill) 'setq))
+                      (not (eq (nth 1 kill) symbol))))
+        (setq kill nil))
+       (if (not kill)
+          (progn
+            (goto-char (point-min))
+            (insert string))
+        (delete-region beg (point))
+        (insert string)))))
     
- (defun gnus-kill-file-set-expunge-below (level)
+(defun gnus-kill-file-set-expunge-below (level)
    "Automatically expunge articles with score below LEVEL."
    (interactive "P")
    (setq level (if level
                  (prefix-numeric-value level)
-               gnus-summary-default-interest))
-   (gnus-kill-file-set-variable 'expunge-below level)
+               gnus-summary-default-score))
+   (if (eq major-mode 'gnus-summary-mode)
+       (progn
+        (gnus-score-set 'expunge level)
+        (gnus-score-set 'touched t))
+     (gnus-kill-file-set-variable 'expunge-below level))
    (message "Set expunge below level to %d." level))
-  
+
  (defun gnus-kill-file-set-mark-below (level)
-   "Automatically mark articles with score below LEVEL as killed."
+   "Automatically mark articles with score below LEVEL as read."
    (interactive "P")
    (setq level (if level
-                 (prefix-numeric-value level)
-               gnus-summary-default-interest))
-   (gnus-kill-file-set-variable 'mark-below level)
+                  (prefix-numeric-value level)
+                gnus-summary-default-score))
+   (if (eq major-mode 'gnus-summary-mode)
+       (progn
+        (gnus-score-set 'mark level)
+        (gnus-score-set 'touched t)
+        (gnus-summary-set-mark-below level))
+     (gnus-kill-file-set-variable 'mark-below level))
    (message "Set mark below level to %d." level))
  
  (defun gnus-kill-file-temporarily-raise-by-subject (level &optional header)
-     "Temporarily raise score by LEVEL for current subject.
+   "Temporarily raise score by LEVEL for current subject.
  See `gnus-kill-expiry-days'."
    (interactive "p")
    (gnus-kill-file-raise-by-subject level header (current-time-string)))
@@ -8016,14 +9160,14 @@ If NEWSGROUP is nil, the global KILL file is selected."
     nil))
   
  (defun gnus-kill-file-temporarily-raise-by-xref (level &optional header)
-   "Insert temporary KILL commands for articles that have been crossposted.
+   "Insert temporary score commands for articles that have been crossposted.
  By default use the current crossposted groups.
  See `gnus-kill-expiry-days'."
    (interactive "p")
    (gnus-kill-file-raise-by-xref level header (current-time-string)))
   
  (defun gnus-kill-file-raise-by-subject (level &optional header date)
-     "Raise score by LEVEL for current subject."
+   "Raise score by LEVEL for current subject."
    (interactive "p")
    (gnus-kill-file-enter-kill
     "Subject"
@@ -8048,22 +9192,22 @@ If NEWSGROUP is nil, the global KILL file is selected."
    "Raise score by LEVEL for articles that have been crossposted.
  By default use the current crossposted groups."
    (interactive "p")
-    (let ((xref (header-xref (or header gnus-current-headers)))
-       (start 0)
-       group)
-    (if xref
-       (while (string-match " \\([^ \t]+\\):" xref start)
-         (setq start (match-end 0))
-         (if (not (string= 
-                   (setq group 
-                         (substring xref (match-beginning 1) (match-end 1)))
-                   gnus-newsgroup-name))
-             (gnus-kill-file-enter-kill 
-              "Xref"
-              (concat " " (regexp-quote group) ":")
-              level
-              date
-              t))))))
+   (let ((xref (header-xref (or header gnus-current-headers)))
+        (start 0)
+        group)
+     (if xref
+        (while (string-match " \\([^ \t]+\\):" xref start)
+          (setq start (match-end 0))
+          (if (not (string= 
+                    (setq group 
+                          (substring xref (match-beginning 1) (match-end 1)))
+                    gnus-newsgroup-name))
+              (gnus-kill-file-enter-kill 
+               "Xref"
+               (concat " " (regexp-quote group) ":")
+               level
+               date
+               t))))))
 
 (defun gnus-kill-file-raise-followups-to-author
   (level &optional header)
@@ -8082,10 +9226,10 @@ If NEWSGROUP is nil, the global KILL file is selected."
                    "From" name level))
       (insert string)
       (gnus-kill-file-apply-string string))
-    (message "Added permanent kill file entry for followups to %s." name)))
+    (message "Added permanent score file entry for followups to %s." name)))
 
 (defun gnus-kill-file-temporarily-lower-by-subject (level &optional header)
-    "Temporarily lower score by LEVEL for current subject.
+  "Temporarily lower score by LEVEL for current subject.
 See `gnus-kill-expiry-days'."
   (interactive "p")
   (gnus-kill-file-lower-by-subject level header (current-time-string)))
@@ -8103,7 +9247,7 @@ See `gnus-kill-expiry-days'."
   (gnus-kill-file-temporarily-raise-by-thread (- level) header))
 
 (defun gnus-kill-file-temporarily-lower-by-xref (level &optional header)
-  "Insert temporary KILL commands for articles that have been crossposted.
+  "Insert temporary score commands for articles that have been crossposted.
 By default use the current crossposted groups.
 See `gnus-kill-expiry-days'."
   (interactive "p")
@@ -8164,11 +9308,11 @@ By default use the current crossposted groups."
     (ding) (message "No newsgroup is selected.")))
 
 (defun gnus-kill-file-exit ()
-  "Save a KILL file, then return to the previous buffer."
+  "Save a score file, then return to the previous buffer."
   (interactive)
   (save-buffer)
   (let ((killbuf (current-buffer)))
-    ;; We don't want to return to Article buffer.
+    ;; We don't want to return to article buffer.
     (and (get-buffer gnus-article-buffer)
         (bury-buffer gnus-article-buffer))
     ;; Delete the KILL file windows.
@@ -8182,59 +9326,60 @@ By default use the current crossposted groups."
 
 ;; Basic ideas by emv@math.lsa.umich.edu (Edward Vielmetti)
 
-(defun gnus-batch-kill ()
-  "Run batched KILL.
-Usage: emacs -batch -l gnus -f gnus-batch-kill NEWSGROUP ..."
-  (if (not noninteractive)
-      (error "gnus-batch-kill is to be used only with -batch"))
-  (let* ((group nil)
-        (subscribed nil)
-        (newsrc nil)
-        (yes-and-no
+(defalias 'gnus-batch-kill 'gnus-batch-score)
+;;;###autoload
+(defun gnus-batch-score ()
+  "Run batched scoring.
+Usage: emacs -batch -l gnus -f gnus-batch-kill <newsgroups> ...
+Newsgroups is a list of strings on the .newsrc options -n format. 
+If you want to score the comp hierarchy, you'd say \"comp.all\". If
+you would not like to score the alt hierarchy, you'd say
+\"!alt.all\"."
+  (interactive)
+;  (or noninteractive
+;      (error "gnus-batch-kill is to be used only with -batch"))
+  (let* ((yes-and-no
          (gnus-parse-n-options
           (apply (function concat)
                  (mapcar (lambda (g) (concat g " "))
                          command-line-args-left))))
         (yes (car yes-and-no))
-        (no  (cdr yes-and-no))
+        (no (cdr yes-and-no))
+        group subscribed newsrc entry
         ;; Disable verbose message.
-        (gnus-novice-user nil)
-        (gnus-large-newsgroup nil))
+        gnus-novice-user gnus-large-newsgroup)
     ;; Eat all arguments.
     (setq command-line-args-left nil)
-    ;; Startup Gnus.
+    ;; Start Gnus.
     (gnus)
     ;; Apply kills to specified newsgroups in command line arguments.
-    (setq newsrc (copy-sequence gnus-newsrc-assoc))
+    (setq newsrc gnus-newsrc-assoc)
     (while newsrc
       (setq group (car (car newsrc)))
-      (setq subscribed (nth 1 (car newsrc)))
-      (setq newsrc (cdr newsrc))
-      (if (and subscribed
-              (not (zerop (car (gnus-gethash group gnus-newsrc-hashtb))))
-              (if yes
-                  (string-match yes group) t)
-              (or (null no)
-                  (not (string-match no group))))
+      (setq entry (gnus-gethash group gnus-newsrc-hashtb))
+      (if (and (<= (nth 1 (car newsrc)) 5)
+              (and (car entry)
+                   (or (eq (car entry) t)
+                       (not (zerop (car entry)))))
+              (if yes (string-match yes group) t)
+              (or (null no) (not (string-match no group))))
          (progn
            (gnus-summary-read-group group nil t)
-           (if (eq (current-buffer) (get-buffer gnus-summary-buffer))
-               (gnus-summary-exit t))
-           ))
-      )
-    ;; Finally, exit Emacs.
+           (and (eq (current-buffer) (get-buffer gnus-summary-buffer))
+                (gnus-summary-exit))))
+      (setq newsrc (cdr newsrc)))
+    ;; Exit Emacs.
     (set-buffer gnus-group-buffer)
-    (gnus-group-exit)
-    ))
+    (gnus-group-exit)))
 
-;; For KILL files
+;; For score files
 
 (defun gnus-Newsgroup-kill-file (newsgroup)
-  "Return the name of a KILL file of NEWSGROUP.
-If NEWSGROUP is nil, return the global KILL file instead."
+  "Return the name of a score file for NEWSGROUP.
+If NEWSGROUP is nil, return the global score file instead."
   (cond ((or (null newsgroup)
             (string-equal newsgroup ""))
-        ;; The global KILL file is placed at top of the directory.
+        ;; The global score file is placed at top of the directory.
         (expand-file-name gnus-kill-file-name
                           (or gnus-kill-files-directory "~/News")))
        (gnus-use-long-file-name
@@ -8250,8 +9395,8 @@ If NEWSGROUP is nil, return the global KILL file instead."
        ))
 
 (defun gnus-newsgroup-kill-file (newsgroup)
-  "Return the name of a KILL file of NEWSGROUP.
-If NEWSGROUP is nil, return the global KILL file instead."
+  "Return the name of a score file name for NEWSGROUP.
+If NEWSGROUP is nil, return the global score file name instead."
   (cond ((or (null newsgroup)
             (string-equal newsgroup ""))
         ;; The global KILL file is placed at top of the directory.
@@ -8269,43 +9414,74 @@ If NEWSGROUP is nil, return the global KILL file instead."
        ))
 
 
-(defalias 'gnus-expunge 'gnus-summary-delete-marked-with)
+(defalias 'gnus-expunge 'gnus-summary-remove-lines-marked-with)
 
 (defun gnus-apply-kill-file ()
-  "Apply KILL file to the current newsgroup.
-Returns the number of articles killed."
-  (let ((kill-files (list (gnus-newsgroup-kill-file nil)
-                         (gnus-newsgroup-kill-file gnus-newsgroup-name)))
-       (unreads (length gnus-newsgroup-unreads))
-       (mark-below gnus-summary-default-interest)
-       (gnus-summary-inhibit-highlight t)
-       (expunge-below nil)
-       form beg)
-    (save-excursion
-      (while kill-files
-       (if (file-exists-p (car kill-files))
-           (progn
-             (find-file (car kill-files))
-             (goto-char (point-min))
-             (while (progn
-                      (setq beg (point))
-                      (setq form (condition-case nil 
-                                     (read (current-buffer)) (error nil))))
-               (if (eq (car form) 'gnus-kill)
-                   (progn
-                     (delete-region beg (point))
-                     (insert (or (eval form) "")))
-                 (eval form)))
-             (save-buffer)))
-       (setq kill-files (cdr kill-files))))
+  "Apply a score file to the current newsgroup.
+Returns the number of articles marked as read."
+  (let* ((kill-files (list (gnus-newsgroup-kill-file nil)
+                          (gnus-newsgroup-kill-file gnus-newsgroup-name)))
+        (unreads (length gnus-newsgroup-unreads))
+        (gnus-summary-inhibit-highlight t)
+        (mark-below (or gnus-summary-mark-below gnus-summary-default-score))
+        (expunge-below gnus-summary-expunge-below)
+        form beg)
+    (setq gnus-newsgroup-kill-headers nil)
+    (or gnus-newsgroup-headers-hashtb-by-number
+       (gnus-make-headers-hashtable-by-number))
+    ;; If there are any previously scored articles, we remove these
+    ;; from the `gnus-newsgroup-headers' list that the score functions
+    ;; will see. This is probably pretty wasteful when it comes to
+    ;; conses, but is, I think, faster than having to assq in every
+    ;; single score funtion.
+    (let ((files kill-files))
+      (while files
+       (if (file-exists-p (car files))
+           (let ((headers gnus-newsgroup-headers))
+             (if gnus-kill-killed
+                 (setq gnus-newsgroup-kill-headers
+                       (mapcar (lambda (header) (header-number header))
+                               headers))
+               (while headers
+                 (or (gnus-member-of-range 
+                      (header-number (car headers)) 
+                      gnus-newsgroup-killed)
+                     (setq gnus-newsgroup-kill-headers 
+                           (cons (header-number (car headers))
+                                 gnus-newsgroup-kill-headers)))
+                 (setq headers (cdr headers))))
+             (setq files nil))
+         (setq files (cdr files)))))
+    (if gnus-newsgroup-kill-headers
+       (save-excursion
+         (while kill-files
+           (if (file-exists-p (car kill-files))
+               (progn
+                 (message "Processing kill file %s..." (car kill-files))
+                 (find-file (car kill-files))
+                 (goto-char (point-min))
+                 (while (progn
+                          (setq beg (point))
+                          (setq form (condition-case nil 
+                                         (read (current-buffer)) 
+                                       (error nil))))
+                   (if (or (eq (car form) 'gnus-kill)
+                           (eq (car form) 'gnus-raise)
+                           (eq (car form) 'gnus-lower))
+                       (progn
+                         (delete-region beg (point))
+                         (insert (or (eval form) "")))
+                     (eval form)))
+                 (and (buffer-modified-p) (save-buffer))
+                 (message "Processing kill file %s...done" (car kill-files))))
+           (setq kill-files (cdr kill-files)))))
     (if expunge-below (gnus-summary-expunge-below expunge-below))
-    (if mark-below (gnus-summary-mark-below mark-below ?X) )
     (let (gnus-summary-inhibit-highlight)
-      (gnus-summary-update-lines))
+      (gnus-summary-set-mark-below mark-below))
     (if beg
        (let ((nunreads (- unreads (length gnus-newsgroup-unreads))))
          (or (eq nunreads 0)
-             (message "Killed %d articles" nunreads))
+             (message "Marked %d articles as read" nunreads))
          nunreads)
       0)))
 
@@ -8321,7 +9497,7 @@ COMMAND must be a lisp expression or a string representing a key sequence."
   ;; We don't want to change current point nor window configuration.
   (save-excursion
     (save-window-excursion
-      ;; Selected window must be Summary buffer to execute keyboard
+      ;; Selected window must be summary buffer to execute keyboard
       ;; macros correctly. See command_loop_1.
       (switch-to-buffer gnus-summary-buffer 'norecord)
       (goto-char (point-min))          ;From the beginning.
@@ -8334,9 +9510,9 @@ COMMAND must be a lisp expression or a string representing a key sequence."
            ;; It is a list.
            (if (not (consp (cdr kill-list)))
                ;; It's on the form (regexp . date).
-               (if (= 0 (gnus-execute field (car kill-list) 
-                                      command nil (not all)))
-                   (if (> (gnus-days-between (cdr kill-list) date)
+               (if (zerop (gnus-execute field (car kill-list) 
+                                        command nil (not all)))
+                   (if (> (gnus-days-between date (cdr kill-list))
                           gnus-kill-expiry-days)
                        (setq regexp nil))
                  (setcdr kill-list date))
@@ -8345,9 +9521,9 @@ COMMAND must be a lisp expression or a string representing a key sequence."
                    ;; It's a temporary kill.
                    (progn
                      (setq kdate (cdr kill))
-                     (if (= 0 (gnus-execute field (car kill) command 
-                                            nil (not all)))
-                         (if (> (gnus-days-between kdate date)
+                     (if (zerop (gnus-execute 
+                                 field (car kill) command nil (not all)))
+                         (if (> (gnus-days-between date kdate)
                                 gnus-kill-expiry-days)
                              ;; Time limit has been exceeded, so we
                              ;; remove the match.
@@ -8379,83 +9555,35 @@ COMMAND must be a lisp expression or a string representing a key sequence."
       (set-buffer (get-buffer-create "*Gnus PP*"))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (insert (format "\n(gnus-kill %S\n  '(" (nth 1 object)))
+      (insert (format "\n(%S %S\n  '(" (nth 0 object) (nth 1 object)))
       (let ((klist (car (cdr (nth 2 object))))
            (first t))
        (while klist
-         (insert (if first (progn (setq first nil) "")  "\n   ")
+         (insert (if first (progn (setq first nil) "")  "\n    ")
                  (prin1-to-string (car klist)))
          (setq klist (cdr klist))))
       (insert ")")
-      (if (nth 3 object)
-         (insert "\n  '" (prin1-to-string (nth 3 object))))
-      (if (nth 4 object)
-         (insert "\n  t"))
+      (and (nth 3 object)
+          (insert "\n  " 
+                  (if (and (consp (nth 3 object))
+                           (not (eq 'quote (car (nth 3 object))))) 
+                      "'" "")
+                  (prin1-to-string (nth 3 object))))
+      (and (nth 4 object)
+          (insert "\n  t"))
       (insert ")")
       (prog1
          (buffer-substring (point-min) (point-max))
        (kill-buffer (current-buffer))))))
 
-(defun gnus-days-between (date1 date2)
-  ;; Return the number of days between date1 and date2.
-  (let ((d1 (mapcar (lambda (s) (and s (string-to-int s)) )
-                   (timezone-parse-date date1)))
-       (d2 (mapcar (lambda (s) (and s (string-to-int s)) )
-                   (timezone-parse-date date2))))
-    (- (timezone-absolute-from-gregorian 
-       (nth 1 d1) (nth 2 d1) (car d1))
-       (timezone-absolute-from-gregorian 
-       (nth 1 d2) (nth 2 d2) (car d2)))))
-
-(defun gnus-execute (field regexp form &optional backward ignore-marked)
-  "If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
-If FIELD is an empty string (or nil), entire article body is searched for.
-If optional 1st argument BACKWARD is non-nil, do backward instead.
-If optional 2nd argument IGNORE-MARKED is non-nil, articles which are
-marked as read or ticked are ignored."
-  (save-excursion
-    (let ((killed-no 0)
-         function header article)
-      (if (or (null field) (string-equal field ""))
-         (setq field nil)
-       ;; Get access function of header filed.
-       (setq function (intern-soft (concat "gnus-header-" (downcase field))))
-       (if (and function (fboundp function))
-           (setq function (symbol-function function))
-         (error "Unknown header field: \"%s\"" field))
-       ;; The function is a macro, so we have to check whether is has
-       ;; been compiled or not, and make a real function out of it. 
-       ;;      (if (consp (cdr function))
-       ;;        (setq function (nth 3 function))
-       ;;      (setq function (list 'byte-code (aref function 1) (aref function 2)
-       ;;                           (aref function 3)))))
-       ;; Make FORM funcallable.
-       (if (and (listp form) (not (eq (car form) 'lambda)))
-           (setq form (list 'lambda nil form)))
-       ;; Starting from the current article.
-       (while (or (not article) ; Do the first line.
-                  (gnus-summary-search-subject backward ignore-marked))
-         (setq article (gnus-summary-article-number))
-         (or (gnus-member-of-range article gnus-newsgroup-killed)
-             (and ignore-marked
-                  ;; Articles marked as read, ticked and dormant
-                  ;; should be ignored. 
-                  (or (not (memq article gnus-newsgroup-unreads))
-                      (memq article gnus-newsgroup-marked)
-                      (memq article gnus-newsgroup-dormant)))
-             (gnus-execute-1 function regexp form article) 
-             (setq killed-no (1+ killed-no)))))
-      killed-no)))
-
-(defun gnus-execute-1 (function regexp form article)
+(defun gnus-execute-1 (function regexp form header)
   (save-excursion
     (let (did-kill)
-      (if (null article)
+      (if (null header)
          nil                           ;Nothing to do.
        (if function
            ;; Compare with header field.
-           (let ((header (gnus-get-header-by-number article))
-                 value)
+           (let (value)
              (and header
                   (progn
                     (setq value (funcall function header))
@@ -8471,9 +9599,9 @@ marked as read or ticked are ignored."
                (gnus-last-article nil)
                (gnus-break-pages nil)  ;No need to break pages.
                (gnus-mark-article-hook nil)) ;Inhibit marking as read.
-           (message "Searching for article: %d..." article)
+           (message "Searching for article: %d..." (header-number header))
            (gnus-article-setup-buffer)
-           (gnus-article-prepare article t)
+           (gnus-article-prepare (header-number header) t)
            (if (save-excursion
                  (set-buffer gnus-article-buffer)
                  (goto-char (point-min))
@@ -8483,8 +9611,417 @@ marked as read or ticked are ignored."
                  (funcall form))))))
       did-kill)))
 
+(defun gnus-execute (field regexp form &optional backward ignore-marked)
+  "If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
+If FIELD is an empty string (or nil), entire article body is searched for.
+If optional 1st argument BACKWARD is non-nil, do backward instead.
+If optional 2nd argument IGNORE-MARKED is non-nil, articles which are
+marked as read or ticked are ignored."
+  (save-excursion
+    (let ((killed-no 0)
+         function header article)
+      (if (or (null field) (string-equal field ""))
+         (setq field nil)
+       ;; Get access function of header filed.
+       (setq function (intern-soft (concat "gnus-header-" (downcase field))))
+       (if (and function (fboundp function))
+           (setq function (symbol-function function))
+         (error "Unknown header field: \"%s\"" field))
+       ;; Make FORM funcallable.
+       (if (and (listp form) (not (eq (car form) 'lambda)))
+           (setq form (list 'lambda nil form)))
+       ;; Starting from the current article.
+       (while (or (and (not article)
+                       (setq article (gnus-summary-article-number))
+                       t)
+                  (setq article 
+                        (gnus-summary-search-subject 
+                         backward (not ignore-marked))))
+         (and (memq article gnus-newsgroup-kill-headers)
+              (gnus-execute-1 function regexp form 
+                              (gnus-get-header-by-number article))
+              (setq killed-no (1+ killed-no)))))
+      killed-no)))
+
+\f
+;;; Gnus Score File
+
+;; All score code written by Per Abrahamsen <abraham@iesd.auc.dk>.
+
+(defun gnus-score-set (symbol value &optional alist)
+  ;; Set SYMBOL to VALUE in ALIST.
+  (let* ((alist (or alist gnus-score-alist
+                   (progn
+                     (gnus-score-load gnus-newsgroup-name)
+                     gnus-score-alist)))
+        (entry (assoc symbol alist)))
+    (cond (entry
+          (setcdr entry value))
+         ((null alist)
+          (error "Empty alist"))
+         (t
+          (setcdr alist (cons (cons symbol value) (cdr alist)))))))
+
+(defun gnus-score-get (symbol &optional alist)
+  ;; Get SYMBOL's definition in ALIST.
+  (cdr (assoc symbol (or alist gnus-score-alist
+                        (progn
+                          (gnus-score-load gnus-newsgroup-name)
+                          gnus-score-alist)))))
+
+(defun gnus-score-edit-file (group)
+  "Edit score file for GROUP."
+  (interactive (list (read-string "Edit SCORE file for: "
+                                 (cons (or gnus-newsgroup-name "") 1))))
+  (and (get-buffer gnus-summary-buffer) (gnus-score-save))
+  (find-file (gnus-score-file-name group))
+  (emacs-lisp-mode))
+
+(defun gnus-score-load-file (file)
+  ;; Load score file FILE.
+  (let ((cache (assoc file gnus-score-cache)))
+    (if cache
+       (setq gnus-score-alist (cdr cache))
+      (setq gnus-score-alist nil)
+      (load file t nil t)
+      (or gnus-score-alist
+         (setq gnus-score-alist (copy-alist '((touched . nil)))))
+      (setq gnus-score-cache
+           (cons (cons file gnus-score-alist) gnus-score-cache))))
+  (let ((mark (gnus-score-get 'mark))
+       (expunge (gnus-score-get 'expunge))
+       (files (gnus-score-get 'files))
+       (eval (gnus-score-get 'eval)))
+    (if files (mapcar (lambda (file) (gnus-score-load-file file)) files))
+    (if eval (eval eval))
+    (if mark (setq gnus-summary-mark-below mark))
+    (if expunge (setq gnus-summary-expunge-below expunge))))
+
+(defun gnus-score-load (group)
+  ;; Load score file for GROUP.
+  ;; If optional argument NO-RECURSE is set, the files and eval
+  ;; members will be ignored.
+  ;; Updates free variables `gnus-score-alist' and `scores'.
+
+  (let ((cache (assoc group gnus-score-cache)))
+    (if cache
+       (setq gnus-score-alist (cdr cache))
+      (setq gnus-score-alist nil)
+      (load (gnus-score-file-name group) t nil t)
+      (or gnus-score-alist
+         (setq gnus-score-alist (copy-alist '((touched . nil)))))
+      (setq gnus-score-cache
+           (cons (cons (gnus-score-file-name group)
+                       gnus-score-alist) gnus-score-cache))))
+  (let ((mark (gnus-score-get 'mark))
+       (expunge (gnus-score-get 'expunge))
+       (files (gnus-score-get 'files))
+       (eval (gnus-score-get 'eval)))
+    (if eval (eval eval))
+    (if mark (setq gnus-summary-mark-below mark))
+    (if expunge (setq gnus-summary-expunge-below expunge))
+    (if files (mapcar (lambda (file) (gnus-score-load-file file)) files))))
+  
+(defun gnus-score-save ()
+  ;; Save all SCORE information.
+  (let (cache)
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (setq cache gnus-score-cache
+           gnus-score-cache nil))
+    (save-excursion
+      (setq gnus-score-alist nil)
+      (set-buffer (get-buffer-create "*Score*"))
+      (buffer-disable-undo)
+      (let (entry score file)
+       (while cache
+         (setq entry (car cache)
+               cache (cdr cache)
+               file (car entry)
+               score (cdr entry))
+         (if (null (gnus-score-get 'touched score))
+             ()
+           (gnus-score-set 'touched nil score)
+           (erase-buffer)
+           (pp (list 'setq 'gnus-score-alist (list 'quote score))
+               (current-buffer))
+           (make-directory (file-name-directory file) t)
+             (write-region (point-min) (point-max) file nil 'silent))))
+      (kill-buffer (current-buffer)))))
+  
+(defun gnus-score-headers ()
+  ;; Score `gnus-newsgroup-headers'.
+  (let ((score-files (gnus-score-files-for-group gnus-newsgroup-name))
+       scores)
+    ;; Load the SCORE files.
+    (while score-files
+      (gnus-score-load-file (car score-files))
+      (if (< 1 (length gnus-score-alist))
+        (setq scores (cons gnus-score-alist scores)))
+      (setq score-files (cdr score-files)))
+    (if (not (and gnus-summary-default-score
+                 scores
+                 (> (length gnus-newsgroup-headers)
+                    (length gnus-newsgroup-scored))))
+       ()
+      (let* ((entries gnus-header-index)
+            (now (current-time-string))
+            (expire (- (gnus-useful-date now) gnus-kill-expiry-days))
+            (headers gnus-newsgroup-headers)
+            entry articles header)
+       (message "Scoring...")
+       ;; Create articles, an alist of the form `(HEADER . SCORE)'.
+       (while headers
+         (setq header (car headers)
+               headers (cdr headers))
+         ;; WARNING: The assq makes the function O(N*S) while it could
+         ;; be written as O(N+S), where N is (length gnus-newsgroup-headers)
+         ;; and S is (length gnus-newsgroup-scored).
+         (or (assq (header-number header) gnus-newsgroup-scored)
+             (setq articles            ;Total of 2 * N cons-cells used.
+                   (cons (cons header gnus-summary-default-score)
+                         articles))))
+  
+       (save-excursion
+         (set-buffer (get-buffer-create "*Headers*"))
+         (buffer-disable-undo)
+         ;; Run each header through the score process.
+         (while entries
+           (setq entry (car entries)
+                 header (nth 0 entry)
+                 entries (cdr entries))
+           (setq gnus-score-index (nth 1 (assoc header gnus-header-index)))
+           (if (< 0 (apply 'max (mapcar
+                                 (lambda (score)
+                                   (length (gnus-score-get header score)))
+                                 scores)))
+               (progn
+                 ;; Sorting the articles costs os O(N*log N) but will
+                 ;; allow us to only match with each unique header.
+                 ;; Thus the actual matching will be O(M*U) where M
+                 ;; is the number of strings to match with, and U is
+                 ;; the number of unique headers.  It is assumed (but
+                 ;; untested) this will be a net win because of the
+                 ;; large constant factor involved with string
+                 ;; matching.
+                 (message "Scoring...%s sort" header)
+                 (setq articles (sort articles 'gnus-score-compare-articles))
+                 (funcall (nth 2 entry) scores header articles now expire))))
+         ;; Remove the buffer.
+         (kill-buffer (current-buffer)))
+
+       (message "Scoring...")
+       ;; Add articles to `gnus-newsgroup-scored'.
+       (while articles
+         (or (= gnus-summary-default-score (cdr (car articles)))
+             (setq gnus-newsgroup-scored
+                   (cons (cons (header-number (car (car articles)))
+                               (cdr (car articles)))
+                         gnus-newsgroup-scored)))
+         (setq articles (cdr articles)))
+
+       (message "Scoring...done")))))
+
+(defun gnus-score-integer (scores header articles now expire)
+  )
+
+(defun gnus-score-date (scores header articles now expire)
+  )
+
+(defun gnus-score-string (scores header articles now expire)
+  ;; Score ARTICLES according to HEADER in SCORES.
+  ;; Update matches entries to NOW and remove unmatched entried older
+  ;; than EXPIRE.
+  
+  ;; Insert the unique article headers in the buffer.
+  (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
+       ;; gnus-score-index is used as a free variable.
+       alike last this art entries alist)
+
+    (message "Scoring...%s build" header)
+    (erase-buffer)
+    (while articles
+      (setq art (car articles)
+           this (aref (car art) gnus-score-index)
+           articles (cdr articles))
+      (if (equal last this)
+         ;; O(N*H) cons-cells used here, where H is the number of
+         ;; headers.
+         (setq alike (cons art alike))
+       (if last
+           (progn
+             ;; Insert the line, with a text property on the
+             ;; terminating newline refering to the articles with
+             ;; this line.
+             (insert last ?\n)
+             (put-text-property (1- (point)) (point) 'articles alike)))
+       (setq alike (list art)
+             last this)))
+    (and last                          ; Bwadr, duplicate code.
+        (progn
+          (insert last ?\n)                    
+          (put-text-property (1- (point)) (point) 'articles alike)))
+  
+    ;; Find matches.
+    (message "Scoring...%s match" header)
+    (while scores
+      (setq alist (car scores)
+           scores (cdr scores)
+           entries (assoc header alist))
+      (while (cdr entries)             ;First entry is the header index.
+       (let* ((rest (cdr entries))             
+              (kill (car rest))
+              (match (nth 0 kill))
+              (type (nth 1 kill))
+              (score (nth 2 kill))
+              (date (nth 3 kill))
+              (found nil)
+              (case-fold-search t)
+              arts art)
+         (goto-char (point-min))
+         (while (if type
+                    (re-search-forward match nil t)
+                  (search-forward match nil t))
+           (end-of-line 1)
+           (setq found t
+                 arts (get-text-property (point) 'articles))
+           ;; Found a match, update scores.
+           (while arts
+             (setq art (car arts)
+                   arts (cdr arts))
+             (setcdr art (+ score (cdr art)))))
+         ;; Update expire date
+         (cond ((null date))           ;Permanent entry.
+               (found                  ;Match, update date.
+                (gnus-score-set 'touched t alist)
+                (setcar (nthcdr 3 kill) now))
+               ((< (gnus-useful-date date) expire) ;Old entry, remove.
+                (gnus-score-set 'touched t alist)
+                (setcdr entries (cdr rest))
+                (setq rest entries)))
+         (setq entries rest))))))
+
+(defun gnus-score-compare-articles (a1 a2)
+  ;; Compare headers in articles A2 and A2.
+  ;; The header index used is the free variable `gnus-score-index'.
+  (string-lessp (aref (car a1) gnus-score-index)
+               (aref (car a2) gnus-score-index)))
+
+(defun gnus-useful-date (date)
+  ;; Return the numeric day corresponding to the DATE string.
+  (let ((d (mapcar (lambda (s) (and s (string-to-int s)) )
+                  (timezone-parse-date date))))
+    (timezone-absolute-from-gregorian (nth 1 d) (nth 2 d) (car d))))
+
+(defun gnus-score-build-cons (article)
+  ;; Build a `gnus-newsgroup-scored' type cons from ARTICLE.
+  (cons (header-number (car article)) (cdr article)))
+
+(defconst gnus-header-index
+  ;; Name to index alist.
+  '(("number" 0 gnus-score-integer)
+    ("subject" 1 gnus-score-string)
+    ("from" 2 gnus-score-string)
+    ("date" 3 gnus-score-date)
+    ("id" 4 gnus-score-string) 
+    ("references" 5 gnus-score-string) 
+    ("chars" 6 gnus-score-integer) 
+    ("lines" 7 gnus-score-integer) 
+    ("xref" 8 gnus-score-string)))
+
+(defvar gnus-score-file-suffix "SCORE"
+  "Suffix of the score files.")
+
+(defun gnus-score-file-name (newsgroup)
+  "Return the name of a score file for NEWSGROUP."
+  (cond  ((or (null newsgroup)
+             (string-equal newsgroup ""))
+         ;; The global score file is placed at top of the directory.
+         (expand-file-name gnus-score-file-suffix
+                           (or gnus-kill-files-directory "~/News")))
+        (gnus-use-long-file-name
+         ;; Append ".SCORE" to newsgroup name.
+         (expand-file-name (concat newsgroup "." gnus-score-file-suffix)
+                           (or gnus-kill-files-directory "~/News")))
+        (t
+         ;; Place "KILL" under the hierarchical directory.
+         (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
+                                   "/" gnus-score-file-suffix)
+                           (or gnus-kill-files-directory "~/News")))))
+
+(defun gnus-score-score-files (group)
+  "Return a list of all possible score files."
+  (or gnus-kill-files-directory (setq gnus-kill-files-directory "~/News/"))
+  (if (not (file-exists-p gnus-kill-files-directory))
+      (setq gnus-score-file-list nil)
+    (if gnus-use-long-file-name
+       (if (or (not gnus-score-file-list)
+               (gnus-file-newer-than gnus-kill-files-directory
+                                     (car gnus-score-file-list)))
+           (setq gnus-score-file-list
+                 (cons (nth 5 (file-attributes gnus-kill-files-directory))
+                       (directory-files
+                        gnus-kill-files-directory t
+                        (concat gnus-score-file-suffix "$")))))
+      (let ((dir (expand-file-name
+                 (concat gnus-kill-files-directory
+                         (gnus-replace-chars-in-string group ?. ?/))))
+           (mdir (length (expand-file-name gnus-kill-files-directory)))
+           files)
+       (if (file-exists-p (concat dir "/" gnus-score-file-suffix))
+           (setq files (list (concat dir "/" gnus-score-file-suffix))))
+       (while (>= (1+ (length dir)) mdir)
+         (and (file-exists-p (concat dir "/all/" gnus-score-file-suffix))
+              (setq files (cons (concat dir "/all/" gnus-score-file-suffix)
+                                files)))
+         (string-match "/[^/]*$" dir)
+         (setq dir (substring dir (match-beginning 0))))
+       (setq gnus-score-file-list (cons nil files)))))
+  (cdr gnus-score-file-list))
+       
+(defun gnus-score-files-for-group (group)
+  "Return a list of score files for GROUP."
+  (if (and gnus-score-find-score-files-function
+          (fboundp gnus-score-find-score-files-function))
+      (funcall gnus-score-find-score-files-function group)
+    (if (not gnus-score-hierarchical)
+       (let ((file (gnus-score-file-name group)))
+         (and (file-exists-p file)
+              (list file)))
+      (let ((sfiles (gnus-score-score-files group))
+           (klen (length (expand-file-name gnus-kill-files-directory)))
+           ofiles not-match regexp)
+       (save-excursion
+         (set-buffer (get-buffer-create "*gnus score files*"))
+         (buffer-disable-undo)
+         (while sfiles
+           (erase-buffer)
+           (insert (car sfiles))
+           (goto-char 1)
+           (re-search-forward (concat "." gnus-score-file-suffix "$"))
+           (replace-match "") 
+           (goto-char 1)
+           (delete-char klen)
+           (while (search-forward "all" nil t)
+             (replace-match ".+"))
+           (goto-char 1)
+           (if (looking-at "not.")
+               (progn
+                 (setq not-match t)
+                 (setq regexp (buffer-substring 5 (point-max))))
+             (setq regexp (buffer-substring 1 (point-max)))
+             (setq not-match nil))
+           (if (or (and not-match
+                        (not (string-match regexp group)))
+                   (and (not not-match)
+                        (string-match regexp group)))
+               (setq ofiles (cons (car sfiles) ofiles)))
+           (setq sfiles (cdr sfiles)))
+         (kill-buffer (current-buffer))
+         ofiles)))))
+
+
 \f
-;;; 
 ;;; Gnus Posting Functions
 ;;;
 
@@ -8496,7 +10033,7 @@ marked as read or ticked are ignored."
 
 (autoload 'news-reply-mode "rnewspost")
 
-;;; Post news commands of Gnus Group Mode and Summary Mode
+;;; Post news commands of Gnus group mode and summary mode
 
 (defun gnus-group-post-news ()
   "Post an article."
@@ -8510,8 +10047,10 @@ marked as read or ticked are ignored."
     (or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
             (not (zerop (buffer-size))))
        ;; Restore last window configuration.
-       (set-window-configuration gnus-winconf-post-news)))
-  ;; We don't want to return to Summary buffer nor Article buffer later.
+       (and gnus-winconf-post-news
+            (set-window-configuration gnus-winconf-post-news))))
+  ;; We don't want to return to summary buffer nor article buffer later.
+  (setq gnus-winconf-post-news nil)
   (if (get-buffer gnus-summary-buffer)
       (bury-buffer gnus-summary-buffer))
   (if (get-buffer gnus-article-buffer)
@@ -8527,8 +10066,10 @@ marked as read or ticked are ignored."
     (or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
             (not (zerop (buffer-size))))
        ;; Restore last window configuration.
-       (set-window-configuration gnus-winconf-post-news)))
-  ;; We don't want to return to Article buffer later.
+       (and gnus-winconf-post-news
+            (set-window-configuration gnus-winconf-post-news))))
+  ;; We don't want to return to article buffer later.
+  (setq gnus-winconf-post-news nil)
   (if (get-buffer gnus-article-buffer)
       (bury-buffer gnus-article-buffer)))
 
@@ -8555,8 +10096,10 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
        (or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
                 (not (zerop (buffer-size))))
            ;; Restore last window configuration.
-           (set-window-configuration gnus-winconf-post-news)))
-      ;; We don't want to return to Article buffer later.
+           (and gnus-winconf-post-news
+                (set-window-configuration gnus-winconf-post-news))))
+      ;; We don't want to return to article buffer later.
+      (setq gnus-winconf-post-news nil)
       (bury-buffer gnus-article-buffer))))
 
 (defun gnus-summary-followup-with-original ()
@@ -8569,7 +10112,7 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
   (interactive)
   (gnus-summary-select-article t)
   (gnus-eval-in-buffer-window gnus-article-buffer
-    (gnus-cancel-news)))
+                             (gnus-cancel-news)))
 
 (defun gnus-summary-supersede-article ()
   "Compose an article that will supersede a previous article.
@@ -8620,7 +10163,8 @@ Type \\[describe-mode] in the buffer to get a list of commands."
          gnus-expert-user
          (not (eq 'post 
                   (nth 1 (assoc 
-                          (format "%s" (car gnus-current-select-method))
+                          (format "%s" (car (gnus-find-method-for-group 
+                                             gnus-newsgroup-name)))
                           gnus-valid-select-methods))))
          (y-or-n-p "Are you sure you want to post to all of USENET? "))
       (let ((sumart (if (eq method 'followup)
@@ -8633,7 +10177,7 @@ Type \\[describe-mode] in the buffer to get a list of commands."
                 (eq method 'post)
                 (not header))
            (setq header 
-                 (completing-read "Newsgroup: " gnus-active-hashtb nil t)))
+                 (completing-read "Group: " gnus-active-hashtb nil t)))
        (setq mail-reply-buffer article-buffer)
        (setq gnus-post-news-buffer 
              (setq post-buf
@@ -8655,6 +10199,13 @@ Type \\[describe-mode] in the buffer to get a list of commands."
        (make-local-variable 'gnus-article-reply)
        (make-local-variable 'gnus-article-check-size)
        (setq gnus-article-reply sumart)
+       ;; Handle author copy using BCC field.
+       (if gnus-mail-self-blind
+           (progn
+             (mail-position-on-field "BCC")
+             (insert (if (stringp gnus-mail-self-blind)
+                         gnus-mail-self-blind
+                       (user-login-name)))))
        ;; Handle author copy using FCC field.
        (if gnus-author-copy
            (progn
@@ -8679,7 +10230,7 @@ Type \\[describe-mode] in the buffer to get a list of commands."
   "Send a news message."
   (interactive)
   ;; Check whether the article is a Good Net Citizen.
-  (if (not (gnus-inews-check-post))
+  (if (and gnus-article-check-size (not (gnus-inews-check-post)))
       ;; Aber nein!
       ()
     ;; Looks ok, so we do the nasty.
@@ -8715,11 +10266,50 @@ Type \\[describe-mode] in the buffer to get a list of commands."
                (goto-char (point-min))
                (replace-regexp "\n[ \t]+" " ") ;No line breaks (too confusing)
                (goto-char (point-min))
-               (replace-regexp "[ \t\n]*,[ \t\n]*\\|[ \t]+" ",")
-               ))
+               (replace-regexp "[ \t\n]*,[ \t\n]*\\|[ \t]+" ",")))
+
+         ;; Added by Per Abrahamsen <abraham@iesd.auc.dk>.
+         ;; Help save the the world!
+         (or 
+          gnus-expert-user
+          (let ((newsgroups (mail-fetch-field "newsgroups"))
+                (followup-to (mail-fetch-field "followup-to"))
+                groups to)
+            (if (and (string-match "," newsgroups) (not followup-to))
+                (progn
+                  (while (string-match "," newsgroups)
+                    (setq groups
+                          (cons (list (substring newsgroups
+                                                 0 (match-beginning 0)))
+                                groups))
+                    (setq newsgroups (substring newsgroups (match-end 0))))
+                  (setq groups (nreverse (cons (list newsgroups) groups)))
+
+                  (setq to
+                        (completing-read "Followups to: (default all groups) "
+                                         groups))
+                  (if (> (length to) 0)
+                      (progn
+                        (goto-char (point-min))
+                        (insert "Followup-To: " to "\n")))))))
+
+         ;; Cleanup Followup-To.
+         (goto-char (point-min))
+         (if (search-forward-regexp "^Followup-To: +" nil t)
+             (save-restriction
+               (narrow-to-region
+                (point)
+                (if (re-search-forward "^[^ \t]" nil 'end)
+                    (match-beginning 0)
+                  (point-max)))
+               (goto-char (point-min))
+               (replace-regexp "\n[ \t]+" " ") ;No line breaks (too confusing)
+               (goto-char (point-min))
+               (replace-regexp "[ \t\n]*,[ \t\n]*\\|[ \t]+" ",")))
 
-         ;; Mail the message too if To: or Cc: exists.
+         ;; Mail the message too if To:, Bcc:. or Cc: exists.
          (if (or (mail-fetch-field "to" nil t)
+                 (mail-fetch-field "bcc" nil t)
                  (mail-fetch-field "cc" nil t))
              (if gnus-mail-send-method
                  (progn
@@ -8750,7 +10340,7 @@ Type \\[describe-mode] in the buffer to get a list of commands."
        (set-buffer-modified-p nil))
       ;; If NNTP server is opened by gnus-inews-news, close it by myself.
       (or server-running
-         (gnus-close-server gnus-current-select-method))
+         (gnus-close-server (gnus-find-method-for-group gnus-newsgroup-name)))
       (and (fboundp 'bury-buffer) (bury-buffer))
       ;; Restore last window configuration.
       (and gnus-winconf-post-news
@@ -8760,24 +10350,71 @@ Type \\[describe-mode] in the buffer to get a list of commands."
 (defun gnus-inews-check-post ()
   "Check whether the post looks ok."
   (and 
-   ;; First check for an empty Subject line. 
+   ;; Check excessive size.
+   (if (> (buffer-size) 60000)
+       (y-or-n-p (format "The article is %d octets long. Really post? "
+                        (buffer-size)))
+     t)
+   ;; Check for commands in Subject.
+   (save-excursion
+     (save-restriction
+       (goto-char (point-min))
+       (narrow-to-region (point) (search-forward mail-header-separator))
+       (if (string-match "^cmsg " (mail-fetch-field "subject"))
+          (y-or-n-p
+           "The control code \"cmsg \" is in the subject. Really post? ")
+        t)))
+   ;; Check for control characters.
+   (save-excursion
+     (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
+        (y-or-n-p "The article contains control characters. Really post? ")
+       t))
+   ;; Check for multiple identical headers.
+   (let (found)
+     (save-excursion
+       (save-restriction
+        (goto-char (point-min))
+        (narrow-to-region (point) (search-forward mail-header-separator))
+        (goto-char (point-min))
+        (while (and (not found) (re-search-forward "^[^ \t:]+: " nil t))
+          (save-excursion
+            (or (re-search-forward 
+                 (concat "^" (setq found
+                                   (buffer-substring (match-beginning 0) 
+                                                     (match-end 0))))
+                 nil t)
+                (setq found nil))))
+        (if found
+            (y-or-n-p (format "Multiple %s headers. Really post? " found))
+          t))))
+   ;; Check for version and sendsys.
    (save-excursion
      (save-restriction
-       (narrow-to-region 
-       (goto-char (point-min))
-       (progn (search-forward (concat "\n" mail-header-separator "\n")) 
-              (point)))
        (goto-char (point-min))
-       (if (or (not (re-search-forward "^Subject: +" nil t))
-              (eolp))
+       (narrow-to-region (point) (search-forward mail-header-separator))
+       (if (re-search-backward "^Sendsys:\\|^Version:" nil t)
           (yes-or-no-p
-           "The Subject field is empty. Do you really want to post this article? ")
+           (format "The article contains a %s command. Really post? "
+                   (buffer-substring (match-beginning 0) (match-end 0))))
         t)))
-   ;; Then use the (size . checksum) variable to see whether the
+   (save-excursion
+     (save-restriction
+       (goto-char (point-min))
+       (narrow-to-region (point) (search-forward mail-header-separator))
+       (let* ((case-fold-search t)
+             (from (mail-fetch-field "from")))
+        (if (and from
+                 (string-match "@" from)
+                 (not (string-match "@[^\\.]*\\." from)))
+            (yes-or-no-p
+             (format "The domain looks strange: \"%s\". Really post? "
+                     from))
+          t))))
+   ;; Use the (size . checksum) variable to see whether the
    ;; article is empty or has only quoted text.
    (if (and (= (buffer-size) (car gnus-article-check-size))
            (= (gnus-article-checksum) (cdr gnus-article-check-size)))
-       (yes-or-no-p "It looks like there's no new text in your article. Really post it? ")
+       (yes-or-no-p "It looks like there's no new text in your article. Really post? ")
      t)))
 
 (defun gnus-article-checksum ()
@@ -8823,7 +10460,7 @@ Type \\[describe-mode] in the buffer to get a list of commands."
                    "Subject: cancel " message-id "\n"
                    "Control: cancel " message-id "\n"
                    mail-header-separator "\n"
-                   )
+                   "This is a cancel message from " from ".\n")
            ;; Send the control article to NNTP server.
            (message "Canceling your article...")
            (if (gnus-inews-article)
@@ -8876,98 +10513,144 @@ Type \\[describe-mode] in the buffer to get a list of commands."
       ;; Post an article to NNTP server.
       ;; Return NIL if post failed.
       (prog1
-         (gnus-request-post gnus-current-select-method)
+         (gnus-request-post (gnus-find-method-for-group gnus-newsgroup-name))
        (kill-buffer (current-buffer)))
       )))
 
 (defun gnus-inews-insert-headers ()
   "Prepare article headers.
-Fields already prepared in the buffer are not modified.
-Fields in `gnus-required-headers' will be generated."
-  (save-excursion
-    (let ((date (gnus-inews-date))
-         (message-id (gnus-inews-message-id))
-         (organization (gnus-inews-organization)))
+Headers already prepared in the buffer are not modified.
+Headers in `gnus-required-headers' will be generated."
+  (let ((Date (gnus-inews-date))
+       (Message-ID (gnus-inews-message-id))
+       (Organization (gnus-inews-organization))
+       (From (gnus-inews-user-name))
+       (Path (gnus-inews-path))
+       (Subject nil)
+       (Newsgroups nil)
+       (Distribution nil)
+       (Lines (gnus-inews-lines))
+       (X-Newsreader gnus-version)
+       (headers gnus-required-headers)
+       (case-fold-search t)
+       header value)
+    ;; First we remove any old Message-IDs. This might be slightly
+    ;; fascist, but if the user really wants to generate Message-IDs
+    ;; by herself, she should remove it from the `gnus-required-list'. 
+    (goto-char (point-min))
+    (and (memq 'Message-ID headers)
+        (re-search-forward "^Message-ID:" nil t)
+        (delete-region (progn (beginning-of-line) (point))
+                       (progn (forward-line 1) (point))))
+    ;; Remove NNTP-posting-host.
+    (goto-char (point-min))
+    (and (re-search-forward "nntp-posting-host^:" nil t)
+        (delete-region (progn (beginning-of-line) (point))
+                       (progn (forward-line 1) (point))))
+    ;; Insert new Sender if the From is strange. 
+    (let ((from (mail-fetch-field "from")))
+      (if (and from (not (string= (downcase from) (downcase From))))
+         (progn
+           (goto-char (point-min))    
+           (and (re-search-forward "^Sender:" nil t)
+                (delete-region (progn (beginning-of-line) (point))
+                               (progn (forward-line 1) (point))))
+           (insert "Sender: " From "\n"))))
+    ;; If there are References, and no "Re: ", then the thread has
+    ;; changed name. See Son-of-1036.
+    (if (and (mail-fetch-field "references")
+            (get-buffer gnus-article-buffer))
+       (let ((psubject (gnus-simplify-subject-re
+                        (mail-fetch-field "subject")))
+             subject)
+         (save-excursion
+           (set-buffer (get-buffer gnus-article-buffer))
+           (save-restriction
+             (gnus-narrow-to-headers)
+             (if (setq subject (mail-fetch-field "subject"))
+                 (progn
+                   (and gnus-summary-gather-subject-limit
+                        (> (length subject) gnus-summary-gather-subject-limit)
+                        (setq subject
+                              (substring subject 0
+                                         gnus-summary-gather-subject-limit)))
+                   (setq subject (gnus-simplify-subject-re subject))))))
+         (or (and psubject subject (string= subject psubject))
+             (progn
+               (string-match "@" Message-ID)
+               (setq Message-ID
+                     (concat (substring Message-ID 0 (match-beginning 0))
+                             "_-_" 
+                             (substring Message-ID (match-beginning 0))))))))
+    ;; Go through all the required headers and see if they are in the
+    ;; articles already. If they are not, or are empty, they are
+    ;; inserted automatically - except for Subject, Newsgroups and
+    ;; Distribution. 
+    (while headers
       (goto-char (point-min))
-      (and (memq 'Path gnus-required-headers)
-          (or (mail-fetch-field "path")
-              (gnus-insert-end "Path: " (gnus-inews-path) "\n")))
-      (and (memq 'From gnus-required-headers)
-          (or (mail-fetch-field "from")
-              (gnus-insert-end "From: " (gnus-inews-user-name) "\n")))
-      ;; If there is no subject, make Subject: field.
-      (and (memq 'Subject gnus-required-headers)
-          (or (mail-fetch-field "subject")
-              (gnus-insert-end "Subject: \n")))
-      ;; If there is no newsgroups, make Newsgroups: field.
-      (and (memq 'Newsgroups gnus-required-headers)
-          (or (mail-fetch-field "newsgroups")
-              (gnus-insert-end "Newsgroups: \n")))
-      (and message-id
-          (memq 'Message-ID gnus-required-headers)
-          (progn
-            (if (mail-fetch-field "message-id")
-                (progn
-                  (goto-char (point-min))
-                  (re-search-forward "^Message-ID" nil t)
-                  (delete-region (progn (beginning-of-line) (point))
-                                 (progn (forward-line 1) (point)))))
-            (gnus-insert-end "Message-ID: " message-id "\n")))
-      (and date
-          (memq 'Date gnus-required-headers)
-          (or (mail-fetch-field "date")
-              (gnus-insert-end "Date: " date "\n")))
-      ;; Optional fields in RFC977 and RFC1036
-      (and organization
-          (memq 'Organization gnus-required-headers)
-          (or (mail-fetch-field "organization")
-              (let ((begin (point-max))
-                    (fill-column 79)
-                    (fill-prefix "\t"))
-                (gnus-insert-end "Organization: " organization "\n")
-                (fill-region-as-paragraph begin (point-max)))))
-      (and (memq 'Distribution gnus-required-headers)
-          (or (mail-fetch-field "distribution")
-              (gnus-insert-end "Distribution: \n")))
-      (and (memq 'Lines gnus-required-headers)
-          (or (mail-fetch-field "lines")
-              (gnus-insert-end "Lines: " (gnus-inews-lines) "\n")))
-      (and (memq 'X-Newsreader gnus-required-headers)
-          (or (mail-fetch-field "x-newsreader")
-              (gnus-insert-end "X-Newsreader: " gnus-version "\n")))
-      )))
-
-
-(defun gnus-insert-end (&rest args)
-  (save-excursion
-    (goto-char (point-max))
-    (apply 'insert args)))
+      (setq header (car headers))
+      (if (or (not (re-search-forward 
+                   (concat "^" (downcase (symbol-name header)) ":") nil t))
+             (progn
+               (if (= (following-char) ? ) (forward-char 1) (insert " "))
+               (looking-at "[ \t]*$")))
+         (progn
+           (setq value (or (and (boundp header) (symbol-value header))
+                           (read-from-minibuffer
+                            (format "Empty header for %s; enter value: " 
+                                    header))))
+           (if (bolp)
+               (save-excursion
+                 (goto-char (point-max))
+                 (insert (symbol-name header) ": " value "\n"))
+             (replace-match value))))
+      (setq headers (cdr headers)))))
 
 (defun gnus-inews-insert-signature ()
-  "Insert signature file in current article buffer.
-If there is a file named .signature-DISTRIBUTION. Set the variable to
-nil to prevent appending the signature file automatically.
-Signature file is specified by the variable gnus-signature-file."
+  "Insert a signature file.
+If `gnus-signature-function' is bound and returns a string, this
+string is used instead of the variable `gnus-signature-file'.
+In either case, if the string is a file name, this file is
+inserted. If the string is not a file name, the string itself is
+inserted. 
+If you never want any signature inserted, set both those variables to
+nil."
   (save-excursion
-    (save-restriction
-      (let ((signature
-            (if gnus-signature-file
-                (expand-file-name gnus-signature-file nil)))
-           distribution)
-       (goto-char (point-min))
-       (search-forward "\n\n")
-       (narrow-to-region (point-min) (point))
-       (setq distribution (mail-fetch-field "distribution"))
-       (widen)
-       (if signature
-           (progn
-             ;; Insert signature.
-             (if (file-exists-p signature)
-                 (progn
-                   (goto-char (point-max))
-                   (insert "--\n")
-                   (insert-file-contents signature)))
-             ))))))
+    (let ((signature 
+          (or (and gnus-signature-function
+                   (fboundp gnus-signature-function)
+                   (funcall gnus-signature-function gnus-newsgroup-name))
+              gnus-signature-file))
+         b)
+      (if (and signature
+              (or (file-exists-p signature)
+                  (string-match " " signature)
+                  (not (string-match 
+                        "^/[^/]+/" (expand-file-name signature)))))
+         (progn
+           (goto-char (point-max))
+           ;; Delete any previous signatures.
+           (if (and mail-signature (search-backward "\n-- \n" nil t))
+               (delete-region (1+ (point)) (point-max)))
+           (insert "\n-- \n")
+           (and (< 4 (setq b (count-lines 
+                              (point)
+                              (progn
+                                (if (file-exists-p signature)
+                                    (insert-file-contents signature)
+                                  (insert signature))
+                                (goto-char (point-max))
+                                (or (bolp) (insert "\n"))
+                                (point)))))
+                (not gnus-expert-user)
+                (not
+                 (y-or-n-p
+                  (format
+                   "Your .sig is %d lines; it should be max 4. Really post? "
+                   b)))
+                (if (file-exists-p signature)
+                    (error (format "Edit %s." signature))
+                  (error "Trim your signature."))))))))
 
 (defun gnus-inews-do-fcc ()
   "Process FCC: fields in current article buffer.
@@ -9036,50 +10719,44 @@ a program specified by the rest of the value."
     ))
 
 (defun gnus-inews-user-name ()
-  "Return user's network address as `NAME@DOMAIN (FULLNAME)'."
+  "Return user's network address as \"NAME@DOMAIN (FULL-NAME)\"."
   (let ((full-name (gnus-inews-full-name)))
-    (concat (or user-mail-address
-               (if (or gnus-user-login-name gnus-use-generic-from
-                       gnus-local-domain (getenv "DOMAINNAME"))
-                   (concat (gnus-inews-login-name) "@"
-                           (gnus-inews-domain-name gnus-use-generic-from))
-                 user-mail-address))
+    (concat (if (or gnus-user-login-name gnus-use-generic-from
+                   gnus-local-domain (getenv "DOMAINNAME"))
+               (concat (gnus-inews-login-name) "@"
+                       (gnus-inews-domain-name gnus-use-generic-from))
+             user-mail-address)
            ;; User's full name.
            (cond ((string-equal full-name "") "")
                  ((string-equal full-name "&") ;Unix hack.
                   (concat " (" (user-login-name) ")"))
                  (t
-                  (concat " (" full-name ")")))
-           )))
+                  (concat " (" full-name ")"))))))
 
 (defun gnus-inews-login-name ()
-  "Return user login name.
-Got from the variable `gnus-user-login-name' and the function
-`user-login-name'."
-  (or gnus-user-login-name (user-login-name)))
+  "Return login name."
+  (or gnus-user-login-name (getenv "LOGNAME") (user-login-name)))
 
 (defun gnus-inews-full-name ()
-  "Return user full name.
-Got from the variable `gnus-user-full-name', the environment variable
-NAME, and the function `user-full-name'."
-  (or gnus-user-full-name
-      (getenv "NAME") (user-full-name)))
+  "Return full user name."
+  (or gnus-user-full-name (getenv "NAME") (user-full-name)))
 
 (defun gnus-inews-domain-name (&optional genericfrom)
   "Return user's domain name.
 If optional argument GENERICFROM is a string, use it as the domain
-name; if it is non-nil, strip of local host name from the domain name.
+name; if it is non-nil, strip off local host name from the domain name.
 If the function `system-name' returns full internet name and the
 domain is undefined, the domain name is got from it."
   (if (or genericfrom gnus-local-domain (getenv "DOMAINNAME"))
-      (let ((domain (or (if (stringp genericfrom) genericfrom)
-                       (getenv "DOMAINNAME")
-                       gnus-local-domain
-                       ;; Function `system-name' may return full internet name.
-                       ;; Suggested by Mike DeCorte <mrd@sun.soe.clarkson.edu>.
-                       (if (string-match "\\." (system-name))
-                           (substring (system-name) (match-end 0)))
-                       (read-string "Domain name (no host): ")))
+      (let ((domain 
+            (or (if (stringp genericfrom) genericfrom)
+                (getenv "DOMAINNAME")
+                gnus-local-domain
+                ;; Function `system-name' may return full internet name.
+                ;; Suggested by Mike DeCorte <mrd@sun.soe.clarkson.edu>.
+                (if (string-match "\\." (system-name))
+                    (substring (system-name) (match-end 0)))
+                (read-string "Domain name (no host): ")))
            (host (or (if (string-match "\\." (system-name))
                          (substring (system-name) 0 (match-beginning 0)))
                      (system-name))))
@@ -9093,120 +10770,99 @@ domain is undefined, the domain name is got from it."
              (t domain)))
     (substring user-mail-address (1+ (string-match "@" user-mail-address)))))
 
+(defun gnus-inews-full-address ()
+  (let ((domain (gnus-inews-domain-name))
+       (system (system-name))
+       (case-fold-search t))
+    (if (string-match "\\." system) system
+      (if (string-match (concat "^" (regexp-quote system)) domain) domain
+       (concat system "." domain)))))
+
 (defun gnus-inews-message-id ()
   "Generate unique Message-ID for user."
   ;; Message-ID should not contain a slash and should be terminated by
   ;; a number.  I don't know the reason why it is so.
-  (concat "<" (gnus-inews-unique-id) "@" (gnus-inews-domain-name) ">"))
+  (concat "<" (gnus-inews-unique-id) "@" (gnus-inews-full-address) ">"))
+
+(defconst gnus-inews-unique-id-char ?a)
 
 (defun gnus-inews-unique-id ()
   "Generate unique ID from user name and current time."
-  (let ((date (current-time-string))
-       (name (gnus-inews-login-name)))
-    (if (string-match "^[^ ]+ \\([^ ]+\\)[ ]+\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) [0-9][0-9]\\([0-9][0-9]\\)"
-                     date)
-       (concat (upcase name) "."
-               (substring date (match-beginning 6) (match-end 6)) ;Year
-               (substring date (match-beginning 1) (match-end 1)) ;Month
-               (substring date (match-beginning 2) (match-end 2)) ;Day
-               (substring date (match-beginning 3) (match-end 3)) ;Hour
-               (substring date (match-beginning 4) (match-end 4)) ;Minute
-               (substring date (match-beginning 5) (match-end 5)) ;Second
-               )
-      (error "Cannot understand current-time-string: %s." date))
-    ))
-
-(defun gnus-current-time-zone (time)
-  "The local time zone in effect at TIME, or nil if not known."
-  (let ((z (and (fboundp 'current-time-zone) (current-time-zone time))))
-    (if (and z (car z)) z gnus-local-timezone)))
+  (let* ((char (char-to-string 
+               (setq gnus-inews-unique-id-char
+                     (if (or (> gnus-inews-unique-id-char ?z)
+                             (< gnus-inews-unique-id-char ?a))
+                         ?a (1+ gnus-inews-unique-id-char)))))
+        (date (timezone-parse-date (current-time-string)))
+        (time (aref date 3))
+        (user-name (downcase (gnus-inews-login-name)))
+        string)
+    (save-excursion
+      (set-buffer (get-buffer-create " *gnus id work*"))
+      (buffer-disable-undo)
+      (erase-buffer)
+      (insert user-name)
+      (random t)
+      (goto-char (point-min))
+      (while (re-search-forward "[^-a-zA-Z0-9\\.]" nil t)
+       (replace-match (char-to-string (+ (random 26) ?a))))
+      (setq user-name (buffer-substring (point-min) (point-max)))
+      (kill-buffer (current-buffer)))
+    (setq string
+         (concat user-name
+                 (aref date 0)
+                 (aref date 1)
+                 (aref date 2)
+                 (substring time 0 1)
+                 (substring time 3 4)
+                 (substring time 7 8)
+                 char))
+    (let ((i (1- (length string)))
+         c)
+      (while (>= i 0)
+       (setq c (aref string i))
+       (if (and (>= c ?0) (<= c ?9))
+           (aset string i (- ?z (- c ?0))))
+       (setq i (1- i))))
+    string))
 
 (defun gnus-inews-date ()
-  "Date string of today.
-If `current-time-zone' works, or if `gnus-local-timezone' is set correctly,
-this yields a date that conforms to RFC 822.  Otherwise a buggy date will
-be generated; this might work with some older news servers."
-  (let* ((now (and (fboundp 'current-time) (current-time)))
-        (zone (gnus-current-time-zone now)))
-    (if zone
-       (gnus-inews-valid-date now zone)
-      ;; No timezone info.
-      (gnus-inews-buggy-date now))))
-
-(defun gnus-inews-valid-date (&optional time zone)
-  "A date string that represents TIME and conforms to the Usenet standard.
-TIME is optional and defaults to the current time.
-Some older versions of Emacs always act as if TIME is nil.
-The optional argument ZONE specifies the local time zone (default GMT)."
-  (timezone-make-date-arpa-standard
-   (if (fboundp 'current-time)
-       (current-time-string time)
-     (current-time-string))
-   zone "GMT"))
-
-(defun gnus-inews-buggy-date (&optional time)
-  "A buggy date string that represents TIME.
-TIME is optional and defaults to the current time.
-Some older versions of Emacs always act as if TIME is nil."
-  (let ((date (if (fboundp 'current-time)
-                 (current-time-string time)
-               (current-time-string))))
-    (if (string-match "^[^ ]+ \\([^ ]+\\)[ ]+\\([0-9]+\\) \\([0-9:]+\\) [0-9][0-9]\\([0-9][0-9]\\)"
-                     date)
-       (concat (substring date (match-beginning 2) (match-end 2)) ;Day
-               " "
-               (substring date (match-beginning 1) (match-end 1)) ;Month
-               " "
-               (substring date (match-beginning 4) (match-end 4)) ;Year
-               " "
-               (substring date (match-beginning 3) (match-end 3))) ;Time
-      (error "Cannot understand current-time-string: %s." date))
-    ))
+  "Current time string."
+  (timezone-make-date-arpa-standard (current-time-string)))
 
 (defun gnus-inews-organization ()
   "Return user's organization.
 The ORGANIZATION environment variable is used if defined.
-If not, the variable gnus-local-organization is used instead.
-If the value begins with a slash, it is taken as the name of a file
-containing the organization."
-  ;; The organization must be got in this order since the ORGANIZATION
-  ;; environment variable is intended for user specific while
-  ;; gnus-local-organization is for machine or organization specific.
-
-  (let* ((private-file (expand-file-name "~/.organization" nil))
-        (organization (or (getenv "ORGANIZATION")
-                          gnus-local-organization
-                          private-file)))
+If not, the variable `gnus-local-organization' is used instead.
+If it is a function, the function will be called with the current
+newsgroup name as the argument.
+If this is a file name, the contents of this file will be used as the
+organization."
+  (let* ((organization 
+         (or (getenv "ORGANIZATION")
+             (if gnus-local-organization
+                 (if (and (symbolp gnus-local-organization)
+                          (fboundp gnus-local-organization))
+                     (funcall gnus-local-organization gnus-newsgroup-name)
+                   gnus-local-organization))
+             gnus-organization-file
+             "~/.organization")))
     (and (stringp organization)
         (> (length organization) 0)
-        (string-equal (substring organization 0 1) "/")
-        ;; Get it from the user and system file.
-        ;; Suggested by roland@wheaties.ai.mit.edu (Roland McGrath).
-        (let ((dist (mail-fetch-field "distribution")))
-          (setq organization
-                (cond ((file-exists-p (concat organization "-" dist))
-                       (concat organization "-" dist))
-                      ((file-exists-p organization) organization)
-                      ((file-exists-p gnus-organization-file)
-                       gnus-organization-file)
-                      (t organization)))
-          ))
-    (cond ((not (stringp organization)) nil)
-         ((and (string-equal (substring organization 0 1) "/")
-               (file-exists-p organization))
-          ;; If the first character is `/', assume it is the name of
-          ;; a file containing the organization.
-          (save-excursion
-            (let ((tmpbuf (get-buffer-create " *Gnus organization*")))
-              (set-buffer tmpbuf)
-              (erase-buffer)
+        (or (file-exists-p organization)
+            (string-match " " organization)
+            (not (string-match  "^/[^/]+/" (expand-file-name organization))))
+        (save-excursion
+          (set-buffer (get-buffer-create " *Gnus organization*"))
+          (buffer-disable-undo (current-buffer))
+          (erase-buffer)
+          (if (file-exists-p organization)
               (insert-file-contents organization)
-              (prog1 (buffer-string)
-                (kill-buffer tmpbuf))
-              )))
-         ((string-equal organization private-file) nil) ;No such file
-         (t organization))
-    ))
+            (insert organization))
+          (goto-char (point-min))
+          (while (re-search-forward " *\n *" nil t)
+            (replace-match " "))
+          (buffer-substring (point-min) (point-max))))))
 
 (defun gnus-inews-lines ()
   "Count the number of lines and return numeric string."
@@ -9225,7 +10881,7 @@ containing the organization."
 (autoload 'news-mail-reply "rnewspost")
 (autoload 'news-mail-other-window "rnewspost")
 
-;;; Mail reply commands of Gnus Summary Mode
+;;; Mail reply commands of Gnus summary mode
 
 (defun gnus-summary-reply (yank)
   "Reply mail to news author.
@@ -9270,13 +10926,12 @@ mailer."
          (group (gnus-group-real-name gnus-newsgroup-name))
          (cur (cons (current-buffer) gnus-current-article))
          from subject date to reply-to message-of
-         references message-id sender follow-to)
+         references message-id sender follow-to cc)
       (set-buffer (get-buffer-create "*mail*"))
       (mail-mode)
       (make-local-variable 'gnus-article-reply)
       (setq gnus-article-reply cur)
       (local-set-key "\C-c\C-c" 'gnus-mail-send-and-exit)
-      (local-set-key "\C-c\C-y" 'gnus-mail-yank-original)
       (if (and (buffer-modified-p)
               (> (buffer-size) 0)
               (not (y-or-n-p "Unsent article being composed; erase it? ")))
@@ -9284,10 +10939,11 @@ mailer."
        (erase-buffer)
        (save-excursion
          (set-buffer gnus-article-buffer)
-         (goto-char (point-min))
-         (narrow-to-region (point-min)
-                           (progn (search-forward "\n\n") (point)))
-         (set-text-properties (point-min) (point-max) nil)
+         (let ((buffer-read-only nil))
+           (goto-char (point-min))
+           (narrow-to-region (point-min)
+                             (progn (search-forward "\n\n") (point)))
+           (add-text-properties (point-min) (point-max) '(invisible nil)))
          (if (and (boundp 'gnus-reply-to-function)
                   gnus-reply-to-function)
              (save-excursion
@@ -9307,13 +10963,14 @@ mailer."
                            "Re: none"))
          (or (string-match "^[Rr][Ee]:" subject)
              (setq subject (concat "Re: " subject)))
+         (setq cc (mail-fetch-field "cc"))
          (setq reply-to (mail-fetch-field "reply-to"))
          (setq references (mail-fetch-field "references"))
          (setq message-id (mail-fetch-field "message-id"))
          (widen))
        (setq news-reply-yank-from from)
        (setq news-reply-yank-message-id message-id)
-       (mail-setup (or to-address follow-to reply-to from sender)
+       (mail-setup (or to-address follow-to reply-to from sender "") 
                    subject message-of nil gnus-article-buffer nil)
        ;; Fold long references line to follow RFC1036.
        (mail-position-on-field "References")
@@ -9348,17 +11005,23 @@ mailer."
 
 (defun gnus-mail-send-and-exit ()
   (interactive)
-  (let ((reply gnus-article-reply))
+  (let ((cbuf (current-buffer)))
     (mail-send-and-exit nil)
-    (if (and reply
-            (get-buffer (car reply))
-            (buffer-name (car reply)))
+    (if (get-buffer gnus-group-buffer)
        (progn
-         (set-buffer (car reply))
-         (gnus-summary-mark-article-as-replied 
-          (cdr reply)))))
-  (if gnus-winconf-post-news
-      (set-window-configuration gnus-winconf-post-news)))
+         (save-excursion
+           (set-buffer cbuf)
+           (let ((reply gnus-article-reply))
+             (if (and reply
+                      (get-buffer (car reply))
+                      (buffer-name (car reply)))
+                 (progn
+                   (set-buffer (car reply))
+                   (gnus-summary-mark-article-as-replied 
+                    (cdr reply))))))
+         (and gnus-winconf-post-news
+              (set-window-configuration gnus-winconf-post-news))
+         (setq gnus-winconf-post-news nil)))))
 
 (defun gnus-mail-forward-using-mail ()
   "Forward the current message to another user using mail."
@@ -9496,10 +11159,11 @@ If CONFIRM is non-nil, the user will be asked for an NNTP server."
            ;; Read server name with completion.
            (setq gnus-nntp-server
                  (completing-read "NNTP server: "
-                                  (cons (list gnus-nntp-server)
-                                        gnus-secondary-servers)
+                                  (mapcar (lambda (server) (list server))
+                                          (cons (list gnus-nntp-server)
+                                                gnus-secondary-servers))
                                   nil nil gnus-nntp-server))
-           (setq gnus-select-method
+           (setq gnus-select-method 
                  (list 'nntp gnus-nntp-server)))
 
        (if (and gnus-nntp-server 
@@ -9541,18 +11205,19 @@ If CONFIRM is non-nil, the user will be asked for an NNTP server."
     (if (gnus-server-opened method)
        ;; Stream is already opened.
        t
-      ;; Open NNTP server.
+      ;; Open server.
       (message "Opening server %s on %s..." (car method) (nth 1 method))
       (run-hooks 'gnus-open-server-hook)
-      (message "")
       (or (gnus-server-opened method)
-         (gnus-open-server method)))))
+         (gnus-open-server method))
+      (message ""))))
 
 (defun gnus-nntp-message (&optional message)
   "Check the status of the NNTP server.
 If the status of the server is clear and MESSAGE is non-nil, MESSAGE
 is returned insted of the status string."
-  (let ((status (gnus-status-message gnus-current-select-method))
+  (let ((status (gnus-status-message (gnus-find-method-for-group 
+                                     gnus-newsgroup-name)))
        (message (or message "")))
     (if (and (stringp status) (> (length status) 0))
        status message)))
@@ -9579,6 +11244,10 @@ is returned insted of the status string."
 (defun gnus-request-list-newsgroups (method)
   (funcall (gnus-get-function method 'request-list-newsgroups) (nth 1 method)))
 
+(defun gnus-request-newgroups (date method)
+  (funcall (gnus-get-function method 'request-newgroups) 
+          date (nth 1 method)))
+
 (defun gnus-server-opened (method)
   (funcall (gnus-get-function method 'server-opened) (nth 1 method)))
 
@@ -9590,6 +11259,11 @@ is returned insted of the status string."
     (funcall (gnus-get-function method 'request-group) 
             (gnus-group-real-name group) (nth 1 method) dont-check)))
 
+(defun gnus-close-group (group)
+  (let ((method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function method 'close-group) 
+            (gnus-group-real-name group) (nth 1 method))))
+
 (defun gnus-retrieve-headers (articles group)
   (let ((method (gnus-find-method-for-group group)))
     (funcall (gnus-get-function method 'retrieve-headers) 
@@ -9613,10 +11287,11 @@ is returned insted of the status string."
           (if (and gnus-post-method
                    ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
                    (memq 'post (assoc
-                                (format "%s" (car gnus-current-select-method))
+                                (format "%s" (car (gnus-find-method-for-group
+                                                   gnus-newsgroup-name)))
                                        gnus-valid-select-methods)))
               gnus-post-method
-            gnus-current-select-method)))
+            (gnus-find-method-for-group gnus-newsgroup-name))))
     (funcall (gnus-get-function method 'request-post-buffer) 
             post header artbuf (gnus-group-real-name group) info)))
 
@@ -9644,7 +11319,8 @@ is returned insted of the status string."
   (let ((func (if (symbolp group) group
                (car (gnus-find-method-for-group group)))))
     (funcall (intern (format "%s-request-accept-article" func))
-            (gnus-group-real-name group))))
+            (if (stringp group) (gnus-group-real-name group)
+              group))))
 
 (defun gnus-find-method-for-group (group)
   (let ((info (nth 2 (gnus-gethash group gnus-newsrc-hashtb))))
@@ -9706,14 +11382,10 @@ is returned insted of the status string."
   "Setup news information.
 If RAWFILE is non-nil, the .newsrc file will also be read.
 If LEVEL is non-nil, the news will be set up at level LEVEL."
-  (let ((init (not (and gnus-newsrc-assoc
-                       gnus-active-hashtb
-                       (not rawfile)))))
+  (let ((init (not (and gnus-newsrc-assoc gnus-active-hashtb (not rawfile)))))
     ;; Clear some variables to re-initialize news information.
-    (if init
-       (setq gnus-newsrc-assoc nil
-             gnus-active-hashtb nil))
-    ;; Read the acitve file and create `gnus-active-hashtb'.
+    (if init (setq gnus-newsrc-assoc nil gnus-active-hashtb nil))
+    ;; Read the active file and create `gnus-active-hashtb'.
     ;; If `gnus-read-active-file' is nil, then we just create an empty
     ;; hash table. The partial filling out of the hash table will be
     ;; done in `gnus-get-unread-articles'.
@@ -9724,7 +11396,7 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
     ;; Read the newsrc file and create `gnus-newsrc-hashtb'.
     (if init (gnus-read-newsrc-file rawfile))
     ;; Find the number of unread articles in each non-dead group.
-    (gnus-get-unread-articles (or level 7))
+    (gnus-get-unread-articles (or level 6))
     ;; Find new newsgroups and treat them.
     (if (and init gnus-check-new-newsgroups gnus-read-active-file (not level))
        (gnus-find-new-newsgroups))
@@ -9737,41 +11409,90 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
 Each new newsgroup will be treated with `gnus-subscribe-newsgroup-method.'
 The `-n' option line from .newsrc is respected."
   (interactive)
-  (if (not gnus-have-read-active-file) (gnus-read-active-file))
-  (if (not (gnus-check-first-time-used))
-      (let ((groups 0)
-           group new-newsgroups)
-       (if (not gnus-killed-hashtb) (gnus-make-hashtable-from-killed))
-       ;; Go though every newsgroup in `gnus-active-hashtb' and compare
-       ;; with `gnus-newsrc-hashtb' and `gnus-killed-hashtb'.
-       (mapatoms
-        (lambda (sym)
-          (setq group (symbol-name sym))
-          (if (or (gnus-gethash group gnus-killed-hashtb)
-                  (gnus-gethash group gnus-newsrc-hashtb))
-              ()
-            (if (and gnus-newsrc-options-n-yes
-                     (string-match gnus-newsrc-options-n-yes group))
-                (progn
-                  (setq groups (1+ groups))
-                  (gnus-sethash group group gnus-killed-hashtb)
-                  (funcall gnus-subscribe-options-newsgroup-method group))
-              (if (or (null gnus-newsrc-options-n-no)
-                      (not (string-match gnus-newsrc-options-n-no group)))
-                  ;; Add this group.
+  (or (gnus-check-first-time-used)
+      (if (eq gnus-check-new-newsgroups 'ask-server)
+         (gnus-ask-server-for-new-groups)
+       (let ((groups 0)
+             group new-newsgroups)
+         (or gnus-have-read-active-file (gnus-read-active-file))
+         (setq gnus-newsrc-last-checked-date (current-time-string))
+         (if (not gnus-killed-hashtb) (gnus-make-hashtable-from-killed))
+         ;; Go though every newsgroup in `gnus-active-hashtb' and compare
+         ;; with `gnus-newsrc-hashtb' and `gnus-killed-hashtb'.
+         (mapatoms
+          (lambda (sym)
+            (setq group (symbol-name sym))
+            (if (or (gnus-gethash group gnus-killed-hashtb)
+                    (gnus-gethash group gnus-newsrc-hashtb))
+                ()
+              (if (and gnus-newsrc-options-n-yes
+                       (string-match gnus-newsrc-options-n-yes group))
                   (progn
                     (setq groups (1+ groups))
                     (gnus-sethash group group gnus-killed-hashtb)
-                    (if gnus-subscribe-hierarchical-interactive
-                        (setq new-newsgroups (cons group new-newsgroups))
-                      (funcall gnus-subscribe-newsgroup-method group)))))))
-        gnus-active-hashtb)
-       (if new-newsgroups 
-           (gnus-subscribe-hierarchical-interactive new-newsgroups))
-       ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
-       (if (> groups 0)
-           (message "%d new newsgroup%s arrived." 
-                    groups (if (> groups 1) "s have" " has"))))))
+                    (funcall gnus-subscribe-options-newsgroup-method group))
+                (if (or (null gnus-newsrc-options-n-no)
+                        (not (string-match gnus-newsrc-options-n-no group)))
+                    ;; Add this group.
+                    (progn
+                      (setq groups (1+ groups))
+                      (gnus-sethash group group gnus-killed-hashtb)
+                      (if gnus-subscribe-hierarchical-interactive
+                          (setq new-newsgroups (cons group new-newsgroups))
+                        (funcall gnus-subscribe-newsgroup-method group)))))))
+          gnus-active-hashtb)
+         (if new-newsgroups 
+             (gnus-subscribe-hierarchical-interactive new-newsgroups))
+         ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
+         (if (> groups 0)
+             (message "%d new newsgroup%s arrived." 
+                      groups (if (> groups 1) "s have" " has")))))))
+
+(defun gnus-ask-server-for-new-groups ()
+  (let* ((date (timezone-parse-date (or gnus-newsrc-last-checked-date
+                                       (current-time-string))))
+        (methods (cons gnus-select-method gnus-secondary-select-methods))
+        (time-string
+         (format "%s%02d%02d %s%s%s"
+                 (substring (aref date 0) 2) (string-to-int (aref date 1)) 
+                 (string-to-int (aref date 2)) (substring (aref date 3) 0 2)
+                 (substring (aref date 3) 3 5) (substring (aref date 3) 6 8)))
+        (groups 0)
+        (new-date (current-time-string))
+        hashtb group new-newsgroups)
+    (while methods
+      (if (gnus-request-newgroups time-string (car methods))
+         (save-excursion
+           (or hashtb (setq hashtb (gnus-make-hashtable 
+                                    (count-lines (point-min) (point-max)))))
+           (set-buffer nntp-server-buffer)
+           (gnus-active-to-gnus-format (car methods) hashtb)))
+      (setq methods (cdr methods)))
+    (mapatoms
+     (lambda (group-sym)
+       (setq group (symbol-name group-sym))
+       (gnus-sethash group (symbol-value group-sym) gnus-active-hashtb)
+       (if (and gnus-newsrc-options-n-yes
+               (string-match gnus-newsrc-options-n-yes group))
+          (progn
+            (setq groups (1+ groups))
+            (funcall gnus-subscribe-options-newsgroup-method group))
+        (if (or (null gnus-newsrc-options-n-no)
+                (not (string-match gnus-newsrc-options-n-no group)))
+            ;; Add this group.
+            (progn
+              (setq groups (1+ groups))
+              (if gnus-subscribe-hierarchical-interactive
+                  (setq new-newsgroups (cons group new-newsgroups))
+                (funcall gnus-subscribe-newsgroup-method group))))))
+     hashtb)
+    (if new-newsgroups 
+       (gnus-subscribe-hierarchical-interactive new-newsgroups))
+    (setq gnus-newsrc-last-checked-date new-date)
+    ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
+    (if (> groups 0)
+       (message "%d new newsgroup%s arrived." 
+                groups (if (> groups 1) "s have" " has")))))
 
 (defun gnus-check-first-time-used ()
   (if (or (file-exists-p gnus-startup-file)
@@ -9779,6 +11500,8 @@ The `-n' option line from .newsrc is respected."
          (file-exists-p (concat gnus-startup-file ".eld")))
       nil
     (message "First time user; subscribing you to default groups")
+    (or gnus-have-read-active-file (gnus-read-active-file))
+    (setq gnus-newsrc-last-checked-date (current-time-string))
     (let ((groups gnus-default-subscribed-newsgroups)
          group)
       (if (eq groups t)
@@ -9875,7 +11598,15 @@ The `-n' option line from .newsrc is respected."
                       (setq num (car entry)))
                   (setq active (gnus-gethash group gnus-active-hashtb))
                   (setq num (- (1+ (cdr active)) (car active)))
-                  (setq info (list group level (cons 1 (1- (car active))))))
+                  ;; Check whether the group is foreign. If so, the
+                  ;; foreign select method has to be entered into the
+                  ;; info. 
+                  (let ((method (gnus-group-method-name group)))
+                    (if (eq method gnus-select-method)
+                        (setq info (list group level 
+                                         (cons 1 (1- (car active)))))
+                      (setq info (list group level (cons 1 (1- (car active)))
+                                       nil method)))))
                 (setq entry (cons info (if previous (cdr (cdr previous))
                                          (cdr gnus-newsrc-assoc))))
                 (setcdr (if previous (cdr previous) gnus-newsrc-assoc)
@@ -9897,14 +11628,13 @@ The `-n' option line from .newsrc is respected."
   (gnus-group-change-level (gnus-gethash newsgroup gnus-newsrc-hashtb) 9))
 
 (defun gnus-check-bogus-newsgroups (&optional confirm)
-  "Delete bogus newsgroups.
+  "Remove bogus newsgroups.
 If CONFIRM is non-nil, the user has to confirm the deletion of every
 newsgroup." 
   (let ((newsrc (cdr gnus-newsrc-assoc))
-       (dead-lists '(gnus-killed-list gnus-zombie-list))
-       bogus group killed)
+       bogus group)
     (message "Checking bogus newsgroups...")
-    (if (not gnus-have-read-active-file) (gnus-read-active-file))
+    (or gnus-have-read-active-file (gnus-read-active-file))
     ;; Find all bogus newsgroup that are subscribed.
     (while newsrc
       (setq group (car (car newsrc)))
@@ -9912,7 +11642,7 @@ newsgroup."
              (nth 4 (car newsrc))
              (and confirm
                   (not (y-or-n-p
-                        (format "Delete bogus newsgroup: %s " group)))))
+                        (format "Remove bogus newsgroup: %s " group)))))
          ;; Active newsgroup.
          ()
        ;; Found a bogus newsgroup.
@@ -9923,61 +11653,65 @@ newsgroup."
     (while bogus
       (gnus-group-change-level 
        (gnus-gethash (car bogus) gnus-newsrc-hashtb) 9)
-      (setq gnus-killed-list (delq (car bogus) gnus-killed-list))
+      (setq gnus-killed-list (delete (car bogus) gnus-killed-list))
       (setq bogus (cdr bogus)))
     ;; Then we remove all bogus groups from the list of killed and
-    ;; zombie groups. They are are deleted without confirmation.
-    (while dead-lists
-      (setq killed (symbol-value (car dead-lists)))
+    ;; zombie groups. They are are removed without confirmation.
+    (let ((dead-lists '(gnus-killed-list gnus-zombie-list))
+         killed)
+      (while dead-lists
+       (setq killed (symbol-value (car dead-lists)))
+       (while killed
+         (setq group (car killed))
+         (or (gnus-gethash group gnus-active-hashtb)
+             ;; The group is bogus.
+             (set (car dead-lists)
+                  (delete group (symbol-value (car dead-lists)))))
+         (setq killed (cdr killed)))
+       (setq dead-lists (cdr dead-lists))))
+    ;; While we're at it, we check the killed list for duplicates.
+    ;; This has nothing to do with bogosity, but it's a convenient
+    ;; place to put the check.
+    (let ((killed gnus-killed-list))
       (while killed
-       (setq group (car killed))
-       (or (gnus-gethash group gnus-active-hashtb)
-           ;; The group is bogus.
-           (setq bogus (cons group bogus)))
-       (setq killed (cdr killed)))
-      (while bogus
-       (set (car dead-lists)
-            (delq (car bogus) (symbol-value (car dead-lists))))
-       (setq bogus (cdr bogus)))
-      (setq dead-lists (cdr dead-lists)))
+       (message "%d" (length killed))
+       (setcdr killed (delete (car killed) (cdr killed)))
+       (setq killed (cdr killed))))
     (message "Checking bogus newsgroups... done")))
 
 ;; Go though `gnus-newsrc-assoc' and compare with `gnus-active-hashtb'
 ;; and compute how many unread articles there are in each group.
 (defun gnus-get-unread-articles (&optional level)
   (let ((newsrc (cdr gnus-newsrc-assoc))
-       (level (or level 7))
+       (level (or level 6))
        info group active)
     (message "Checking new news...")
     (while newsrc
       (setq info (car newsrc))
       (setq group (car info))
+      (setq active (gnus-gethash group gnus-active-hashtb))
 
-      ;; Check foreign newsgroups. If the user doesn't want to check
-      ;; them, or they can't be checked, for instance, if the news
-      ;; server can't be reached, we just set the number of unread
-      ;; articles in this newsgroup to t. This means that Gnus
-      ;; thinks that there are unread articles, but it has no idea how
-      ;; many. 
+      ;; Check newsgroups. If the user doesn't want to check them, or
+      ;; they can't be checked (for instance, if the news server can't
+      ;; be reached) we just set the number of unread articles in this
+      ;; newsgroup to t. This means that Gnus thinks that there are
+      ;; unread articles, but it has no idea how many.
       (if (nth 4 info)
-         (and (or (if (numberp gnus-activate-foreign-newsgroups)
-                      (> (nth 1 info) gnus-activate-foreign-newsgroups)
-                    (not gnus-activate-foreign-newsgroups))
-                  (not (gnus-activate-foreign-newsgroup info)))
-              (progn
-                (gnus-sethash group nil gnus-active-hashtb)
-                (setcar (gnus-gethash group gnus-newsrc-hashtb) t))))
-
-      (if (or (and (> (nth 1 info) level)
-                  (not (car (gnus-gethash group gnus-newsrc-hashtb)))
-                  (setcar (gnus-gethash group gnus-newsrc-hashtb) t))
-             (not (or (setq active (gnus-gethash group gnus-active-hashtb))
-                      (and (not gnus-read-active-file)
-                           (setq active (gnus-activate-newsgroup 
-                                         (car info)))))))
-         ;; If this is a bogus group, there's not much we can do.
-         ()
-       (gnus-get-unread-articles-in-group info active))
+         (if (or (and gnus-activate-foreign-newsgroups 
+                      (not (numberp gnus-activate-foreign-newsgroups)))
+                 (and (numberp gnus-activate-foreign-newsgroups)
+                      (<= (nth 1 info) gnus-activate-foreign-newsgroups)
+                      (<= (nth 1 info) level)))
+             (or (eq (car (nth 4 info)) 'nnvirtual)
+                 (setq active (gnus-activate-newsgroup (car info)))))
+       (if (and (not gnus-read-active-file)
+                (<= (nth 1 info) level))
+           (progn
+             (setq active (gnus-activate-newsgroup (car info))))))
+      
+      (or active (progn (gnus-sethash group nil gnus-active-hashtb)
+                       (setcar (gnus-gethash group gnus-newsrc-hashtb) t)))
+      (and active (gnus-get-unread-articles-in-group info active))
       (setq newsrc (cdr newsrc)))
     (message "Checking new news... done")))
 
@@ -10016,7 +11750,9 @@ newsgroup."
     ;; number to the group hash table entry.
     (setq range (nth 2 info))
     (setq num 0)
-    (cond ((not range)
+    (cond ((zerop (cdr active))
+          (setq num 0))
+         ((not range)
           (setq num (- (1+ (cdr active)) (car active))))
          ((atom (car range))
           ;; Fix a single (num . num) range according to the
@@ -10046,30 +11782,24 @@ newsgroup."
     (setcar (gnus-gethash (car info) gnus-newsrc-hashtb) num)
     num))
 
-(defun gnus-activate-foreign-newsgroup (info)
-  (and (gnus-check-news-server (nth 4 info))
-       (gnus-activate-newsgroup (car info) (gnus-group-real-name (car info)))))
-
-(defun gnus-activate-newsgroup (group &optional real-group-name)
+(defun gnus-activate-newsgroup (group)
   (let (active)
-    (if (gnus-request-group group)
-       (save-excursion
-         (set-buffer nntp-server-buffer)
-         (goto-char 1)
-         (if (looking-at "[0-9]+ [0-9]+ \\([0-9]+\\) \\([0-9]+\\)")
-             (gnus-sethash group 
-              (setq active
-                    (cons (string-to-int (buffer-substring (match-beginning 1)
-                                                           (match-end 1)))
-                          (string-to-int 
-                           (buffer-substring (match-beginning 2) 
-                                             (match-end 2)))))
-              gnus-active-hashtb))))
+    (and (gnus-request-group group)
+        (save-excursion
+          (set-buffer nntp-server-buffer)
+          (goto-char 1)
+          (and (looking-at "[0-9]+ [0-9]+ \\([0-9]+\\) [0-9]+")
+               (progn
+                 (goto-char (match-beginning 1))
+                 (gnus-sethash 
+                  group (setq active (cons (read (current-buffer))
+                                           (read (current-buffer))))
+                  gnus-active-hashtb)))))
     active))
 
 (defun gnus-update-read-articles 
   (group unread unselected ticked &optional domarks replied expirable killed
-        dormant bookmark)
+        dormant bookmark score)
   "Update the list of read and ticked articles in GROUP using the
 UNREAD and TICKED lists.
 Note: UNSELECTED has to be sorted over `<'."
@@ -10091,11 +11821,12 @@ Note: UNSELECTED has to be sorted over `<'."
       ;; Remove any negative articles numbers.
       (while (and unread (< (car unread) 0))
        (setq unread (cdr unread)))
-      (if (not (and (numberp number) (= 0 number)))
+      (if (not (and (numberp number) (zerop number)))
          (setq unread (nconc unselected unread)))
       ;; Set the number of unread articles in gnus-newsrc-hashtb.
-      (or (eq 'nnvirtual (car gnus-current-select-method))
-         (setcar entry (length unread)))
+;      (or (eq 'nnvirtual (car (gnus-find-method-for-group 
+;                             gnus-newsgroup-name)))
+      (setcar entry (length unread))
       ;; Compute the ranges of read articles by looking at the list of
       ;; unread articles.  
       (while unread
@@ -10115,14 +11846,12 @@ Note: UNSELECTED has to be sorted over `<'."
        (if domarks expirable (cdr (assq 'expire marked)))
        (if domarks killed (cdr (assq 'killed marked)))
        (if domarks dormant (cdr (assq 'dormant marked)))
-       (if domarks bookmark (cdr (assq 'bookmark marked)))))))
+       (if domarks bookmark (cdr (assq 'bookmark marked)))
+       (if domarks score (cdr (assq 'score marked)))))))
 
 (defun gnus-make-articles-unread (group articles)
   "Mark ARTICLES in GROUP as unread."
-  (let ((info (nth 2 (or (gnus-gethash group gnus-newsrc-hashtb)
-                        (gnus-gethash (concat gnus-foreign-group-prefix
-                                              group)
-                                      gnus-newsrc-hashtb)))))
+  (let ((info (nth 2 (gnus-gethash group gnus-newsrc-hashtb))))
     (setcar (nthcdr 2 info)
            (gnus-remove-from-range (nth 2 info) articles))
     (gnus-group-update-group group t)))
@@ -10130,35 +11859,51 @@ Note: UNSELECTED has to be sorted over `<'."
 (defun gnus-read-active-file ()
   "Get active file from NNTP server."
   (gnus-group-set-mode-line)
-  (setq gnus-have-read-active-file t)
-  ;; Make sure a connection to NNTP server is alive.
-  (gnus-check-news-server gnus-select-method)
-  (let ((mesg (format "Reading active file from %s via %s..."
-                     (nth 1 gnus-select-method) (car gnus-select-method))))
-    (message mesg)
-    (if (gnus-request-list gnus-select-method) ; Get active 
-       (save-excursion
-         (set-buffer nntp-server-buffer)
-         (gnus-active-to-gnus-format)
-         (setq gnus-have-read-active-file t)
-         (message "%s...done" mesg))
-      (error "Cannot read active file from NNTP server."))))
+  (let ((methods (cons gnus-select-method gnus-secondary-select-methods)))
+    (setq gnus-have-read-active-file nil)
+    (while methods
+      (let* ((where (nth 1 (car methods)))
+            (mesg (format "Reading active file%s via %s..."
+                          (if (and where (not (zerop (length where))))
+                              (concat " from " where) "")
+                          (car (car methods)))))
+       (message mesg)
+       (if (gnus-request-list (car methods)) ; Get active 
+           (save-excursion
+             (set-buffer nntp-server-buffer)
+             (gnus-active-to-gnus-format 
+              (and gnus-have-read-active-file (car methods)))
+             (setq gnus-have-read-active-file t)
+             (message "%s...done" mesg))
+         (message "Cannot read active file from %s server." 
+                  (car (car methods)))
+         (ding)))
+      (setq methods (cdr methods)))))
 
 ;; rewritten by jwz based on ideas from Rick Sladkey <jrs@world.std.com>
 ;; Further rewrites by lmi.
-(defun gnus-active-to-gnus-format ()
+(defun gnus-active-to-gnus-format (method &optional hashtb)
   "Convert active file format to internal format.
-Lines matching gnus-ignored-newsgroups are ignored."
-  (let ((cur (current-buffer)))
+Lines matching `gnus-ignored-newsgroups' are ignored."
+  (let ((cur (current-buffer))
+       (hashtb (or hashtb 
+                   (if method
+                       gnus-active-hashtb
+                     (setq gnus-active-hashtb
+                           (gnus-make-hashtable 
+                            (count-lines (point-min) (point-max))))))))
     ;; Delete unnecessary lines.
     (goto-char (point-min))
     (delete-matching-lines gnus-ignored-newsgroups)
-    ;; Make large enough hash table.
-    (setq gnus-active-hashtb
-         (gnus-make-hashtable (count-lines (point-min) (point-max))))
+    (and method (not (eq method gnus-select-method))
+        (let ((prefix (gnus-group-prefixed-name "" method)))
+          (goto-char (point-min))
+          (while (and (not (eobp))
+                      (null (insert prefix))
+                      (zerop (forward-line 1))))))
+    (goto-char (point-min))
     ;; Store active file in hashtable.
     (save-restriction
-      (goto-char (point-min))
       (if (or (re-search-forward "\n.\r?$" nil t)
              (goto-char (point-max)))
          (progn
@@ -10169,31 +11914,36 @@ Lines matching gnus-ignored-newsgroups are ignored."
          ;; Suggested by Brian Edmonds <edmonds@cs.ubc.ca>.
          ;; If we want information on moderated groups, we use this
          ;; loop...   
-         (let ((mod-hashtb (make-vector 7 0))
-               group max mod)
-           (while (not (eobp))
-             (setq group (let ((obarray gnus-active-hashtb))
-                           (read cur)))
-             (setq max (read cur))
-             (set group (cons (read cur) max))
-             ;; Enter moderated groups into a list.
-             (if (string= 
-                  (symbol-name  (let ((obarray mod-hashtb)) (read cur)))
-                  "m")
-                 (setq gnus-moderated-list 
-                       (cons (symbol-name group) gnus-moderated-list)))
-             (forward-line 1)))
+         (condition-case ()
+             (let ((mod-hashtb (make-vector 7 0))
+                   group max mod)
+               (while (not (eobp))
+                 (setq group (let ((obarray hashtb))
+                               (read cur)))
+                 (setq max (read cur))
+                 (set group (cons (read cur) max))
+                 ;; Enter moderated groups into a list.
+                 (if (string= 
+                      (symbol-name  (let ((obarray mod-hashtb)) (read cur)))
+                      "m")
+                     (setq gnus-moderated-list 
+                           (cons (symbol-name group) gnus-moderated-list)))
+                 (forward-line 1)))
+           (error 
+            (progn (ding) (message "Possible error in active file."))))
        ;; And if we do not care about moderation, we use this loop,
        ;; which is faster.
-       (let (group max)
-         (while (not (eobp))
-           ;; group gets set to a symbol interned in gnus-active-hashtb
-           ;; (what a hack!!)
-           (setq group (let ((obarray gnus-active-hashtb))
-                         (read cur)))
-           (setq max (read cur))
-           (set group (cons (read cur) max))
-           (forward-line 1)))))))
+       (condition-case ()
+           (let (group max)
+             (while (not (eobp))
+               ;; group gets set to a symbol interned in the hash table
+               ;; (what a hack!!)
+               (setq group (let ((obarray hashtb)) (read cur)))
+               (setq max (read cur))
+               (set group (cons (read cur) max))
+               (forward-line 1)))
+         (error 
+          (progn (ding) (message "Possible error in active file."))))))))
 
 (defun gnus-read-newsrc-file (&optional force)
   "Read startup file.
@@ -10305,7 +12055,7 @@ If FORCE is non-nil, the .newsrc file is read."
 (defun gnus-newsrc-to-gnus-format ()
   "Parse current buffer as .newsrc file."
   ;; We have to re-initialize these variables (except for
-  ;; gnus-killed-list) because quick startup file may contain bogus
+  ;; gnus-killed-list) because the quick startup file may contain bogus
   ;; values.
   (setq gnus-newsrc-options nil)
   (setq gnus-newsrc-options-n-yes nil)
@@ -10449,18 +12199,19 @@ If FORCE is non-nil, the .newsrc file is read."
               (message "Ignoring bogus line %d for %s in %s"
                        line newsgroup (buffer-name))
               (sleep-for 1))))
-         (if read-list
-             (let ((info (nth 2 (gnus-gethash newsgroup gnus-newsrc-hashtb))))
-               (if info
-                   (progn
-                     (setcar (nthcdr 2 info) (nreverse read-list))
-                     (setcar (cdr info) (if subscribe 3 6))
-                     (setq gnus-newsrc-assoc (cons info gnus-newsrc-assoc)))
-                 (setq gnus-newsrc-assoc
-                       (cons (list newsgroup (if subscribe 3 6) 
-                                   (nreverse read-list))
-                             gnus-newsrc-assoc))))
-           (setq gnus-killed-list (cons newsgroup gnus-killed-list)))))
+         ;; We have already read .newsrc.eld, so we gently update the
+         ;; data in the hash table with the information we have just
+         ;; read. 
+         (let ((info (nth 2 (gnus-gethash newsgroup gnus-newsrc-hashtb))))
+           (if info
+               (progn
+                 (setcar (nthcdr 2 info) (nreverse read-list))
+                 (setcar (cdr info) (if subscribe 3 (if read-list 6 7)))
+                 (setq gnus-newsrc-assoc (cons info gnus-newsrc-assoc)))
+             (setq gnus-newsrc-assoc
+                   (cons (list newsgroup (if subscribe 3 (if read-list 6 7))
+                               (nreverse read-list))
+                         gnus-newsrc-assoc))))))
        (setq line (1+ line))
        (forward-line 1))))
   (setq gnus-newsrc-assoc (nreverse gnus-newsrc-assoc))
@@ -10522,13 +12273,13 @@ If FORCE is non-nil, the .newsrc file is read."
     ))
 
 (defun gnus-save-newsrc-file ()
-  "Save to .newsrc FILE."
+  "Save .newsrc file."
   ;; Note: We cannot save .newsrc file if all newsgroups are removed
   ;; from the variable gnus-newsrc-assoc.
   (and (or gnus-newsrc-assoc gnus-killed-list)
        gnus-current-startup-file
        (save-excursion
-        (if (= 0 (save-excursion
+        (if (zerop (save-excursion
                    (set-buffer gnus-dribble-buffer)
                    (buffer-size)))
             (message "(No changes need to be saved)")
@@ -10573,55 +12324,49 @@ If FORCE is non-nil, the .newsrc file is read."
       (setq variable (car variables))
       (and (boundp variable)
           (symbol-value variable)
-          (or gnus-save-killed-list 
-              (not (or (eq variable 'gnus-killed-list)
-                       (eq variable 'gnus-zombie-list))))
+          (or gnus-save-killed-list (not (eq variable 'gnus-killed-list)))
           (insert "(setq " (symbol-name variable) " '"
                   (prin1-to-string (symbol-value variable))
                   ")\n"))
       (setq variables (cdr variables)))))
 
 (defun gnus-gnus-to-newsrc-format ()
+  ;; Generate and save the .newsrc file.
   (let ((newsrc (cdr gnus-newsrc-assoc))
-       group ranges)
+       info ranges range)
     (save-excursion
       (set-buffer (create-file-buffer gnus-startup-file))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
+      ;; Write options.
       (if gnus-newsrc-options (insert "options " gnus-newsrc-options "\n"))
+      ;; Write subscribed and unsubscribed.
       (while newsrc
-       (setq group (car newsrc))
-       (insert (car group) (if (>= (nth 1 group) 6) "!" ":"))
-       (if (setq ranges (nth 2 group))
+       (setq info (car newsrc))
+       (if (not (nth 4 info))          ;Don't write foreign groups to .newsrc.
            (progn
-             (insert " ")
-             (gnus-ranges-to-newsrc-format
-              (if (atom (car ranges)) (list ranges) ranges))))
-       (insert "\n")
+             (insert (car info) (if (>= (nth 1 info) 6) "!" ":"))
+             (if (setq ranges (nth 2 info))
+                 (progn
+                   (insert " ")
+                   (if (atom (car ranges))
+                       (if (= (car ranges) (cdr ranges))
+                           (insert (int-to-string (car ranges)))
+                         (insert (int-to-string (car ranges)) "-" 
+                                 (int-to-string (cdr ranges))))
+                     (while ranges
+                       (setq range (car ranges)
+                             ranges (cdr ranges))
+                       (if (= (car range) (cdr range))
+                           (insert (int-to-string (car range)))
+                         (insert (int-to-string (car range)) "-"
+                                 (int-to-string (cdr range))))
+                       (if ranges (insert ","))))))
+             (insert "\n")))
        (setq newsrc (cdr newsrc)))
       (write-region 1 (point-max) gnus-current-startup-file nil 'nomesg)
       (kill-buffer (current-buffer)))))
 
-(defun gnus-ranges-to-newsrc-format (ranges)
-  "Insert ranges of read articles."
-  (let ((range nil))                   ;Range is a pair of BEGIN and END.
-    (while ranges
-      (setq range (car ranges))
-      (setq ranges (cdr ranges))
-      (cond ((= (car range) (cdr range))
-            (if (= (car range) 0)
-                (setq ranges nil)      ;No unread articles.
-              (insert (int-to-string (car range)))
-              (if ranges (insert ","))
-              ))
-           (t
-            (insert (int-to-string (car range))
-                    "-"
-                    (int-to-string (cdr range)))
-            (if ranges (insert ","))
-            ))
-      )))
-
 (defun gnus-read-descriptions-file ()
   (message "Reading descriptions file...")
   (if (not (gnus-request-list-newsgroups gnus-select-method))
diff --git a/lisp/mhspool.el b/lisp/mhspool.el
deleted file mode 100644 (file)
index 785f253..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-;;; mhspool.el --- MH folder access using NNTP for GNU Emacs
-
-;; Copyright (C) 1988, 1989, 1990, 1993 Free Software Foundation, Inc.
-
-;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
-;; Maintainer: FSF
-;; Keywords: mail, news
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;; This package enables you to read mail or articles in MH folders, or
-;; articles saved by GNUS. In any case, the file names of mail or
-;; articles must consist of only numeric letters.
-
-;; Before using this package, you have to create a server specific
-;; startup file according to the directory which you want to read. For
-;; example, if you want to read mail under the directory named
-;; `~/Mail', the file must be a file named `.newsrc-:Mail'. (There is
-;; no way to specify hierarchical directory now.) In this case, the
-;; name of the NNTP server passed to GNUS must be `:Mail'.
-
-;;; Code:
-
-(require 'nntp)
-
-(defvar mhspool-list-folders-method
-  (function mhspool-list-folders-using-sh)
-  "*Function to list files in folders.
-The function should accept a directory as its argument, and fill the
-current buffer with file and directory names.  The output format must
-be the same as that of 'ls -R1'.  Two functions
-mhspool-list-folders-using-ls and mhspool-list-folders-using-sh are
-provided now.  I suppose the later is faster.")
-
-(defvar mhspool-list-directory-switches '("-R")
-  "*Switches for mhspool-list-folders-using-ls to pass to `ls' for getting file lists.
-One entry should appear on one line. You may need to add `-1' option.")
-
-\f
-
-(defconst mhspool-version "MHSPOOL 1.8"
-  "Version numbers of this version of MHSPOOL.")
-
-(defvar mhspool-spool-directory "~/Mail"
-  "Private mail directory.")
-
-(defvar mhspool-current-directory nil
-  "Current news group directory.")
-
-;;;
-;;; Replacement of Extended Command for retrieving many headers.
-;;;
-
-(defun mhspool-retrieve-headers (sequence)
-  "Return list of article headers specified by SEQUENCE of article id.
-The format of list is
- `([NUMBER SUBJECT FROM XREF LINES DATE MESSAGE-ID REFERENCES] ...)'.
-If there is no References: field, In-Reply-To: field is used instead.
-Reader macros for the vector are defined as `nntp-header-FIELD'.
-Writer macros for the vector are defined as `nntp-set-header-FIELD'.
-Newsgroup must be selected before calling this."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    ;;(erase-buffer)
-    (let ((file nil)
-         (number (length sequence))
-         (count 0)
-         (headers nil)                 ;Result list.
-         (article 0)
-         (subject nil)
-         (message-id nil)
-         (from nil)
-         (xref nil)
-         (lines 0)
-         (date nil)
-         (references nil))
-      (while sequence
-       ;;(nntp-send-strings-to-server "HEAD" (car sequence))
-       (setq article (car sequence))
-       (setq file
-             (concat mhspool-current-directory (prin1-to-string article)))
-       (if (and (file-exists-p file)
-                (not (file-directory-p file)))
-           (progn
-             (erase-buffer)
-             (insert-file-contents file)
-             ;; Make message body invisible.
-             (goto-char (point-min))
-             (search-forward "\n\n" nil 'move)
-             (narrow-to-region (point-min) (point))
-             ;; Fold continuation lines.
-             (goto-char (point-min))
-             (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-               (replace-match " " t t))
-             ;; Make it possible to search for `\nFIELD'.
-             (goto-char (point-min))
-             (insert "\n")
-             ;; Extract From:
-             (goto-char (point-min))
-             (if (search-forward "\nFrom: " nil t)
-                 (setq from (buffer-substring
-                             (point)
-                             (save-excursion (end-of-line) (point))))
-               (setq from "(Unknown User)"))
-             ;; Extract Subject:
-             (goto-char (point-min))
-             (if (search-forward "\nSubject: " nil t)
-                 (setq subject (buffer-substring
-                                (point)
-                                (save-excursion (end-of-line) (point))))
-               (setq subject "(None)"))
-             ;; Extract Message-ID:
-             (goto-char (point-min))
-             (if (search-forward "\nMessage-ID: " nil t)
-                 (setq message-id (buffer-substring
-                                   (point)
-                                   (save-excursion (end-of-line) (point))))
-               (setq message-id nil))
-             ;; Extract Date:
-             (goto-char (point-min))
-             (if (search-forward "\nDate: " nil t)
-                 (setq date (buffer-substring
-                             (point)
-                             (save-excursion (end-of-line) (point))))
-               (setq date nil))
-             ;; Extract Lines:
-             (goto-char (point-min))
-             (if (search-forward "\nLines: " nil t)
-                 (setq lines (string-to-int
-                              (buffer-substring
-                               (point)
-                               (save-excursion (end-of-line) (point)))))
-               ;; Count lines since there is no lines field in most cases.
-               (setq lines
-                     (save-restriction
-                       (goto-char (point-max))
-                       (widen)
-                       (count-lines (point) (point-max)))))
-             ;; Extract Xref:
-             (goto-char (point-min))
-             (if (search-forward "\nXref: " nil t)
-                 (setq xref (buffer-substring
-                             (point)
-                             (save-excursion (end-of-line) (point))))
-               (setq xref nil))
-             ;; Extract References:
-             ;; If no References: field, use In-Reply-To: field instead.
-             ;; Suggested by tanaka@flab.fujitsu.co.jp (Hiroshi TANAKA).
-             (goto-char (point-min))
-             (if (or (search-forward "\nReferences: " nil t)
-                     (search-forward "\nIn-Reply-To: " nil t))
-                 (setq references (buffer-substring
-                                   (point)
-                                   (save-excursion (end-of-line) (point))))
-               (setq references nil))
-             ;; Collect valid article only.
-             (and article
-                  message-id
-                  (setq headers
-                        (cons (vector article subject from
-                                      xref lines date
-                                      message-id references) headers)))
-             ))
-       (setq sequence (cdr sequence))
-       (setq count (1+ count))
-       (and (numberp nntp-large-newsgroup)
-            (> number nntp-large-newsgroup)
-            (zerop (% count 20))
-            (message "MHSPOOL: Receiving headers... %d%%"
-                     (/ (* count 100) number)))
-       )
-      (and (numberp nntp-large-newsgroup)
-          (> number nntp-large-newsgroup)
-          (message "MHSPOOL: Receiving headers... done"))
-      (nreverse headers)
-      )))
-
-\f
-;;;
-;;; Replacement of NNTP Raw Interface.
-;;;
-
-(defun mhspool-open-server (host &optional service)
-  "Open news server on HOST.
-If HOST is nil, use value of environment variable `NNTPSERVER'.
-If optional argument SERVICE is non-nil, open by the service name."
-  (let ((host (or host (getenv "NNTPSERVER")))
-       (status nil))
-    ;; Get directory name from HOST name.
-    (if (string-match ":\\(.+\\)$" host)
-       (progn
-         (setq mhspool-spool-directory
-               (file-name-as-directory
-                (expand-file-name
-                 (substring host (match-beginning 1) (match-end 1))
-                 (expand-file-name "~/" nil))))
-         (setq host (system-name)))
-      (setq mhspool-spool-directory nil))
-    (setq nntp-status-string "")
-    (cond ((and (stringp host)
-               (stringp mhspool-spool-directory)
-               (file-directory-p mhspool-spool-directory)
-               (string-equal host (system-name)))
-          (setq status (mhspool-open-server-internal host service)))
-         ((string-equal host (system-name))
-          (setq nntp-status-string
-                (format "No such directory: %s.  Goodbye."
-                        mhspool-spool-directory)))
-         ((null host)
-          (setq nntp-status-string "NNTP server is not specified."))
-         (t
-          (setq nntp-status-string
-                (format "MHSPOOL: cannot talk to %s." host)))
-         )
-    status
-    ))
-
-(defun mhspool-close-server ()
-  "Close news server."
-  (mhspool-close-server-internal))
-
-(fset 'mhspool-request-quit (symbol-function 'mhspool-close-server))
-
-(defun mhspool-server-opened ()
-  "Return server process status, T or NIL.
-If the stream is opened, return T, otherwise return NIL."
-  (and nntp-server-buffer
-       (get-buffer nntp-server-buffer)))
-
-(defun mhspool-status-message ()
-  "Return server status response as string."
-  nntp-status-string
-  )
-
-(defun mhspool-request-article (id)
-  "Select article by message ID (or number)."
-  (let ((file (concat mhspool-current-directory (prin1-to-string id))))
-    (if (and (stringp file)
-            (file-exists-p file)
-            (not (file-directory-p file)))
-       (save-excursion
-         (mhspool-find-file file)))
-    ))
-
-(defun mhspool-request-body (id)
-  "Select article body by message ID (or number)."
-  (if (mhspool-request-article id)
-      (save-excursion
-       (set-buffer nntp-server-buffer)
-       (goto-char (point-min))
-       (if (search-forward "\n\n" nil t)
-           (delete-region (point-min) (point)))
-       t
-       )
-    ))
-
-(defun mhspool-request-head (id)
-  "Select article head by message ID (or number)."
-  (if (mhspool-request-article id)
-      (save-excursion
-       (set-buffer nntp-server-buffer)
-       (goto-char (point-min))
-       (if (search-forward "\n\n" nil t)
-           (delete-region (1- (point)) (point-max)))
-       t
-       )
-    ))
-
-(defun mhspool-request-stat (id)
-  "Select article by message ID (or number)."
-  (setq nntp-status-string "MHSPOOL: STAT is not implemented.")
-  nil
-  )
-
-(defun mhspool-request-group (group)
-  "Select news GROUP."
-  (cond ((file-directory-p
-         (mhspool-article-pathname group))
-        ;; Mail/NEWS.GROUP/N
-        (setq mhspool-current-directory
-              (mhspool-article-pathname group)))
-       ((file-directory-p
-         (mhspool-article-pathname
-          (mhspool-replace-chars-in-string group ?. ?/)))
-        ;; Mail/NEWS/GROUP/N
-        (setq mhspool-current-directory
-              (mhspool-article-pathname
-               (mhspool-replace-chars-in-string group ?. ?/))))
-       ))
-
-(defun mhspool-request-list ()
-  "List active newsgoups."
-  (save-excursion
-    (let* ((newsgroup nil)
-          (articles nil)
-          (directory (file-name-as-directory
-                      (expand-file-name mhspool-spool-directory nil)))
-          (folder-regexp (concat "^" (regexp-quote directory) "\\(.+\\):$"))
-          (buffer (get-buffer-create " *MHSPOOL File List*")))
-      (set-buffer nntp-server-buffer)
-      (erase-buffer)
-      (set-buffer buffer)
-      (erase-buffer)
-;;      (apply 'call-process
-;;          "ls" nil t nil
-;;          (append mhspool-list-directory-switches (list directory)))
-      (funcall mhspool-list-folders-method directory)
-      (goto-char (point-min))
-      (while (re-search-forward folder-regexp nil t)
-       (setq newsgroup
-             (mhspool-replace-chars-in-string
-              (buffer-substring (match-beginning 1) (match-end 1)) ?/ ?.))
-       (setq articles nil)
-       (forward-line 1)                ;(beginning-of-line)
-       ;; Thank nobu@flab.fujitsu.junet for his bug fixes.
-       (while (and (not (eobp))
-                   (not (looking-at "^$")))
-         (if (looking-at "^[0-9]+$")
-             (setq articles
-                   (cons (string-to-int
-                          (buffer-substring
-                           (match-beginning 0) (match-end 0)))
-                         articles)))
-         (forward-line 1))
-       (if articles
-           (princ (format "%s %d %d n\n" newsgroup
-                          (apply (function max) articles)
-                          (apply (function min) articles))
-                  nntp-server-buffer))
-       )
-      (kill-buffer buffer)
-      (set-buffer nntp-server-buffer)
-      (buffer-size)
-      )))
-
-(defun mhspool-request-list-newsgroups ()
-  "List newsgoups (defined in NNTP2)."
-  (setq nntp-status-string "MHSPOOL: LIST NEWSGROUPS is not implemented.")
-  nil
-  )
-
-(defun mhspool-request-list-distributions ()
-  "List distributions (defined in NNTP2)."
-  (setq nntp-status-string "MHSPOOL: LIST DISTRIBUTIONS is not implemented.")
-  nil
-  )
-
-(defun mhspool-request-last ()
-  "Set current article pointer to the previous article
-in the current news group."
-  (setq nntp-status-string "MHSPOOL: LAST is not implemented.")
-  nil
-  )
-
-(defun mhspool-request-next ()
-  "Advance current article pointer."
-  (setq nntp-status-string "MHSPOOL: NEXT is not implemented.")
-  nil
-  )
-
-(defun mhspool-request-post ()
-  "Post a new news in current buffer."
-  (setq nntp-status-string "MHSPOOL: POST: what do you mean?")
-  nil
-  )
-
-\f
-;;;
-;;; Replacement of Low-Level Interface to NNTP Server.
-;;; 
-
-(defun mhspool-open-server-internal (host &optional service)
-  "Open connection to news server on HOST by SERVICE (default is nntp)."
-  (save-excursion
-    (if (not (string-equal host (system-name)))
-       (error "MHSPOOL: cannot talk to %s." host))
-    ;; Initialize communication buffer.
-    (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
-    (set-buffer nntp-server-buffer)
-    (buffer-disable-undo (current-buffer))
-    (erase-buffer)
-    (kill-all-local-variables)
-    (setq case-fold-search t)          ;Should ignore case.
-    (setq nntp-server-process nil)
-    (setq nntp-server-name host)
-    ;; It is possible to change kanji-fileio-code in this hook.
-    (run-hooks 'nntp-server-hook)
-    t
-    ))
-
-(defun mhspool-close-server-internal ()
-  "Close connection to news server."
-  (if nntp-server-buffer
-      (kill-buffer nntp-server-buffer))
-  (setq nntp-server-buffer nil)
-  (setq nntp-server-process nil))
-
-(defun mhspool-find-file (file)
-  "Insert FILE in server buffer safely."
-  (set-buffer nntp-server-buffer)
-  (erase-buffer)
-  (condition-case ()
-      (progn
-       (insert-file-contents file)
-       (goto-char (point-min))
-       ;; If there is no body, `^L' appears at end of file. Special
-       ;; hack for MH folder.
-       (and (search-forward "\n\n" nil t)
-            (string-equal (buffer-substring (point) (point-max)) "\^L")
-            (delete-char 1))
-       t
-       )
-    (file-error nil)
-    ))
-
-(defun mhspool-article-pathname (group)
-  "Make pathname for GROUP."
-  (concat (file-name-as-directory mhspool-spool-directory) group "/"))
-
-(defun mhspool-replace-chars-in-string (string from to)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))  ;Copy string.
-       (len (length string))
-       (idx 0))
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (if (= (aref string idx) from)
-         (aset string idx to))
-      (setq idx (1+ idx)))
-    string
-    ))
-
-\f
-;; Methods for listing files in folders.
-
-(defun mhspool-list-folders-using-ls (directory)
-  "List files in folders under DIRECTORY using 'ls'."
-  (apply 'call-process
-        "ls" nil t nil
-        (append mhspool-list-directory-switches (list directory))))
-
-;; Basic ideas by tanaka@flab.fujitsu.co.jp (Hiroshi TANAKA)
-
-(defun mhspool-list-folders-using-sh (directory)
-  "List files in folders under DIRECTORY using '/bin/sh'."
-  (let ((buffer (current-buffer))
-       (script (get-buffer-create " *MHSPOOL Shell Script Buffer*")))
-    (save-excursion
-      (save-restriction
-       (set-buffer script)
-       (erase-buffer)
-       ;; /bin/sh script which does 'ls -R'.
-       (insert
-        "PS2=
-          ffind() {
-               cd $1; echo $1:
-               ls -1
-               echo
-               for j in `echo *[a-zA-Z]*`
-               do
-                 if [ -d $1/$j ]; then
-                       ffind $1/$j
-                 fi
-               done
-         }
-         cd " directory "; ffind `pwd`; exit 0\n")
-       (call-process-region (point-min) (point-max) "sh" nil buffer nil)
-       ))
-    (kill-buffer script)
-    ))
-
-(provide 'mhspool)
-
-;;; mhspool.el ends here
diff --git a/lisp/nndir.el b/lisp/nndir.el
new file mode 100644 (file)
index 0000000..479db2a
--- /dev/null
@@ -0,0 +1,156 @@
+;;; nndir.el --- single directory newsgroup access for Gnus
+;; Copyright (C) 1995 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'nnmh)
+(require 'nnml)
+
+\f
+
+(defconst nndir-version "nndir 0.0")
+
+(defvar nndir-current-directory nil
+  "Current news group directory.")
+
+(defvar nndir-status-string "")
+
+(defvar nndir-nov-is-evil nil
+  "*Non-nil means that nndir will never retrieve NOV headers.")
+
+\f
+
+;;; Interface functions.
+
+
+(defun nndir-retrieve-headers (sequence &optional newsgroup server)
+  (nndir-execute-nnml-command
+   '(nnml-retrieve-headers sequence group server) server))
+
+(defun nndir-open-server (host &optional service)
+  "Open nndir backend."
+  (setq nndir-status-string "")
+  (nndir-open-server-internal host service))
+
+(defun nndir-close-server (&optional server)
+  "Close news server."
+  (nndir-close-server-internal))
+
+(defalias 'nndir-request-quit 'nndir-close-server)
+
+(defun nndir-server-opened (&optional server)
+  "Return server process status, T or NIL.
+If the stream is opened, return T, otherwise return NIL."
+  (and nntp-server-buffer
+       (get-buffer nntp-server-buffer)))
+
+(defun nndir-status-message ()
+  "Return server status response as string."
+  nndir-status-string)
+
+(defun nndir-request-article (id &optional newsgroup server buffer)
+  (nndir-execute-nnmh-command
+   '(nnmh-request-article id group server buffer) server))
+
+(defun nndir-request-group (group &optional server dont-check)
+  "Select news GROUP."
+  (nndir-execute-nnmh-command
+   '(nnmh-request-group group "" dont-check) server))
+
+(defun nndir-request-list (&optional server dir)
+  "Get list of active articles in all newsgroups."
+  (nndir-execute-nnmh-command
+   '(nnmh-request-list nil dir) server))
+
+(defun nndir-request-newgroups (date &optional server)
+  (nndir-execute-nnmh-command
+   '(nnmh-request-newgroups date server) server))
+
+(defun nndir-request-post (&optional server)
+  "Post a new news in current buffer."
+  (mail-send-and-exit nil))
+
+(fset 'nndir-request-post-buffer 'nnmail-request-post-buffer)
+
+(defun nndir-request-expire-articles (articles newsgroup &optional server force)
+  "Expire all articles in the ARTICLES list in group GROUP."
+  (setq nndir-status-string "nndir: expire not possible")
+  nil)
+
+(defun nndir-close-group (group &optional server)
+  t)
+
+(defun nndir-request-move-article (article group server accept-form)
+  (setq nndir-status-string "nndir: move not possible")
+  nil)
+
+(defun nndir-request-accept-article (group)
+  (setq nndir-status-string "nndir: accept not possible")
+  nil)
+
+\f
+;;; Low-Level Interface
+
+(defun nndir-open-server-internal (host &optional service)
+  "Open connection to news server on HOST by SERVICE."
+  (save-excursion
+    ;; Initialize communication buffer.
+    (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
+    (set-buffer nntp-server-buffer)
+    (buffer-disable-undo (current-buffer))
+    (erase-buffer)
+    (kill-all-local-variables)
+    (setq case-fold-search t)          ;Should ignore case.
+    t))
+
+(defun nndir-close-server-internal ()
+  "Close connection to news server."
+  nil)
+
+(defun nndir-execute-nnmh-command (command server)
+  (let ((dir (expand-file-name server)))
+    (and (string-match "/$" dir)
+        (setq dir (substring dir 0 (match-beginning 0))))
+    (string-match "/[^/]+$" dir)
+    (let ((group (substring dir (1+ (match-beginning 0))))
+         (nnmh-directory (substring dir 0 (1+ (match-beginning 0))))
+         (nnmh-get-new-mail nil))
+      (eval command))))
+
+(defun nndir-execute-nnml-command (command server)
+  (let ((dir (expand-file-name server)))
+    (and (string-match "/$" dir)
+        (setq dir (substring dir 0 (match-beginning 0))))
+    (string-match "/[^/]+$" dir)
+    (let ((group (substring dir (1+ (match-beginning 0))))
+         (nnml-directory (substring dir 0 (1+ (match-beginning 0))))
+         (nnml-nov-is-evil nndir-nov-is-evil)
+         (nnml-get-new-mail nil))
+      (eval command))))
+
+(provide 'nndir)
+
+;;; nndir.el ends here
index 4933b91..be3b998 100644 (file)
 ;; Various cruft the backends and Gnus need to communicate.
 
 (defvar nntp-server-buffer nil)
-(defvar gnus-backends-are-talkative t
+(defvar gnus-verbose-backends t
   "*If non-nil, Gnus backends will generate lots of comments.")
+(defvar gnus-nov-is-evil nil
+  "If non-nil, Gnus backends will never output headers in the NOV format.")
 (defvar news-reply-yank-from nil)
 (defvar news-reply-yank-message-id nil)
 
index 9862eef..91ef62d 100644 (file)
@@ -1,8 +1,7 @@
-;;; nnmail.el --- mail mbox access for Gnus
+;;; nnmail.el --- mail support functions for the Gnus mail backends
 ;; Copyright (C) 1995 Free Software Foundation, Inc.
 
 ;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
-;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;; Keywords: news, mail
 
 ;; This file is part of GNU Emacs.
@@ -27,6 +26,7 @@
 
 (require 'nnheader)
 (require 'rmail)
+(require 'timezone)
 
 (defvar nnmail-split-methods
   '(("mail.misc" ""))
   "If non-nil, do crossposting if several split methods match the mail.
 If nil, the first match found will be used.")
 
-(defvar nnmail-mbox-file (expand-file-name "~/mbox")
-  "The name of the mail box file in the users home directory.")
-
-(defvar nnmail-active-file (expand-file-name "~/.mbox-active")
-  "The name of the active file for the mail box.")
-
 (defvar nnmail-expiry-wait 7
   "Articles that are older than `nnmail-expiry-wait' days will be expired.")
 
-;; Quote fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
 (defvar nnmail-expiry-wait-function nil
   "Variable that holds funtion to specify how old articles should be before they are expired.
   The function will be called with the name of the group that the
@@ -65,7 +58,9 @@ Eg.:
 
 (defvar nnmail-spool-file 
   (or (getenv "MAIL")
-      (concat "/usr/spool/mail/" (user-login-name))))
+      (concat "/usr/spool/mail/" (user-login-name)))
+  "Where the mail backends will look for incoming mail.
+If this variable is nil, no mail backends will read incoming mail.")
 
 (defvar nnmail-read-incoming-hook nil
   "Hook that will be run after the incoming mail has been transferred.
@@ -89,156 +84,21 @@ Eg.
 The hook is run in a buffer with all the new, incoming mail.")
 
 (defvar nnmail-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
+  "The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
 messages will be shown to indicate the current status.")
 
 \f
 
-(defconst nnmail-version "nnmail 0.1"
+(defconst nnmail-version "nnml 0.0"
   "nnmail version.")
 
-(defvar nnmail-current-group nil
-  "Current nnmail news group directory.")
-
-(defconst nnmail-mbox-buffer "*nnmail mbox buffer*")
-
-(defvar nnmail-active-alist nil)
-
-(defvar nnmail-status-string "")
-
-;;; Interface functions
-
-(defun nnmail-retrieve-headers (sequence &optional newsgroup server)
-  "Retrieve the headers for the articles in SEQUENCE.
-Newsgroup must be selected before calling this function."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    (let ((file nil)
-         (number (length sequence))
-         (count 0)
-         beg article art-string start stop)
-      (nnmail-possibly-change-newsgroup newsgroup)
-      (while sequence
-       (setq article (car sequence))
-       (setq art-string (nnmail-article-string article))
-       (set-buffer nnmail-mbox-buffer)
-       (if (or (search-forward art-string nil t)
-               (progn (goto-char 1)
-                      (search-forward art-string nil t)))
-           (progn
-             (setq start 
-                   (save-excursion
-                     (re-search-backward 
-                      (concat "^" rmail-unix-mail-delimiter) nil t)
-                     (point)))
-             (search-forward "\n\n" nil t)
-             (setq stop (1- (point)))
-             (set-buffer nntp-server-buffer)
-             (insert (format "221 %d Article retrieved.\n" article))
-             (setq beg (point))
-             (insert-buffer-substring nnmail-mbox-buffer start stop)
-             (goto-char (point-max))
-             (insert ".\n")))
-       (setq sequence (cdr sequence))
-       (setq count (1+ count))
-       (and (numberp nnmail-large-newsgroup)
-            (> number nnmail-large-newsgroup)
-            (zerop (% count 20))
-            (message "NNMAIL: Receiving headers... %d%%"
-                     (/ (* count 100) number))))
-
-      (and (numberp nnmail-large-newsgroup)
-          (> number nnmail-large-newsgroup)
-          (message "NNMAIL: Receiving headers... done"))
-
-      ;; Fold continuation lines.
-      (goto-char 1)
-      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-       (replace-match " " t t))
-      'headers)))
-
-(defun nnmail-open-server (host &optional service)
-  "Open mbox backend."
-  (setq nnmail-status-string "")
-  (nnmail-open-server-internal host service))
-
-(defun nnmail-close-server (&optional server)
-  "Close news server."
-  (nnmail-close-server-internal))
-
-(fset 'nnmail-request-quit (symbol-function 'nnmail-close-server))
-
-(defun nnmail-server-opened (&optional server)
-  "Return server process status, T or NIL.
-If the stream is opened, return T, otherwise return NIL."
-  (and nntp-server-buffer
-       (get-buffer nntp-server-buffer)))
-
-(defun nnmail-status-message ()
-  "Return server status response as string."
-  nnmail-status-string)
-
-(defun nnmail-request-article (article &optional newsgroup server buffer)
-  "Select ARTICLE by number."
-  (nnmail-possibly-change-newsgroup newsgroup)
-  (if (stringp article)
-      nil
-    (save-excursion
-      (set-buffer nnmail-mbox-buffer)
-      (goto-char 1)
-      (if (search-forward (nnmail-article-string article) nil t)
-         (let (start stop)
-           (re-search-backward (concat "^" rmail-unix-mail-delimiter) nil t)
-           (setq start (point))
-           (forward-line 1)
-           (or (and (re-search-forward 
-                     (concat "^" rmail-unix-mail-delimiter) nil t)
-                    (forward-line -1))
-               (goto-char (point-max)))
-           (setq stop (point))
-           (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
-             (set-buffer nntp-server-buffer)
-             (erase-buffer)
-             (insert-buffer-substring nnmail-mbox-buffer start stop)
-             t))))))
-
-(defun nnmail-request-group (group &optional server dont-check)
-  "Select news GROUP."
-  (if (nnmail-possibly-change-newsgroup group)
-      (if dont-check
-         t
-       (nnmail-get-new-mail)
-       (save-excursion
-         (set-buffer nntp-server-buffer)
-         (erase-buffer)
-         (let ((active (assoc group nnmail-active-alist)))
-           (insert (format "211 %d %d %d %s\n" 
-                           (1+ (- (cdr (car (cdr active)))
-                                  (car (car (cdr active)))))
-                           (car (car (cdr active)))
-                           (cdr (car (cdr active)))
-                           (car active))))
-         t))))
-
-(defun nnmail-request-list (&optional server)
-  "List active newsgoups."
-  (nnmail-find-file nnmail-active-file))
-
-(defun nnmail-request-list-newsgroups (&optional server)
-  "List newsgroups (defined in NNTP2)."
-  (setq nnmail-status-string "NNMAIL: LIST NEWSGROUPS is not implemented.")
-  nil)
-
-(defun nnmail-request-post (&optional server)
-  "Post a new news in current buffer."
-  (mail-send-and-exit nil))
+\f
 
 (defun nnmail-request-post-buffer (method header article-buffer group info)
-  (let ((method-address (nth 1 (nth 4 info)))
+  (let ((method-address (cdr (assq 'to-address (nth 4 info))))
        from subject date to reply-to message-of
-       references message-id sender follow-to)
+       references message-id sender follow-to cc)
     (setq method-address
          (if (and (stringp method-address) 
                   (string= method-address ""))
@@ -247,7 +107,6 @@ If the stream is opened, return T, otherwise return NIL."
       (set-buffer (get-buffer-create "*mail*"))
       (mail-mode)
       (local-set-key "\C-c\C-c" 'gnus-mail-send-and-exit)
-      (local-set-key "\C-c\C-y" 'gnus-mail-yank-original)
       (if (and (buffer-modified-p)
               (> (buffer-size) 0)
               (not (y-or-n-p "Unsent mail being composed; erase it? ")))
@@ -273,6 +132,8 @@ If the stream is opened, return T, otherwise return NIL."
                         (concat (if stop-pos (substring from 0 stop-pos) from)
                                 "'s message of " date))))
            (setq sender (mail-fetch-field "sender"))
+           (setq cc (mail-fetch-field "cc"))
+           (setq to (mail-fetch-field "to"))
            (setq subject (header-subject header))
            (or (string-match "^[Rr][Ee]:" subject)
                (setq subject (concat "Re: " subject)))
@@ -282,7 +143,10 @@ If the stream is opened, return T, otherwise return NIL."
            (widen))
          (setq news-reply-yank-from from)
          (setq news-reply-yank-message-id message-id)
-         (mail-setup (or follow-to method-address sender reply-to from)
+         (mail-setup (or follow-to method-address 
+                         (concat (or sender reply-to from "")
+                                 (if to (concat ", " to) "")
+                                 (if cc (concat ", " cc) "")))
                      subject message-of nil article-buffer nil)
          ;; Fold long references line to follow RFC1036.
          (mail-position-on-field "References")
@@ -298,160 +162,121 @@ If the stream is opened, return T, otherwise return NIL."
          ))
       (current-buffer))))
 
-(defun nnmail-request-expire-articles (articles newsgroup &optional server force)
-  "Expire all articles in the ARTICLES list in group GROUP.
-The list of unexpired articles will be returned (ie. all articles that
-were too fresh to be expired).
-If FORCE is non-nil, the ARTICLES will be deleted without looking at
-the date."
-  (nnmail-possibly-change-newsgroup newsgroup)
-  (let* ((days (or (and nnmail-expiry-wait-function
-                       (funcall nnmail-expiry-wait-function newsgroup))
-                  nnmail-expiry-wait))
-        (cur-time (current-time))
-        (day-sec (* 24 60 60 days))
-        (day-time (list nil nil))
-        mod-time article rest)
-    (setcar day-time (/ day-sec 65536))
-    (setcar (cdr day-time) (- day-sec (* (car day-time) 65536)))
-    (if (< (car (cdr cur-time)) (car (cdr day-time)))
-       (progn
-         (setcar day-time (+ 1 (- (car cur-time) (car day-time))))
-         (setcar (cdr day-time) (- (+ 65536 (car (cdr cur-time)))
-                                   (car (cdr day-time)))))
-      (setcar day-time (- (car cur-time) (car day-time)))
-      (setcar (cdr day-time) (- (car (cdr cur-time)) (car (cdr day-time)))))
-    (save-excursion 
-      (set-buffer nnmail-mbox-buffer)
-      (while articles
-       (goto-char 1)
-       (if (and (search-forward (nnmail-article-string (car articles)) nil t)
-                (or force
-                    (setq mod-time (read (current-buffer)))
-                    (or (< (car mod-time) (car day-time))
-                        (and (= (car mod-time) (car day-time))
-                             (< (car (cdr mod-time)) (car (cdr day-time)))))))
-           (progn
-             (message "Deleting: %s" article)
-             (nnmail-delete-mail))
-         (setq rest (cons (car articles) rest)))
-       (setq articles (cdr articles)))
-      (save-buffer)
-      rest)))
-
-(defun nnmail-request-move-article (article group server accept-form)
-  (let ((buf (get-buffer-create " *nnmail move*"))
-       result)
-    (and 
-     (nnmail-request-article article group server)
-     (save-excursion
-       (set-buffer buf)
-       (insert-buffer-substring nntp-server-buffer)
-       (goto-char (point-min))
-       (if (re-search-forward 
-           "^X-Gnus-Newsgroup:" 
-           (save-excursion (search-forward "\n\n" nil t) (point)) t)
-          (delete-region (progn (beginning-of-line) (point))
-                         (progn (forward-line 1) (point))))
-       (setq result (eval accept-form))
-       (kill-buffer (current-buffer))
-       result)
-     (save-excursion
-       (set-buffer nnmail-mbox-buffer)
-       (goto-char 1)
-       (if (search-forward (nnmail-article-string article) nil t)
-          (nnmail-delete-mail))
-       (save-buffer)))
-    result))
-
-(defun nnmail-request-accept-article (group)
-  (let ((buf (current-buffer))
-       result beg)
-    (and 
-     (nnmail-get-active)
-     (save-excursion
-       (set-buffer nnmail-mbox-buffer)
-       (setq beg (goto-char (point-max)))
-       (insert-buffer-substring buf)
-       (goto-char beg)
-       (if (stringp group)
-          (progn
-            (search-forward "\n\n" nil t)
-            (forward-line -1)
-            (save-excursion
-              (while (re-search-backward "^X-Gnus-Newsgroup: " beg t)
-                (delete-region
-                 (point)
-                 (progn
-                   (forward-line 1)
-                   (point)))))
-            (setq result (nnmail-insert-newsgroup-line group beg (point))))
-        (setq result (nnmail-choose-mail beg (point-max))))
-       (save-buffer)
-       result)
-     (nnmail-save-active))
-    result))
-
-\f
-;;; Low-Level Interface
-
-(defun nnmail-delete-mail ()
-  (re-search-backward (concat "^" rmail-unix-mail-delimiter) nil t)
-  (delete-region 
-   (point)
-   (progn
-     (forward-line 1)
-     (or (and (re-search-forward 
-              (concat "^" rmail-unix-mail-delimiter) nil t)
-             (forward-line -1)
-             (point))
-        (point-max)))))
-
-(defun nnmail-open-server-internal (host &optional service)
-  "Open connection to news server on HOST by SERVICE (default is nntp)."
-  (save-excursion
-    (if (not (string-equal host (system-name)))
-       (error "NNMAIL: cannot talk to %s." host))
-    ;; Initialize communication buffer.
-    (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
-    (set-buffer nntp-server-buffer)
-    (buffer-disable-undo (current-buffer))
-    (erase-buffer)
-    (kill-all-local-variables)
-    (setq case-fold-search t)          ;Should ignore case.
-    t))
-
-(defun nnmail-close-server-internal ()
-  "Close connection to news server."
-  nil)
-
 (defun nnmail-find-file (file)
   "Insert FILE in server buffer safely."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    (condition-case ()
-       (progn (insert-file-contents file) t)
-      (file-error nil))))
-
-(defun nnmail-possibly-change-newsgroup (newsgroup)
-  (if (not (get-buffer nnmail-mbox-buffer))
-      (save-excursion
-       (set-buffer (setq nnmail-mbox-buffer 
-                         (find-file-noselect nnmail-mbox-file)))
-       (buffer-disable-undo (current-buffer))))
-  (if (not nnmail-active-alist)
-      (nnmail-get-active))
-  (if newsgroup
-      (if (assoc newsgroup nnmail-active-alist)
-         (setq nnmail-current-group newsgroup))))
-
-;; Most of this function was taken from rmail.el
-(defun nnmail-move-inbox ()
-  (let ((inbox (expand-file-name nnmail-spool-file))
-       tofile errors)
-    (setq tofile (make-temp-name
-                 (expand-file-name (concat nnmail-mbox-file "-Incoming"))))
+  (set-buffer nntp-server-buffer)
+  (erase-buffer)
+  (condition-case ()
+      (progn (insert-file-contents file) t)
+    (file-error nil)))
+
+(defun nnmail-article-pathname (group mail-dir)
+  "Make pathname for GROUP."
+  (concat (file-name-as-directory (expand-file-name mail-dir))
+         (nnmail-replace-chars-in-string group ?. ?/) "/"))
+
+(defun nnmail-replace-chars-in-string (string from to)
+  "Replace characters in STRING from FROM to TO."
+  (let ((string (substring string 0))  ;Copy string.
+       (len (length string))
+       (idx 0))
+    ;; Replace all occurrences of FROM with TO.
+    (while (< idx len)
+      (if (= (aref string idx) from)
+         (aset string idx to))
+      (setq idx (1+ idx)))
+    string))
+
+(defun nnmail-days-between (date1 date2)
+  ;; Return the number of days between date1 and date2.
+  (let ((d1 (mapcar (lambda (s) (and s (string-to-int s)) )
+                   (timezone-parse-date date1)))
+       (d2 (mapcar (lambda (s) (and s (string-to-int s)) )
+                   (timezone-parse-date date2))))
+    (- (timezone-absolute-from-gregorian 
+       (nth 1 d1) (nth 2 d1) (car d1))
+       (timezone-absolute-from-gregorian 
+       (nth 1 d2) (nth 2 d2) (car d2)))))
+
+;; Function taken from rmail.el.
+(defun nnmail-move-inbox (inbox tofile)
+  (let ((inbox (file-truename
+               (expand-file-name (substitute-in-file-name inbox))))
+       (tofile (make-temp-name (expand-file-name tofile)))
+       movemail popmail errors)
+    ;; If getting from mail spool directory,
+    ;; use movemail to move rather than just renaming,
+    ;; so as to interlock with the mailer.
+    (setq movemail (string= (file-name-directory inbox)
+                           (file-truename rmail-spool-directory))
+         popmail (string-match "^po:" (file-name-nondirectory inbox)))
+    (if popmail (setq inbox (file-name-nondirectory inbox)))
+    (if movemail
+       ;; On some systems, /usr/spool/mail/foo is a directory
+       ;; and the actual inbox is /usr/spool/mail/foo/foo.
+       (if (file-directory-p inbox)
+           (setq inbox (expand-file-name (user-login-name) inbox))))
+    (if popmail
+       (message "Getting mail from post office ...")
+      (if (or (and (file-exists-p tofile)
+                  (/= 0 (nth 7 (file-attributes tofile))))
+             (and (file-exists-p inbox)
+                  (/= 0 (nth 7 (file-attributes inbox)))))
+         (message "Getting mail from %s..." inbox)))
+    ;; Set TOFILE if have not already done so, and
+    ;; rename or copy the file INBOX to TOFILE if and as appropriate.
+    (cond ((or (file-exists-p tofile) (and (not popmail)
+                                          (not (file-exists-p inbox))))
+          nil)
+         ((and (not movemail) (not popmail))
+          ;; Try copying.  If that fails (perhaps no space),
+          ;; rename instead.
+          (condition-case nil
+              (copy-file inbox tofile nil)
+            (error
+             ;; Third arg is t so we can replace existing file TOFILE.
+             (rename-file inbox tofile t)))
+          ;; Make the real inbox file empty.
+          ;; Leaving it deleted could cause lossage
+          ;; because mailers often won't create the file.
+          (condition-case ()
+              (write-region (point) (point) inbox)
+            (file-error nil)))
+         (t
+          (unwind-protect
+              (save-excursion
+                (setq errors (generate-new-buffer " *nnmail loss*"))
+                (buffer-disable-undo errors)
+                (call-process
+                 (expand-file-name "movemail" exec-directory)
+                 nil errors nil inbox tofile)
+                (if (not (buffer-modified-p errors))
+                    ;; No output => movemail won
+                    nil
+                  (set-buffer errors)
+                  (subst-char-in-region (point-min) (point-max)
+                                        ?\n ?\  )
+                  (goto-char (point-max))
+                  (skip-chars-backward " \t")
+                  (delete-region (point) (point-max))
+                  (goto-char (point-min))
+                  (if (looking-at "movemail: ")
+                      (delete-region (point-min) (match-end 0)))
+                  (beep t)
+                  (message (concat "movemail: "
+                                   (buffer-substring (point-min)
+                                                     (point-max))))
+                  (sit-for 3)
+                  nil)))))
+    (if (buffer-name errors)
+       (kill-buffer errors))
+    tofile))
+
+
+(defun nnmail-move-inbox-old (inbox tofile)
+  (let ((inbox (expand-file-name inbox))
+       (tofile (make-temp-name (expand-file-name tofile)))
+       errors)
     (unwind-protect
        (save-excursion
          (setq errors (generate-new-buffer " *nnmail loss*"))
@@ -473,162 +298,163 @@ the date."
            (error (concat "movemail: "
                           (buffer-substring (point-min)
                                             (point-max)))))))
+    (if (buffer-name errors)
+       (kill-buffer errors))
     tofile))
 
-(defun nnmail-article-string (article)
-  (concat "\nX-Gnus-Newsgroup: " nnmail-current-group ":" 
-         (int-to-string article) " ("))
-
-(defun nnmail-choose-mail (beg end)
-  (let (result)
-    (save-excursion
-      (goto-char end)
-      (let ((methods nnmail-split-methods)
-           found)
-       (while (and (not found) methods)
-         (if (re-search-backward (car (cdr (car methods))) beg t)
-             (progn
-               (goto-char end)
-               (setq result (nnmail-insert-newsgroup-line 
-                             (car (car methods)) beg end))
-               (setq found t))
-           (setq methods (cdr methods))))
-       (if (not found)
-           (progn
-             (goto-char end)
-             (setq result (nnmail-insert-newsgroup-line 
-                           (car (car nnmail-split-methods)) beg end))))))
-    result))
-
-(defun nnmail-insert-newsgroup-line (group beg end)
-  (let ((active (car (cdr (assoc group nnmail-active-alist))))
-       (time (current-time)))
-    (if (not active)
-       (progn
-         (setq nnmail-active-alist 
-               (cons (list group (cons 1 0)) nnmail-active-alist))
-         (setq active (car (cdr (car nnmail-active-alist))))))
-    (setcdr active (1+ (cdr active)))
-    (insert (format "X-Gnus-Newsgroup: %s:%d (%d %d)\n" group (cdr active)
-                   (car time) (car (cdr time))))
-    (cons group (cdr active))))
-
-(defun nnmail-split-region (beg end)
-  (save-excursion
-    (save-restriction
-      (goto-char beg)
-      (narrow-to-region beg end)
-      (let ((delim (concat "^" rmail-unix-mail-delimiter))
-           start)
-       (while (re-search-forward delim nil t)
-         (setq start (match-beginning 0))
-         (search-forward "\n\n" nil t)
-         (forward-char -1)
-         (save-excursion
-           (if (not (save-excursion (re-search-backward "^Lines:" start t)))
-               (insert 
-                (format "Lines: %d\n" 
-                        (- (count-lines 
-                            (point) 
-                            (or (save-excursion
-                                  (and (re-search-forward
-                                        rmail-unix-mail-delimiter nil t)
-                                       (match-beginning 0)))
-                                (point-max)))
-                           2)))))
-         (if (not (search-backward "\nX-Gnus-Newsgroup: " start t))
-             (nnmail-choose-mail start (point))))))))
-
-(defun nnmail-read-mbox ()
-  (if (not (file-exists-p nnmail-mbox-file))
-      (write-region 1 1 nnmail-mbox-file t 'nomesg))
-  (if (and nnmail-mbox-buffer
-          (get-buffer nnmail-mbox-buffer)
-          (buffer-name nnmail-mbox-buffer)
-          (save-excursion
-            (set-buffer nnmail-mbox-buffer)
-            (= (buffer-size) (nth 7 (file-attributes nnmail-mbox-file)))))
-      ()
-    (save-excursion
-      (set-buffer (setq nnmail-mbox-buffer 
-                       (find-file-noselect nnmail-mbox-file)))
-      (buffer-disable-undo (current-buffer))
-      (nnmail-split-region (point-min) (point-max)))))
-
-(defun nnmail-split-incoming (incoming)
-  (save-excursion
-    (set-buffer nnmail-mbox-buffer)
-    (goto-char (point-max))
-    (let ((start (point)))
-      (insert-file-contents incoming)
-      (save-excursion
-       (save-restriction
-         (narrow-to-region start (point-max))
-         (run-hooks 'nnmail-prepare-incoming-hook)))
-      (nnmail-split-region start (point-max)))))
-
 (defun nnmail-get-active ()
-  (let ((methods nnmail-split-methods))
-    (setq nnmail-active-alist nil)
-    (if (nnmail-request-list)
-       (save-excursion
-         (set-buffer (get-buffer-create " *nntpd*"))
-         (goto-char 1)
-         (while (re-search-forward 
-                 "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
-           (setq nnmail-active-alist 
-                 (cons (list (buffer-substring (match-beginning 1) 
-                                               (match-end 1))
-                             (cons (string-to-int 
-                                    (buffer-substring (match-beginning 3)
-                                                      (match-end 3)))
-                                   (string-to-int 
-                                    (buffer-substring (match-beginning 2)
-                                                      (match-end 2)))))
-                       nnmail-active-alist)))))
-    (while methods
-      (if (not (assoc (car (car methods)) nnmail-active-alist))
-         (setq nnmail-active-alist
-               (cons (list (car (car methods)) (cons 1 0)) 
-                     nnmail-active-alist)))
-      (setq methods (cdr methods)))
-    t))
-
-(defun nnmail-save-active ()
-  (let ((groups nnmail-active-alist)
-       group)
+  "Returns an assoc of group names and active ranges.
+nn*-request-list should have been called before calling this function."
+  (let (group-assoc)
+    ;; Go through all groups from the active list.
     (save-excursion
-      (set-buffer (get-buffer-create " *nnmail*"))
+      (set-buffer nntp-server-buffer)
+      (goto-char 1)
+      (while (re-search-forward 
+             "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
+       (setq group-assoc
+             (cons (list (buffer-substring (match-beginning 1) 
+                                           (match-end 1))
+                         (cons (string-to-int 
+                                (buffer-substring (match-beginning 3)
+                                                  (match-end 3)))
+                               (string-to-int 
+                                (buffer-substring (match-beginning 2)
+                                                  (match-end 2)))))
+                   group-assoc))))
+    ;; In addition, add all groups mentioned in `nnmail-split-methods'.
+    (let ((methods nnmail-split-methods))
+      (while methods
+       (if (not (assoc (car (car methods)) group-assoc))
+           (setq group-assoc
+                 (cons (list (car (car methods)) (cons 1 0)) 
+                       group-assoc)))
+       (setq methods (cdr methods))))
+    group-assoc))
+
+(defun nnmail-save-active (group-assoc file-name)
+  (let (group)
+    (save-excursion
+      (set-buffer (get-buffer-create " *nnmail active*"))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (while groups
-       (setq group (car groups))
+      (while group-assoc
+       (setq group (car group-assoc))
        (insert (format "%s %d %d y\n" (car group) (cdr (car (cdr group)) )
                        (car (car (cdr group)))))
-       (setq groups (cdr groups)))
-      (write-region 1 (point-max) (expand-file-name nnmail-active-file) nil 
-                   'nomesg)
+       (setq group-assoc (cdr group-assoc)))
+      (write-region 1 (point-max) (expand-file-name file-name) nil 'nomesg)
       (kill-buffer (current-buffer)))))
 
-(defun nnmail-get-new-mail ()
-  (let (incoming)
-    (nnmail-get-active)
-    (nnmail-read-mbox)
-    (if (and (file-exists-p nnmail-spool-file)
-            (> (nth 7 (file-attributes nnmail-spool-file)) 0))
+(defun nnmail-split-incoming (incoming func &optional dont-kill)
+  "Go through the entire INCOMING file and pick out each individual mail.
+FUNC will be called with the buffer narrowed to each mail."
+  (let ((delim (concat "^" rmail-unix-mail-delimiter))
+       start)
+    (save-excursion
+      (set-buffer (get-buffer-create " *nnmail incoming*"))
+      (buffer-disable-undo (current-buffer))
+      (erase-buffer)
+      (insert-file-contents incoming)
+      (goto-char 1)
+      (save-excursion (run-hooks 'nnmail-prepare-incoming-hook))
+      ;; Go to the beginning of the first mail...
+      (if (and (re-search-forward delim nil t)
+              (goto-char (match-beginning 0)))
+         ;; and then carry on until the bitter end.
+         (while (not (eobp))
+           (setq start (point))
+           ;; Skip all the headers in case there are mode "From "s...
+           (if (not (search-forward "\n\n" nil t))
+               (forward-line 1))
+           (if (re-search-forward delim nil t)
+               (goto-char (match-beginning 0))
+             (goto-char (point-max)))
+           (save-excursion
+             (save-restriction
+               (narrow-to-region start (point))
+               (goto-char (point-min))
+               (funcall func)))))
+      (if dont-kill
+         (current-buffer)
+       (kill-buffer (current-buffer))))))
+
+;; Mail crossposts syggested by Brian Edmonds <edmonds@cs.ubc.ca>. 
+(defun nnmail-article-group (func)
+  "Look at the headers and return an alist of groups that match.
+FUNC will be called with the group name to determine the article number."
+  (let ((methods nnmail-split-methods)
+       (obuf (current-buffer))
+       (beg (point-min))
+       end found group-art)
+    (save-excursion
+      ;; Find headers.
+      (goto-char beg)
+      (setq end (if (search-forward "\n\n" nil t) (point) (point-max)))
+      (set-buffer (get-buffer-create " *nnmail work*"))
+      (buffer-disable-undo (current-buffer))
+      (erase-buffer)
+      ;; Copy the headers into the work buffer.
+      (insert-buffer-substring obuf beg end)
+      ;; Fold continuation lines.
+      (goto-char (point-min))
+      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+       (replace-match " " t t))
+      ;; Go throught the split methods to find a match.
+      (while (and methods (or nnmail-crosspost (not group-art)))
+       (goto-char (point-max))
+       (if (or (cdr methods)
+               (not (string= "" (nth 1 (car methods)))))
+           (if (and (condition-case () 
+                        (re-search-backward (car (cdr (car methods))) nil t)
+                      (error nil))
+                    ;; Don't enter the article into the same group twice.
+                    (not (assoc (car (car methods)) group-art)))
+               (setq group-art
+                     (cons (cons (car (car methods))
+                                 (funcall func (car (car methods)))) 
+                           group-art)))
+         (or group-art
+             (setq group-art 
+                   (list (cons (car (car methods)) 
+                               (funcall func (car (car methods))))))))
+       (setq methods (cdr methods)))
+      (kill-buffer (current-buffer))
+      group-art)))
+
+(defun nnmail-insert-lines ()
+  "Insert how many lines and chars there are in the body of the mail."
+  (let (lines chars)
+    (save-excursion
+      (goto-char (point-min))
+      (if (search-forward "\n\n" nil t) 
+         (progn
+           (setq chars (- (point-max) (point)))
+           (setq lines (- (count-lines (point) (point-max)) 1))
+           (forward-char -1)
+           (save-excursion
+             (if (re-search-backward "^Lines: " nil t)
+                 (delete-region (point) (progn (forward-line 1) (point)))))
+           (insert (format "Lines: %d\n" lines))
+           chars)))))
+
+(defun nnmail-insert-xref (group-alist)
+  "Insert an Xref line based on the (group . article) alist."
+  (save-excursion
+    (goto-char (point-min))
+    (if (search-forward "\n\n" nil t) 
        (progn
-         (setq incoming (nnmail-move-inbox))
-         (nnmail-split-incoming incoming)
-         (run-hooks 'nnmail-read-incoming-hook)))
-    (and (buffer-modified-p nnmail-mbox-buffer) 
-        (save-excursion
-          (nnmail-save-active)
-          (set-buffer nnmail-mbox-buffer)
-          (save-buffer)))
-;    (if incoming
-;      (delete-file incoming))
-    ))
+         (forward-char -1)
+         (if (re-search-backward "^Xref: " nil t)
+             (delete-region (match-beginning 0) 
+                            (progn (forward-line 1) (point))))
+         (insert (format "Xref: %s" (system-name)))
+         (while group-alist
+           (insert (format " %s:%d" (car (car group-alist)) 
+                           (cdr (car group-alist))))
+           (setq group-alist (cdr group-alist)))
+         (insert "\n")))))
 
 (provide 'nnmail)
 
-;;; nnmail.el ends here
+;;; nnml.el ends here
diff --git a/lisp/nnmbox.el b/lisp/nnmbox.el
new file mode 100644 (file)
index 0000000..3c3a88c
--- /dev/null
@@ -0,0 +1,428 @@
+;;; nnmbox.el --- mail mbox access for Gnus
+;; Copyright (C) 1995 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
+;;     Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
+;; Keywords: news, mail
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnheader)
+(require 'rmail)
+(require 'nnmail)
+
+(defvar nnmbox-mbox-file (expand-file-name "~/mbox")
+  "The name of the mail box file in the users home directory.")
+
+(defvar nnmbox-active-file (expand-file-name "~/.mbox-active")
+  "The name of the active file for the mail box.")
+
+(defvar nnmbox-get-new-mail t
+  "If non-nil, nnml will check the incoming mail file and split the mail.")
+
+\f
+
+(defconst nnmbox-version "nnmbox 0.1"
+  "nnmbox version.")
+
+(defvar nnmbox-current-group nil
+  "Current nnmbox news group directory.")
+
+(defconst nnmbox-mbox-buffer " *nnmbox mbox buffer*")
+
+(defvar nnmbox-status-string "")
+
+(defvar nnmbox-group-alist nil)
+
+;;; Interface functions
+
+(defun nnmbox-retrieve-headers (sequence &optional newsgroup server)
+  "Retrieve the headers for the articles in SEQUENCE.
+Newsgroup must be selected before calling this function."
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    (erase-buffer)
+    (let ((file nil)
+         (number (length sequence))
+         (count 0)
+         beg article art-string start stop)
+      (nnmbox-possibly-change-newsgroup newsgroup)
+      (while sequence
+       (setq article (car sequence))
+       (setq art-string (nnmbox-article-string article))
+       (set-buffer nnmbox-mbox-buffer)
+       (if (or (search-forward art-string nil t)
+               (progn (goto-char 1)
+                      (search-forward art-string nil t)))
+           (progn
+             (setq start 
+                   (save-excursion
+                     (re-search-backward 
+                      (concat "^" rmail-unix-mail-delimiter) nil t)
+                     (point)))
+             (search-forward "\n\n" nil t)
+             (setq stop (1- (point)))
+             (set-buffer nntp-server-buffer)
+             (insert (format "221 %d Article retrieved.\n" article))
+             (setq beg (point))
+             (insert-buffer-substring nnmbox-mbox-buffer start stop)
+             (goto-char (point-max))
+             (insert ".\n")))
+       (setq sequence (cdr sequence))
+       (setq count (1+ count))
+       (and (numberp nnmail-large-newsgroup)
+            (> number nnmail-large-newsgroup)
+            (zerop (% count 20))
+            gnus-verbose-backends
+            (message "nnmbox: Receiving headers... %d%%"
+                     (/ (* count 100) number))))
+
+      (and (numberp nnmail-large-newsgroup)
+          (> number nnmail-large-newsgroup)
+          gnus-verbose-backends
+          (message "nnmbox: Receiving headers... done"))
+
+      ;; Fold continuation lines.
+      (goto-char 1)
+      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+       (replace-match " " t t))
+      'headers)))
+
+(defun nnmbox-open-server (host &optional service)
+  "Open mbox backend."
+  (setq nnmbox-status-string "")
+  (nnmbox-open-server-internal host service))
+
+(defun nnmbox-close-server (&optional server)
+  "Close news server."
+  (nnmbox-close-server-internal))
+
+(fset 'nnmbox-request-quit (symbol-function 'nnmbox-close-server))
+
+(defun nnmbox-server-opened (&optional server)
+  "Return server process status, T or NIL.
+If the stream is opened, return T, otherwise return NIL."
+  (and nntp-server-buffer
+       (get-buffer nntp-server-buffer)))
+
+(defun nnmbox-status-message ()
+  "Return server status response as string."
+  nnmbox-status-string)
+
+(defun nnmbox-request-article (article &optional newsgroup server buffer)
+  "Select ARTICLE by number."
+  (nnmbox-possibly-change-newsgroup newsgroup)
+  (if (stringp article)
+      nil
+    (save-excursion
+      (set-buffer nnmbox-mbox-buffer)
+      (goto-char 1)
+      (if (search-forward (nnmbox-article-string article) nil t)
+         (let (start stop)
+           (re-search-backward (concat "^" rmail-unix-mail-delimiter) nil t)
+           (forward-line 1)
+           (setq start (point))
+           (or (and (re-search-forward 
+                     (concat "^" rmail-unix-mail-delimiter) nil t)
+                    (forward-line -1))
+               (goto-char (point-max)))
+           (setq stop (point))
+           (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
+             (set-buffer nntp-server-buffer)
+             (erase-buffer)
+             (insert-buffer-substring nnmbox-mbox-buffer start stop)
+             t))))))
+
+(defun nnmbox-request-group (group &optional server dont-check)
+  "Select news GROUP."
+  (save-excursion
+    (if (nnmbox-possibly-change-newsgroup group)
+       (if dont-check
+           t
+         (nnmbox-get-new-mail)
+         (save-excursion
+           (set-buffer nntp-server-buffer)
+           (erase-buffer)
+           (let ((active (assoc group nnmbox-group-alist)))
+             (insert (format "211 %d %d %d %s\n" 
+                             (1+ (- (cdr (car (cdr active)))
+                                    (car (car (cdr active)))))
+                             (car (car (cdr active)))
+                             (cdr (car (cdr active)))
+                             (car active))))
+           t)))))
+
+(defun nnmbox-close-group (group &optional server)
+  t)
+
+(defun nnmbox-request-list (&optional server)
+  "List active newsgoups."
+  (if server (nnmbox-get-new-mail))
+  (nnmail-find-file nnmbox-active-file))
+
+(defun nnmbox-request-newgroups (date &optional server)
+  "List groups created after DATE."
+  (nnmbox-request-list server))
+
+(defun nnmbox-request-list-newsgroups (&optional server)
+  "List newsgroups (defined in NNTP2)."
+  (setq nnmbox-status-string "nnmbox: LIST NEWSGROUPS is not implemented.")
+  nil)
+
+(defun nnmbox-request-post (&optional server)
+  "Post a new news in current buffer."
+  (mail-send-and-exit nil))
+
+(fset 'nnmbox-request-post-buffer 'nnmbox-request-post-buffer)
+
+(defun nnmbox-request-expire-articles (articles newsgroup &optional server force)
+  "Expire all articles in the ARTICLES list in group GROUP.
+The list of unexpired articles will be returned (ie. all articles that
+were too fresh to be expired).
+If FORCE is non-nil, the ARTICLES will be deleted without looking at
+the date."
+  (nnmbox-possibly-change-newsgroup newsgroup)
+  (let* ((days (or (and nnmail-expiry-wait-function
+                       (funcall nnmail-expiry-wait-function newsgroup))
+                  nnmail-expiry-wait))
+        article rest)
+    (save-excursion 
+      (set-buffer nnmbox-mbox-buffer)
+      (while articles
+       (goto-char 1)
+       (if (search-forward (nnmbox-article-string (car articles)) nil t)
+           (if (or force
+                   (> (nnmail-days-between 
+                       (current-time-string)
+                       (buffer-substring 
+                        (point) (progn (end-of-line) (point))))
+                      days))
+               (progn
+                 (and gnus-verbose-backends
+                      (message "Deleting: %s" (car articles)))
+                 (nnmbox-delete-mail))
+             (setq rest (cons (car articles) rest))))
+       (setq articles (cdr articles)))
+      (save-buffer)
+      rest)))
+
+(defun nnmbox-request-move-article (article group server accept-form)
+  (let ((buf (get-buffer-create " *nnmbox move*"))
+       result)
+    (and 
+     (nnmbox-request-article article group server)
+     (save-excursion
+       (set-buffer buf)
+       (insert-buffer-substring nntp-server-buffer)
+       (goto-char (point-min))
+       (if (re-search-forward 
+           "^X-Gnus-Newsgroup:" 
+           (save-excursion (search-forward "\n\n" nil t) (point)) t)
+          (delete-region (progn (beginning-of-line) (point))
+                         (progn (forward-line 1) (point))))
+       (setq result (eval accept-form))
+       (kill-buffer (current-buffer))
+       result)
+     (save-excursion
+       (set-buffer nnmbox-mbox-buffer)
+       (goto-char 1)
+       (if (search-forward (nnmbox-article-string article) nil t)
+          (nnmbox-delete-mail))
+       (save-buffer)))
+    result))
+
+(defun nnmbox-request-accept-article (group)
+  (let ((buf (current-buffer))
+       result beg)
+    (and 
+     (setq nnmbox-group-alist (nnmail-get-active))
+     (save-excursion
+       (set-buffer nnmbox-mbox-buffer)
+       (setq beg (goto-char (point-max)))
+       (insert-buffer-substring buf)
+       (goto-char beg)
+       (if (stringp group)
+          (progn
+            (search-forward "\n\n" nil t)
+            (forward-line -1)
+            (save-excursion
+              (while (re-search-backward "^X-Gnus-Newsgroup: " beg t)
+                (delete-region (point) (progn (forward-line 1) (point)))))
+            (setq result (nnmbox-insert-newsgroup-line group)))
+        (setq result (nnmbox-save-mail)))
+       (save-buffer)
+       result)
+     (nnmail-save-active nnmbox-group-alist nnmbox-active-file))
+    result))
+
+\f
+;;; Low-Level Interface
+
+(defun nnmbox-delete-mail ()
+  ;; Delete the current X-Gnus-Newsgroup line.
+  (delete-region
+   (progn (beginning-of-line) (point))
+   (progn (forward-line 1) (point)))
+  ;; Beginning of the article.
+  (save-excursion
+    (save-restriction
+      (narrow-to-region
+       (save-excursion
+        (re-search-backward (concat "^" rmail-unix-mail-delimiter) nil t)
+        (match-beginning 0))
+       (progn
+        (re-search-forward (concat "^" rmail-unix-mail-delimiter) nil t)
+        (match-beginning 0)))
+      (goto-char (point-min))
+      ;; Only delete the article if no other groups owns it as well.
+      (if (not (re-search-forward "^X-Gnus-Newsgroup: " nil t))
+         (delete-region (point-min) (point-max))))))
+
+(defun nnmbox-open-server-internal (host &optional service)
+  "Open connection to news server on HOST by SERVICE (default is nntp)."
+  (save-excursion
+    (if (not (string-equal host (system-name)))
+       (error "nnmbox: cannot talk to %s." host))
+    ;; Initialize communication buffer.
+    (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
+    (set-buffer nntp-server-buffer)
+    (buffer-disable-undo (current-buffer))
+    (erase-buffer)
+    (kill-all-local-variables)
+    (setq case-fold-search t)          ;Should ignore case.
+    (setq nnmbox-group-alist nil)
+    t))
+
+(defun nnmbox-close-server-internal ()
+  "Close connection to news server."
+  nil)
+
+(defun nnmbox-possibly-change-newsgroup (newsgroup)
+  (if (not (get-buffer nnmbox-mbox-buffer))
+      (save-excursion
+       (set-buffer (setq nnmbox-mbox-buffer 
+                         (find-file-noselect nnmbox-mbox-file)))
+       (buffer-disable-undo (current-buffer))))
+  (if (not nnmbox-group-alist)
+      (setq nnmbox-group-alist (nnmail-get-active)))
+  (if newsgroup
+      (if (assoc newsgroup nnmbox-group-alist)
+         (setq nnmbox-current-group newsgroup))))
+
+(defun nnmbox-article-string (article)
+  (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":" 
+         (int-to-string article)))
+
+(defun nnmbox-save-mail ()
+  "Called narrowed to an article."
+  (let ((group-art (nreverse (nnmail-article-group 'nnmbox-active-number))))
+    (nnmail-insert-lines)
+    (nnmail-insert-xref group-art)
+    (nnmbox-insert-newsgroup-line group-art)))
+
+(defun nnmbox-insert-newsgroup-line (group-art)
+  (save-excursion
+    (goto-char (point-min))
+    (if (search-forward "\n\n" nil t)
+       (progn
+         (forward-char -1)
+         (while group-art
+           (insert (format "X-Gnus-Newsgroup: %s:%d   %s\n" 
+                           (car (car group-art)) (cdr (car group-art))
+                           (current-time-string)))
+           (setq group-art (cdr group-art)))))))
+
+(defun nnmbox-active-number (group)
+  "Find the next article number in GROUP."
+  (let ((active (car (cdr (assoc group nnmbox-group-alist)))))
+    (setcdr active (1+ (cdr active)))
+    (cdr active)))
+
+(defun nnmbox-read-mbox ()
+  (nnmbox-request-list)
+  (setq nnmbox-group-alist (nnmail-get-active))
+  (if (not (file-exists-p nnmbox-mbox-file))
+      (write-region 1 1 nnmbox-mbox-file t 'nomesg))
+  (if (and nnmbox-mbox-buffer
+          (get-buffer nnmbox-mbox-buffer)
+          (buffer-name nnmbox-mbox-buffer)
+          (save-excursion
+            (set-buffer nnmbox-mbox-buffer)
+            (= (buffer-size) (nth 7 (file-attributes nnmbox-mbox-file)))))
+      ()
+    (save-excursion
+      (let ((delim (concat "^" rmail-unix-mail-delimiter))
+           start end)
+       (set-buffer (setq nnmbox-mbox-buffer 
+                         (find-file-noselect nnmbox-mbox-file)))
+       (buffer-disable-undo (current-buffer))
+       (goto-char (point-min))
+       (while (re-search-forward delim nil t)
+         (setq start (match-beginning 0))
+         (if (not (search-forward "\nX-Gnus-Newsgroup: " 
+                                  (save-excursion 
+                                    (setq end
+                                          (or
+                                           (and
+                                            (re-search-forward delim nil t)
+                                            (match-beginning 0))
+                                           (point-max))))
+                                  t))
+             (save-excursion
+               (save-restriction
+                 (narrow-to-region start end)
+                 (nnmbox-save-mail))))
+         (goto-char end))))))
+
+(defun nnmbox-get-new-mail ()
+  (let (incoming)
+    (nnmbox-read-mbox)
+    (if (and nnmail-spool-file
+            (file-exists-p nnmail-spool-file)
+            (> (nth 7 (file-attributes nnmail-spool-file)) 0))
+       (progn
+         (and gnus-verbose-backends
+              (message "nnmbox: Reading incoming mail..."))
+         (setq incoming 
+               (nnmail-move-inbox nnmail-spool-file
+                                  (concat nnmbox-mbox-file "-Incoming")))
+         (save-excursion
+           (let ((in-buf (nnmail-split-incoming 
+                          incoming 'nnmbox-save-mail t)))
+             (set-buffer nnmbox-mbox-buffer)
+             (goto-char (point-max))
+             (insert-buffer-substring in-buf)
+             (kill-buffer in-buf)))
+         (run-hooks 'nnmail-read-incoming-hook)
+         (and gnus-verbose-backends
+              (message "nnmbox: Reading incoming mail...done"))))
+    (and (buffer-modified-p nnmbox-mbox-buffer) 
+        (save-excursion
+          (nnmail-save-active nnmbox-group-alist nnmbox-active-file)
+          (set-buffer nnmbox-mbox-buffer)
+          (save-buffer)))
+;    (if incoming
+;      (delete-file incoming))
+    ))
+
+(provide 'nnmbox)
+
+;;; nnmbox.el ends here
index 23f5a0a..492c3c2 100644 (file)
@@ -1,4 +1,4 @@
-;;; nnmh.el --- mail spool access for Gnus
+;;; nnmh.el --- mail spool access for Gnus (mhspool)
 ;; Copyright (C) 1995 Free Software Foundation, Inc.
 
 ;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
 (require 'gnus)
 
 (defvar nnmh-directory "~/Mail/"
-  "*Mail directory.")
+  "Mail directory.")
 
-(defvar nnmh-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
-If the number of the articles is greater than the value, verbose
-messages will be shown to indicate the current status.")
+(defvar nnmh-get-new-mail t
+  "If non-nil, nnmh will check the incoming mail file and split the mail.")
 
 \f
 
@@ -50,6 +48,8 @@ messages will be shown to indicate the current status.")
 
 (defvar nnmh-status-string "")
 
+(defvar nnmh-group-alist nil)
+
 \f
 
 ;;; Interface functions.
@@ -84,15 +84,15 @@ Newsgroup must be selected before calling this function."
              (delete-region (point) (point-max))))
        (setq sequence (cdr sequence))
        (setq count (1+ count))
-       (and (numberp nnmh-large-newsgroup)
-            (> number nnmh-large-newsgroup)
+       (and (numberp nnmail-large-newsgroup)
+            (> number nnmail-large-newsgroup)
             (zerop (% count 20))
-            (message "NNMH: Receiving headers... %d%%"
+            (message "nnmh: Receiving headers... %d%%"
                      (/ (* count 100) number))))
 
-      (and (numberp nnmh-large-newsgroup)
-          (> number nnmh-large-newsgroup)
-          (message "NNMH: Receiving headers... done"))
+      (and (numberp nnmail-large-newsgroup)
+          (> number nnmail-large-newsgroup)
+          (message "nnmh: Receiving headers... done"))
 
       ;; Fold continuation lines.
       (goto-char 1)
@@ -101,11 +101,9 @@ Newsgroup must be selected before calling this function."
       'headers)))
 
 (defun nnmh-open-server (host &optional service)
-  "Open news server on HOST.
-If HOST is nil, use value of environment variable `NNTPSERVER'.
-If optional argument SERVICE is non-nil, open by the service name."
+  "Open nnmh mail backend."
   (setq nnmh-status-string "")
-  (nnmail-open-server-internal host service))
+  (nnmh-open-server-internal host service))
 
 (defun nnmh-close-server (&optional server)
   "Close news server."
@@ -134,19 +132,18 @@ If the stream is opened, return T, otherwise return NIL."
             (file-exists-p file)
             (not (file-directory-p file)))
        (save-excursion
-         (nnmh-find-file file)))))
+         (nnmail-find-file file)))))
 
 (defun nnmh-request-group (group &optional server dont-check)
   "Select news GROUP."
-  (if (not dont-check)
-      (nnmh-get-new-mail))
-  (let ((pathname (nnmh-article-pathname group))
+  (and nnmh-get-new-mail (or dont-check (nnmh-get-new-mail)))
+  (let ((pathname (nnmail-article-pathname group nnmh-directory))
        dir)
     (if (file-directory-p pathname)
        (progn
          (setq nnmh-current-directory pathname)
-         (nnmh-update-gnus-unreads group)
-         (if (not dont-check)
+         (and nnmh-get-new-mail (nnmh-update-gnus-unreads group))
+         (or dont-check
              (progn
                (setq dir 
                      (sort
@@ -171,11 +168,13 @@ If the stream is opened, return T, otherwise return NIL."
 
 (defun nnmh-request-list (&optional server dir)
   "Get list of active articles in all newsgroups."
+  (and server nnmh-get-new-mail (nnmh-get-new-mail))
   (or dir
       (save-excursion
        (set-buffer nntp-server-buffer)
        (erase-buffer)
        (setq dir nnmh-directory)))
+  (setq dir (expand-file-name dir))
   ;; Recurse down all directories.
   (let ((dirs (directory-files dir t nil t)))
     (while dirs 
@@ -185,23 +184,26 @@ If the stream is opened, return T, otherwise return NIL."
          (nnmh-request-list server (car dirs)))
       (setq dirs (cdr dirs))))
   ;; For each directory, generate an active file line.
-  (if (not (string= (expand-file-name nnmh-directory) (expand-file-name dir)))
+  (if (not (string= (expand-file-name nnmh-directory) dir))
       (let ((files (mapcar
-                   (function
-                    (lambda (name)
-                      (string-to-int name)))
+                   (lambda (name) (string-to-int name))
                    (directory-files dir nil "^[0-9]+$" t))))
        (save-excursion
          (set-buffer nntp-server-buffer)
-         (insert (format "%s %d %d y\n" 
-                         (progn
-                           (string-match 
-                            (expand-file-name nnmh-directory) dir)
-                           (nnmh-replace-chars-in-string
-                            (substring (expand-file-name dir)
-                                       (match-end 0)) ?/ ?.))
-                         (if files (apply (function max) files) 0)
-                         (if files (apply (function min) files) 0)))))))
+         (insert 
+          (format 
+           "%s %d %d y\n" 
+           (progn
+             (string-match (expand-file-name nnmh-directory) dir)
+             (nnmail-replace-chars-in-string
+              (substring dir (match-end 0)) ?/ ?.))
+           (if files (apply (function max) files) 0)
+           (if files (apply (function min) files) 0))))))
+  t)
+
+(defun nnmh-request-newgroups (date &optional server)
+  "List groups created after DATE."
+  (nnmh-request-list server))
 
 (defun nnmh-request-post (&optional server)
   "Post a new news in current buffer."
@@ -218,27 +220,16 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   (let* ((days (or (and nnmail-expiry-wait-function
                        (funcall nnmail-expiry-wait-function newsgroup))
                   nnmail-expiry-wait))
-        (cur-time (current-time))
-        (day-sec (* 24 60 60 days))
-        (day-time (list nil nil))
-        mod-time article rest)
-    (setcar day-time (/ day-sec 65536))
-    (setcar (cdr day-time) (- day-sec (* (car day-time) 65536)))
-    (if (< (car (cdr cur-time)) (car (cdr day-time)))
-       (progn
-         (setcar day-time (+ 1 (- (car cur-time) (car day-time))))
-         (setcar (cdr day-time) (- (+ 65536 (car (cdr cur-time)))
-                                   (car (cdr day-time)))))
-      (setcar day-time (- (car cur-time) (car day-time)))
-      (setcar (cdr day-time) (- (car (cdr cur-time)) (car (cdr day-time)))))
+        article rest mod-time)
     (while articles
       (setq article (concat nnmh-current-directory (int-to-string
-                                                     (car articles))))
+                                                   (car articles))))
       (if (setq mod-time (nth 5 (file-attributes article)))
          (if (or force
-                 (< (car mod-time) (car day-time))
-                 (and (= (car mod-time) (car day-time))
-                      (< (car (cdr mod-time)) (car (cdr day-time)))))
+                 (> (nnmail-days-between
+                     (current-time-string)
+                     (current-time-string mod-time))
+                    days))
              (progn
                (message "Deleting %s..." article)
                (condition-case ()
@@ -248,6 +239,9 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
       (setq articles (cdr articles)))
     rest))
 
+(defun nnmh-close-group (group &optional server)
+  t)
+
 (defun nnmh-request-move-article (article group server accept-form)
   (let ((buf (get-buffer-create " *nnmh move*"))
        result)
@@ -266,19 +260,18 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
  result))
 
 (defun nnmh-request-accept-article (group)
-  (let (result)
-    (if (stringp group)
-       (and 
-        (nnmh-get-active)
-        ;; We trick the choosing function into believing that only one
-        ;; group is availiable.  
-        (let ((nnmail-split-methods '(group "")))
-          (setq result 
-                (cons group (nnmh-choose-mail (point-min) (point-max))))))
-      (and
-       (nnmh-get-active)
-       (setq result (nnmh-choose-mail (point-min) (point-max)))))
-    result))
+  (if (stringp group)
+      (and 
+       (nnmh-request-list)
+       (setq nnmh-group-alist (nnmail-get-active))
+       ;; We trick the choosing function into believing that only one
+       ;; group is availiable.  
+       (let ((nnmail-split-methods '(group "")))
+        (cons group (nnmh-save-mail))))
+    (and
+     (nnmh-request-list)
+     (setq nnmh-group-alist (nnmail-get-active))
+     (nnmh-save-mail))))
 
 \f
 ;;; Low-Level Interface
@@ -299,43 +292,18 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Close connection to news server."
   nil)
 
-(defun nnmh-find-file (file)
-  "Insert FILE in server buffer safely."
-  (set-buffer nntp-server-buffer)
-  (erase-buffer)
-  (condition-case ()
-      (progn (insert-file-contents file) t)
-    (file-error nil)))
-
 (defun nnmh-possibly-change-directory (newsgroup)
   (if newsgroup
-      (let ((pathname (nnmh-article-pathname newsgroup)))
+      (let ((pathname (nnmail-article-pathname newsgroup nnmh-directory)))
        (if (file-directory-p pathname)
            (setq nnmh-current-directory pathname)
          (error "No such newsgroup: %s" newsgroup)))))
 
-(defun nnmh-article-pathname (group)
-  "Make pathname for GROUP."
-  (concat (file-name-as-directory (expand-file-name nnmh-directory))
-         (nnmh-replace-chars-in-string group ?. ?/) "/"))
-
-(defun nnmh-replace-chars-in-string (string from to)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))  ;Copy string.
-       (len (length string))
-       (idx 0))
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (if (= (aref string idx) from)
-         (aset string idx to))
-      (setq idx (1+ idx)))
-    string))
-
 (defun nnmh-create-directories ()
   (let ((methods nnmail-split-methods)
        dir dirs)
     (while methods
-      (setq dir (nnmh-article-pathname (car (car methods))))
+      (setq dir (nnmail-article-pathname (car (car methods)) nnmh-directory))
       (while (not (file-directory-p dir))
        (setq dirs (cons dir dirs))
        (setq dir (file-name-directory (directory-file-name dir))))
@@ -346,173 +314,40 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
        (setq dirs (cdr dirs)))
       (setq methods (cdr methods)))))
 
-;; Most of this function was taken from rmail.el
-(defun nnmh-move-inbox ()
-  (let ((inbox (expand-file-name nnmail-spool-file))
-       tofile errors)
-    (setq tofile (make-temp-name
-                 (expand-file-name (concat nnmh-directory "Incoming"))))
-    (unwind-protect
-       (save-excursion
-         (setq errors (generate-new-buffer " *nnmh loss*"))
-         (buffer-disable-undo errors)
-         (call-process
-          (expand-file-name "movemail" exec-directory)
-          nil errors nil inbox tofile)
-         (if (not (buffer-modified-p errors))
-             ;; No output => movemail won
-             nil
-           (set-buffer errors)
-           (subst-char-in-region (point-min) (point-max) ?\n ?\  )
-           (goto-char (point-max))
-           (skip-chars-backward " \t")
-           (delete-region (point) (point-max))
-           (goto-char (point-min))
-           (if (looking-at "movemail: ")
-               (delete-region (point-min) (match-end 0)))
-           (error (concat "movemail: "
-                          (buffer-substring (point-min)
-                                            (point-max)))))))
-    (if (buffer-name errors)
-       (kill-buffer errors))
-    tofile))
-
-(defvar nnmh-newsgroups nil)
-
-(defun nnmh-get-active ()
-  (let ((methods nnmail-split-methods))
-    (setq nnmh-newsgroups nil)
-    (if (nnmh-request-list)
-       (save-excursion
-         (set-buffer (get-buffer-create " *nntpd*"))
-         (goto-char 1)
-         (while (re-search-forward 
-                 "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
-           (setq nnmh-newsgroups 
-                 (cons (list (buffer-substring (match-beginning 1) 
-                                               (match-end 1))
-                             (cons (string-to-int 
-                                    (buffer-substring (match-beginning 3)
-                                                      (match-end 3)))
-                                   (string-to-int 
-                                    (buffer-substring (match-beginning 2)
-                                                      (match-end 2)))))
-                       nnmh-newsgroups)))))
-    (while methods
-      (if (not (assoc (car (car methods)) nnmh-newsgroups))
-         (setq nnmh-newsgroups
-               (cons (list (car (car methods)) (cons 1 0)) 
-                     nnmh-newsgroups)))
-      (setq methods (cdr methods)))
-    t))
-
-(defun nnmh-split-incoming (incoming)
-  "Go through the entire INCOMING file and pick out each individual mail."
-  (let (start)
-    (nnmh-get-active)
-    (save-excursion
-      (set-buffer (get-buffer-create "*(ding) Gnus mail*"))
-      (buffer-disable-undo (current-buffer))
-      (erase-buffer)
-      (insert-file-contents incoming)
-      (goto-char 1)
-      (save-excursion
-       (run-hooks 'nnmail-prepare-incoming-hook))
-      ;; Go to the beginning of the first mail...
-      (if (and (re-search-forward (concat "^" rmail-unix-mail-delimiter) nil t)
-              (goto-char (match-beginning 0)))
-         ;; and then carry on until the bitter end.
-         (while (not (eobp))
-           (setq start (point))
-           ;; Skip all the headers in case there are mode "From "s...
-           (if (not (search-forward "\n\n" nil t))
-               (forward-line 1))
-           (if (re-search-forward 
-                (concat "^" rmail-unix-mail-delimiter) nil t)
-               (goto-char (match-beginning 0))
-             (goto-char (point-max)))
-           (nnmh-choose-mail start (point))))
-      (kill-buffer (current-buffer)))))
-
-;; Mail crossposts syggested by Brian Edmonds <edmonds@cs.ubc.ca>. 
-(defun nnmh-article-group (beg end)
-  (let ((methods nnmail-split-methods)
-       found group-art)
-    (save-excursion
-      (save-restriction
-       (narrow-to-region beg end)
-       (while methods
-         (goto-char (point-max))
-         (if (or (cdr methods)
-                 (not (string= "" (nth 1 (car methods)))))
-             (if (re-search-backward (car (cdr (car methods))) nil t)
-                 (setq group-art
-                       (cons 
-                        (cons (car (car methods))
-                              (nnmh-active-number (car (car methods))))
-                        group-art)))
-           (or group-art
-               (setq group-art 
-                     (list (cons (car (car methods)) 
-                                 (nnmh-active-number (car (car methods))))))))
-         (setq methods (cdr methods)))
-       group-art))))
-
-(defun nnmh-choose-mail (beg end)
-  "Find out what mail group the mail between BEG and END belongs in."
-  (let ((group-art (nreverse (nnmh-article-group beg end)))
-       lines)
-    (save-excursion
-      (save-restriction
-       (narrow-to-region beg end)
-       ;; First fix headers.
-       (goto-char (point-min))
-       (save-excursion
-         (save-restriction
-           (narrow-to-region (point)
-                             (progn (search-forward "\n\n" nil t) 
-                                    (setq lines (- (count-lines 
-                                                    (point) (point-max)) 1))
-                                    (1- (point))))
-           ;; Insert Lines.
-           (if (not (save-excursion (re-search-backward "^Lines:" beg t)))
-               (insert (format "Lines: %d\n" lines)))
-           ;; Make an Xref header.
-           (save-excursion
-             (goto-char (point-max))
-             (if (re-search-backward "^Xref:" nil t)
-                 (delete-region (match-beginning 0) 
-                                (progn (forward-line 1) (point)))))
-           (insert (format "Xref: %s" (system-name)))
-           (let ((ga group-art))
-             (while ga
-               (insert (format " %s:%d" (car (car ga)) (cdr (car ga))))
-               (setq ga (cdr ga))))
-           (insert "\n")))
-       ;; Then we actually save the article.
-       (let ((ga group-art)
-             first)
-         (while ga
-           (let ((file (concat (nnmh-article-pathname 
-                                (car (car ga)))
-                               (int-to-string (cdr (car ga))))))
-             (if first
-                 ;; It was already saved, so we just make a hard link.
-                 (add-name-to-file first file t)
-               ;; Save the article.
-               (write-region (point-min) (point-max) file nil nil)
-               (sleep-for 1)
-               (setq first file)))
-           (setq ga (cdr ga))))
-       group-art))))
+(defun nnmh-save-mail ()
+  "Called narrowed to an article."
+  (let ((group-art (nreverse (nnmail-article-group 'nnmh-active-number)))
+       chars nov-line lines hbeg hend)
+    (setq chars (nnmail-insert-lines))
+    (nnmail-insert-xref group-art)
+    (goto-char (point-min))
+    (while (looking-at "From ")
+      (replace-match "X-From-Line: ")
+      (forward-line 1))
+    ;; We save the article in all the newsgroups it belongs in.
+    (let ((ga group-art)
+         first)
+      (while ga
+       (let ((file (concat (nnmail-article-pathname 
+                            (car (car ga)) nnmh-directory) 
+                           (int-to-string (cdr (car ga))))))
+         (if first
+             ;; It was already saved, so we just make a hard link.
+             (add-name-to-file first file t)
+           ;; Save the article.
+           (write-region (point-min) (point-max) file nil nil)
+           (setq first file)))
+       (setq ga (cdr ga))))
+    group-art))
 
 (defun nnmh-active-number (group)
   "Compute the next article number in GROUP."
-  (let ((active (car (cdr (assoc group nnmh-newsgroups)))))
+  (let ((active (car (cdr (assoc group nnmh-group-alist)))))
     (setcdr active (1+ (cdr active)))
     (let (file)
       (while (file-exists-p
-             (setq file (concat (nnmh-article-pathname group)
+             (setq file (concat (nnmail-article-pathname 
+                                 group nnmh-directory)
                                 (int-to-string (cdr active)))))
        (setcdr active (1+ (cdr active)))))
     (cdr active)))
@@ -521,12 +356,17 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Read new incoming mail."
   (let (incoming)
     (nnmh-create-directories)
-    (if (and (file-exists-p nnmail-spool-file)
+    (if (and nnmh-get-new-mail nnmail-spool-file
+            (file-exists-p nnmail-spool-file)
             (> (nth 7 (file-attributes nnmail-spool-file)) 0))
        (progn
          (message "nnmh: Reading incoming mail...")
-         (setq incoming (nnmh-move-inbox))
-         (nnmh-split-incoming incoming)
+         (setq incoming 
+               (nnmail-move-inbox nnmail-spool-file
+                                  (concat nnmh-directory "Incoming")))
+         (nnmh-request-list)
+         (setq nnmh-group-alist (nnmail-get-active))
+         (nnmail-split-incoming incoming 'nnmh-save-mail)
          (run-hooks 'nnmail-read-incoming-hook)
 ;;         (delete-file incoming)
          (message "nnmh: Reading incoming mail...done")))))
@@ -581,8 +421,10 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
                    articles))
        (setq n (cdr n))))
     ;; Make Gnus mark all new articles as unread.
-    (save-excursion
-      (gnus-make-articles-unread group (setq new (sort new '<))))
+    (or (zerop (length new))
+       (gnus-make-articles-unread 
+        (gnus-group-prefixed-name group (list 'nnmh ""))
+        (setq new (sort new '<))))
     ;; Sort the article list with highest numbers first.
     (setq articles (sort articles (lambda (art1 art2) 
                                    (> (car art1) (car art2)))))
index d48f853..202b6bd 100644 (file)
 ;;; Code:
 
 (require 'nnheader)
-(require 'rmail)
 (require 'nnmail)
 
 (defvar nnml-directory "~/Mail/"
-  "*Mail directory.")
+  "Mail directory.")
 
 (defvar nnml-active-file (concat nnml-directory "active")
-  "*Mail active file.")
+  "Mail active file.")
 
 (defvar nnml-newsgroups-file (concat nnml-directory "newsgroups")
-  "*Mail newsgroups description file.")
+  "Mail newsgroups description file.")
+
+(defvar nnml-get-new-mail t
+  "If non-nil, nnml will check the incoming mail file and split the mail.")
 
 (defvar nnml-nov-is-evil nil
   "If non-nil, Gnus will never generate and use nov databases for mail groups.
@@ -49,11 +51,6 @@ the `nnml-generate-nov-databases' command. The function will go
 through all nnml directories and generate nov databases for them
 all. This may very well take some time.")
 
-(defvar nnml-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
-If the number of the articles is greater than the value, verbose
-messages will be shown to indicate the current status.")
-
 \f
 
 (defconst nnml-version "nnml 0.2"
@@ -66,6 +63,8 @@ messages will be shown to indicate the current status.")
 
 (defvar nnml-nov-buffer-alist nil)
 
+(defvar nnml-group-alist nil)
+
 \f
 
 ;;; Interface functions.
@@ -81,7 +80,7 @@ Newsgroup must be selected before calling this function."
          (count 0)
          beg article)
       (nnml-possibly-change-directory newsgroup)
-      (if (nnml-retrieve-header-with-nov sequence)
+      (if (nnml-retrieve-headers-with-nov sequence)
          'nov
        (while sequence
          (setq article (car sequence))
@@ -102,15 +101,17 @@ Newsgroup must be selected before calling this function."
                (delete-region (point) (point-max))))
          (setq sequence (cdr sequence))
          (setq count (1+ count))
-         (and (numberp nnml-large-newsgroup)
-              (> number nnml-large-newsgroup)
+         (and (numberp nnmail-large-newsgroup)
+              (> number nnmail-large-newsgroup)
               (zerop (% count 20))
-              (message "NNML: Receiving headers... %d%%"
+              gnus-verbose-backends
+              (message "nnml: Receiving headers... %d%%"
                        (/ (* count 100) number))))
 
-       (and (numberp nnml-large-newsgroup)
-            (> number nnml-large-newsgroup)
-            (message "NNML: Receiving headers... done"))
+       (and (numberp nnmail-large-newsgroup)
+            (> number nnmail-large-newsgroup)
+            gnus-verbose-backends
+            (message "nnml: Receiving headers... done"))
 
        ;; Fold continuation lines.
        (goto-char 1)
@@ -124,7 +125,7 @@ If HOST is nil, use value of environment variable `NNTPSERVER'.
 If optional argument SERVICE is non-nil, open by the service name."
   (let ((host (or host (getenv "NNTPSERVER"))))
     (setq nnml-status-string "")
-    (nnmail-open-server-internal host service)))
+    (nnml-open-server-internal host service)))
 
 (defun nnml-close-server (&optional server)
   "Close news server."
@@ -153,13 +154,13 @@ If the stream is opened, return T, otherwise return NIL."
             (file-exists-p file)
             (not (file-directory-p file)))
        (save-excursion
-         (nnml-find-file file)))))
+         (nnmail-find-file file)))))
 
 (defun nnml-request-group (group &optional server dont-check)
   "Select news GROUP."
   (if (not dont-check)
       (nnml-get-new-mail))
-  (let ((pathname (nnml-article-pathname group))
+  (let ((pathname (nnmail-article-pathname group nnml-directory))
        dir)
     (if (file-directory-p pathname)
        (progn
@@ -187,15 +188,23 @@ If the stream is opened, return T, otherwise return NIL."
                    (insert (format "211 0 1 0 %s\n" group))))))
          t))))
 
+(defun nnml-close-group (group &optional server)
+  t)
+
 (defun nnml-request-list (&optional server)
   "List active newsgoups."
+  (if server (nnml-get-new-mail))
   (save-excursion
-    (nnml-find-file nnml-active-file)))
+    (nnmail-find-file nnml-active-file)))
+
+(defun nnml-request-newgroups (date &optional server)
+  "List groups created after DATE."
+  (nnml-request-list server))
 
 (defun nnml-request-list-newsgroups (&optional server)
   "List newsgroups (defined in NNTP2)."
   (save-excursion
-    (nnml-find-file nnml-newsgroups-file)))
+    (nnmail-find-file nnml-newsgroups-file)))
 
 (defun nnml-request-post (&optional server)
   "Post a new news in current buffer."
@@ -212,29 +221,18 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   (let* ((days (or (and nnmail-expiry-wait-function
                        (funcall nnmail-expiry-wait-function newsgroup))
                   nnmail-expiry-wait))
-        (cur-time (current-time))
-        (day-sec (* 24 60 60 days))
-        (day-time (list nil nil))
-        mod-time article rest)
-    (setcar day-time (/ day-sec 65536))
-    (setcar (cdr day-time) (- day-sec (* (car day-time) 65536)))
-    (if (< (car (cdr cur-time)) (car (cdr day-time)))
-       (progn
-         (setcar day-time (+ 1 (- (car cur-time) (car day-time))))
-         (setcar (cdr day-time) (- (+ 65536 (car (cdr cur-time)))
-                                   (car (cdr day-time)))))
-      (setcar day-time (- (car cur-time) (car day-time)))
-      (setcar (cdr day-time) (- (car (cdr cur-time)) (car (cdr day-time)))))
+        article rest mod-time)
     (while articles
       (setq article (concat nnml-current-directory (int-to-string
                                                      (car articles))))
       (if (setq mod-time (nth 5 (file-attributes article)))
          (if (or force
-                 (< (car mod-time) (car day-time))
-                 (and (= (car mod-time) (car day-time))
-                      (< (car (cdr mod-time)) (car (cdr day-time)))))
+                 (> (nnmail-days-between
+                     (current-time-string)
+                     (current-time-string mod-time))
+                    days))
              (progn
-               (message "Deleting %s..." article)
+               (and gnus-verbose-backends (message "Deleting %s..." article))
                (condition-case ()
                    (delete-file article)
                  (file-error nil))
@@ -255,36 +253,42 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
        (setq result (eval accept-form))
        (kill-buffer (current-buffer))
        result)
-     (and (condition-case ()
-             (delete-file (concat nnml-current-directory 
-                                  (int-to-string article)))
-           (file-error nil))
-         (nnml-nov-delete-article group article)
-         (nnml-save-nov)))
+     (progn
+       (condition-case ()
+          (delete-file (concat nnml-current-directory 
+                               (int-to-string article)))
+        (file-error nil))
+       (nnml-nov-delete-article group article)
+       (nnml-save-nov)))
     result))
 
 (defun nnml-request-accept-article (group)
   (let (result)
     (if (stringp group)
        (and 
-        (nnml-get-active)
+        (nnml-request-list)
+        (setq nnml-group-alist (nnmail-get-active))
         ;; We trick the choosing function into believing that only one
         ;; group is availiable.  
-        (let ((nnmail-split-methods '(group "")))
-          (setq result 
-                (cons group (nnml-choose-mail (point-min) (point-max)))))
-        (nnml-save-active))
+        (let ((nnmail-split-methods (list (list group ""))))
+          (setq result (car (nnml-save-mail))))
+        (progn
+          (nnmail-save-active nnml-group-alist nnml-active-file)
+          (nnml-save-nov)))
       (and
-       (nnml-get-active)
-       (setq result (nnml-choose-mail (point-min) (point-max)))
-       (nnml-save-active)))
+       (nnml-request-list)
+       (setq nnml-group-alist (nnmail-get-active))
+       (setq result (car (nnml-save-mail)))
+       (progn
+        (nnmail-save-active nnml-group-alist nnml-active-file)
+        (nnml-save-nov))))
     result))
 
 \f
 ;;; Low-Level Interface
 
-(defun nnml-retrieve-header-with-nov (articles)
-  (if nnml-nov-is-evil
+(defun nnml-retrieve-headers-with-nov (articles)
+  (if (or gnus-nov-is-evil nnml-nov-is-evil)
       nil
     (let ((first (car articles))
          (last (progn (while (cdr articles) (setq articles (cdr articles)))
@@ -322,264 +326,73 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Close connection to news server."
   nil)
 
-(defun nnml-find-file (file)
-  "Insert FILE in server buffer safely."
-  (set-buffer nntp-server-buffer)
-  (erase-buffer)
-  (condition-case ()
-      (progn (insert-file-contents file) t)
-    (file-error nil)))
-
 (defun nnml-possibly-change-directory (newsgroup)
   (if newsgroup
-      (let ((pathname (nnml-article-pathname newsgroup)))
+      (let ((pathname (nnmail-article-pathname newsgroup nnml-directory)))
        (if (file-directory-p pathname)
            (setq nnml-current-directory pathname)
          (error "No such newsgroup: %s" newsgroup)))))
 
-(defun nnml-article-pathname (group)
-  "Make pathname for GROUP."
-  (concat (file-name-as-directory (expand-file-name nnml-directory))
-         (nnml-replace-chars-in-string group ?. ?/) "/"))
-
-(defun nnml-replace-chars-in-string (string from to)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))  ;Copy string.
-       (len (length string))
-       (idx 0))
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (if (= (aref string idx) from)
-         (aset string idx to))
-      (setq idx (1+ idx)))
-    string))
-
 (defun nnml-create-directories ()
   (let ((methods nnmail-split-methods)
        dir dirs)
     (while methods
-      (setq dir (nnml-article-pathname (car (car methods))))
+      (setq dir (nnmail-article-pathname (car (car methods)) nnml-directory))
       (while (not (file-directory-p dir))
        (setq dirs (cons dir dirs))
        (setq dir (file-name-directory (directory-file-name dir))))
       (while dirs
        (if (make-directory (directory-file-name (car dirs)))
            (error "Could not create directory %s" (car dirs)))
-       (message "Creating mail directory %s" (car dirs))
+       (and gnus-verbose-backends 
+            (message "Creating mail directory %s" (car dirs)))
        (setq dirs (cdr dirs)))
       (setq methods (cdr methods)))))
 
-;; Most of this function was taken from rmail.el
-(defun nnml-move-inbox ()
-  (let ((inbox (expand-file-name nnmail-spool-file))
-       tofile errors)
-    (setq tofile (make-temp-name
-                 (expand-file-name (concat nnml-directory "Incoming"))))
-    (unwind-protect
-       (save-excursion
-         (setq errors (generate-new-buffer " *nnml loss*"))
-         (buffer-disable-undo errors)
-         (call-process
-          (expand-file-name "movemail" exec-directory)
-          nil errors nil inbox tofile)
-         (if (not (buffer-modified-p errors))
-             ;; No output => movemail won
-             nil
-           (set-buffer errors)
-           (subst-char-in-region (point-min) (point-max) ?\n ?\  )
-           (goto-char (point-max))
-           (skip-chars-backward " \t")
-           (delete-region (point) (point-max))
-           (goto-char (point-min))
-           (if (looking-at "movemail: ")
-               (delete-region (point-min) (match-end 0)))
-           (error (concat "movemail: "
-                          (buffer-substring (point-min)
-                                            (point-max)))))))
-    (if (buffer-name errors)
-       (kill-buffer errors))
-    tofile))
-
-(defvar nnml-newsgroups nil)
-
-(defun nnml-get-active ()
-  (let ((methods nnmail-split-methods))
-    (setq nnml-newsgroups nil)
-    (if (nnml-request-list)
-       (save-excursion
-         (set-buffer (get-buffer-create " *nntpd*"))
-         (goto-char 1)
-         (while (re-search-forward 
-                 "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
-           (setq nnml-newsgroups 
-                 (cons (list (buffer-substring (match-beginning 1) 
-                                               (match-end 1))
-                             (cons (string-to-int 
-                                    (buffer-substring (match-beginning 3)
-                                                      (match-end 3)))
-                                   (string-to-int 
-                                    (buffer-substring (match-beginning 2)
-                                                      (match-end 2)))))
-                       nnml-newsgroups)))))
-    (while methods
-      (if (not (assoc (car (car methods)) nnml-newsgroups))
-         (setq nnml-newsgroups
-               (cons (list (car (car methods)) (cons 1 0)) 
-                     nnml-newsgroups)))
-      (setq methods (cdr methods)))
-    t))
-
-(defun nnml-save-active ()
-  (let ((groups nnml-newsgroups)
-       group)
-    (save-excursion
-      (set-buffer (get-buffer-create " *nnml*"))
-      (buffer-disable-undo (current-buffer))
-      (erase-buffer)
-      (while groups
-       (setq group (car groups))
-       (insert (format "%s %d %d y\n" (car group) (cdr (car (cdr group)) )
-                       (car (car (cdr group)))))
-       (setq groups (cdr groups)))
-      (write-region 1 (point-max) (expand-file-name nnml-active-file) nil 
-                   'nomesg)
-      (kill-buffer (current-buffer)))))
-
-(defun nnml-split-incoming (incoming)
-  "Go through the entire INCOMING file and pick out each individual mail."
-  (let (start)
-    (nnml-get-active)
-    (save-excursion
-      (set-buffer (get-buffer-create "*(ding) Gnus mail*"))
-      (buffer-disable-undo (current-buffer))
-      (erase-buffer)
-      (insert-file-contents incoming)
-      (goto-char 1)
-      (save-excursion
-       (run-hooks 'nnmail-prepare-incoming-hook))
-      ;; Go to the beginning of the first mail...
-      (if (and (re-search-forward (concat "^" rmail-unix-mail-delimiter) nil t)
-              (goto-char (match-beginning 0)))
-         ;; and then carry on until the bitter end.
-         (while (not (eobp))
-           (setq start (point))
-           ;; Skip all the headers in case there are mode "From "s...
-           (if (not (search-forward "\n\n" nil t))
-               (forward-line 1))
-           (if (re-search-forward 
-                (concat "^" rmail-unix-mail-delimiter) nil t)
-               (goto-char (match-beginning 0))
-             (goto-char (point-max)))
-           (nnml-choose-mail start (point))))
-      (kill-buffer (current-buffer)))))
-
-;; Mail crossposts syggested by Brian Edmonds <edmonds@cs.ubc.ca>. 
-(defun nnml-article-group (beg end)
-  (let ((methods nnmail-split-methods)
-       (obuf (current-buffer))
-       found group-art)
-  (save-excursion
-    ;; Find headers.
-    (goto-char beg)
-    (setq end (if (search-forward "\n\n" end t) (point) end))
-    (set-buffer (get-buffer-create " *nnml work*"))
-    (buffer-disable-undo (current-buffer))
-    (erase-buffer)
-    ;; Copy the headers into the work buffer.
-    (insert-buffer-substring obuf beg end)
-    ;; Fold continuation lines.
+(defun nnml-save-mail ()
+  "Called narrowed to an article."
+  (let ((group-art (nreverse (nnmail-article-group 'nnml-active-number)))
+       chars nov-line)
+    (setq chars (nnmail-insert-lines))
+    (nnmail-insert-xref group-art)
     (goto-char (point-min))
-    (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-      (replace-match " " t t))
-    ;; Go throught the split methods to find a match.
-    (while (and methods (or nnmail-crosspost (not group-art)))
-      (goto-char (point-max))
-      (if (or (cdr methods)
-             (not (string= "" (nth 1 (car methods)))))
-         (if (and (re-search-backward (car (cdr (car methods))) nil t)
-                  ;; Don't enter the article into the same group twice.
-                  (not (memq (car (car methods)) group-art)))
-             (setq group-art
-                   (cons 
-                    (cons (car (car methods))
-                          (nnml-active-number (car (car methods))))
-                    group-art)))
-       (or group-art
-           (setq group-art 
-                 (list (cons (car (car methods)) 
-                             (nnml-active-number (car (car methods))))))))
-      (setq methods (cdr methods)))
-    group-art)))
-
-(defun nnml-choose-mail (beg end)
-  "Find out what mail group the mail between BEG and END belongs in."
-  (let ((group-art (nreverse (nnml-article-group beg end)))
-       chars nov-line lines hbeg hend)
-    (save-excursion
-      (save-restriction
-       (narrow-to-region beg end)
-       ;; First fix headers.
-       (goto-char (point-min))
-       (save-excursion
-         (save-restriction
-           (narrow-to-region (point)
-                             (progn (search-forward "\n\n" nil t) 
-                                    (setq chars (- (point-max) (point)))
-                                    (setq lines (- (count-lines 
-                                                    (point) (point-max)) 1))
-                                    (1- (point))))
-           ;; Insert Lines.
-           (if (not (save-excursion (re-search-backward "^Lines:" beg t)))
-               (insert (format "Lines: %d\n" lines)))
-           ;; Make an Xref header.
-           (save-excursion
-             (goto-char (point-max))
-             (if (re-search-backward "^Xref:" nil t)
-                 (delete-region (match-beginning 0) 
-                                (progn (forward-line 1) (point)))))
-           (insert (format "Xref: %s" (system-name)))
-           (let ((ga group-art))
-             (while ga
-               (insert (format " %s:%d" (car (car ga)) (cdr (car ga))))
-               (setq ga (cdr ga))))
-           (insert "\n")
-           (setq hbeg (point-min))
-           (setq hend (point-max))))
-       ;; We save the article in all the newsgroups it belongs in.
-       (let ((ga group-art)
-             first)
-         (while ga
-           (let ((file (concat (nnml-article-pathname 
-                                (car (car ga)))
-                               (int-to-string (cdr (car ga))))))
-             (if first
-                 ;; It was already saved, so we just make a hard link.
-                 (add-name-to-file first file t)
-               ;; Save the article.
-               (write-region (point-min) (point-max) file nil nil)
-               (setq first file)))
-           (setq ga (cdr ga))))
-       ;; Generate a nov line for this article. We generate the nov
-       ;; line after saving, because nov generation destroys the
-       ;; header. 
-       (save-excursion
-         (save-restriction
-           (narrow-to-region hbeg hend)
-           (setq nov-line (nnml-make-nov-line chars))))
-       ;; Output the nov line to all nov databases that should have it.
-       (let ((ga group-art))
-         (while ga
-           (nnml-add-nov (car (car ga)) (cdr (car ga)) nov-line)
-           (setq ga (cdr ga))))
-       group-art))))
+    (while (looking-at "From ")
+      (replace-match "X-From-Line: ")
+      (forward-line 1))
+    ;; We save the article in all the newsgroups it belongs in.
+    (let ((ga group-art)
+         first)
+      (while ga
+       (let ((file (concat (nnmail-article-pathname 
+                            (car (car ga)) nnml-directory)
+                           (int-to-string (cdr (car ga))))))
+         (if first
+             ;; It was already saved, so we just make a hard link.
+             (add-name-to-file first file t)
+           ;; Save the article.
+           (write-region (point-min) (point-max) file nil 
+                         (if gnus-verbose-backends nil 'nomesg))
+           (setq first file)))
+       (setq ga (cdr ga))))
+    ;; Generate a nov line for this article. We generate the nov
+    ;; line after saving, because nov generation destroys the
+    ;; header. 
+    (setq nov-line (nnml-make-nov-line chars))
+    ;; Output the nov line to all nov databases that should have it.
+    (let ((ga group-art))
+      (while ga
+       (nnml-add-nov (car (car ga)) (cdr (car ga)) nov-line)
+       (setq ga (cdr ga))))
+    group-art))
 
 (defun nnml-active-number (group)
   "Compute the next article number in GROUP."
-  (let ((active (car (cdr (assoc group nnml-newsgroups)))))
+  (let ((active (car (cdr (assoc group nnml-group-alist)))))
     (setcdr active (1+ (cdr active)))
     (let (file)
       (while (file-exists-p
-             (setq file (concat (nnml-article-pathname group)
+             (setq file (concat (nnmail-article-pathname 
+                                 group nnml-directory)
                                 (int-to-string (cdr active)))))
        (setcdr active (1+ (cdr active)))))
     (cdr active)))
@@ -588,17 +401,24 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Read new incoming mail."
   (let (incoming)
     (nnml-create-directories)
-    (if (and (file-exists-p nnmail-spool-file)
+    (if (and nnml-get-new-mail nnmail-spool-file
+            (file-exists-p nnmail-spool-file)
             (> (nth 7 (file-attributes nnmail-spool-file)) 0))
        (progn
-         (message "nnml: Reading incoming mail...")
-         (setq incoming (nnml-move-inbox))
-         (nnml-split-incoming incoming)
-         (nnml-save-active)
+         (and gnus-verbose-backends 
+              (message "nnml: Reading incoming mail..."))
+         (setq incoming 
+               (nnmail-move-inbox nnmail-spool-file 
+                                  (concat nnml-directory "Incoming")))
+         (nnml-request-list)
+         (setq nnml-group-alist (nnmail-get-active))
+         (nnmail-split-incoming incoming 'nnml-save-mail)
+         (nnmail-save-active nnml-group-alist nnml-active-file)
          (nnml-save-nov)
          (run-hooks 'nnmail-read-incoming-hook)
 ;;         (delete-file incoming)
-         (message "nnml: Reading incoming mail...done")))))
+         (and gnus-verbose-backends
+              (message "nnml: Reading incoming mail...done"))))))
 
 
 (defun nnml-add-nov (group article line)
@@ -615,59 +435,66 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Create a nov from the current headers."
   (let ((case-fold-search t)
        subject from date id references lines xref in-reply-to char)
-    ;; Fold continuation lines.
-    (goto-char (point-min))
-    (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-      (replace-match " " t t))
-    (subst-char-in-region (point-min) (point-max) ?\t ? )
-    ;; [number subject from date id references chars lines xref]
     (save-excursion
-      (goto-char (point-min))
-      (while (re-search-forward "^\\(from\\|subject\\|message-id\\|date\\|lines\\|xref\\|references\\|in-reply-to\\): "
-                               nil t)
-       (beginning-of-line)
-       (setq char (downcase (following-char))) 
-       (cond
-        ((eq char ?s)
-         (setq subject (nnml-header-value)))
-        ((eq char ?f)
-         (setq from (nnml-header-value)))
-        ((eq char ?x)
-         (setq xref (nnml-header-value)))
-        ((eq char ?l)
-         (setq lines (nnml-header-value)))
-        ((eq char ?d)
-         (setq date (nnml-header-value)))
-        ((eq char ?m)
-         (setq id (setq id (nnml-header-value))))
-        ((eq char ?r)
-         (setq references (nnml-header-value)))
-        ((eq char ?i)
-         (setq in-reply-to (nnml-header-value))))
-       (forward-line 1))
+      (save-restriction
+       (goto-char (point-min))
+       (narrow-to-region 
+        (point)
+        (1- (or (search-forward "\n\n" nil t) (point-max))))
+       ;; Fold continuation lines.
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+         (replace-match " " t t))
+       (subst-char-in-region (point-min) (point-max) ?\t ? )
+       ;; [number subject from date id references chars lines xref]
+       (save-excursion
+         (goto-char (point-min))
+         (while (re-search-forward "^\\(from\\|subject\\|message-id\\|date\\|lines\\|xref\\|references\\|in-reply-to\\): "
+                                   nil t)
+           (beginning-of-line)
+           (setq char (downcase (following-char))) 
+           (cond
+            ((eq char ?s)
+             (setq subject (nnml-header-value)))
+            ((eq char ?f)
+             (setq from (nnml-header-value)))
+            ((eq char ?x)
+             (setq xref (nnml-header-value)))
+            ((eq char ?l)
+             (setq lines (nnml-header-value)))
+            ((eq char ?d)
+             (setq date (nnml-header-value)))
+            ((eq char ?m)
+             (setq id (setq id (nnml-header-value))))
+            ((eq char ?r)
+             (setq references (nnml-header-value)))
+            ((eq char ?i)
+             (setq in-reply-to (nnml-header-value))))
+           (forward-line 1))
       
-      (and (not references)
-          in-reply-to
-          (string-match "<[^>]+>" in-reply-to)
-          (setq references
-                (substring in-reply-to (match-beginning 0)
-                           (match-end 0)))))
-      ;; [number subject from date id references chars lines xref]
-      (format "\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n"
-             (or subject "(none)")
-             (or from "(nobody)") (or date "")
-             (or id "") (or references "")
-             chars (or lines "0") (or xref ""))))
+         (and (not references)
+              in-reply-to
+              (string-match "<[^>]+>" in-reply-to)
+              (setq references
+                    (substring in-reply-to (match-beginning 0)
+                               (match-end 0)))))
+       ;; [number subject from date id references chars lines xref]
+       (format "\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n"
+               (or subject "(none)")
+               (or from "(nobody)") (or date "")
+               (or id "") (or references "")
+               (or chars 0) (or lines "0") (or xref ""))))))
 
 (defun nnml-open-nov (group)
   (or (cdr (assoc group nnml-nov-buffer-alist))
       (let ((buffer (find-file-noselect 
-                    (concat (nnml-article-pathname group) ".nov"))))
+                    (concat (nnmail-article-pathname 
+                             group nnml-directory) ".nov"))))
        (save-excursion
          (set-buffer buffer)
          (buffer-disable-undo (current-buffer)))
-       (setq nnml-nov-buffer-alist (cons (cons group buffer)
-                                         nnml-nov-buffer-alist))
+       (setq nnml-nov-buffer-alist 
+             (cons (cons group buffer) nnml-nov-buffer-alist))
        buffer)))
 
 (defun nnml-save-nov ()
@@ -685,7 +512,7 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
   "Generate nov databases in all nnml mail newsgroups."
   (interactive 
    (progn   
-     (setq nnml-newsgroups nil)
+     (setq nnml-group-alist nil)
      (list nnml-directory)))
   (nnml-open-server (system-name))
   (let ((dirs (directory-files dir t nil t)))
@@ -706,8 +533,8 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
        (nov-buffer (get-buffer-create "*nov*"))
        nov-line chars)
     (if files
-       (setq nnml-newsgroups 
-             (cons (list (nnml-replace-chars-in-string 
+       (setq nnml-group-alist 
+             (cons (list (nnmail-replace-chars-in-string 
                           (substring (expand-file-name dir)
                                      (length (expand-file-name 
                                               nnml-directory)))
@@ -716,7 +543,7 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
                                (let ((f files))
                                  (while (cdr f) (setq f (cdr f)))
                                  (car f))))
-                   nnml-newsgroups)))
+                   nnml-group-alist)))
     (if files
        (save-excursion
          (set-buffer nntp-server-buffer)
@@ -746,14 +573,15 @@ If FORCE is non-nil, ARTICLES will be deleted whether they are old or not."
            (write-region 1 (point-max) (expand-file-name nov) nil
                          'nomesg)
            (kill-buffer (current-buffer)))))
-    (nnml-save-active)))
+    (nnmail-save-active nnml-group-alist nnml-active-file)))
 
 (defun nnml-nov-delete-article (group article)
   (save-excursion
     (set-buffer (nnml-open-nov group))
     (goto-char 1)
     (if (re-search-forward (concat "^" (int-to-string article) "\t"))
-       (delete-region (match-beginning 0) (progn (forward-line 1) (point))))))
+       (delete-region (match-beginning 0) (progn (forward-line 1) (point))))
+    t))
 
 (provide 'nnml)
 
index 57c3c21..1b802ae 100644 (file)
 ;; Switch to GROUP. If DISCARD is nil, active information on the group
 ;; must be returned.
 ;;
+;; `choke-close-group GROUP &optional SERVER'
+;; Close group. Most backends won't have to do anything with this
+;; call, but it is an opportunity to clean up, if that is needed. It
+;; is called when Gnus exits a group.
+;;
 ;; `choke-request-article ARTICLE &optional GROUP SERVER'
 ;; Return ARTICLE, which is either an article number or id.
 ;;
 (require 'nntp)
 
 (defvar nnspool-inews-program news-inews-program
-  "*Program to post news.")
+  "Program to post news.")
 
 (defvar nnspool-inews-switches '("-h")
-  "*Switches for nnspool-request-post to pass to `inews' for posting news.")
+  "Switches for nnspool-request-post to pass to `inews' for posting news.")
 
 (defvar nnspool-spool-directory news-path
-  "*Local news spool directory.")
+  "Local news spool directory.")
+
+(defvar nnspool-lib-dir "/usr/lib/news/"
+  "Where the local news library files are stored.")
+
+(defvar nnspool-active-file (concat nnspool-lib-dir "active")
+  "Local news active file.")
 
-(defvar nnspool-active-file "/usr/lib/news/active"
-  "*Local news active file.")
+(defvar nnspool-newsgroups-file (concat nnspool-lib-dir "newsgroups")
+  "Local news newsgroups file.")
 
-(defvar nnspool-newsgroups-file "/usr/lib/news/newsgroups"
-  "*Local news newsgroups file.")
+(defvar nnspool-distributions-file (concat nnspool-lib-dir "distributions")
+  "Local news distributions file.")
 
-(defvar nnspool-distributions-file "/usr/lib/news/distributions"
-  "*Local news distributions file.")
+(defvar nnspool-history-file (concat nnspool-lib-dir "history")
+  "Local news history file.")
 
-(defvar nnspool-history-file "/usr/lib/news/history"
-  "*Local news history file.")
+(defvar nnspool-active-times-file (concat nnspool-lib-dir "active.times")
+  "Local news active date file.")
 
 (defvar nnspool-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
+  "The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
 messages will be shown to indicate the current status.")
 
+(defvar nnspool-nov-is-evil nil
+  "Non-nil means that nnspool will never return NOV lines instead of headers.")
+
 \f
 
 (defconst nnspool-version "nnspool 2.0"
@@ -142,34 +156,36 @@ Newsgroup must be selected before calling this function."
                            (> number nnspool-large-newsgroup)))
           file beg article)
       (nnspool-possibly-change-directory newsgroup)
-      (while sequence
-       (setq article (car sequence))
-       (setq file
-             (concat nnspool-current-directory (prin1-to-string article)))
-       (if (file-exists-p file)
-           (progn
-             (insert (format "221 %d Article retrieved.\n" article))
-             (setq beg (point))
-             (insert-file-contents file)
-             (goto-char beg)
-             (search-forward "\n\n" nil t)
-             (forward-char -1)
-             (insert ".\n")
-             (delete-region (point) (point-max))))
-       (setq sequence (cdr sequence))
-
-       (and do-message
-            (zerop (% (setq count (1+ count)) 20))
-            (message "NNSPOOL: Receiving headers... %d%%"
-                     (/ (* count 100) number))))
-
-      (if do-message (message "NNSPOOL: Receiving headers... done"))
-
-      ;; Fold continuation lines.
-      (goto-char 1)
-      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-       (replace-match " " t t))
-      'headers)))
+      (if (nnspool-retrieve-headers-with-nov sequence)
+         'nov
+       (while sequence
+         (setq article (car sequence))
+         (setq file (concat nnspool-current-directory 
+                            (int-to-string article)))
+         (and (file-exists-p file)
+              (progn
+                (insert (format "221 %d Article retrieved.\n" article))
+                (setq beg (point))
+                (insert-file-contents file)
+                (goto-char beg)
+                (search-forward "\n\n" nil t)
+                (forward-char -1)
+                (insert ".\n")
+                (delete-region (point) (point-max))))
+         (setq sequence (cdr sequence))
+
+         (and do-message
+              (zerop (% (setq count (1+ count)) 20))
+              (message "NNSPOOL: Receiving headers... %d%%"
+                       (/ (* count 100) number))))
+
+       (and do-message (message "NNSPOOL: Receiving headers... done"))
+
+       ;; Fold continuation lines.
+       (goto-char 1)
+       (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+         (replace-match " " t t))
+       'headers))))
 
 (defun nnspool-open-server (host &optional service)
   "Open local spool."
@@ -267,6 +283,9 @@ If the stream is opened, return T, otherwise return NIL."
                    (insert (format "211 0 0 0 %s\n" group))))))
          t))))
 
+(defun nnspool-close-group (group &optional server)
+  t)
+
 (defun nnspool-request-list (&optional server)
   "List active newsgoups."
   (save-excursion
@@ -282,6 +301,13 @@ If the stream is opened, return T, otherwise return NIL."
   (save-excursion
     (nnspool-find-file nnspool-distributions-file)))
 
+(defun nnspool-request-newgroups (date &optional server)
+  "List groups created after DATE."
+  (save-excursion
+    (nnspool-find-file nnspool-active-times-file)
+    (setq nnspool-status-string "NEWGROUPS is not supported.")
+    nil))
+
 (defun nnspool-request-post (&optional server)
   "Post a new news in current buffer."
   (save-excursion
@@ -307,10 +333,55 @@ If the stream is opened, return T, otherwise return NIL."
 (fset 'nnspool-request-post-buffer 'nntp-request-post-buffer)
 
 \f
-;;; Low-Level Interface.
+;;; Internal functions.
+
+(defun nnspool-retrieve-headers-with-nov (articles)
+  (if (or gnus-nov-is-evil nnspool-nov-is-evil)
+      nil
+    (let ((nov (concat nnspool-current-directory ".nov"))
+         article)
+      (if (file-exists-p nov)
+         (save-excursion
+           (set-buffer nntp-server-buffer)
+           (erase-buffer)
+           (insert-file-contents nov)
+           ;; First we find the first wanted line. We issue a number
+           ;; of search-forwards - the first article we are lookign
+           ;; for may be expired, so we have to go on searching until
+           ;; we find one of the articles we want.
+           (while (and articles
+                       (setq article (concat (int-to-string 
+                                              (car articles) "\t")))
+                       (not (or (looking-at article)
+                                (search-forward (concat "\n" article) 
+                                                nil t))))
+             (setq articles (cdr articles)))
+           (if (not articles)
+               ()
+             (beginning-of-line)
+             (delete-region (point-min) (point))
+             ;; Then we find the last wanted line. We go to the end
+             ;; of the buffer and search backward much the same way
+             ;; we did to find the first article.
+             ;; !!! Perhaps it would be better just to do a (last articles), 
+             ;; and go forward successively over each line and
+             ;; compare to avoid this (reverse), like this:
+             ;; (while (and (>= last (read nntp-server-buffer)))
+             ;;             (zerop (forward-line 1))))
+             (setq articles (reverse articles))
+             (goto-char (point-max))
+             (while (and articles
+                         (not (search-backward 
+                               (concat "\n" (int-to-string (car articles))
+                                       "\t") nil t)))
+               (setq articles (cdr articles)))
+             (if articles
+                 (progn
+                   (forward-line 2)
+                   (delete-region (point) (point-max)))))
+           (or articles (progn (erase-buffer) nil)))))))
 
 (defun nnspool-open-server-internal (host &optional service)
-  "Open connection to news server on HOST by SERVICE (default is nntp)."
   (save-excursion
     ;; Initialize communication buffer.
     (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
@@ -323,30 +394,20 @@ If the stream is opened, return T, otherwise return NIL."
 
 (defun nnspool-close-server-internal ()
   "Close connection to news server."
-  (if (get-file-buffer nnspool-history-file)
-      (kill-buffer (get-file-buffer nnspool-history-file))))
+  )
 
 (defun nnspool-find-article-by-message-id (id)
   "Return full pathname of an article identified by message-ID."
   (save-excursion
-    (let ((buffer (get-file-buffer nnspool-history-file)))
-      (if buffer
-         (set-buffer buffer)
-       ;; Finding history file may take lots of time.
-       (message "Reading history file...")
-       (set-buffer (find-file-noselect nnspool-history-file))
-       (message "Reading history file... done")))
-    ;; Search from end of the file. I think this is much faster than
-    ;; do from the beginning of the file.
-    (goto-char (point-max))
-    (if (re-search-backward
-        (concat "^" (regexp-quote id)
-                "[ \t].*[ \t]\\([^ \t/]+\\)/\\([0-9]+\\)[ \t]*$") nil t)
-       (let ((group (buffer-substring (match-beginning 1) (match-end 1)))
-             (number (buffer-substring (match-beginning 2) (match-end 2))))
-         (concat (nnspool-article-pathname
-                  (nnspool-replace-chars-in-string group ?. ?/))
-                 number)))))
+    (set-buffer nntp-server-buffer)
+    (erase-buffer)
+    (call-process "grep" nil t nil id nnspool-history-file)
+    (goto-char (point-min))
+    (if (looking-at "<[^>]+>[ \t]+[-0-9~]+[ \t]+\\(.*\\)$")
+       (concat nnspool-spool-directory
+               (nnspool-replace-chars-in-string 
+                (buffer-substring (match-beginning 1) (match-end 1)) 
+                ?. ?/)))))
 
 (defun nnspool-find-file (file)
   "Insert FILE in server buffer safely."
index 01362c5..71fb502 100644 (file)
@@ -34,7 +34,7 @@
   (autoload 'news-reply-mode "rnewspost"))
 
 (defvar nntp-server-hook nil
-  "*Hooks for the NNTP server.
+  "Hooks for the NNTP server.
 If the kanji code of the NNTP server is different from the local kanji
 code, the correct kanji code of the buffer associated with the NNTP
 server must be specified as follows:
@@ -49,41 +49,38 @@ server must be specified as follows:
 If you'd like to change something depending on the server in this
 hook, use the variable `nntp-server-name'.")
 
-(defvar nntp-server-opened-hook nil
-  "You can send commands at startup like AUTHINFO with this hook.")
+(defvar nntp-server-opened-hook 
+  (list
+   (lambda ()
+     (nntp-send-command "MODE" "READER")))
+  "Hook used for sending commands to the server at startup.
+It is used by default to send the \"MODE READER\" command to the
+server. This makes innd servers spawn an nnrpd server.
+Other useful commands might be \"AUTHINFO\".")
 
 (defvar nntp-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
+  "The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
 messages will be shown to indicate the current status.")
 
 (defvar nntp-buggy-select (memq system-type '(usg-unix-v fujitsu-uts))
-  "*T if your select routine is buggy.
+  "t if your select routine is buggy.
 If the select routine signals error or fall into infinite loop while
 waiting for the server response, the variable must be set to t.  In
 case of Fujitsu UTS, it is set to T since `accept-process-output'
 doesn't work properly.")
 
 (defvar nntp-maximum-request 1
-  "*The maximum number of the requests sent to the NNTP server at one time.
+  "The maximum number of the requests sent to the NNTP server at one time.
 If Emacs hangs up while retrieving headers, set the variable to a
 lower value.")
 
 (defvar nntp-debug-read 10000
-  "*Display '...' every 10Kbytes of a message being received if it is non-nil.
+  "Display '...' every 10Kbytes of a message being received if it is non-nil.
 If it is a number, dots are displayed per the number.")
 
-(defvar nntp-xover-is-evil nil
-  "*If non-nil, nntp will never attempt to use XOVER when talking to the server.")
-
-(defvar nntp-build-old-threads nil
-  "*Non-nil means that Gnus will try to build threads by grabbing old headers.
-If an unread article in the group refers to an older, already read (or
-just marked as read) article, the old article will not normally be
-displayed in the Summary buffer. If this variable is non-nil, Gnus
-will attempt to grab the headers to the old articles, and thereby
-build complete threads. `nntp-xover-is-evil' has to be nil if this is
-to work.")
+(defvar nntp-nov-is-evil nil
+  "If non-nil, nntp will never attempt to use XOVER when talking to the server.")
 
 (defvar nntp-xover-commands '("XOVER" "XOVERVIEW")
   "List of strings that are used as commands to fetch NOV lines from a server.
@@ -127,7 +124,8 @@ instead call function `nntp-status-message' to get status message.")
   (save-excursion
     (set-buffer nntp-server-buffer)
     (erase-buffer)
-    (if (and (not nntp-xover-is-evil)
+    (if (and (not gnus-nov-is-evil) 
+            (not nntp-nov-is-evil)
             (nntp-retrieve-headers-with-xover sequence))
         'nov
       (let ((number (length sequence))
@@ -258,13 +256,14 @@ If the stream is opened, return non-nil, otherwise return nil."
 (defun nntp-request-article (id &optional newsgroup server buffer)
   "Select article by message ID (or number)."
   (nntp-possibly-change-server newsgroup server)
-  (if buffer (set-process-buffer nntp-server-process buffer))
-  (prog1
-      (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
-       ;; If NEmacs, end of message may look like: "\256\215" (".^M")
-       (prog1
-           (nntp-send-command "^\\.\r$" "ARTICLE" id)
-         (nntp-decode-text)))
+  (unwind-protect
+      (progn
+       (if buffer (set-process-buffer nntp-server-process buffer))
+       (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
+         ;; If NEmacs, end of message may look like: "\256\215" (".^M")
+         (prog1
+             (nntp-send-command "^\\.\r$" "ARTICLE" id)
+           (nntp-decode-text))))
     (if buffer (set-process-buffer nntp-server-process nntp-server-buffer))))
 
 (defun nntp-request-body (id &optional newsgroup server)
@@ -296,6 +295,9 @@ If the stream is opened, return non-nil, otherwise return nil."
        (nntp-send-command "^.*\r$" "GROUP" group)
        )))
 
+(defun nntp-close-group (group &optional server)
+  t)
+
 (defun nntp-request-list (&optional server)
   "List active newsgroups."
   (nntp-possibly-change-server nil server)
@@ -312,6 +314,13 @@ If the stream is opened, return non-nil, otherwise return nil."
     (nntp-decode-text)
     ))
 
+(defun nntp-request-newgroups (date &optional server)
+  "List new groups (defined in NNTP2)."
+  (nntp-possibly-change-server nil server)
+  (prog1
+      (nntp-send-command "^\\.\r$" "NEWGROUPS" date)
+    (nntp-decode-text)))
+
 (defun nntp-request-list-distributions (&optional server)
   "List distributions (defined in NNTP2)."
   (nntp-possibly-change-server nil server)
@@ -390,7 +399,14 @@ in the current news group."
            (widen))
          (setq news-reply-yank-from from)
          (setq news-reply-yank-message-id message-id)
-         (news-setup nil subject message-of newsgroups article-buffer)
+         ;; Prevent getting BCC or FCC fields inserted for both mail
+         ;; and news.  
+         (let ((mail-self-blind
+                (and (not gnus-mail-self-blind) mail-self-blind))
+               (mail-archive-file-name
+                (and (not gnus-author-copy) mail-archive-file-name)))
+           (news-setup (and gnus-auto-mail-to-author from)
+                       subject message-of newsgroups article-buffer))
          ;; Fold long references line to follow RFC1036.
          (mail-position-on-field "References")
          (let ((begin (- (point) (length "References: ")))
@@ -416,8 +432,9 @@ in the current news group."
     (while (and servers 
                (not (equal proc (nth 1 (car servers)))))
       (setq servers (cdr servers)))
-    (error "nntp: Connection closed to server %s." 
-          (or (car (car servers)) "(none)"))))
+    (message "nntp: Connection closed to server %s." 
+            (or (car (car servers)) "(none)"))
+    (ding)))
 
 ;; Encoding and decoding of NNTP text.
 
@@ -560,8 +577,7 @@ in the current news group."
 (defun nntp-retrieve-headers-with-xover (sequence)
   (if (not nntp-server-xover)
       ()
-    (let ((range (format "%d-%d" 
-                        (if nntp-build-old-threads 1 (car sequence))
+    (let ((range (format "%d-%d" (car sequence)
                         (nntp-last-element sequence))))
       (prog1
          (if (stringp nntp-server-xover)
index 88e0fcc..801af71 100644 (file)
   "Version numbers of this version of nnvirual.")
 
 (defvar nnvirtual-large-newsgroup 50
-  "*The number of the articles which indicates a large newsgroup.
+  "The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
 messages will be shown to indicate the current status.")
 
 \f
 
-(defvar nnvirtual-newsgroups nil
-  "The newsgroups that belong to this virtual newsgroup.")
-
-(defvar nnvirtual-newsgroups-regexp nil
-  "The newsgroups that belong to this virtual newsgroup.")
-
-(defvar nnvirtual-mapping nil)
+(defvar nnvirtual-group-alist nil)
+(defvar nnvirtual-current-group nil)
+(defvar nnvirtual-current-groups nil)
+(defvar nnvirtual-current-mapping nil)
 
 (defvar nnvirtual-do-not-open nil)
 
@@ -67,12 +64,13 @@ messages will be shown to indicate the current status.")
     (erase-buffer)
     (let ((number (length sequence))
          (count 0)
-         (nntp-xover-is-evil t)
+         (gnus-nov-is-evil t)
          (i 0)
          prev articles group-articles beg art-info article group)
-      (if sequence (setq prev (car (aref nnvirtual-mapping (car sequence)))))
+      (if sequence (setq prev (car (aref nnvirtual-current-mapping 
+                                        (car sequence)))))
       (while sequence
-       (setq art-info (aref nnvirtual-mapping (car sequence)))
+       (setq art-info (aref nnvirtual-current-mapping (car sequence)))
        (if (not (equal prev (car art-info)))
            (progn
              (setq group-articles (cons (list prev (nreverse articles)) 
@@ -98,7 +96,7 @@ messages will be shown to indicate the current status.")
                ()
              (setq article (string-to-int (gnus-buffer-substring 1 1)))
              (setq i 1)
-             (while (/= article (cdr (aref nnvirtual-mapping i)))
+             (while (/= article (cdr (aref nnvirtual-current-mapping i)))
                (setq i (1+ i)))
              (goto-char (match-beginning 1))
              (looking-at "[0-9]+ ")
@@ -115,24 +113,6 @@ messages will be shown to indicate the current status.")
        (goto-char (point-max))
        (insert-buffer-substring nntp-server-buffer 4)
        (setq group-articles (cdr group-articles)))
-      ;; Weed out articles that appear twice because of cross-posting.
-      ;; Suggested by Stephane Laveau <laveau@corse.inria.fr>.
-      (let ((id-hashtb (make-vector number 0))
-           id)
-       (goto-char (point-min))
-       ;; We look at the message-ids...
-       (while (search-forward "\nMessage-ID: " nil t)
-         ;; ... and check if they are entered into the hash table.
-         (if (boundp (setq id (intern (buffer-substring 
-                                       (point) (progn (end-of-line) (point)))
-                                      id-hashtb)))
-             ;; Yup, so we delete this header.
-             (delete-region
-              (if (search-backward "\n.\n" nil t) (1+ (point)) (point-min))
-              (if (search-forward "\n.\n" nil t) (1+ (match-beginning 0))
-                (point-max))))
-         ;; Nope, so we just enter it into the hash table.
-         (set id t)))
       ;; The headers are ready for reading, so they are inserted into
       ;; the nntp-server-buffer, which is where Gnus expects to find
       ;; them.
@@ -148,20 +128,7 @@ messages will be shown to indicate the current status.")
 
 (defun nnvirtual-open-server (newsgroups &optional something)
   "Open a virtual newsgroup that contains NEWSGROUPS."
-  (let ((newsrc gnus-newsrc-assoc))
-    (setq nnvirtual-newsgroups nil)
-    (setq nnvirtual-newsgroups-regexp newsgroups)
-    (while newsrc
-      (if (string-match newsgroups (car (car newsrc)))
-         (setq nnvirtual-newsgroups (cons (car (car newsrc)) 
-                                          nnvirtual-newsgroups)))
-      (setq newsrc (cdr newsrc)))
-    (if (null nnvirtual-newsgroups)
-       (setq nnvirtual-status-string 
-             (format 
-              "nnvirtual: No newsgroups for this virtual newsgroup"))
-      (nnvirtual-open-server-internal))
-    nnvirtual-newsgroups))
+  (nnvirtual-open-server-internal))
 
 (defun nnvirtual-close-server (&rest dum)
   "Close news server."
@@ -183,48 +150,39 @@ If the stream is opened, return T, otherwise return NIL."
   "Select article by message ID (or number)."
   (nnvirtual-possibly-change-newsgroups newsgroup server)
   (let (art)
-    (setq art (aref nnvirtual-mapping id))
+    (setq art (aref nnvirtual-current-mapping id))
     (gnus-request-group (car art))
     (gnus-request-article (cdr art) (car art) buffer)))
 
 (defun nnvirtual-request-group (group &optional server dont-check)
   "Make GROUP the current newsgroup."
-  (nnvirtual-possibly-change-newsgroups nil server)
-  (let* ((group (concat gnus-foreign-group-prefix group))
-        (info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
-        (groups nnvirtual-newsgroups)
-        (i 0)
-        (total 0)
-        unread igroup)
-    (if (not info)
-       (error "No such group: %s" group))
-    (setcar (nthcdr 2 info) nil)
-    (while groups
-      (setq unread (car (gnus-gethash (car groups) gnus-newsrc-hashtb)))
-      (if (numberp unread) (setq total (+ total unread)))
-      (setq groups (cdr groups)))
-    (setq nnvirtual-mapping (make-vector (+ 3 total) nil))
-    (setq groups nnvirtual-newsgroups)
-    (while groups
-      (setq igroup (car groups))
-      (setq unread (gnus-list-of-unread-articles igroup))
-      (while unread
-       (aset nnvirtual-mapping (setq i (1+ i)) (cons igroup (car unread)))
-       (setq unread (cdr unread)))
-      (setq groups (cdr groups)))
+  (nnvirtual-possibly-change-newsgroups group server dont-check)
+  (let ((total (length nnvirtual-current-mapping)))
     (save-excursion
       (set-buffer nntp-server-buffer)
       (erase-buffer)
-      (insert (format "211 %d %d %d %s\n" (1+ total) 1 total group)))
+      (insert (format "211 %d %d %d %s\n" total 1 (1- total) group)))
     t))
 
+(defun nnvirtual-close-group (group &optional server)
+  (nnvirtual-possibly-change-newsgroups group server)
+  (nnvirtual-update-marked)
+  (setq nnvirtual-current-group nil)
+  (setq nnvirtual-current-groups nil)
+  (setq nnvirtual-current-mapping nil)
+  (let ((inf (member group nnvirtual-group-alist)))
+    (setq nnvirtual-group-alist (delq inf nnvirtual-group-alist))))
+
 (defun nnvirtual-request-list (&optional server) 
-  "List active newsgoups."
   (setq nnvirtual-status-string "nnvirtual: LIST is not implemented.")
   nil)
 
+(defun nnvirtual-request-newgroups (date &optional server)
+  "List new groups."
+  (setq nnvirtual-status-string "NEWGROUPS is not supported.")
+  nil)
+
 (defun nnvirtual-request-list-newsgroups (&optional server)
-  "List newsgroups (defined in NNTP2)."
   (setq nnvirtual-status-string "nnvirtual: LIST NEWSGROUPS is not implemented.")
   nil)
 
@@ -233,13 +191,12 @@ If the stream is opened, return T, otherwise return NIL."
 (fset 'nnvirtual-request-post-buffer 'nntp-request-post-buffer)
 
 \f
-;;; Low-Level Interface
+;;; Low-level functions.
 
 (defun nnvirtual-open-server-internal ()
   "Fix some internal variables."
   (save-excursion
-    ;; Initialize communicatin buffer.
-    (setq nnvirtual-mapping nil)
+    ;; Initialize communication buffer.
     (setq nntp-server-buffer (get-buffer-create " *nntpd*"))
     (set-buffer nntp-server-buffer)
     (buffer-disable-undo (current-buffer))
@@ -250,11 +207,125 @@ If the stream is opened, return T, otherwise return NIL."
   "Close connection to news server."
   nil)
 
-(defun nnvirtual-possibly-change-newsgroups (group groups-regexp)
-  (if (and groups-regexp
-          (not (and nnvirtual-newsgroups-regexp
-                    (string= groups-regexp nnvirtual-newsgroups-regexp))))
-      (nnvirtual-open-server groups-regexp)))
+(defun nnvirtual-possibly-change-newsgroups (group regexp &optional dont-check)
+  (let (inf)
+    (or (not group)
+       (and nnvirtual-current-group
+            (string= group nnvirtual-current-group))
+       (and (setq inf (member group nnvirtual-group-alist))
+            (string= (nth 3 inf) regexp)
+            (progn
+              (setq nnvirtual-current-group (car inf))
+              (setq nnvirtual-current-groups (nth 1 inf))
+              (setq nnvirtual-current-mapping (nth 2 inf)))))
+    (if (or (not dont-check) (not inf))
+       (progn
+         (and inf (setq nnvirtual-group-alist 
+                        (delq inf nnvirtual-group-alist)))
+         (setq nnvirtual-current-mapping nil)
+         (setq nnvirtual-current-group group)
+         (let ((newsrc gnus-newsrc-assoc))
+           (setq nnvirtual-current-groups nil)
+           (while newsrc
+             (and (string-match regexp (car (car newsrc)))
+                  (setq nnvirtual-current-groups
+                        (cons (car (car newsrc)) nnvirtual-current-groups)))
+             (setq newsrc (cdr newsrc))))
+         (if nnvirtual-current-groups
+             (progn
+               (nnvirtual-create-mapping group)
+               (setq nnvirtual-group-alist
+                     (cons (list group nnvirtual-current-groups 
+                                 nnvirtual-current-mapping regexp)
+                           nnvirtual-group-alist)))
+           (setq nnvirtual-status-string 
+                 (format 
+                  "nnvirtual: No newsgroups for this virtual newsgroup"))))))
+  nnvirtual-current-groups)
+
+(defun nnvirtual-create-mapping (group)
+  (let* ((group (gnus-group-prefixed-name group (list 'nnvirtual "")))
+        (info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
+        (groups nnvirtual-current-groups)
+        (i 1)
+        (total 0)
+        unread igroup)
+    ;; The virtual group doesn't exist. (?)
+    (or info (error "No such group: %s" group))
+    ;; Set the list of read articles to nil.
+    (setcar (nthcdr 2 info) nil)
+    (while groups
+      ;; Added by Sudish Joseph <joseph@cis.ohio-state.edu>.
+      (setq igroup (car groups))
+      (let ((info (nth 2 (gnus-gethash igroup gnus-newsrc-hashtb)))
+           (active (gnus-gethash igroup gnus-active-hashtb)))
+       ;; see if the group has had its active list read this session
+       ;; if not, we do it now
+       (if (null active)
+           (if (gnus-activate-newsgroup igroup)
+               (gnus-get-unread-articles-in-group
+                info (gnus-gethash igroup gnus-active-hashtb))
+             (message "Couldn't request newsgroup %s" group)
+             (ding))))
+      (setq unread (car (gnus-gethash (car groups) gnus-newsrc-hashtb)))
+      (setq total (+ total unread))
+      (setq groups (cdr groups)))
+    ;; We create a mapping from nnvirtual article numbers (starting at
+    ;; 1) to the actual groups numbers.
+    (setq nnvirtual-current-mapping (make-vector (1+ total) nil))
+    (let ((groups nnvirtual-current-groups)
+         (marks '(tick dormant reply expire))
+         tick dormant reply expire marked)
+      (while groups
+       (setq igroup (car groups))
+       (setq marked (nth 3 (nth 2 (gnus-gethash igroup gnus-newsrc-hashtb))))
+       (setq unread (gnus-list-of-unread-articles igroup))
+       (while unread
+         (aset nnvirtual-current-mapping i (cons igroup (car unread)))
+         ;; Find out if the article is marked, and enter the marks in
+         ;; the proper lists. 
+         (let ((m marks))
+           (while m
+             (and (memq (car unread) (assq (car m) marked))
+                  (set (car m) (cons i (symbol-value (car m)))))
+             (setq m (cdr m))))
+         (setq i (1+ i))
+         (setq unread (cdr unread)))
+       (setq groups (cdr groups)))
+      ;; Put the list of marked articles in the info of the virtual group.
+      (let ((m marks)
+           marked)
+       (while m
+         (and (symbol-value (car m))
+              (setq marked (cons (cons (car m) (symbol-value (car m)))
+                                 marked)))
+         (setq m (cdr m)))
+       (if (nthcdr 3 info)
+           (setcar (nthcdr 3 info) marked)
+         (setcdr (nthcdr 2 info) (list marked)))))))
+
+(defun nnvirtual-update-marked ()
+  (let ((mark-lists '((gnus-newsgroup-marked . tick)
+                     (gnus-newsgroup-dormant . dormant)
+                     (gnus-newsgroup-expirable . expire)
+                     (gnus-newsgroup-replied . reply)))
+       marks art-group group-alist g)
+    (while mark-lists
+      (setq marks (symbol-value (car (car mark-lists))))
+      (while marks
+       (setq art-group (aref nnvirtual-current-mapping (car marks)))
+       (if (setq g (assoc (car art-group) group-alist))
+           (nconc g (list (cdr art-group)))
+         (setq group-alist (cons (list (car art-group) (cdr art-group)) 
+                                 group-alist)))
+       (setq marks (cdr marks)))
+      (while group-alist
+       (gnus-add-marked-articles (car (car group-alist)) 
+                                 (cdr (car mark-lists))
+                                 (cdr (car group-alist)))
+       (gnus-group-update-group (car (car group-alist)))
+       (setq group-alist (cdr group-alist)))
+      (setq mark-lists (cdr mark-lists)))))
 
 (provide 'nnvirtual)
 
index eb9ae76..5b7c550 100644 (file)
@@ -73,10 +73,12 @@ You can read news (and mail) from within Emacs by using (ding) Gnus.  The
 news can be gotten by any nefarious means you can think of - NNTP, local
 spool, mail spool.  All at the same time, if you want to push your luck.
 
+This manual documents (ding) Gnus 0.11.
+
 @menu
 * History::                 How Gnus got where it is today.
 * Starting Up::             Finding news can be a pain.
-* The Newsgroup Buffer::    Treating newsgroups.
+* The Group Buffer::        Treating groups.
 * The Summary Buffer::      Reading articles.
 * The Article Buffer::      Doing stuff to articles.
 * Various::                 General options.
@@ -93,8 +95,8 @@ spool, mail spool.  All at the same time, if you want to push your luck.
 GNUS was written by Masanobu UMEDA.  When autumn crept up in '94, Lars
 Ingebrigtsen grew bored and decided to write (ding) Gnus.
 
-(ding) Gnus is based on GNUS 4.1 and includes bits and pieces by Felix
-Lee and jwz.
+(ding) Gnus is based on GNUS 4.1 and includes bits and pieces by Per
+Abrahamsen, Sudish Joseph, Felix Lee and jwz. 
 
 The recommended pronounciation of the name this program is "ding
 guh-noose", with "ding" being half-sung in a loud, high-pitched voice,
@@ -135,8 +137,8 @@ internals should suffer no problems.  If problems occur, please let me
 know (@kbd{M-x gnus-bug}).
 
 However, code that depends on the buffers looking a particular way will
-almost invaribaly fail.  For instance, the Summary buffer does not
-display article numbers by default.
+almost invaribaly fail.  For instance, the summary buffer no longer 
+displays article numbers by default.
 
 @node New Features
 @section New Features
@@ -144,24 +146,23 @@ display article numbers by default.
 The look of all buffers can be changed by setting format-like variables.
  
 Local spool and several NNTP servers can be used at once.  Virtual
-newsgroups and private mail newsgroups are featured.
-
-Killing can be done on arbitrary headers.
+groups and private mail groups are featured.
 
-Gnus can generate dummy roots for threads that have lost their roots
-(thereby gathering loose sub-threads in one thread) or it can go back
-and retrieve enough headers to build a complete thread.
+Gnus can use various strategies for gathering threads that have lost
+their roots (thereby gathering loose sub-threads in one thread) or it
+can go back and retrieve enough headers to build a complete thread.
 
-Killed groups can be displayed in the Newsgroup buffer, and you can read
+Killed groups can be displayed in the group buffer, and you can read
 them as well.
 
 Gnus can do partial updates of new articles - you do not have to
 retrieve the entire active file just to check for new articles in a few
 groups.
 
-Gnus implements a sliding scale of subscribedness to newsgroups.
+Gnus implements a sliding scale of subscribedness to groups.
 
-Gnus can sort the displayed headers of articles.
+The approach to killing has been changed. Instead of simply killing or
+not, you can score articles for easier reading.
 
 @node Starting Up
 @chapter Starting Gnus
@@ -176,7 +177,8 @@ variables.
 @menu
 * Finding the News::    Choosing a method for getting news.
 * First Time::          What does Gnus do the first time you start it?
-* New Newsgroups::      What is Gnus supposed to do with new newsgroups?
+* The Server is Down::  How can I read my mail then?
+* New Groups::          What is Gnus supposed to do with new groups?
 * Startup Files::       Those pesky startup files - @file{.newsrc}.
 * Auto Save::           Recovering from a crash.
 * The Active File::     Reading the active file over a slow line Takes Time.
@@ -186,22 +188,23 @@ variables.
 @node Finding the News
 @section Finding the News
 
-@vindex gnus-default-select-method
-The @code{gnus-default-select-method} variable controls how Gnus finds
-news.  This variable should be a list where the first element says "how"
-and the second element says "where".
+@vindex gnus-select-method
+The @code{gnus-select-method} variable controls how Gnus finds news.
+This variable should be a list where the first element says "how" and
+the second element says "where". This server is is your @dfn{local
+server}. All other servers are @dfn{foreign servers}.
 
 For instance, if you want to get your daily dosage of news from the NNTP
 server "news.friendly.server", you'd say:
 
 @example
-(setq gnus-default-select-method '(nntp "news.friendly.server"))
+(setq gnus-select-method '(nntp "news.friendly.server"))
 @end example
 
 If you want to use a local spool, say:
 
 @example
-(setq gnus-default-select-method '(nnspool ""))
+(setq gnus-select-method '(nnspool ""))
 @end example
 
 If this variable is not set, Gnus will take a look at the
@@ -216,41 +219,68 @@ gnus'), Gnus will let you choose between the servers in the
 in the name of any server you feel like visiting.
 
 However, if you use one NNTP server regularly, and is just interested in
-a couple of newsgroups from a different server, you would be better
+a couple of groups from a different server, you would be better
 served by using the @code{gnus-group-browse-foreign-server} command from
-the Newsgroup buffer.  It will let you have a look at what groups are
+the group buffer.  It will let you have a look at what groups are
 available, and you can subscribe to any of the groups you want to.  This
 also makes @file{.newsrc} maintenance much tidier.
 
+@vindex gnus-secondary-select-methods
+A slightly different approach is to set the
+@code{gnus-secondary-select-methods}. The select methods listed in this
+variable are in many ways just as local as the @code{gnus-select-method}
+server. They will also be asked for active files during startup (if
+that's wanted), and new newsgroups that appear from these servers will
+be subscribed (or not) just as local groups are.
+
+For instance, if you use the @code{nnmbox} backend to read you mail, you
+would typically set this variable to
+
+@example
+(setq gnus-secondary-select-methods 
+  '((nnmbox "")))
+@end example
+
 @node First Time
 @section The First Time
 
 One time has to be the first, but it doesn't have to be painful.
 
-If no startup files exist, Gnus will try to determine what newsgroups
-should be subscribed by default.
+If no startup files exist, Gnus will try to determine what groups
+that should be subscribed by default.
 
 @vindex gnus-default-subscribed-newsgroups
 If the variable @code{gnus-default-subscribed-newsgroups} is set, Gnus
-will subscribe you to just those newsgroups in that list, leaving the
+will subscribe you to just those groups in that list, leaving the
 rest killed.  Your systems administrator should have set this variable to
 something useful.
 
-Since he hasn't, Gnus will ask the NNTP server (if you use one) if it
-has any idea. 
-
-If that fails as well, Gnus will just subscribe you to a few randomly
-picked newsgroups (ie. @samp{*.newusers}).
+Since she hasn't, Gnus will just subscribe you to a few randomly picked
+groups (ie. @samp{*.newusers}). (@dfn{Random} is here defined as
+"whatever Lars think you should read".)
 
 If @code{gnus-default-subscribed-newsgroups} is t, Gnus will just use
-the normal functions for treating new newsgroups, and not do anything
+the normal functions for treating new groups, and not do anything
 special.
 
-@node New Newsgroups
-@section New Newsgroups
+@node The Server is Down
+@section The Server is Down
+
+If the default server is down, Gnus will understandably have some
+problems starting. However, if you have some mail groups in addition to
+the news groups, you may want to start Gnus anyway.
+
+You can bo that by @kbd{M-x gnus-no-server}. This will start Gnus
+without attempting to contact the default server. Gnus will be started
+on level two, so you shouldn't have any groups from the local server on
+level one or two, but only have mail groups and other foreign groups on
+these two levels.
+
+@node New Groups
+@section New Groups
 
 @vindex gnus-subscribe-newsgroup-method
-What Gnus does when it encounters a new newsgroup is determined by the
+What Gnus does when it encounters a new group is determined by the
 @code{gnus-subscribe-newsgroup-method} variable.
 
 This variable should contain a function.  Some handy ready-made values
@@ -259,24 +289,24 @@ are:
 @table @code
 @item gnus-subscribe-randomly
 @vindex gnus-subscribe-randomly
-Subscribe all new newsgroups randomly.
+Subscribe all new groups randomly.
 
 @item gnus-subscribe-alphabetically
 @vindex gnus-subscribe-alphabetically
-Subscribe all new newsgroups alphabetically.
+Subscribe all new groups alphabetically.
 
 @item gnus-subscribe-hierarchically
 @vindex gnus-subscribe-hierarchically
-Subscribe all new newsgroups hierarchially.
+Subscribe all new groups hierarchially.
 
 @item gnus-subscribe-interactively
 @vindex gnus-subscribe-interactively
-Subscribe new newsgroups interactively.  This means that Gnus will ask
-you about *all* new newsgroups.
+Subscribe new groups interactively.  This means that Gnus will ask
+you about *all* new groups.
 
 @item gnus-subscribe-zombies
 @vindex gnus-subscribe-zombies
-Make all new newsgroups zombies.  You can browse the zombies later and
+Make all new groups zombies.  You can browse the zombies later and
 either kill them off properly or subscribe to them.  This is the
 default. 
 
@@ -284,23 +314,51 @@ default.
 
 @vindex gnus-subscribe-hierarchical-interactive
 A closely related variable is
-@code{gnus-subscribe-hierarchical-interactive}.  If this variable is
-non-nil, Gnus will ask you in a hierarchial fashion whether to subscribe
-to new newsgroups or not.  Gnus will ask you for each sub-hierarchy
-whether you want to descend the hierarchy or not. 
+@code{gnus-subscribe-hierarchical-interactive}. (That's quite a
+mouthful.)  If this variable is non-nil, Gnus will ask you in a
+hierarchial fashion whether to subscribe to new groups or not.  Gnus
+will ask you for each sub-hierarchy whether you want to descend the
+hierarchy or not.
+
+One common way to control which new newsgroups should be subscribed or
+ignored is to put an @dfn{options} line at the start of the
+@file{.newsrc} file. Here's an example:
+
+@example
+options -n !alt.all !rec.all sci.all
+@end example
+
+@vindex gnus-subscribe-options-newsgroup-method
+This line obviously belongs to a serious-minded intellectual scientific
+person (or she may just be plain old boring), because it says that all
+groups that have names beginning with @samp{alt} and @samp{rec} should
+be ignored, and all groups with names beginning with @samp{sci} should
+be subscribed. Gnus doesn't use the normal subscription method for
+subscribing these groups. @code{gnus-subscribe-options-newsgroup-method}
+is used instead. This variable defaults to
+@code{gnus-subscribe-alphabetically}. 
 
 @vindex gnus-check-new-newsgroups
 If you are satisfied that you never really want to see any new
-newsgroups, you could set @code{gnus-check-new-newsgroups} to
+groups, you could set @code{gnus-check-new-newsgroups} to
 nil.  This will also save you some time at startup.  Even if this
-variable is nil, you can always subscribe to the new newsgroups
-by just pressing @kbd{U} in the @dfn{Newsgroup buffer}.
+variable is nil, you can always subscribe to the new groups
+by just pressing @kbd{U} in the @dfn{group buffer}.
+
+If @code{gnus-check-new-newsgroups} is @code{ask-server}, Gnus will ask
+the server for new groups since last time it asked instead of
+determining what groups are new by comparing active groups with known
+groups. This is both faster & cheaper. This also means that you can get
+rid of the list of killed groups altogether, so you may set
+@code{gnus-save-killed-list} to nil, which will save time both at
+startup, at exit, and all over. Saves disk space, too. The only problem
+with this method is that not all servers support this functionality.
 
 @node Startup Files
 @section Startup Files
 
 Now, you all know about the @file{.newsrc} files.  All information about
-what newsgroups you read is traditionally stored in this file, which has
+what groups you read is traditionally stored in this file, which has
 a rather rigid structure.
 
 Things got a bit more complicated with GNUS.  In addition to keeping the
@@ -325,15 +383,14 @@ than (ding) Gnus.  But hey, who would want to, right?
 @vindex gnus-save-killed-list
 If @code{gnus-save-killed-list} is nil, Gnus will not save the list of
 killed groups to the startup file.  This will save both time (when
-starting and quitting) and space (on disk).  It will also means that Gnus
-has no record of what newsgroups are new or old, so the automatic new
-newsgroups subscription methods become meaningless.  You should always
-set `gnus-check-new-newsgroups' to nil if you set this variable to
-nil.
+starting and quitting) and space (on disk).  It will also means that
+Gnus has no record of what groups are new or old, so the automatic new
+groups subscription methods become meaningless.  You should always set
+@code{gnus-check-new-newsgroups} to nil if you set this variable to nil.
 
 @vindex gnus-startup-file
-The @code{gnus-startup-file} variable says where the startup files
-are.  The default value is @file{"~/.newsrc"}, with the Gnus (El Dingo)
+The @code{gnus-startup-file} variable says where the startup files are.
+The default value is @file{"~/.newsrc"}, with the Gnus (El Dingo)
 startup file being whatever that one is with a @samp{".eld"} appended.
 
 @vindex gnus-save-newsrc-hook
@@ -344,9 +401,9 @@ file.
 @section Auto Save
 
 Whenever you do something that changes the Gnus data (reading articles,
-cathing up, killing/subscribing to newsgroups,) the change is added to a
-special @dfn{dribble} buffer.  This buffer is auto-saved the normal Emacs
-way.
+cathing up, killing/subscribing to groups,) the change is added to a
+special @dfn{dribble} buffer.  This buffer is auto-saved the normal
+Emacs way.
 
 If Gnus detects this file at startup, it will ask the user whether to
 read it.
@@ -357,12 +414,12 @@ The auto save file is deleted whenever the real startup file is saved.
 @section The Active File
 
 When Gnus starts, or indeed whenever it tries to determine if new
-articles has arrived, it reads the active file.  This is a file stored on
-the NNTP server or in the local spool. 
+articles has arrived, it reads the active file.  This is a file stored
+on the NNTP server or in the local spool.
 
 @vindex gnus-ignored-newsgroups
-Before examining the active file to see what newsgroups are available,
-Gnus deletes all lines in this file that match
+Before examining the active file to see what groups are available, Gnus
+deletes all lines in this file that match
 @code{gnus-ignored-newsgroups}.  You may even use this variable to make
 Gnus ignore hierarchies you aren't interested in.
 
@@ -371,75 +428,73 @@ The active file can be rather Huge, so if you have a slow network, you
 can set @code{gnus-read-active-file} to nil to prevent Gnus from reading
 the entire active file.
 
-Gnus will try to make do by just getting information on the newsgroups
+Gnus will try to make do by just getting information on the groups
 that you actually subscribe to.
 
-Note that if you subscribe to lots and lots of newsgroups, setting this
+Note that if you subscribe to lots and lots of groups, setting this
 variable to nil will probabaly make Gnus slower, not faster.
 
-
-
 @node Startup Variables
 @section Startup Variables
 
 @table @code
 @item gnus-check-bogus-newsgroups
 @vindex gnus-check-bogus-newsgroups
-If non-nil, Gnus will check for and delete all bogus newsgroups at
-startup.  A @dfn{bogus newsgroup} is a newsgroup that you have in you
+If non-nil, Gnus will check for and delete all bogus groups at
+startup.  A @dfn{bogus group} is a group that you have in you
 @file{.newsrc} file, but doesn't exist on the news server.  Checking for
-bogus newsgroups isn't very quick, so to save time and resources, it's
+bogus groups isn't very quick, so to save time and resources, it's
 best to leave this option off, and instead do the checking for bogus
-newsgroups once in a while from the Newsgroup buffer.
+groups once in a while from the group buffer.
 @item gnus-inhibit-startup-message
 @vindex gnus-inhibit-startup-message
 If non-nil, the startup message won't be displayed.  That way, nobody will
 notice thay you are reading news instead of doing your job.
 @end table
 
-@node The Newsgroup Buffer
-@chapter The Newsgroup Buffer
+@node The Group Buffer
+@chapter The Group Buffer
 
-The @dfn{Newsgroup buffer} lists all (or parts) of the available
-newsgroups and displays various information regarding these groups. 
+The @dfn{group buffer} lists all (or parts) of the available
+groups and displays various information regarding these groups. 
 It is the first buffer displayed when Gnus starts.
 
 @menu
-* Newsgroup Buffer Format::  Information listed and how you can change it.
-* Newsgroup Manouvering::    Commands for moving in the newsgroup buffer.
-* Selecting a Newsgroup::    Actually reading news.
-* Newsgroup Subscribing::    Unsubscribing, killing, subscribing.
-* Newsgroup Levels::         Levels? What are those, then?
-* Foreign Newsgroups::       How to create foreign newsgroups.
-* Listing Groups::           Gnus can list various portions of the groups.
-* Newsgroup Maintenance::    Maintaining a tidy @file{.newsrc} file.
-* Browse Foreign Server::    You can browse a server.  See what if has to offer.
-* Exiting Gnus::             Stop reading news and get some work done.
-* Misc Newsgroup Stuff::     Other stuff that you can to do.
+* Group Buffer Format::    Information listed and how you can change it.
+* Group Manouvering::      Commands for moving in the group buffer.
+* Selecting a Group::      Actually reading news.
+* Group Subscribing::      Unsubscribing, killing, subscribing.
+* Group Levels::           Levels? What are those, then?
+* Foreign Groups::         How to create foreign groups.
+* Listing Groups::         Gnus can list various classes of groups.
+* Group Maintenance::      Maintaining a tidy @file{.newsrc} file.
+* Browse Foreign Server::  You can browse a server.  See what if has to offer.
+* Exiting Gnus::           Stop reading news and get some work done.
+* Misc Group Stuff::       Other stuff that you can to do.
 @end menu
 
-@node Newsgroup Buffer Format
-@section Newsgroup Buffer Format
+@node Group Buffer Format
+@section Group Buffer Format
 
-The default format of the Newsgroup buffer is nice and dull, but you can
+The default format of the group buffer is nice and dull, but you can
 make it as exciting and ugly as you feel like.
 
-Here's a couple of example newsgroup lines:
+Here's a couple of example group lines:
 
 @example
      25: news.announce.newusers
- *    3: alt.fan.andrea-dworkin
+ *    0: alt.fan.andrea-dworkin
 @end example
 
 Quite simple, huh?
 
 Those lines mean that there are 25 unread articles in
-@samp{news.announce.newusers} and 3 marked articles in
-@samp{alt.fan.andrea-dworkin} and no unread artcles (see that little
-asterisk at the beginning of the line?)
+@samp{news.announce.newusers} and no unread articles, but some ticked
+articles in @samp{alt.fan.andrea-dworkin} (see that little asterisk at
+the beginning of the line?)
 
 @vindex gnus-group-line-format
-You can fuck that up to your hearts delight by fiddling with the
+You can fuck that up to your heart's delight by fiddling with the
 @code{gnus-group-line-format} variable.  This variable works along the
 lines of a @code{format} specification, which is pretty much the same as
 a @code{printf} specifications, for those of you who use (feh!) C.
@@ -449,10 +504,10 @@ which means that the field will be at least 7 characters long, and no
 more that 12 characters long.
 
 The default value that produced those lines above is 
-@samp{"%M%S%5N: %G\n"}.
+@samp{"%M%S%5y: %g\n"}.
 
 There should always be a colon on the line; the cursor is always moved
-to the colon.  Nothing else is required - not even the newsgroup name. 
+to the colon.  Nothing else is required - not even the group name. 
 
 Here's a list of all available format characters:
 
@@ -465,14 +520,28 @@ Whether the group is subscribed
 Level of subscribedness 
 @item N
 Number of unread articles
+@item I
+Number of dormant articles
+@item T
+Number of ticked articles
+@item R
+Number of read articles
+@item t
+Total number of articles
+@item y
+Number of unread, unticked, non-dormant articles
+@item i
+Number of ticked and dormant articles
+@item g
+Full group name
 @item G
 Group name 
-@item m
-Number of marked articles 
-@item T
-Total number of articles; both read and unread 
 @item D
 Newsgroup description
+@item o
+Moderated
+@item O
+Moderated
 @item s
 Select method 
 @item n
@@ -483,9 +552,8 @@ used.
 @end table
 
 @vindex gnus-group-mode-line-format
-The mode line can also be changed by using the
-@code{gnus-group-mode-line-format} variable.  It does not understand that
-many format specifiers:
+The mode line can also be changed (@code{gnus-group-mode-line-format}).
+It does not understand that many format specifiers:
 
 @table @samp
 @item S
@@ -494,8 +562,8 @@ Default news server
 Default select method
 @end table
 
-@node Newsgroup Manouvering
-@section Newsgroup Manouvering
+@node Group Manouvering
+@section Group Manouvering
 
 All movement commands understand the numeric prefix and will behave as
 expected, hopefully. 
@@ -512,14 +580,12 @@ Go to the next group with unread articles
 @findex gnus-group-prev-unread-group
 Go to the previous group group with unread articles
 (@code{gnus-group-prev-unread-group}). 
-@item N, C-n
+@item N
 @kindex N (Group)
-@kindex C-n (Group)
 @findex gnus-group-next-group
 Go to the next group (@code{gnus-group-next-group}).
-@item P, C-p
+@item P
 @kindex P (Group)
-@kindex C-p (Group)
 @findex gnus-group-prev-group
 Go to the previous group (@code{gnus-group-prev-group}).
 @item M-p
@@ -539,103 +605,103 @@ Jump to a group (and make it visible if it isn't already)
 (@code{gnus-group-jump-to-group}). 
 @end table
 
-@node Selecting a Newsgroup
-@section Selecting a Newsgroup
+@node Selecting a Group
+@section Selecting a Group
 
 @table @kbd
 @item SPACE
 @kindex SPACE (Group)
 @findex gnus-group-read-group
-Select the current newsgroup, switch to the Summary buffer and display
-the first unread article in the newsgroup
+Select the current group, switch to the summary buffer and display
+the first unread article in the group
 (@code{gnus-group-read-group}).  If there are no unread articles in the
-newsgroup, or if you give a prefix to this command, Gnus will offer to
-fetch all the old articles in this newsgroup from the server.
+group, or if you give a prefix to this command, Gnus will offer to
+fetch all the old articles in this group from the server.
 server. 
-@item =
-@kindex = (Group)
+@item RET
+@kindex RET (Group)
 @findex gnus-group-select-group
-Select the current newsgroup and switch to the Summary buffer
+Select the current group and switch to the summary buffer
 (@code{gnus-group-select-group}). 
 @item c
 @kindex c (Group)
 @findex gnus-group-catchup-current
-Mark all unticked articles in this newsgroup as read
+Mark all unticked articles in this group as read
 (@code{gnus-group-catchup-current}). 
 @item C
 @kindex C (Group)
 @findex gnus-group-catchup-current-all
-Mark all articles in this newsgroup, even the ticked ones, as read
+Mark all articles in this group, even the ticked ones, as read
 (@code{gnus-group-catchup-current-all}). 
 @end table
 
 @vindex gnus-large-newsgroup
 The @code{gnus-large-newsgroup} variable says what Gnus considers to be
-a "big" newsgroup.  If the newsgroup is big, Gnus will query the user
-before entering the newsgroup.  The user can then specify how many
-articles should be fetched from the server.  If the user specifies a
-negative number (@samp{-n}), the @samp{n} articles that have arrived
-most recently will be fetched.  If it is positive, the @samp{n} oldest
-articles will be fetched.
+a "big" group.  If the group is big, Gnus will query the user before
+entering the group.  The user can then specify how many articles should
+be fetched from the server.  If the user specifies a negative number
+(@samp{-n}), the @samp{n} oldest articles will be fetched.  If it is
+positive, the @samp{n} articles that have arrived most recently will be
+fetched.
 
 @vindex gnus-auto-select-newsgroup
 If @code{gnus-auto-select-newsgroup} is non-nil, the first unread
-article in the newsgroup will be displayed when you enter the
-newsgroup.  If you want to prevent automatic selection in some newsgroup
-(say, in a binary newsgroup with Huge articles) you can set til variable
-to nil in `gnus-select-group-hook', which is called when a newsgroup is
-selected.  This hook is also popularly used for sorting headers before
-generating the Summary buffer.
+article in the group will be displayed when you enter the group.  If you
+want to prevent automatic selection in some group (say, in a binary
+group with Huge articles) you can set this variable to nil in
+`gnus-select-group-hook', which is called when a group is selected.
+This hook is also popularly used for sorting headers before generating
+the summary buffer.
 
-@node Newsgroup Subscribing
-@section Newsgroup Subscribing
+@node Group Subscribing
+@section Group Subscribing
 
 @table @kbd
 @item u
 @kindex u (Group)
 @findex gnus-group-unsubscribe-current-group
-Unsubscribe the current newsgroup, or, if it was unsubscribed already,
+Unsubscribe the current group, or, if it was unsubscribed already,
 subscribe it (@code{gnus-group-unsubscribe-current-group}). 
 @item U
 @kindex U (Group)
 @findex gnus-group-unsubscribe-group
-Ask the user for a newsgroup to unsubscribe, and then unsubscribe it.  If
+Ask the user for a group to unsubscribe, and then unsubscribe it.  If
 it was unsubscribed already, subscribe it instead
 (@code{gnus-group-unsubscribe-group}). 
-@item k
-@kindex k (Group)
+@item C-k
+@kindex C-k (Group)
 @findex gnus-group-kill-group
-Kill the current newsgroup (@code{gnus-group-kill-group}).
-@item y
-@kindex y (Group)
+Kill the current group (@code{gnus-group-kill-group}).
+@item C-y
+@kindex C-y (Group)
 @findex gnus-group-yank-group
-Yank the last killed newsgroup (@code{gnus-group-yank-group}).
+Yank the last killed group (@code{gnus-group-yank-group}).
 @item C-w
 @kindex C-w (Group)
 @findex gnus-group-kill-region
-Kill all newsgroups in the region (@code{gnus-group-kill-region}). 
+Kill all groups in the region (@code{gnus-group-kill-region}). 
 @item M-z
 @kindex M-z (Group)
 @findex gnus-group-kill-all-zombies
-Kill all zombie newsgroups (@code{gnus-group-kill-all-zombies}).
+Kill all zombie groups (@code{gnus-group-kill-all-zombies}).
 @end table
 
-@node Newsgroup Levels
-@section Newsgroup Levels
+@node Group Levels
+@section Group Levels
 
-All newsgroups have a level of "subscribedness".  For instance, if a
-newsgroup is on level 2, it is "more" subscribed than a newsgroup on
-level 5.  You can ask Gnus to just list newsgroups on a given level and
-lower, or to just check new articles in newsgroups on a given level and
+All groups have a level of "subscribedness".  For instance, if a
+group is on level 2, it is "more" subscribed than a group on
+level 5.  You can ask Gnus to just list groups on a given level and
+lower, or to just check new articles in groups on a given level and
 lower, etc. 
 
 @table @kbd
-@item s
-@kindex s (Group)
+@item S
+@kindex S (Group)
 @findex gnus-group-set-current-level
-Set the level of the current newsgroup depending on the numeric
+Set the level of the current group depending on the numeric
 prefix.  For instance, @kbd{3 s} will set the level of the current
-newsgroup to three (@code{gnus-group-set-current-level}).
+group to three (@code{gnus-group-set-current-level}).
 @end table
 
 Gnus considers groups on levels 1-5 to be subscribed, 6-7 to be
@@ -644,68 +710,73 @@ completely dead.  Gnus treats subscribed and unsubscribed groups exactly
 the same, but zombie and killed groups have no information on what
 articles you have read, etc, stored.
 
+It is recommended that you keep all your "ordinary" groups on level 3 or
+higher, and keep your mail groups (if any) on level 1 or 2.
+
 @vindex gnus-keep-same-level
 If @code{gnus-keep-same-level} is non-nil, some movement commands will
 only move to groups that are of the same level (or lower).  In
-particular, going from the last article in one newsgroup to the next
-newsgroup will go to the next newsgroup of the same level (or
-lower).  This might be handy if you want to read the most important
-newsgroups before you read the rest.
+particular, going from the last article in one group to the next group
+will go to the next group of the same level (or lower).  This might be
+handy if you want to read the most important groups before you read the
+rest.
 
-@node Foreign Newsgroups
-@section Foreign Newsgroups
+@node Foreign Groups
+@section Foreign Groups
 
-A @dfn{foreign newsgroup} is a newsgroup that is not read by the usual
-(or default) means.  It could be, for instance, a newsgroup from a
-different NNTP server, it could be a virtual newsgroup or it could be a
-"newsgroup" of your own personal mail.
+A @dfn{foreign group} is a group that is not read by the usual (or
+default) means.  It could be, for instance, a group from a different
+NNTP server, it could be a virtual group or it could be your own
+personal mail group.
 
 @table @kbd
 @item M-a
 @kindex M-a (Group)
-@findex gnus-group-add-newsgroup
-Add a new newsgroup.  Gnus will prompt you for a name, a method and an
-"address" (@code{gnus-group-add-newsgroup}).
+@findex gnus-group-add-group
+Add a new group.  Gnus will prompt you for a name, a method and an
+"address" (@code{gnus-group-add-group}).
 @item M-e
 @kindex M-e (Group)
-@findex gnus-group-edit-newsgroup
-Edit a newsgroup entry.  Gnus will pop up a new buffer where you can edit
-the entry (@code{gnus-group-edit-newsgroup}). 
+@findex gnus-group-edit-group
+Edit a group entry.  Gnus will pop up a new buffer where you can edit
+the entry (@code{gnus-group-edit-group}).
 @end table
 
 The different methods all have their peculiarities, of course.
 
 @menu
-* nntp::           Reading news from a different NNTP server
-* nnspool::        Reading news from the local spool
-* nnvirtual::      Combining articles from many newsgroups
-* Mail::           Reading your personal mail with Gnus
+* nntp::           Reading news from a different NNTP server.
+* nnspool::        Reading news from the local spool.
+* nnvirtual::      Combining articles from many groups.
+* nndir::          You can read a directory as if it were a newsgroup.
+* Mail::           Reading your personal mail with Gnus.
 @end menu
 
 @vindex gnus-activate-foreign-newsgroups
-If the @code{gnus-activate-foreign-newsgroups} is t, Gnus will
-check all foreign newsgroup at startup.  This might take quite a while,
-especially if you subscribe to lots of groups from different NNTP
-servers.  It is @code{nil} by default, which means that you won't be told
-whether there are new articles in these groups.  How many unread articles
-there are will be determined when, or if, you decide to enter them.
+If the @code{gnus-activate-foreign-newsgroups} is a positive number,
+Gnus will check all foreign groups with this level or lower at startup.
+This might take quite a while, especially if you subscribe to lots of
+groups from different NNTP servers.  It is nil by default, which means
+that you won't be told whether there are new articles in these groups.
+How many unread articles there are will be determined when, or if, you
+decide to enter them.
 
 @node nntp
 @subsection nntp
 
 Subscribing to a foreign group from an NNTP server is rather easy.  You
 just specify @code{nntp} as method and the address of the NNTP server as
-the, uhm, address. 
+the, uhm, address.
 
-The name of the foreign newsgroup can be the same as a native
-newsgroup.  However, two foreign newsgroup can not have the same names. 
+The name of the foreign group can be the same as a native group.  In
+fact, you can subscribe to the same group from as many different servers
+you feel like. There will be no name collisions.
 
 @node nnspool
 @subsection nnspool
 
 Subscribing to a foreign group from the local spool is extremely easy,
-even though I don't see quite why you'd want to.  If you have a local
-spool, why don't you use that as the default method?
+and might be useful, for instance, to speed up reading binaries groups. 
 
 Anyways, you just specify @code{nnspool} as the method and @samp{""} as
 the address.
@@ -713,29 +784,40 @@ the address.
 @node nnvirtual
 @subsection nnvirtual
 
-A @dfn{virtual newsgroup} is really nothing more than a collection of
-other newsgroups. 
+A @dfn{virtual group} is really nothing more than a collection of
+other groups. 
 
 You specify @code{nnvirtual} as the method and a regular expression that
-says which newsgroups that you wish to have in this one as the address. 
+says which groups that you wish to have in this one as the address. 
 
-For instance, if you are tired of reading many small newsgroup, you can
-put them all in one big newsgroup, and then grow tired of reading one
-big, unwieldy newsgroup.  The joys of computing!
+For instance, if you are tired of reading many small group, you can
+put them all in one big group, and then grow tired of reading one
+big, unwieldy group.  The joys of computing!
 
 @example
 "^alt\\.fan\\.andrea-dworkin$\\|rec\\.dworkin.*"
 @end example
 
-These newsgroups can be native or foreign; everything should work
-smoothly, but if your computer should explode, it was probably my
-fault.  (Including other virtual newsgroups in this one will probably
-confuse Gnus, so don't do that.)
+These groups can be native or foreign; everything should work smoothly,
+but if your computer explodes, it was probably my fault.  (Including
+other virtual groups in this one will probably confuse Gnus, so don't do
+that.)
+
+One limitation, however - all groups that are included in a virtual
+group has to be alive (ie. subscribed or unsubscribed).  In fact, if you
+include a group in a virtual group, and it was killed, it will be
+subscribed automagically.
 
-One limitation, however - all newsgroups that are included in 
-a virtual newsgroup has to be alive (ie. subscribed or unsubscribed).  In
-fact, if you include a newsgroup in a virtual newsgroup, and it was
-killed, it will be subscribed automagically.
+@node nndir
+@subsection nndir
+
+If you have a directory that has lots of articles in separate files in
+it, you might treat it as a newsgroup. The files have to have numerical
+names, of course.
+
+This situation is kinda special, so there's a shortcut for creating
+these "groups": @kbd{d} (@code{gnus-group-make-directory-group}) in the
+group buffer. You will be prompted for a directory to read.
 
 @node Mail
 @subsection Mail
@@ -744,18 +826,19 @@ Reading mail with a newsreader - isn't that just plain WeIrD? But of
 course.
 
 @menu
-* Creating Mail Newsgroups::     How to create mail newsgroups (duh).
-* Expiring Old Mail Articles::   Yes.
+* Creating Mail Groups::         How to create mail groups (duh).
+* Expiring Old Mail Articles::   Getting rid of unwanted mail.
 @end menu
 
-Gnus will read the mail spool when you activate the newsgroup.  The mail
+Gnus will read the mail spool when you activate a mail group.  The mail
 file is first copied to your home directory.  What happens after that
 depends on what format you want to store you mail in.
 
 @menu
-* nnmail::    Using the quite standard Un*x mbox.
+* nnmbox::    Using the quite standard Un*x mbox.
 * nnrmail::   Many Emacs programs use the rmail babyl format.
 * nnml::      Store your mail in a private spool?
+* nnmh::      An mhspool-like backend useful for procmail people.
 @end menu
 
 @vindex nnmail-read-incoming-hook
@@ -764,31 +847,30 @@ reading new mail.  You can use this hook to notify any mail watch
 programs, if you want to.
 
 Gnus gives you all the opportunity you want for shooting yourself in
-your foot.  Let's say you create a newsgroup that will contain all the
-mail you get from your boss.  And then you accidentally unsubscribe from
-the newsgroup.  Gnus will still put all the mail from your boss in the
-unsubscribed newsgroup, and so, when your boss mails you "Have that
-report ready by Monday or you're fired!", you'll never see it and, come
-Tuesday, you'll still beleive that you're gainfully unemplyed while you
+your foot.  Let's say you create a group that will contain all the mail
+you get from your boss.  And then you accidentally unsubscribe from the
+group.  Gnus will still put all the mail from your boss in the
+unsubscribed group, and so, when your boss mails you "Have that report
+ready by Monday or you're fired!", you'll never see it and, come
+Tuesday, you'll still believe that you're gainfully unemplyed while you
 really should be out collecting empty bottles to save up for next
 month's rent money.
 
-@node Creating Mail Newsgroups
-@subsubsection Creating Mail Newsgroups
-
-There are two ways of making Gnus read your personal, private, secret
-mail.  One is pretty easy, and the other requires minor tinkering.
+@node Creating Mail Groups
+@subsubsection Creating Mail Groups
 
-@kindex M-x gnus-group-make-mail-groups (Summary)
-First the easy way: Type @kbd{M-x gnus-group-make-mail-groups}.  That
-will create a newsgroup called @samp{mail.misc} that will contain all
-your mail.
+You can make Gnus read your personal, private, secret mail.
 
-Then the hard(er) way.
+You should first set @code{gnus-secondary-select-methods} to, for
+instance, @code{((nnmbox ""))}. When you start up Gnus, Gnus will ask
+this backend for what groups it has (@samp{mail.misc} by default) and
+subscribe it the normal way. (Which means you may have to look for it
+among the zombie groups, I guess, all depending on your
+@code{gnus-subscribe-newsgroup-method} variable.)
 
 @vindex nnmail-split-methods
-Set the variable @code{nnmail-split-methods} to specify how the incoming
-mail is to be split into newsgroups.
+The you should set the variable @code{nnmail-split-methods} to specify
+how the incoming mail is to be split into groups.
 
 @example
 (setq nnmail-split-methods
@@ -798,46 +880,44 @@ mail is to be split into newsgroups.
 @end example
 
 This variable is a list of lists, where the first element of each of
-these lists contain the name of the mail newsgroup (they do not have to
-be called something beginning with @samp{"mail"}, by the way), and the
+these lists contain the name of the mail group (they do not have to be
+called something beginning with @samp{"mail"}, by the way), and the
 second element is a regular expression used on the header of each mail
-to determine if it belongs in this mail newsgroup.
+to determine if it belongs in this mail group.
 
-The last of these newsgroups should always be a general one, and the
-regular expression should *always* be @samp{""} so that it matches all
-mails.
-
-You should always do a @kbd{M-x gnus-group-make-mail-groups} after
-changing this variable to create all the newsgroups you have specified. 
+The last of these groups should always be a general one, and the regular
+expression should *always* be @samp{""} so that it matches all mails.
 
 @node Expiring Old Mail Articles
 @subsubsection Expiring Old Mail Articles
 
 Traditional mail readers have a tendency to remove mail articles when
-you mark them as read, in some way.  Gnus takes a fundamentally different
-approach to mail reading.
+you mark them as read, in some way.  Gnus takes a fundamentally
+different approach to mail reading.
 
 Gnus basically considers mail just to be news that has been received in
 a rather peculiar manner.  It does not think that it has the power to
 actually change the mail, or delete any mail messages.  If you enter a
-mail newsgroup, and mark articles as "read", or kill them in some other
+mail group, and mark articles as "read", or kill them in some other
 fashion, the mail articles will still exist on the system.  I repeat:
 Gnus will not delete your old, read mail.  Unless you ask it to, of
-course. 
+course.
 
 To make Gnus get rid of your unwanted mail, you have to mark the
 articles as @dfn{expirable}.  This does not mean that the articles will
 disappear right away, however.  In general, a mail article will be
 deleted from your system if, 1) it is marked as expirable, AND 2) it is
 more than one week old.  If you do not mark an article as expirable, it
-will remain on your system until hell freezes over.
+will remain on your system until hell freezes over. This bears repeating
+one more time, with some spurious capitalization: IF you do NOT mark
+articles as EXPIRABLE, Gnus will NEVER delete those ARTICLES.
 
 @vindex gnus-auto-expirable-newsgroups
-You do not have to mark articles as expirable by
-hand.  Newsgroups that match the regular expression
-@code{gnus-auto-expirable-newsgroups} will have all articles that you
-read marked as expirable automatically.  All articles that are marked as
-expirable have an "X" in the third column in the Summary buffer.
+You do not have to mark articles as expirable by hand.  Groups that
+match the regular expression @code{gnus-auto-expirable-newsgroups} will
+have all articles that you read marked as expirable automatically.  All
+articles that are marked as expirable have an @samp{X} in the third
+column in the summary buffer.
 
 Let's say you subscribe to a couple of mailing lists, and you want the
 articles you have read to disappear after a while:
@@ -849,13 +929,13 @@ articles you have read to disappear after a while:
 
 @vindex nnmail-expiry-wait
 The @code{nnmail-expiry-wait} variable supplies the default time an
-expirable article has to live.  The default is 7 - seven days. 
+expirable article has to live.  The default is seven days.
 
 Gnus also supplies a function that lets you fine-tune how long articles
-are to live, based on what newsgroup they are in.  Let's say you want to
-have one month expiry period in the @samp{mail.private} newsgroup, a
-one day expiry period in the @samp{mail.junk} newsgroup, and a six day
-expiry period everywhere else:
+are to live, based on what group they are in.  Let's say you want to
+have one month expiry period in the @samp{mail.private} group, a one day
+expiry period in the @samp{mail.junk} group, and a six day expiry period
+everywhere else:
 
 @example
 (setq nnmail-expiry-wait-function
@@ -868,15 +948,15 @@ expiry period everywhere else:
                 6))))
 @end example
 
-@node nnmail
-@subsubsection nnmail
+@node nnmbox
+@subsubsection nnmbox
 
-@vindex nnmail-active-file
-@vindex nnmail-mbox-file
-The @dfn{nnmail} backend will use the standard Un*x mbox file to store
-mail.  The path of the mbox file is given by the @code{nnmail-mbox-file}
+@vindex nnmbox-active-file
+@vindex nnmbox-mbox-file
+The @dfn{nnmbox} backend will use the standard Un*x mbox file to store
+mail.  The path of the mbox file is given by the @code{nnmbox-mbox-file}
 variable.  In addition, Gnus needs to store information about active
-articles.  The file specified by @code{nnmail-active-file} will be used
+articles.  The file specified by @code{nnmbox-active-file} will be used
 for that.
 
 @node nnrmail
@@ -898,9 +978,9 @@ known format.  It should be used with some caution.
 
 @vindex nnml-directory
 If you use this backend, Gnus will split all incoming mail into files;
-one file for each mail and put the articles into the correct directories
-under the directory specified by the @code{nnml-directory} variable.  The
-default value is @samp{"~/Mail/"}.
+one file for each mail, and put the articles into the correct
+directories under the directory specified by the @code{nnml-directory}
+variable.  The default value is @samp{"~/Mail/"}.
 
 You do not have to create any directories beforehand; Gnus will take
 care of all that.
@@ -911,8 +991,21 @@ own file, you might very well occupy thousands of inodes within a few
 weeks.  If this is no problem for you, and it isn't a problem for you
 having your friendly systems administrator walking around, madly,
 shouting "Who is eating all my inodes?! Who? Who!?!", then you should
-know that this is probably the fastest format to use.  You do not have to
-trudge through a big mbox file just to read your new mail.
+know that this is probably the fastest format to use.  You do not have
+to trudge through a big mbox file just to read your new mail.
+
+@code{nnml} is probably the slowest backend when it comes to article
+splitting. It has to create lots of files, and it also generates NOV
+databases for the incoming mails. This makes is the fastest backend when
+it comes to reading mail.
+
+@node nnmh
+@subsubsection nnmh
+
+@code{nnmh} is just like @code{nnml}, except that is doesn't generate
+NOV databases and it doesn't keep an active file. This makes @code{nnmh}
+a *much* slower backend than @code{nnml}, but it also makes it easier to
+write procmail scripts for.
 
 @node Listing Groups
 @section Listing Groups
@@ -922,51 +1015,50 @@ trudge through a big mbox file just to read your new mail.
 @kindex l (Group)
 @findex gnus-group-list-groups
 List all subscribed groups that have unread articles
-(@code{gnus-group-list-groups}). 
-If the numeric prefix is used, this command will list only newsgroups of
-level ARG and lower.  By default, it only lists newsgroups of level five
-or lower (ie. just subscribed groups).
+(@code{gnus-group-list-groups}).  If the numeric prefix is used, this
+command will list only groups of level ARG and lower.  By default, it
+only lists groups of level five or lower (ie. just subscribed groups).
 @item L
 @kindex L (Group)
 @findex gnus-group-list-all-groups
-List all subscribed and unsubscribed newsgroups, whether they have
-unread articles or not (@code{gnus-group-list-all-groups}).
-If the numeric prefix is used, this command will list only newsgroups of
-level ARG and lower.  By default, it lists newsgroups of level seven or
-lower (ie. just subscribed and unsubscribed groups). 
+List all subscribed and unsubscribed groups, whether they have unread
+articles or not (@code{gnus-group-list-all-groups}).  If the numeric
+prefix is used, this command will list only groups of level ARG and
+lower.  By default, it lists groups of level seven or lower (ie. just
+subscribed and unsubscribed groups).
 @item C-c C-k
 @kindex C-c C-k (Group)
 @findex gnus-group-list-killed
-List all killed newsgroups (@code{gnus-group-list-killed}).
+List all killed groups (@code{gnus-group-list-killed}).
 @item C-c C-z
 @kindex C-c C-z (Group)
 @findex gnus-group-list-zombies
-List all zombie newsgroups (@code{gnus-group-list-zombies}).
+List all zombie groups (@code{gnus-group-list-zombies}).
 @end table
 
-@node Newsgroup Maintenance
-@section Newsgroup Maintenance
+@node Group Maintenance
+@section Group Maintenance
 
 @table @kbd
 @item b
 @kindex b (Group)
 @findex gnus-group-check-bogus-groups
 Check bogus groups and delete them
-(@code{gnus-group-check-bogus-groups}). 
+(@code{gnus-group-check-bogus-groups}).
 @item F
 @kindex F (Group)
 @findex gnus-find-new-newsgroups
-Find new newsgroups (@code{gnus-find-new-newsgroups}). 
+Find new groups (@code{gnus-find-new-newsgroups}).
 @item C-c C-x
 @kindex C-c C-x (Group)
 @findex gnus-group-expire-articles
-Run all expirable articles in the current newsgroup through the expiry
+Run all expirable articles in the current group through the expiry
 process (if any) (@code{gnus-group-expire-articles}).
 @item C-c M-C-x
 @kindex C-c M-C-x (Group)
 @findex gnus-group-expire-all-groups
-Run all articles in all newsgroups through the expiry process
-(@code{gnus-group-expire-all-groups}). 
+Run all articles in all groups through the expiry process
+(@code{gnus-group-expire-all-groups}).
 @end table
 
 @node Browse Foreign Server
@@ -977,28 +1069,27 @@ Run all articles in all newsgroups through the expiry process
 @kindex B (Group)
 @findex gnus-group-browse-foreign-server
 You will be queried for a select method and a server name.  Gnus will
-then attempt to contact this server and let you browse the newsgroups
-there (@code{gnus-group-browse-foreign-server}).
+then attempt to contact this server and let you browse the groups there
+(@code{gnus-group-browse-foreign-server}).
 @end table
 
-A new buffer with a list of available newsgroups will appear.  This
-buffer will be in the @code{gnus-browse-server-mode}.  This buffer looks
-a bit (well, a lot) like a normal Newsgroup buffer, but with one major
-difference - you can't enter any of the newsgroups.  If you want to read
-any of the news available on that server, you have to subscribe to the
-newsgroups you think may be interesting, and then you have to exit this
-buffer.  The new groups will be added to the Newsgroup buffer, and then
-you can read them as you would any other newsgroup.
+A new buffer with a list of available groups will appear.  This buffer
+will be use the @code{gnus-browse-server-mode}.  This buffer looks a bit
+(well, a lot) like a normal group buffer, but with one major difference
+- you can't enter any of the groups.  If you want to read any of the
+news available on that server, you have to subscribe to the groups you
+think may be interesting, and then you have to exit this buffer.  The
+new groups will be added to the group buffer, and then you can read them
+as you would any other group.
 
 Here's a list of keystrokes available in the browse mode:
 
 @table @kbd
-@item C-n, n
-@kindex C-n (Browse)
+@item n
 @kindex n (Browse)
 @findex gnus-group-next-group
 Go to the next group (@code{gnus-group-next-group}).
-@item C-p, p
+@item p
 @kindex C-p (Browse)
 @kindex p (Browse)
 @findex gnus-group-prev-group
@@ -1044,29 +1135,58 @@ Quit Gnus without saving any startup files (@code{gnus-group-quit}).
 @code{gnus-suspend-gnus-hook} is called when you suspend Gnus and
 @code{gnus-exit-gnus-hook} is called when you quit Gnus.
 
-@node Misc Newsgroup Stuff
-@section Misc Newsgroup Stuff
+@node Misc Group Stuff
+@section Misc Group Stuff
 
 @table @kbd
 @item g
 @kindex g (Group)
 @findex gnus-group-get-new-news
 Check server for new articles. 
-If the numeric prefix is used, this command will check only newsgroups of
+If the numeric prefix is used, this command will check only groups of
 level ARG and lower (@code{gnus-group-get-new-news}).
+@item M-g
+@kindex M-g (Group)
+@findex gnus-group-get-new-news-this-group
+Check whether new articles have arrived in the current group
+(@code{gnus-group-get-new-news-this-group}).
 @item R
 @kindex R (Group)
 @findex gnus-group-restart
 Restart Gnus (@code{gnus-group-restart}).
+@item r
+@kindex r (Group)
+@findex gnus-group-read-init-file
+Read the init file (@code{gnus-init-file}, which defaults to
+@file{~/.gnus}) (@code{gnus-group-read-init-file}).
+@item s
+@kindex s (Group)
+@findex gnus-group-save-newsrc
+Save the @file{.newsrc.eld} file (and @file{.newsrc} if wanted)
+(@code{gnus-group-save-newsrc}).
+@item Z
+@kindex Z (Group)
+@findex gnus-group-clear-dribble
+Clear the dribble buffer (@code{gnus-group-clear-dribble}).
 @item D
 @kindex D (Group)
 @findex gnus-group-describe-group
-Give a description of the current newsgroup
-(@code{gnus-group-describe-group}). 
+Give a description of the current group
+(@code{gnus-group-describe-group}).
+@item C-c C-a
+@kindex C-c C-a (Group)
+@findex gnus-group-apropos
+Give a listing of all groups that have names that match a regexp
+(@code{gnus-group-apropos}).
+@item C-c M-C-a 
+@kindex C-c M-C-a (Group)
+@findex gnus-group-description-apropos
+Give a listing of all groups that have names or descriptions that match
+a regexp (@code{gnus-group-description-apropos}).
 @item a
 @kindex a (Group)
 @findex gnus-group-post-news
-Post an article to a newsgroup (@code{gnus-group-post-news}).
+Post an article to a group (@code{gnus-group-post-news}).
 @item m
 @kindex m (Group)
 @findex gnus-group-mail
@@ -1074,7 +1194,7 @@ Mail a message somewhere (@code{gnus-group-mail}).
 @item C-x C-t
 @kindex C-x C-t (Group)
 @findex gnus-group-transpose-groups
-Transpose two newsgroups (@code{gnus-group-transpose-groups}).
+Transpose two groups (@code{gnus-group-transpose-groups}).
 @item V
 @kindex V (Group)
 @findex gnus-version
@@ -1090,8 +1210,8 @@ Go to the Gnus info node (@code{gnus-info-find-node}).
 @end table
 
 @vindex gnus-group-prepare-hook
-@code{gnus-group-prepare-hook} is called after the newsgroup list is
-created in the Newsgroup buffer.  It may be used to modify the newsgroup
+@code{gnus-group-prepare-hook} is called after the group list is
+created in the Group buffer.  It may be used to modify the group
 buffer in some strange, unnatural way.
 
 @node The Summary Buffer
@@ -1101,22 +1221,23 @@ A line for each article is displayed in the Summay buffer.  You can move
 around, read articles, post articles and reply to them.
 
 @menu
-* Summary Buffer Format::       Deciding how the summar buffer is to look
-* Summary Manouvering::         Moving around the Summary buffer
-* Choosing Articles::           Reading articles
-* Paging the Article::          Scrolling the current article
-* Reply Followup and Post::     Posting articles
-* Cancelling and Superceding::  "Whoops, I shouldn't have called him that"
+* Summary Buffer Format::       Deciding how the summar buffer is to look.
+* Summary Manouvering::         Moving around the summary buffer.
+* Choosing Articles::           Reading articles.
+* Paging the Article::          Scrolling the current article.
+* Reply Followup and Post::     Posting articles.
+* Cancelling and Superceding::  "Whoops, I shouldn't have called him that."
 * Ticking and Marking::         Marking articles as read, expirable, etc.
-* Threading::                   How threads are made
-* Exiting the Summary Buffer::  Returning to the Newsgroup buffer
-* Saving Articles::             Ways of customizing article saving
+* Threading::                   How threads are made.
+* Exiting the Summary Buffer::  Returning to the Group buffer.
+* Saving Articles::             Ways of customizing article saving.
 * Decoding Articles::           Gnus can treat series of (uu)encoded articles.
-* Various Article Stuff::       Various stuff dealing with articles
-* Summary Sorting::             You can sort the summary buffer four ways
-* Finding the Parent::          No child support? Get the parent
-* Kill Files::                  Maintaining a kill file
-* Various Summary Stuff::       What didn't fit anywhere else
+* Various Article Stuff::       Various stuff dealing with articles.
+* Summary Sorting::             You can sort the summary buffer four ways.
+* Finding the Parent::          No child support? Get the parent.
+* Score Files::                 Maintaining a score file.
+* Mail Group Commands::         Some commands can only be used in mail groups.
+* Various Summary Stuff::       What didn't fit anywhere else.
 @end menu
 
 @node Summary Buffer Format
@@ -1127,7 +1248,7 @@ You can change the format of the lines in the summary buffer by changing
 the @code{gnus-summary-line-format} variable.  It works along the same
 lines a a normal @code{format} string, with some extensions.
 
-The default string is @samp{"%U%R%X %I[%3L: %-20,20n]%T %S\n"}.
+The default string is @samp{"%U%R%X%i %I%[%4L: %-20,20n%] %s\n"}.
 
 The following format specification characters are understood:
 
@@ -1135,28 +1256,43 @@ The following format specification characters are understood:
 @item N 
 Article number
 @item S
-Subject
+Subject string
+@item s
+Subject if the article is the root, @code{gnus-summary-same-subject}
+otherwise. 
 @item F
-From
+Full From line
 @item n
 The name (from the @code{From} header field)
 @item A
 The address (from the @code{From} header field)
 @item L
 Number of lines in the article
+@item c
+Number of characters in the article
 @item I
 Indentation based on thread level
 @item T
 Nothing if the article is a root and lots of spaces if it isn't (it
 pushes everything after it off the screen)
-@item C
-Current article
+@item \[
+Opening bracket, which is normally @samp{\[}, but can also be @samp{<}
+for adopted articles.
+@item \]
+Closing bracked, which is normally @samp{\]}, but can also be @samp{<}
+for adopted articles.
+@item <
+One space for each thread level.
+@item >
+Twenty minus thread level spaces.
 @item U
 Unread
 @item X
 Expirable
 @item R
 Replied
+@item i
+Score
 @item x
 Xref
 @item D
@@ -1165,15 +1301,17 @@ Date
 Message-ID
 @item r
 References
+@item x
+Xref
 @end table
 
-No elements are required, except the @samp{%U}, @samp{%R} and @samp{%X}
-fields which have to be at the beginning of the line for reasons of
-efficiency.  If you try to remove those, or change them, you'll probably
-end up with a mess.
+No elements are required, except the @samp{%U}, @samp{%R}, @samp{%X} and
+@samp{%i} fields which have to be at the beginning of the line for
+reasons of efficiency.  If you try to remove those, or change them,
+you'll probably end up with a mess, at least in this version of Gnus.
 
 @vindex gnus-summary-mode-line-format
-You can also change the format of the Summary mode bar.  Set
+You can also change the format of the summary mode bar.  Set
 @code{gnus-summary-mode-line-format} to whatever you like.  Here's what
 elements you have to play with:
 
@@ -1204,13 +1342,11 @@ behave pretty much as you'd expect.
 None of these commands select articles.
 
 @table @kbd
-@item C-n, down
-@kindex C-n (Summary)
+@item down
 @kindex down (Summary)
 @findex gnus-summary-next-subject
 Go to the next subject line (@code{gnus-summary-next-subject}).
-@item C-p, up
-@kindex C-p (Summary)
+@item up
 @kindex up (Summary)
 @findex gnus-summary-prev-subject
 Go to the previous subject line (@code{gnus-summary-prev-subject}).
@@ -1237,18 +1373,18 @@ Go to the summary line of the previous article
 @end table
 
 @vindex gnus-auto-select-next
-If you are at the end of the newsgroup and issue one of the movement
-commands, Gnus will offer to go to the next newsgroup.  If
-@code{gnus-auto-select-next} is t and the next newsgroup is empty, Gnus
-will exit Summary mode and return to the Newsgroup buffer.  If this
-variable is neither t nor nil, Gnus will select the next newsgroup, no
+If you are at the end of the group and issue one of the movement
+commands, Gnus will offer to go to the next group.  If
+@code{gnus-auto-select-next} is t and the next group is empty, Gnus
+will exit summary mode and return to the group buffer.  If this
+variable is neither t nor nil, Gnus will select the next group, no
 matter if it has any unread articles or not.  As a special case, if this
-variable equals @code{quietly}, Gnus will select the next newsgroup
+variable equals @code{quietly}, Gnus will select the next group
 without asking for confirmation.  Also see @code{gnus-keep-same-level}. 
 
 @vindex gnus-auto-center-summary
 If @code{gnus-auto-center-summary} is non-nil, Gnus will keep the point
-in the Summary buffer centered at all times.  This makes things quite
+in the summary buffer centered at all times.  This makes things quite
 tidy, but if you have a slow network connection, or do simply not like
 this un-Emacsism, you can set this variable to nil to get the normal
 Emacs scrolling action.
@@ -1264,7 +1400,7 @@ All the following commands select an article.
 @item SPACE
 @kindex SPACE (Summary)
 @findex gnus-summary-next-page
-Select the current article, of, if that one's read already, the next
+Select the current article, or, if that one's read already, the next
 unread article (@code{gnus-summary-next-page}).
 @item n
 @kindex n (Summary)
@@ -1302,7 +1438,7 @@ Go to the first unread article (@code{gnus-summary-first-unread-article}).
 All the movement commands will try to go to the previous (or next)
 article, even if that article isn't displayed in the Summary buffer if
 @code{gnus-auto-extend-newsgroup} is non-nil.  Gnus will fetch the
-article from the server and present it in the Article buffer.
+article from the server and present it in the article buffer.
 
 @vindex gnus-select-article-hook
 @code{gnus-select-article-hook} is called whenever an article is
@@ -1328,8 +1464,8 @@ next article (@code{gnus-summary-next-page}).
 @kindex DEL (Summary)
 @findex gnus-summary-prev-page
 Scoll the current article back one page (@code{gnus-summary-prev-page}). 
-@item RETURN
-@kindex RETURN (Summary)
+@item RET
+@kindex RET (Summary)
 @findex gnus-summary-scroll-up
 Scroll the current article one line forward
 (@code{gnus-summary-scroll-up}).
@@ -1356,7 +1492,7 @@ article by pressing @kbd{C-c C-c}.
 @item a
 @kindex a (Summary)
 @findex gnus-summary-post-news
-Post an article to the current newsgroup
+Post an article to the current group
 (@code{gnus-summary-post-news}).
 @item f
 @kindex f (Summary)
@@ -1403,7 +1539,7 @@ fiddling with the @code{gnus-reply-to-function} and
 @code{gnus-followup-to-function} variables.
 
 To take "reply" as an example: If you want the replies to go to the
-"sender" instead of the "from" in the newsgroup "mail.stupid-list", you
+"sender" instead of the "from" in the group "mail.stupid-list", you
 could do something like this:
 
 @example
@@ -1430,9 +1566,9 @@ two signatures.
 
 @vindex gnus-post-prepare-function
 In any case, @code{gnus-post-prepare-function} is called with the name
-of the current newsgroup after the post buffer has been initialized, and
-can be used for inserting a signature.  Nice if you use different
-signatures in different newsgroups.
+of the current group after the post buffer has been initialized, and can
+be used for inserting a signature.  Nice if you use different signatures
+in different groups.
 
 @vindex gnus-auto-mail-to-author
 If @code{gnus-auto-mail-to-author} is non-nil, Gnus will send a mail
@@ -1476,7 +1612,7 @@ live on in some parts of the world, while most sites will delete the
 cancelled article.
 
 If you discover that you have made some mistakes and want to do some
-corrections, you can post a @dfn{superceding} article that will replace
+corrections, you can post a @dfn{superseding} article that will replace
 your original article.
 
 @findex gnus-summary-supersede-article
@@ -1484,27 +1620,30 @@ your original article.
 Go to the original article and press @kbd{S}
 (@code{gnus-summary-supersede-article}).  You will be put in a buffer
 where you can edit the article all you want before sending it off the
-usual way.  
+usual way.
 
-The same goes for superceding as for cancelling, only more so: Some
-sites do not honor superceding.  On those sites, it will appear that you
+The same goes for superseding as for cancelling, only more so: Some
+sites do not honor superseding.  On those sites, it will appear that you
 have posted almost the same article twice.
 
 If you have just posted the article, and changed your mind right away,
-there is a trick yuo can use to cancel/supersede the article without
+there is a trick you can use to cancel/supersede the article without
 waiting for the article to appear on your site first.  You simply return
 to the post buffer (which is called @code{*post-buf*}).  There you will
 find the article you just posted, with all the headers intact.  Change
 the @samp{Message-ID} header to a @samp{Cancel} or @samp{Supersedes}
 header by substituting one of those words for @samp{Message-ID}.  Then
-just press @kbd{C-c C-c} to send the article as you would do
-normally.  The previous article will be cancelled/superseded.
+just press @kbd{C-c C-c} to send the article as you would do normally.
+The previous article will be cancelled/superseded.
 
 @node Ticking and Marking
 @section Ticking and Marking
 
-There are four kinds of @dfn{marks}: Tick marks, process marks, read
-marks and expiry marks.  
+There are several marks you can set on an article. 
+
+First you have the marks that decide the "readed-ness" (whoo,
+neato-keano neologism ohoy!) of the article. It can be unread, ticked,
+dormant or read, in ascending readed-ness ordering.
 
 @dfn{Ticked articles} are articles that will remain visible always.  If
 you see an article that you find interesting, or you want to put off
@@ -1513,15 +1652,26 @@ tick it.  However, articles can be expired, so if you want to keep an
 article forever, you'll have to save it.  Ticked articles have a @samp{-}
 in the first column.
 
+A @dfn{dormant} article is marked with a @samp{+}, and will only appear
+in the summary buffer if there are followups to it. 
+
 Articles that are marked as read - are just that.  They have a @samp{D}
 in the first column.  Unread articles have a space in the first column.
 
+There are also some marks that do not affect readed-ness:
+
 You can also mark articles as @dfn{expirable} (or have them marked as
-such automatically).  That doesn't make much sense in normal newsgroups,
+such automatically).  That doesn't make much sense in normal groups,
 because a user does not control the expiring of news articles, but in
-mail newsgroups, for instance, articles that are marked as
-@dfn{expirable} can be deleted by Gnus at any time.  Expirable articles
-have a @samp{X} in the third column.
+mail groups, for instance, articles that are marked as @dfn{expirable}
+can be deleted by Gnus at any time.  Expirable articles have a @samp{X}
+in the third column.
+
+You can set a bookmark in the current article. Say you are reading a
+long thesis on cat's urinary tracts, and have to go home for dinner
+before you've finished reading the thesis. You can then set a bookmark
+in the article, and Gnus will jump to this bookmark the next time it
+encounters the article.
 
 Finally we have the @dfn{process mark}.  A variety of commands react to
 the presence of the process mark.  For instance, @kbd{C-c C-v M-C-v}
@@ -1532,10 +1682,15 @@ marked with the process mark have a @samp{#} in the third column.
 All the marking commands understand the numeric prefix.
 
 @table @kbd
-@item '
-@kindex ' (Summary)
+@item -
+@kindex - (Summary)
 @findex gnus-summary-mark-as-unread-forward
 Tick the current article (@code{gnus-summary-mark-as-unread-forward}).
+@item +
+@kindex + (Summary)
+@findex gnus-summary-mark-as-dormant
+Mark the current article as dormant
+(@code{gnus-summary-mark-as-dormant}).
 @item d
 @kindex d (Summary)
 @findex gnus-summary-mark-as-read-forward
@@ -1567,16 +1722,34 @@ Mark the current article as expirable
 @findex gnus-summary-unmark-as-expirable
 Remove the expiry mark from the current article
 (@code{gnus-summary-unmark-as-expirable}). 
+@item b
+@kindex b (Summary)
+@findex gnus-summary-set-bookmark
+Set a bookmark in the current article
+(@code{gnus-summary-set-bookmark}).
+@item B
+@kindex B (Summary)
+@findex gnus-summary-remove-bookmark
+Remove the bookmark from the current article
+(@code{gnus-summary-remove-bookmark}).
 @item M-d
 @kindex M-d (Summary)
 @findex gnus-summary-delete-marked-as-read
-Remove all deleted articles from the Summary buffer
+Expunge all deleted articles from the summary buffer
 (@code{gnus-summary-delete-marked-as-read}). 
 @item M-C-d
 @kindex M-C-d (Summary)
 @findex gnus-summary-delete-marked-with
-Ask for a mark and then remove all articles that have been marked with
+Ask for a mark and then expunge all articles that have been marked with
 that mark (@code{gnus-summary-delete-marked-with}).
+@item C-c M-C-s
+@kindex C-c M-C-s (Summary)
+@findex gnus-summary-show-all-expunged
+Display all expunged articles (@code{gnus-summary-show-all-expunged}).
+@item M-+
+@kindex M-+ (Summary)
+@findex gnus-summary-show-all-dormant
+Display all dormant articles (@code{gnus-summary-show-all-dormant}).
 @end table
 
 There are a few functions for setting the process mark:
@@ -1626,8 +1799,8 @@ replies to articles directly after the articles they reply to - in a
 hierarchial fashion.
 
 @menu
-* Customizing Threading::     Variables you can change to affect the threading
-* Threading Commands::        Thread based commands in the Summary Buffer
+* Customizing Threading::     Variables you can change to affect the threading.
+* Threading Commands::        Thread based commands in the summary buffer.
 @end menu
 
 @node Customizing Threading
@@ -1638,22 +1811,47 @@ hierarchial fashion.
 @vindex gnus-show-threads
 If this variable is nil, no threading will be done, and all of the rest
 of the variables here will have no effect.  Turning threading off will
-speed newsgroup selection up a bit, but it is sure to make reading
+speed group selection up a bit, but it is sure to make reading
 slower and more awkward.
+@item gnus-fetch-old-headers
+@vindex gnus-fetch-old-headers
+If non-nil, Gnus will attempt to build old threads by fetching more old
+headers - headers to articles that are marked as read. This only works
+if the server you are using supports XOVER. Also remember that if the
+root of the thread has been expired by the server, there's not much Gnus
+can do about that.
 @item gnus-gather-loose-threads
 @vindex gnus-gather-loose-threads
 If non-nil, Gnus will gather all loose subtrees into one big tree and
 create a dummy root at the top.  (Wait a minute.  Root at the top? Yup.)
 Loose subtrees occur when the real root has expired, or you've read it
 in a previous session.
-@item gnus-summary-print-dummy-lines
-@vindex gnus-summary-print-dummy-lines
-If non-nil, Gnus will print those dummy roots described above.  It it is
-nil, the dummy roots won't be printed, but the gathering will still take
-place (if @code{gnus-gather-loose-threads} is non-nil, that is.) 
+@item gnus-summary-make-false-root
+@vindex gnus-summary-make-false-root
+When there is no real root of a thread, Gnus will have to fudge
+something. This variable says what method Gnus should use while
+fudging. There are four possible value:
+
+@table @code
+@item adopt
+Gnus will make the first of the orphaned articles the parent. This
+parent will adopt all the other articles. The adopted articles will be
+marked as such by pointy brackeds instead of square brackets.
+@item dummy
+Gnus will create a dummy that will stand in as the parent. This dummy
+will be displayed on a line of its own, but it does not correspond to
+any real article.
+@item empty
+Gnus won't actually make any article the parent, but simply leave the
+subject field of all orphans except the first empty. (It will use
+@code{gnus-summary-same-subject} as the subject.)
+@item nil
+Don't make any article parent at all.
+@end table
+
 @item gnus-thread-hide-subtree
 @vindex gnus-thread-hide-subtree
-If non-nil, all subtrees will be hidden when the Summary buffer is
+If non-nil, all subtrees will be hidden when the summary buffer is
 generated. 
 @item gnus-thread-hide-killed
 @vindex gnus-thread-hide-killed
@@ -1725,35 +1923,35 @@ Ascend the thread (@code{gnus-summary-up-thread}).
 @item q
 @kindex q (Summary)
 @findex gnus-summary-exit
-Exit the current newsgroup and update all the information
+Exit the current group and update all the information
 (@code{gnus-summary-exit}). 
 @item Q
 @kindex Q (Summary)
 @findex gnus-summary-quit
-Exit the current newsgroup without updating any information
+Exit the current group without updating any information
 (@code{gnus-summary-quit}). 
 @item c
 @kindex c (Summary)
 @findex gnus-summary-catchup-and-exit
-Mark all articles in the newsgroup as read and exit
+Mark all articles in the group as read and exit
 (@code{gnus-summary-catchup-and-exit}). 
 @end table
 
 @vindex gnus-exit-group-hook
 @code{gnus-exit-group-hook} is called when you exit the current
-newsgroup.  
+group.  
 
 @vindex gnus-use-cross-reference
-When you exit the Summary buffer, the data on the current newsgroup will
+When you exit the summary buffer, the data on the current group will
 be updated (which articles you have read, which articles you have
 replied to, etc.) If the @code{gnus-use-cross-reference} variable is
-non-nil, articles that are cross-referenced to this newsgroup, and are
-marked as read, will also be marked as read in the other newsgroups they
+non-nil, articles that are cross-referenced to this group, and are
+marked as read, will also be marked as read in the other groups they
 were cross-posted to.  This ensures that you'll never have to read the
 same article more than once.
 
-Unless, of course, somebody has posted it to several newsgroups
-separately. 
+Unless, of course, somebody has posted it to several groups
+separately. If so, send them a nasty-gram.
 
 One other thing that may cause Gnus to not do the cross-posting thing
 correctly is if you use an NNTP server that supports xover (which is
@@ -1763,11 +1961,11 @@ common.  Gnus tries to Do The Right Thing even with xover by registering
 the Xref lines of all articles you actually read, but if you kill the
 articles, or just mark them as read without reading them, Gnus will not
 get a chance to snoop the Xref lines out of these articles, and will be
-unable to use the cross reference mechanism. 
+unable to use the cross reference mechanism.
 
-@vindex nntp-xover-is-evil
+@vindex gnus-nov-is-evil
 If you want Gnus to get the Xrefs right all the time, you have to set
-@code{nntp-xover-is-evil} to t, which slows things down considerably. 
+@code{gnus-nov-is-evil} to t, which slows things down considerably. 
 
 C'est la vie.
 
@@ -1790,9 +1988,9 @@ unwanted headers before saving the article.
 Save the current article (@code{gnus-summary-save-article}).
 @item C-o
 @kindex C-o (Summary)
-@findex gnus-summary-save-in-mail
-Save the current article in mail format
-(@code{gnus-summary-save-in-mail}). 
+@findex gnus-summary-save-rmail
+Save the current article in rmail format
+(@code{gnus-summary-save-rmail}). 
 @end table
 
 @vindex gnus-default-article-saver
@@ -1803,22 +2001,19 @@ functions below, or you can create your own.
 @table @code
 @item gnus-summary-save-in-rmail
 @vindex gnus-summary-save-in-rmail
-This is the format Gnus uses by default, @dfn{babyl}.
-Uses the function in the @code{gnus-rmail-save-name} variable to get a
-file name to save the article in.  The default is
-@code{gnus-plain-save-name}. 
+This is the format Gnus uses by default, @dfn{babyl}.  Uses the function
+in the @code{gnus-rmail-save-name} variable to get a file name to save
+the article in.  The default is @code{gnus-plain-save-name}.
 @item gnus-summary-save-in-mail
 @vindex gnus-summary-save-in-mail
-Save in a Unix mail (mbox) file.
-Uses the function in the @code{gnus-mail-save-name} variable to get a
-file name to save the article in.  The default is
-@code{gnus-plain-save-name}. 
+Save in a Unix mail (mbox) file.  Uses the function in the
+@code{gnus-mail-save-name} variable to get a file name to save the
+article in.  The default is @code{gnus-plain-save-name}.
 @item gnus-summary-save-in-file
 @vindex gnus-summary-save-in-file
-Append the article straight to an ordinary file.
-Uses the function in the @code{gnus-file-save-name} variable to get a
-file name to save the article in.  The default is
-@code{gnus-numeric-save-name}. 
+Append the article straight to an ordinary file.  Uses the function in
+the @code{gnus-file-save-name} variable to get a file name to save the
+article in.  The default is @code{gnus-numeric-save-name}.
 @item gnus-summary-save-in-folder
 @vindex gnus-summary-save-in-folder
 Save the article to an MH folder using @code{rcvstore} from the MH
@@ -1851,10 +2046,10 @@ Generates file names that look like @samp{~/News/alt.andrea-dworkin}.
 @vindex gnus-use-long-file-name
 Finally, you have the @code{gnus-use-long-file-name} variable.  If it is
 nil, all the preceding functions will replace all periods (@samp{.}) in
-the newsgroup names with slashes (@samp{/}) - which means that the
-functions will generate hierarchies of directories instead of having all
-the files in the toplevel directory (@samp{~/News/alt/andrea-dworkin}
-instead of @samp{~/News/alt.andrea-dworkin}.)
+the group names with slashes (@samp{/}) - which means that the functions
+will generate hierarchies of directories instead of having all the files
+in the toplevel directory (@samp{~/News/alt/andrea-dworkin} instead of
+@samp{~/News/alt.andrea-dworkin}.)
 
 @node Decoding Articles
 @section Decoding Articles
@@ -1863,7 +2058,7 @@ Gnus has a plethora of functions for handling series of (uu)encoded
 articles.  Gnus can find out by itself what articles belong to one
 series, decode all the articles and unpack/view/save the resulting
 file(s).  All these functions belong to the `gnus-uu' package and are
-reached from the Summary buffer as three-key keystrokes: @key{C-c C-v
+reached from the summary buffer as three-key keystrokes: @key{C-c C-v
 KEY}.  That last key varies, of course, but all these functions use the
 @key{C-c C-v} prefix keystroke.
 
@@ -1936,12 +2131,12 @@ Decode and save the marked articles
 @item C-c C-v C-w
 @kindex C-c C-v C-w (Summary)
 @findex gnus-uu-decode-and-view-all-articles
-Decode and view all articles in the newsgroup
+Decode and view all articles in the group
 (@code{gnus-uu-decode-and-view-all-articles}).  
 @item C-c C-v w
 @kindex C-c C-v w (Summary)
 @findex gnus-uu-decode-and-save-all-articles
-Decode and save all articles in the newsgroup
+Decode and save all articles in the group
 (@code{gnus-uu-decode-and-save-all-articles}).  
 @item C-c C-v M-C-w
 @kindex C-c C-v M-C-w (Summary)
@@ -1956,12 +2151,12 @@ Decode and save all series of articles that are marked
 @item C-c C-v C-a
 @kindex C-c C-v C-a (Summary)
 @findex gnus-uu-decode-and-view-all-articles
-Decode and view all unread articles in the newsgroup
+Decode and view all unread articles in the group
 (@code{gnus-uu-decode-and-view-all-articles}).  
 @item C-c C-v a
 @kindex C-c C-v a (Summary)
 @findex gnus-uu-decode-and-save-all-articles
-Decode and save all unread articles in the newsgroup
+Decode and save all unread articles in the group
 (@code{gnus-uu-decode-and-save-all-articles}).  
 @item C-c C-v C-b
 @kindex C-c C-v C-b (Summary)
@@ -1974,7 +2169,7 @@ article, for some strange reason
 
 The @code{gnus-uu-decode-and-save-all-marked-files} need some
 explanation.  It allows you to mark all articles that are part of series
-of articles you are interested in in a newsgroup.  You only have to mark
+of articles you are interested in in a group.  You only have to mark
 one article for each series of articles you want, and then you call this
 function, which will find all articles that are part of the series you
 want.  Is that clear? And they say it's a stupid idea getting drunk
@@ -2144,6 +2339,8 @@ for a different approach.
 @node Decoding Variables
 @subsection Decoding Variables
 
+Adjective, not verb.
+
 @menu 
 * Rule Variables::          Variables that say how a file is to be viewed.
 * Other Decode Variables::  Other decode variables.
@@ -2345,7 +2542,7 @@ Pipe the current article through a filter
 @node Summary Sorting
 @section Summary Sorting
 
-You can have the Summary buffer sorted in various ways, even though I
+You can have the summary buffer sorted in various ways, even though I
 can't really se why you'd want that.
 
 @table @kbd
@@ -2373,56 +2570,55 @@ Sort by date (@code{gnus-summary-sort-by-date}).
 @findex gnus-summary-refer-parent-article
 @kindex ^ (Summary)
 If you'd like to read the parent of the current article, and it is not
-displayed in the article buffer, you might still be able to.  That is, if
-the current group is fetched by NNTP, the parent hasn't expired and the
-References in the current article are not mangled, you can just press
-@kbd{^} (@code{gnus-summary-refer-parent-article}).  If everything goes
-well, you'll get the parent.
+displayed in the article buffer, you might still be able to.  That is,
+if the current group is fetched by NNTP, the parent hasn't expired and
+the References in the current article are not mangled, you can just
+press @kbd{^} (@code{gnus-summary-refer-parent-article}).  If everything
+goes well, you'll get the parent. If the parent is already displayed in
+the summary buffer, point will just move to this article.
 
 @findex gnus-summary-refer-article
 @kindex M-^ (Summary)
 You can also ask the NNTP server for an arbitrary article, no matter
-what newsgroup it belongs to.  @kbd{M-^}
-(@code{gnus-summary-refer-article}) will ask you for a message-id, which
-is one of those long thingies that look something like
-@samp{<38o6up$6f2@@hymir.ifi.uio.no>}.  You have to get it all exactly
-right. 
+what group it belongs to.  @kbd{M-^} (@code{gnus-summary-refer-article})
+will ask you for a message-id, which is one of those long thingies that
+look something like @samp{<38o6up$6f2@@hymir.ifi.uio.no>}.  You have to
+get it all exactly right.
 
-@node Kill Files
-@section Kill Files
+@node Score Files
+@section Score Files
 
-If a @dfn{kill file} for the current newsgroup exists, Gnus will read it
-just after having gotten the article headers from the server.
+Other people call them @dfn{kill files}, but we here at (ding) Gnus
+Towers likes scoring better than killing, so we've changed the
+name. We've also changed what they do, so sit up straight and pay
+attention!
 
-The kill files are files that may contain, in general, any elisp
-functions.  However, it is most common just to put functions that either
-delete or undelete articles based on their headers in those files -
-in short, killing articles.  Hence the name. 
+All articles have a default score (@code{gnus-summary-default-score}).
+This score may be raised or lowered either interactively or by the score
+files. Articles that have a score lower than
+@code{gnus-summary-mark-below} are marked as read. 
+
+If a @dfn{score file} for the current group exists, Gnus will read it
+after generating the summary buffer.
 
-There are several commands reachable from the Summary buffer that
-inserts commands for killing articles based on the current article.  You
-can, for instance, ask Gnus to kill all articles with a certain subject.
+The score files are files that may contain, in general, any elisp
+functions.  However, it is most common just to put functions that either
+raises or lowers the score of articles based on their headers in those
+files.  Hence the name.
 
-If you get really irrirated with some annoying twit, you can kill the
-author.  Note that the author won't literally be killed, unless, of
-course, he has an SCSI Gun Extension fitted to his machine.
+There are several commands reachable from the summary buffer that
+inserts commands for scoring articles based on the current article.  You
+can, for instance, ask Gnus to lower or raise the score of all articles
+with a certain subject.
 
 @menu 
-* Summary Kill Commands::   Adding simple kill commands to the kill file.
-* Kill Mode::               A mode for editing the kill file.
-* Kill Variables::          Customize your killing.  (My, what terminology).
+* Summary Score Commands::   Adding simple score commands to the score file.
+* Score Mode::               A mode for editing the score file.
+* Score Variables::          Customize your scoring.  (My, what terminology).
 @end menu
 
-One note: I have seen a few people confused about what killing an
-articles really does.  Killing an article does not remove it from the
-news server.  It does not inhibit other people from reading the
-article.  It only means that you won't ever see that article, nothing
-more.  To really remove an article from the news server, you have to send
-a cancel message, which you can't do if you haven't written the
-article.  (Well, you can, but that's Not Nice.)
-
-@node Summary Kill Commands
-@subsection Summary Kill Commands
+@node Summary Score Commands
+@subsection Summary Score Commands
 
 @table @kbd
 @item C-c C-k C-s
@@ -2453,17 +2649,17 @@ Kill all articles that have similar Xrefs to the current article
 cross-posts. 
 @end table
 
-@node Kill Mode
-@subsection Kill Mode
+@node Score Mode
+@subsection Score Mode
 
-To enter either the global or local kill file, you can use the following
-keystrokes in the Summary buffer:
+To enter either the global or local score file, you can use the
+following keystrokes in the summary buffer:
 
 @table @kbd
 @item M-k
 @kindex M-k (Summary)
 @findex gnus-summary-edit-local-kill
-Edit the kill file for the current newsgroup
+Edit the kill file for the current group
 (@code{gnus-summary-edit-local-kill}). 
 @item M-K
 @kindex M-K (Summary)
@@ -2471,18 +2667,18 @@ Edit the kill file for the current newsgroup
 Edit the global kill file (@code{gnus-summary-edit-global-kill}). 
 @end table
 
-@node Kill Variables
-@subsection Kill Variables
+@node Score Variables
+@subsection Score Variables
 
 @table @code
 @item gnus-kill-killed
 @vindex gnus-kill-killed
-If this variable is nil, Gnus will never apply kill files to articles
-that have already been through the kill process.  While may save you lots
-of time, it also means that if you apply a kill file to a newsgroup, and
-then change the kill file and want to run it over you newsgroup again to
-kill more articles, it won't work.  You have to set this variable to t to
-do that.
+If this variable is nil, Gnus will never apply score files to articles
+that have already been through the kill process.  While this may save
+you lots of time, it also means that if you apply a kill file to a
+group, and then change the kill file and want to run it over you group
+again to kill more articles, it won't work.  You have to set this
+variable to t to do that.
 @item gnus-apply-kill-hook
 @vindex gnus-apply-kill-hook
 This hook is called to do the actual article killing.  This hook may do
@@ -2494,10 +2690,38 @@ All kill files will be stored in this directory, which is initialized
 from the @samp{SAVEDIR} environment variable by default.
 @item gnus-kill-file-name
 @vindex gnus-kill-file-name
-This variable is a string that will be appended to newsgroup names to
+This variable is a string that will be appended to group names to
 make a kill file name.  The default is @samp{KILL}.
 @end table
 
+@node Mail Group Commands
+@section Mail Group Commands
+
+Some commands only make sense in mail groups. 
+
+@table @kbd
+@item M-C-x
+@kindex M-C-x (Summary)
+@findex gnus-summary-expire-articles
+Expire all expirable articles in the group
+(@code{gnus-summary-expire-articles}).
+@item M-DEL
+@kindex M-DEL (Summary)
+@findex gnus-summary-delete-articles
+Delete the mail article. This is "delete" as in "delete it from your
+disk forever and ever, never to return again." Use with caution.
+(@code{gnus-summary-delete-article}).
+@item M-m
+@kindex M-m (Summary)
+@findex gnus-summary-move-article
+Move the article from one mail group to another
+(@code{gnus-summary-move-article}). 
+@item M-C-m
+@kindex M-C-m (Summary)
+@findex gnus-summary-respool-article
+Respool the mail article (@code{gnus-summary-move-article}).
+@end table
+
 @node Various Summary Stuff
 @section Various Summary Stuff
 
@@ -2517,6 +2741,16 @@ Delete all other windows (@code{gnus-summary-expand-window}).
 @findex gnus-summary-reselect-current-group
 Exit this group, and then enter it again
 (@code{gnus-summary-reselect-current-group}).
+@item C-c C-d
+@kindex C-c C-d (Summary)
+@findex gnus-summary-describe-group
+Give a brief description of the current group
+(@code{gnus-summary-describe-group}).
+@item M-g
+@kindex M-g (Summary)
+@findex gnus-summary-rescan-group
+Exit group, check for new articles in the group, and select the group
+(@code{gnus-summary-rescan-group}).
 @item V
 @kindex V (Summary)
 @findex gnus-version
@@ -2524,7 +2758,7 @@ Display the Gnus version numbers (@code{gnus-version}).
 @item ?
 @kindex ? (Summary)
 @findex gnus-summary-describe-briefly
-Give a very brief description of the most important Summary keystrokes
+Give a very brief description of the most important summary keystrokes
 (@code{gnus-summary-describe-briefly}). 
 @item C-c C-i
 @kindex C-c C-i (Summary)
@@ -2533,22 +2767,22 @@ Go to the Gnus info node (@code{gnus-info-find-node}).
 @end table
 
 @vindex gnus-summary-prepare-hook
-@code{gnus-summary-prepare-hook} is called after the Summary buffer has
+@code{gnus-summary-prepare-hook} is called after the summary buffer has
 been generated.  You might use it to, for instance, hilight lines, modify
 the look, or anything else you feel like.  I don't care.
 
 @node The Article Buffer
 @chapter The Article Buffer
 
-The articles are displayed in the Article buffer, of which there is only
-one.  All the Summary buffer share the same Article buffer.
+The articles are displayed in the article buffer, of which there is only
+one.  All the summary buffer share the same article buffer.
 
 @menu
 * Hiding Headers::        Deciding what headers should be displayed.
 * Using Mime::            Pushing articles through MIME before reading them.
 * Customizing Articles::  Tailoring the look of the articles.
-* Article Keymap::        Keystrokes available in the Article buffer
-* Misc Article::          Other stuff
+* Article Keymap::        Keystrokes available in the article buffer
+* Misc Article::          Other stuff.
 @end menu
 
 @node Hiding Headers
@@ -2564,7 +2798,7 @@ be very useful, buf there's also lots of information most people do not
 want to see - what systems the article has passed through before
 reaching you, the message id, the references, etc. ad nauseum - and
 you'll probably want to get rid of some of those lines.  If you want to
-keep all those lines in the Article buffer, you can set
+keep all those lines in the article buffer, you can set
 @code{gnus-show-all-headers} to t.
 
 Gnus provides you with two variables for sifting header lines:
@@ -2573,14 +2807,14 @@ Gnus provides you with two variables for sifting header lines:
 @item gnus-visible-headers
 @vindex gnus-visible-headers
 If this variable is non-nil, it should be a regular expression that says
-what header lines you wish to keep in the Article buffer.  All header
+what header lines you wish to keep in the article buffer.  All header
 lines that does not match this variable will be hidden.
 
 For instance, if you only want to see the name of the person who wrote
 the article and the subject, you'd say:
 
 @example
-(setq gnus-visible-headers "^From:\\^Subject:")
+(setq gnus-visible-headers "^From:\\|^Subject:")
 @end example
 
 @item gnus-ignored-headers
@@ -2638,7 +2872,7 @@ Gnus handles MIME by shoving the articles through
 default.  Set @code{gnus-show-mime} to t if you want to use MIME all the
 time; it might be best just use the toggling functions from the summary
 buffer to avoid getting nasty surprises (for instance, you enter the
-newsgroup @samp{alt.sing-a-long} and, before you know it, MIME has
+group @samp{alt.sing-a-long} and, before you know it, MIME has
 decoded the sounds file in the article and some horrible sing-a-long
 song comes streaming out out your speakers, and you can't find the
 volume button, because there isn't one, and people are starting to look
@@ -2647,15 +2881,14 @@ find the program to control the volume, and everybody else in the room
 suddenly decides to look at you disdainfully, and you'll feel rather
 stupid.
 
-Any similarity between real events and this info page is purely
-coincidental.  Ahem.
+Any similarity to real events and people is purely coincidental.  Ahem.
 
 @node Customizing Articles
 @section Customizing Articles
 
 @vindex gnus-article-display-hook
 The @code{gnus-article-display-hook} is called after the article has
-been inserted into the Article buffer.  It is meant to handle all
+been inserted into the article buffer.  It is meant to handle all
 treatment of the article before it is displayed.  By default it contains
 @code{gnus-article-hide-headers}, which hides unwanted headers.
 
@@ -2663,23 +2896,28 @@ treatment of the article before it is displayed.  By default it contains
 @findex gnus-article-hide-signature
 @findex gnus-article-hide-citation
 Other useful functions you might add to this hook is
-@code{gnus-article-hide-citation} (which hides all cited text),
-@code{gnus-article-hide-signature} (which, umn, hides the signature) and
+@code{gnus-article-hide-citation} (which hides all cited text);
+@code{gnus-article-hide-signature} (which, umn, hides the signature);
 @code{gnus-article-subcite} (which tries to clean up the mess supercite
-makes in The Hands Of The Mad.
+makes in The Hands Of The Mad; @code{gnus-article-treat-overstrike}
+(which treats @samp{^H_} in a reasonable manner); and
+@code{gnus-article-remove-cr} (which removes trailing carriage returns).
 
 You can, of course, write your own functions.  The functions are called
-in the Article buffer, and you can do anything you like, pretty
+in the article buffer, and you can do anything you like, pretty
 much.  There is no information that you have to keep in the buffer - you
 can change everything.
 
 @node Article Keymap
 @section Article Keymap
 
-Not many keystrokes are available in the Article buffer.  You would,
-during normal reading, seldom put the point in that buffer.  All the
-really useful functions are more readily available from the Summary
-buffer. 
+Most of the keystrokes in the summary buffer can also be used in the
+article buffer. They should behave as if you typed them in the summary
+buffer, which means that you don't actually have to have a summary
+buffer displayed when you're reading. You can do it all from the article
+buffer.
+
+A few additional keystrokes are available:
 
 @table @kbd
 @item SPACE
@@ -2690,25 +2928,25 @@ Scroll forwards one page (@code{gnus-article-next-page}).
 @kindex DEL (Article)
 @findex gnus-article-prev-page
 Scroll backwards one page (@code{gnus-article-prev-page}).
-@item r
-@kindex r (Article)
+@item C-x r
+@kindex C-x r (Article)
 @findex gnus-article-refer-article
 If point is in the neighborhood of a message-id and you press @kbd{r},
 Gnus will try to get that article from the server.  (Only available with
 nntp).  (@code{gnus-article-refer-article}).
-@item m
-@kindex m (Article)
+@item C-x m
+@kindex C-x m (Article)
 @findex gnus-article-mail
 Send a reply to the address near point (@code{gnus-article-mail}). 
-@item M
-@kindex M (Article)
+@item C-x M
+@kindex C-x M (Article)
 @findex gnus-article-mail-with-original
 Send a reply to the address near point and include the original article
 (@code{gnus-article-mail-with-original}). 
 @item s
 @kindex s (Article)
 @findex gnus-article-show-summary
-Reconfigure the buffers so that the Summary buffer becomes visible
+Reconfigure the buffers so that the summary buffer becomes visible
 (@code{gnus-article-show-summary}).
 @item ?
 @kindex ? (Article)
@@ -2717,17 +2955,15 @@ Give a very brief description of the available keystrokes
 (@code{gnus-article-describe-briefly}). 
 @end table
 
-That's all, folks!
-
 @node Misc Article
 @section Misc Article
 
 @vindex gnus-article-display-hook
 @vindex gnus-article-prepare-hook
 The @code{gnus-article-prepare-hook} is called right after the article
-has been inserted into the Article buffer.  It is mainly intended for
+has been inserted into the article buffer.  It is mainly intended for
 functions that do something depending on the contents; it should
-probably not be used for changing the contents of the Article
+probably not be used for changing the contents of the article
 buffer.  Use the @code{gnus-article-display-hook} for that, which is
 called after this hook is called.
 
@@ -2743,7 +2979,7 @@ will be divided into pages whenever a @code{gnus-page-delimiter} appears
 in the article.  If this variable is nil, paging will not be done.
 
 @vindex gnus-page-delimiter
-@code{gnus-page-delimiter} is @samp{^L} (linefeed) by default.
+@code{gnus-page-delimiter} is @samp{^L} (form linefeed) by default.
 
 @node Various
 @chapter Various
@@ -2771,10 +3007,10 @@ by Gnus.  It will simply assume you know what your are doing, no matter
 how strange.
 @item gnus-interactive-catchup
 @vindex gnus-interactive-catchup
-Require confirmation before catching up a newsgroup if non-nil.
+Require confirmation before catching up a group if non-nil.
 @item gnus-interactive-post
 @vindex gnus-interactive-post
-If non-nil, the user will be prompted for a newsgroup name when posting
+If non-nil, the user will be prompted for a group name when posting
 an article.
 @item gnus-interactive-exit
 @vindex gnus-interactive-exit
@@ -2799,21 +3035,21 @@ compared to the other Gnus buffers.  Here's an example:
 @example
 (setq gnus-window-configuration
   '((summary (0 1 0))
-    (newsgroups (1 0 0))
+    (groups (1 0 0))
     (article (0 3 10))))
 @end example
 
 This variable is a list of lists, where each of these small lists is on
 the form @var{(action (g s a))}.  As you can see, there are three
-possible @var{action}s - @code{newsgroup} (which is what happens when
-you first start Gnus, or returns from the Summary buffer),
+possible @var{action}s - @code{group} (which is what happens when
+you first start Gnus, or returns from the summary buffer),
 @code{summary} (which is what happens when there are no unread articles
-in the newsgroup, and @code{article} (which is what happens when there
-is an unread article in the newsgroup). 
+in the group, and @code{article} (which is what happens when there
+is an unread article in the group). 
 
 We see that in the first two actions, the respective buffers will fill
-the screen, and in the last, the Article buffer will take ten lines for
-each three the Summary buffer gets.
+the screen, and in the last, the article buffer will take ten lines for
+each three the summary buffer gets.
 
 @findex gnus-window-configuration-split
 This variable can also have a function as its value.  In that case,
@@ -2821,7 +3057,7 @@ whenever Gnus tries to configure the Gnus buffers, that function will be
 called with the @var{action} as its parameter.  There is one pre-made
 function supplied, @code{gnus-window-configuration-split}, which may be
 suitable if you have a very wide Emacs window, and wants to have the
-Summary buffer and the Article buffer side by side.  Here's the
+summary buffer and the article buffer side by side.  Here's the
 definition of this function, which you may use as a template for your
 own function(s):
 
@@ -2832,14 +3068,14 @@ own function(s):
   (switch-to-buffer gnus-group-buffer t)
   (delete-other-windows)
   (split-window-horizontally)
-  (cond ((or (eq action 'newsgroup) (eq action 'summary))
+  (cond ((or (eq action 'group) (eq action 'summary))
         (if (and (get-buffer gnus-summary-buffer)
                  (buffer-name gnus-summary-buffer))
             (switch-to-buffer-other-window gnus-summary-buffer)))
        ((eq action 'article)
         (switch-to-buffer gnus-summary-buffer t)
         (other-window 1)
-         ;; Create and initialize the Article buffer if it doesn't
+         ;; Create and initialize the article buffer if it doesn't
          ;; exist.
         (gnus-article-setup-buffer)
         (switch-to-buffer gnus-article-buffer t))))
@@ -2884,7 +3120,7 @@ file from the server.  This file is often v. large.  You also have to set
 @code{gnus-check-new-news} and @code{gnus-check-bogus-newsgroups} to nil
 to make sure that Gnus doesn't suddenly decide to fetch the active file
 anyway.  Note that this will make it difficult for you to get hold of new
-newsgroups. 
+groups. 
 @item nntp-xover-is-evil
 This one has to be nil.  If not, grabbing article headers from the NNTP
 server will not be very fast.  Not all NNTP servers support XOVER; Gnus
@@ -2900,12 +3136,12 @@ amount of data that is sent over the wires as much as possible.
 
 @table @code
 @item gnus-auto-center-summary
-Set this to nil to inhibit Gnus from recentering the Summary buffer all
+Set this to nil to inhibit Gnus from recentering the summary buffer all
 the time.
 @item gnus-visible-headers
 Cut down on the headers that are included in the articles to the
 minimum.  You can, in fact, make do without them altogether - most of the
-useful data is in the Summary buffer, anyway.  Set this variable to
+useful data is in the summary buffer, anyway.  Set this variable to
 @samp{""} or @samp{"^Date:"}, or whatever you feel you need.
 @item gnus-article-display-hook
 Set this hook to all the available hiding commands:
@@ -2920,7 +3156,7 @@ doesn't really cut down much generally, it means that you have to see
 smaller portions of articles before deciding that you didn't want to
 read them anyway.
 @item gnus-thread-hide-subtree
-If this is non-nil, all threads in the Summary buffer will be hidden
+If this is non-nil, all threads in the summary buffer will be hidden
 initially. 
 @item gnus-updated-mode-lines
 If this is nil, Gnus will not put information in the buffer mode lines,
@@ -2933,15 +3169,15 @@ which might save some time.
 The startup files can get rather large, so you may want to keep their
 sizes down a bit if you are running out of space.
 
-@table
+@table @code
 @item gnus-save-newsrc-file
 If this is nil, Gnus will never save @file{.newsrc} - it will only save
 @file{.newsrc.eld}.  This means that you will not be able to use any
 other newsreaders than Gnus. 
 @item gnus-save-killed-list
-If this is nil, Gnus will not save the list of dead newsgroups.  That
-means that Gnus will not know whether newsgroups are new or old, which
-makes automatic handling of new newsgroups impossible.  You should also
+If this is nil, Gnus will not save the list of dead groups.  That
+means that Gnus will not know whether groups are new or old, which
+makes automatic handling of new groups impossible.  You should also
 set @code{gnus-check-new-newsgroups} and
 @code{gnus-check-bogus-newsgroups} to nil if you set this variable to
 nil. 
@@ -2958,7 +3194,7 @@ Set @code{gnus-read-active-file}, @code{gnus-check-new-newsgroups},
 
 Set @code{gnus-show-threads}, @code{gnus-use-cross-reference} and
 @code{nntp-xover-is-evil} to nil to make entering and exiting the
-Summary buffer faster.
+summary buffer faster.
 
 Set @code{gnus-article-display-hook} to nil to make article processing a
 bit faster.
@@ -2969,7 +3205,13 @@ bit faster.
 @node Reporting Bugs
 @chapter Reporting Bugs
 
+If you find a bug in (ding) Gnus, you can report it with the @kbd{M-x
+gnus-bug} command. @code{(setq debug-on-error t)}, and send me the
+backtrace. I will fix bugs, but I can only fix them if you send me a
+precise description as to how to reproduce the bug.
 
+If you just need help, you are better off asking on
+@samp{gnu.emacs.gnus}. 
 
 @node Index
 @chapter Index