*** empty log message ***
[gnus] / lisp / gnus.el
index 8d36616..9fb10de 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus.el --- a newsreader for GNU Emacs
-;; Copyright (C) 1987,88,89,90,93,94,95 Free Software Foundation, Inc.
+;; Copyright (C) 1987,88,89,90,93,94,95,96 Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;     Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
 
 ;; 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
+;; 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.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
-;; Although Gnus looks suspiciously like GNUS, it isn't quite the same
-;; beast. Most internal structures have been changed. If you have
-;; written packages that depend on any of the hash tables,
-;; `gnus-newsrc-alist', `gnus-killed-assoc', marked lists, the .newsrc
-;; buffer, or internal knowledge of the `nntp-header-' macros, or
-;; dependence on the buffers having a certain format, your code will
-;; fail.
-
 ;;; Code:
 
 (eval '(run-hooks 'gnus-load-hook))
 (require 'mail-utils)
 (require 'timezone)
 (require 'nnheader)
+(require 'message)
+
+(eval-when-compile (require 'cl))
 
-;; Site dependent variables. These variables should be defined in
+(defvar gnus-directory (or (getenv "SAVEDIR") "~/News/")
+  "*Directory variable from which all other Gnus file variables are derived.")
+
+;; Site dependent variables.  These variables should be defined in
 ;; paths.el.
 
 (defvar gnus-default-nntp-server nil
@@ -49,7 +48,7 @@ by the user.
 If you want to change servers, you should use `gnus-select-method'.
 See the documentation to that variable.")
 
-(defconst gnus-backup-default-subscribed-newsgroups 
+(defvar gnus-backup-default-subscribed-newsgroups
   '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
   "Default default new newsgroups the first time Gnus is run.
 Should be set in paths.el, and shouldn't be touched by the user.")
@@ -64,49 +63,60 @@ no need to set this variable.")
   "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
+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, 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 header.
-If stringp, use this; if non-nil, use no host name (user name only).")
-
-
 ;; Customization variables
 
 ;; Don't touch this variable.
 (defvar gnus-nntp-service "nntp"
   "*NNTP service name (\"nntp\" or 119).
-This is an obsolete variable, which is scarcely used. If you use an
+This is an obsolete variable, which is scarcely used.  If you use an
 nntp server for your newsgroup and want to change the port number
 used to 899, you would say something along these lines:
 
  (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
 
-(defvar gnus-select-method 
+(defvar gnus-nntpserver-file "/etc/nntpserver"
+  "*A file with only the name of the nntp server in it.")
+
+;; This function is used to check both the environment variable
+;; NNTPSERVER and the /etc/nntpserver file to see whether one can find
+;; an nntp server name default.
+(defun gnus-getenv-nntpserver ()
+  (or (getenv "NNTPSERVER")
+      (and (file-readable-p gnus-nntpserver-file)
+          (save-excursion
+            (set-buffer (get-buffer-create " *gnus nntp*"))
+            (buffer-disable-undo (current-buffer))
+            (insert-file-contents gnus-nntpserver-file)
+            (let ((name (buffer-string)))
+              (prog1
+                  (if (string-match "^[ \t\n]*$" name)
+                      nil
+                    name)
+                (kill-buffer (current-buffer))))))))
+
+(defvar gnus-select-method
   (nconc
-   (list 'nntp (or (getenv "NNTPSERVER") 
+   (list 'nntp (or (condition-case ()
+                      (gnus-getenv-nntpserver)
+                    (error nil))
                   (if (and gnus-default-nntp-server
                            (not (string= gnus-default-nntp-server "")))
                       gnus-default-nntp-server)
                   (system-name)))
    (if (or (null gnus-nntp-service)
           (equal gnus-nntp-service "nntp"))
-       nil 
+       nil
      (list gnus-nntp-service)))
   "*Default method for selecting a newsgroup.
 This variable should be a list, where the first element is how the
-news is to be fetched, the second is the address. 
+news is to be fetched, the second is the address.
 
 For instance, if you want to get your news via NNTP from
 \"flab.flab.edu\", you could say:
@@ -122,30 +132,29 @@ If you use this variable, you must set `gnus-nntp-server' to nil.
 There is a lot more to know about select methods and virtual servers -
 see the manual for details.")
 
-;; Added by Sudish Joseph <joseph@cis.ohio-state.edu>.
-(defvar gnus-post-method nil
-  "*Preferred method for posting USENET news.
-If this variable is nil, Gnus will use the current method to decide
-which method to use when posting.  If it is non-nil, it will override
-the current method.  This method will not be used in mail groups and
-the like, only in \"real\" newsgroups.
-
-The value must be a valid method as discussed in the documentation of
-`gnus-select-method'.")
+(defvar gnus-message-archive-method 
+  '(nnfolder
+    "archive"
+    (nnfolder-directory (nnheader-concat message-directory "archive"))
+    (nnfolder-active-file (nnheader-concat message-directory "archive/active"))
+    (nnfolder-get-new-mail nil)
+    (nnfolder-inhibit-expiry t))
+  "*Method used for archiving messages you've sent.
+This should be a mail method.")
 
 (defvar gnus-refer-article-method nil
   "*Preferred method for fetching an article by Message-ID.
 If you are reading news from the local spool (with nnspool), fetching
-articles by Message-ID is painfully slow. By setting this method to an
+articles by Message-ID is painfully slow.  By setting this method to an
 nntp method, you might get acceptable results.
 
 The value of this variable must be a valid select method as discussed
-in the documentation of `gnus-select-method'")
+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.
 This is a list where each element is a complete select method (see
-`gnus-select-method').  
+`gnus-select-method').
 
 If, for instance, you want to read your mail with the nnml backend,
 you could set this variable:
@@ -159,7 +168,7 @@ non-numeric prefix - `C-u M-x gnus', in short.")
 
 (defvar gnus-nntp-server nil
   "*The name of the host running the NNTP server.
-This variable is semi-obsolete. Use the `gnus-select-method'
+This variable is semi-obsolete.         Use the `gnus-select-method'
 variable instead.")
 
 (defvar gnus-startup-file "~/.newsrc"
@@ -169,33 +178,46 @@ variable instead.")
 (defvar gnus-init-file "~/.gnus"
   "*Your Gnus elisp startup file.
 If a file with the .el or .elc suffixes exist, it will be read
-instead.") 
+instead.")
 
 (defvar gnus-group-faq-directory
-  "/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
+  '("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
+    "/ftp@sunsite.auc.dk:/pub/usenet/"
+    "/ftp@src.doc.ic.ac.uk:/usenet/news-FAQS/"
+    "/ftp@ftp.seas.gwu.edu:/pub/rtfm/"
+    "/ftp@rtfm.mit.edu:/pub/usenet/"
+    "/ftp@ftp.uni-paderborn.de:/pub/FAQ/"
+    "/ftp@ftp.sunet.se:/pub/usenet/"
+    "/ftp@nctuccca.edu.tw:/USENET/FAQ/"
+    "/ftp@hwarang.postech.ac.kr:/pub/usenet/"
+    "/ftp@ftp.hk.super.net:/mirror/faqs/")
   "*Directory where the group FAQs are stored.
 This will most commonly be on a remote machine, and the file will be
 fetched by ange-ftp.
 
+This variable can also be a list of directories.  In that case, the
+first element in the list will be used by default, and the others will
+be used as backup sites.
+
 Note that Gnus uses an aol machine as the default directory.  If this
 feels fundamentally unclean, just think of it as a way to finally get
 something of value back from them.
 
 If the default site is too slow, try one of these:
 
-   North America: ftp.uu.net                     /usenet/news.answers
-                 mirrors.aol.com                /pub/rtfm/usenet
-                 ftp.seas.gwu.edu               /pub/rtfm
-                  rtfm.mit.edu                   /pub/usenet/news.answers
-   Europe:        ftp.uni-paderborn.de           /pub/FAQ
-                 ftp.Germany.EU.net             /pub/newsarchive/news.answers
-                 ftp.sunet.se                   /pub/usenet
-   Asia:          nctuccca.edu.tw                /USENET/FAQ
-                 hwarang.postech.ac.kr          /pub/usenet/news.answers
-                 ftp.hk.super.net               /mirror/faqs")
+   North America: mirrors.aol.com               /pub/rtfm/usenet
+                 ftp.seas.gwu.edu               /pub/rtfm
+                 rtfm.mit.edu                   /pub/usenet
+   Europe:       ftp.uni-paderborn.de           /pub/FAQ
+                  src.doc.ic.ac.uk               /usenet/news-FAQS
+                 ftp.sunet.se                   /pub/usenet
+                 sunsite.auc.dk                 /pub/usenet
+   Asia:         nctuccca.edu.tw                /USENET/FAQ
+                 hwarang.postech.ac.kr          /pub/usenet
+                 ftp.hk.super.net               /mirror/faqs")
 
 (defvar gnus-group-archive-directory
-  "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/" 
+  "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
   "*The address of the (ding) archives.")
 
 (defvar gnus-group-recent-archive-directory
@@ -211,74 +233,30 @@ started; it'll just use the normal newsgroups subscription methods.")
 (defvar gnus-use-cross-reference t
   "*Non-nil means that cross referenced articles will be marked as read.
 If nil, ignore cross references.  If t, mark articles as read in
-subscribed newsgroups. If neither t nor nil, mark as read in all
-newsgroups.") 
+subscribed newsgroups. If neither t nor nil, mark as read in all
+newsgroups.")
+
+(defvar gnus-single-article-buffer t
+  "*If non-nil, display all articles in the same buffer.
+If nil, each group will get its own article buffer.")
 
 (defvar gnus-use-dribble-file t
   "*Non-nil means that Gnus will use a dribble file to store user updates.
 If Emacs should crash without saving the .newsrc files, complete
 information can be restored from the dribble file.")
 
+(defvar gnus-dribble-directory nil
+  "*The directory where dribble files will be saved.
+If this variable is nil, the directory where the .newsrc files are
+saved will be used.")
+
 (defvar gnus-asynchronous nil
   "*If non-nil, Gnus will supply backends with data needed for async article fetching.")
 
-(defvar gnus-asynchronous-article-function nil
-  "*Function for picking articles to pre-fetch, possibly.")
-
-(defvar gnus-score-file-single-match-alist nil
-  "*Alist mapping regexps to lists of score files.
-Each element of this alist should be of the form
-       (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
-
-If the name of a group is matched by REGEXP, the corresponding scorefiles
-will be used for that group.
-The first match found is used, subsequent matching entries are ignored (to
-use multiple matches, see gnus-score-file-multiple-match-alist).
-
-These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see).")
-
-(defvar gnus-score-file-multiple-match-alist nil
-  "*Alist mapping regexps to lists of score files.
-Each element of this alist should be of the form
-       (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
-
-If the name of a group is matched by REGEXP, the corresponding scorefiles
-will be used for that group.
-If multiple REGEXPs match a group, the score files corresponding to each
-match will be used (for only one match to be used, see
-gnus-score-file-single-match-alist).
-
-These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see).")
-
-
-(defvar gnus-score-file-suffix "SCORE"
-  "*Suffix of the score files.")
-
-(defvar gnus-adaptive-file-suffix "ADAPT"
-  "*Suffix of the adaptive score files.")
-
-(defvar gnus-score-find-score-files-function 'gnus-score-find-bnews
-  "*Function used to find score files.
-The function will be called with the group name as the argument, and
-should return a list of score files to apply to that group.  The score
-files do not actually have to exist.
-
-Predefined values are:
-
-gnus-score-find-single: Only apply the group's own score file.
-gnus-score-find-hierarchical: Also apply score files from parent groups.
-gnus-score-find-bnews: Apply score files whose names matches.
-
-See the documentation to these functions for more information.
-
-This variable can also be a list of functions to be called.  Each
-function should either return a list of score files, or a list of
-score alists.")
-
-(defvar gnus-score-interactive-default-score 1000
-  "*Scoring commands will raise/lower the score with this number as the default.")
+(defvar gnus-kill-summary-on-exit t
+  "*If non-nil, kill the summary buffer when you exit from it.
+If nil, the summary will become a \"*Dead Summary*\" buffer, and
+it will be killed sometime later.")
 
 (defvar gnus-large-newsgroup 200
   "*The number of articles which indicates a large newsgroup.
@@ -299,13 +277,11 @@ contains the element `not-save', long file names will not be used for
 saving; and if it contains the element `not-kill', long file names
 will not be used for kill files.")
 
-(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-article-save-directory gnus-directory
+  "*Name of the directory articles will be saved in (default \"~/News\").")
 
-(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.")
+(defvar gnus-kill-files-directory gnus-directory
+  "*Name of the directory where kill files will be stored (default \"~/News\").")
 
 (defvar gnus-default-article-saver 'gnus-summary-save-in-rmail
   "*A function to save articles in your favorite format.
@@ -320,6 +296,15 @@ Gnus provides the following functions:
 * gnus-summary-save-in-file (article format).
 * gnus-summary-save-in-vm (use VM's folder format).")
 
+(defvar gnus-prompt-before-saving 'always
+  "*This variable says how much prompting is to be done when saving articles.
+If it is nil, no prompting will be done, and the articles will be
+saved to the default files.  If this variable is `always', each and
+every article that is saved will be preceded by a prompt, even when
+saving large batches of articles.  If this variable is neither nil not
+`always', there the user will be prompted once for a file name for
+each invocation of the saving commands.")
+
 (defvar gnus-rmail-save-name (function gnus-plain-save-name)
   "*A function generating a file name to save articles in Rmail format.
 The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
@@ -337,16 +322,31 @@ The function is called with NEWSGROUP, HEADERS, and optional LAST-FOLDER.")
 The function is called with NEWSGROUP, HEADERS, and optional
 LAST-FILE.")
 
-(defvar gnus-split-methods nil
+(defvar gnus-split-methods
+  '((gnus-article-archive-name))
   "*Variable used to suggest where articles are to be saved.
-The syntax of this variable is the same as `nnmail-split-methods'.  
-
 For instance, if you would like to save articles related to Gnus in
 the file \"gnus-stuff\", and articles related to VM in \"vm-stuff\",
 you could set this variable to something like:
 
  '((\"^Subject:.*gnus\\|^Newsgroups:.*gnus\" \"gnus-stuff\")
-   (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))")
+   (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))
+
+This variable is an alist where the where the key is the match and the
+value is a list of possible files to save in if the match is non-nil.
+
+If the match is a string, it is used as a regexp match on the
+article.  If the match is a symbol, that symbol will be funcalled
+from the buffer of the article to be saved with the newsgroup as the
+parameter.  If it is a list, it will be evaled in the same buffer.
+
+If this form or function returns a string, this string will be used as
+a possible file name; and if it returns a non-nil list, that list will
+be used as possible file names.")
+
+(defvar gnus-move-split-methods nil
+  "*Variable used to suggest where articles are to be moved to.
+It uses the same syntax as the `gnus-split-methods' variable.")
 
 (defvar gnus-save-score nil
   "*If non-nil, save group scoring info.")
@@ -355,21 +355,47 @@ you could set this variable to something like:
   "*If non-nil, use some adaptive scoring scheme.")
 
 (defvar gnus-use-cache nil
-  "*If non-nil, Gnus will cache (some) articles locally.")
+  "*If nil, Gnus will ignore the article cache.
+If `passive', it will allow entering (and reading) articles
+explicitly entered into the cache.  If anything else, use the
+cache to the full extent of the law.")
+
+(defvar gnus-use-trees nil
+  "*If non-nil, display a thread tree buffer.")
+
+(defvar gnus-use-grouplens nil
+  "*If non-nil, use GroupLens ratings.")
+
+(defvar gnus-keep-backlog nil
+  "*If non-nil, Gnus will keep read articles for later re-retrieval.
+If it is a number N, then Gnus will only keep the last N articles
+read.  If it is neither nil nor a number, Gnus will keep all read
+articles.  This is not a good idea.")
+
+(defvar gnus-use-nocem nil
+  "*If non-nil, Gnus will read NoCeM cancel messages.")
+
+(defvar gnus-use-demon nil
+  "If non-nil, Gnus might use some demons.")
 
 (defvar gnus-use-scoring t
   "*If non-nil, enable scoring.")
 
+(defvar gnus-use-picons nil
+  "*If non-nil, display picons.")
+
 (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.  If it has the value `some', only enough
+build complete threads.         If it has the value `some', only enough
 headers to connect otherwise loose threads will be displayed.
+This variable can also be a number.  In that case, no more than that
+number of old headers will be fetched.
 
-The server has to support XOVER for any of this to work.")
+The server has to support NOV for any of this to work.")
 
 ;see gnus-cus.el
 ;(defvar gnus-visual t
@@ -397,9 +423,9 @@ jabbering all the time.")
 (defvar gnus-keep-same-level nil
   "*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
+current newsgroup, you will go to the next newsgroup.  If this variable
 is nil, the next newsgroup will be the next from the group
-buffer. 
+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
@@ -411,8 +437,8 @@ with the best level.")
   "*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 can gather them. 
+lost.  Instead of having many small sub-threads from this original thread
+scattered all over the summary buffer, Gnus can gather them.
 
 If non-nil, Gnus will try to gather all loose sub-threads from an
 original thread into one large thread.
@@ -427,9 +453,15 @@ 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.  (Or rather, they will be printed with a string
+subject fields.         (Or rather, they will be printed with a string
 given by the `gnus-summary-same-subject' variable.)")
 
+(defvar gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
+  "*A regexp to match subjects to be excluded from loose thread gathering.
+As loose thread gathering is done on subjects only, that means that
+there can be many false gatherings performed.  By rooting out certain
+common subjects, gathering might become saner.")
+
 (defvar gnus-summary-gather-subject-limit nil
   "*Maximum length of subject comparisons when gathering loose threads.
 Use nil to compare full subjects.  Setting this variable to a low
@@ -441,6 +473,22 @@ same few characters will be incorrectly gathered.
 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
 comparing subjects.")
 
+(defvar gnus-simplify-ignored-prefixes nil
+  "*Regexp, matches for which are removed from subject lines when simplifying.")
+
+(defvar gnus-build-sparse-threads nil
+  "*If non-nil, fill in the gaps in threads.
+If `some', only fill in the gaps that are needed to tie loose threads
+together.  If `more', fill in all leaf nodes that Gnus can find.  If
+non-nil and non-`some', fill in all gaps that Gnus manages to guess.")
+
+(defvar gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject
+  "Function used for gathering loose threads.
+There are two pre-defined functions: `gnus-gather-threads-by-subject',
+which only takes Subjects into consideration; and
+`gnus-gather-threads-by-references', which compared the References
+headers of the articles to find matches.")
+
 ;; 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.
@@ -448,25 +496,30 @@ This variable will only be used if the value of
 `gnus-summary-make-false-root' is `empty'.")
 
 (defvar gnus-summary-goto-unread t
-  "*If non-nil, marking commands will go to the next unread article.")
+  "*If non-nil, marking commands will go to the next unread article.
+If `never', \\<gnus-summary-mode-map>\\[gnus-summary-next-page] will go to the next article,
+whether it is read or not.")
 
 (defvar gnus-group-goto-unread t
   "*If non-nil, movement commands will go to the next unread and subscribed group.")
 
+(defvar gnus-goto-next-group-when-activating t
+  "*If non-nil, the \\<gnus-group-mode-map>\\[gnus-group-get-new-news-this-group] command will advance point to the next group.")
+
 (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
+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. 
+nil.
 
-A variant is to have this variable be a list of select methods. Gnus
+A variant is to have this variable be a list of select methods.         Gnus
 will then use the `ask-server' method on all these select methods to
 query for new groups from all those servers.
 
 Eg.
-  (setq gnus-check-new-newsgroups 
-        '((nntp \"some.server\") (nntp \"other.server\")))
+  (setq gnus-check-new-newsgroups
+       '((nntp \"some.server\") (nntp \"other.server\")))
 
 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].")
@@ -511,16 +564,21 @@ less than this variable, are subscribed.")
 (defvar gnus-level-default-unsubscribed 6
   "*New unsubscribed groups will be unsubscribed at this level.")
 
+(defvar gnus-activate-level (1+ gnus-level-subscribed)
+  "*Groups higher than this level won't be activated on startup.
+Setting this variable to something log might save lots of time when
+you have many groups that you aren't interested in.")
+
 (defvar gnus-activate-foreign-newsgroups 4
   "*If nil, Gnus will not check foreign newsgroups at startup.
-If it is non-nil, it should be a number between one and nine. Foreign
+If it is non-nil, it should be a number between one and nine.  Foreign
 newsgroups that have a level lower or equal to this number will be
-activated on startup. For instance, if you want to active all
-subscribed newsgroups, but not the rest, you'd set this variable to 
+activated on startup.  For instance, if you want to active all
+subscribed newsgroups, but not the rest, you'd set this variable to
 `gnus-level-subscribed'.
 
 If you subscribe to lots of newsgroups from different servers, startup
-might take a while. By setting this variable to nil, you'll save time,
+might take a while.  By setting this variable to nil, you'll save time,
 but you won't be told how many unread articles there are in the
 groups.")
 
@@ -534,19 +592,17 @@ exit.")
 
 (defvar gnus-save-killed-list t
   "*If non-nil, save the list of killed groups to the startup file.
-This will save both time (when starting and quitting) and space (both
-memory and disk), but it will also mean that Gnus has no record of
-which groups are new and which are old, so the automatic new
-newsgroups subscription methods become meaningless. You should always
-set `gnus-check-new-newsgroups' to `ask-server' or nil if you set this
-variable to nil.")
+If you set this variable to nil, you'll save both time (when starting
+and quitting) and space (both memory and disk), but it will also mean
+that Gnus has no record of which groups are new and which are old, so
+the automatic new newsgroups subscription methods become meaningless.
+
+You should always set `gnus-check-new-newsgroups' to `ask-server' or
+nil if you set this variable to nil.")
 
 (defvar gnus-interactive-catchup t
   "*If non-nil, require your confirmation when catching up a group.")
 
-(defvar gnus-interactive-post t
-  "*If non-nil, group name will be asked for when posting.")
-
 (defvar gnus-interactive-exit t
   "*If non-nil, require your confirmation when exiting Gnus.")
 
@@ -573,28 +629,46 @@ Articles with scores closer than this to `gnus-summary-default-score'
 will not be marked.")
 
 (defvar gnus-simplify-subject-fuzzy-regexp nil
-  "*Regular expression that will be removed from subject strings if
-fuzzy subject simplification is selected.")
+  "*Strings to be removed when doing fuzzy matches.
+This can either be a regular expression or list of regular expressions
+that will be removed from subject strings if fuzzy subject
+simplification is selected.")
+
+(defvar gnus-permanently-visible-groups nil
+  "*Regexp to match groups that should always be listed in the group buffer.
+This means that they will still be listed when there are no unread
+articles in the groups.")
+
+(defvar gnus-list-groups-with-ticked-articles t
+  "*If non-nil, list groups that have only ticked articles.
+If nil, only list groups that have unread articles.")
 
 (defvar gnus-group-default-list-level gnus-level-subscribed
-  "*Default listing level. 
+  "*Default listing level.
 Ignored if `gnus-group-use-permanent-levels' is non-nil.")
 
 (defvar gnus-group-use-permanent-levels nil
   "*If non-nil, once you set a level, Gnus will use this level.")
 
+(defvar gnus-group-list-inactive-groups t
+  "*If non-nil, inactive groups will be listed.")
+
 (defvar gnus-show-mime nil
   "*If non-nil, do mime processing of articles.
 The articles will simply be fed to the function given by
 `gnus-show-mime-method'.")
 
 (defvar gnus-strict-mime t
-  "*If nil, decode MIME header even if there is not Mime-Version field.")
-(defvar gnus-show-mime-method (function metamail-buffer)
+  "*If nil, MIME-decode even if there is no Mime-Version header in the article.")
+
+(defvar gnus-show-mime-method 'metamail-buffer
   "*Function to process a MIME message.
 The function is called from the article buffer.")
 
+(defvar gnus-decode-encoded-word-method (lambda ())
+  "*Function to decode a MIME encoded-words.
+The function is called from the article buffer.")
+
 (defvar gnus-show-threads t
   "*If non-nil, display threads in summary mode.")
 
@@ -612,16 +686,26 @@ to expose hidden threads.")
 If nil, which is the default, articles that have different subjects
 from their parents will start separate threads.")
 
+(defvar gnus-thread-operation-ignore-subject t
+  "*If non-nil, subjects will be ignored when doing thread commands.
+This affects commands like `gnus-summary-kill-thread' and
+`gnus-summary-lower-thread'.
+
+If this variable is nil, articles in the same thread with different
+subjects will not be included in the operation in question.  If this
+variable is `fuzzy', only articles that have subjects that are fuzzily
+equal will be included.")
+
 (defvar gnus-thread-indent-level 4
   "*Number that says how much each sub-thread should be indented.")
 
-(defvar gnus-ignored-newsgroups 
+(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.
 Any lines in the active file matching this regular expression are
 removed from the newsgroup list before anything else is done to it,
@@ -630,48 +714,78 @@ thus making them effectively non-existent.")
 (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 headers that match this regexp will be hidden.
+This variable can also be a list of regexps of headers to be ignored.
 If `gnus-visible-headers' is non-nil, this variable will be ignored.")
 
-(defvar gnus-visible-headers "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:"
+(defvar gnus-visible-headers "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-"
   "*All headers that do not match this regexp will be hidden.
+This variable can also be a list of regexp of headers to remain visible.
 If this variable is non-nil, `gnus-ignored-headers' will be ignored.")
 
 (defvar gnus-sorted-header-list
-  '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:" "^To:" 
+  '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:" "^To:"
     "^Cc:" "^Date:" "^Organization:")
   "*This variable is a list of regular expressions.
 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-boring-article-headers
+  '(empty followup-to reply-to)
+  "*Headers that are only to be displayed if they have interesting data.
+Possible values in this list are `empty', `newsgroups', `followup-to',
+`reply-to', and `date'.")
+
 (defvar gnus-show-all-headers nil
   "*If non-nil, don't hide any headers.")
 
 (defvar gnus-save-all-headers t
   "*If non-nil, don't remove any headers before saving.")
 
+(defvar gnus-saved-headers gnus-visible-headers
+  "*Headers to keep if `gnus-save-all-headers' is nil.
+If `gnus-save-all-headers' is non-nil, this variable will be ignored.
+If that variable is nil, however, all headers that match this regexp
+will be kept while the rest will be deleted before saving.")
+
 (defvar gnus-inhibit-startup-message nil
   "*If non-nil, the startup message will not be displayed.")
 
 (defvar gnus-signature-separator "^-- *$"
   "Regexp matching signature separator.")
 
+(defvar gnus-signature-limit nil
+  "Provide a limit to what is considered a signature.
+If it is a number, no signature may not be longer (in characters) than
+that number.  If it is a function, the function will be called without
+any parameters, and if it returns nil, there is no signature in the
+buffer.  If it is a string, it will be used as a regexp.  If it
+matches, the text in question is not a signature.")
+
 (defvar gnus-auto-extend-newsgroup t
   "*If non-nil, extend newsgroup forward and backward when requested.")
 
 (defvar gnus-auto-select-first t
-  "*If non-nil, select the first unread article when entering a group.
+  "*If nil, don't select the first unread article when entering a group.
+If this variable is `best', select the highest-scored unread article
+in the group.  If neither nil nor `best', select the first unread
+article.
+
 If you want to prevent automatic selection of the first unread article
 in some newsgroups, set the variable to nil in
-`gnus-select-group-hook'.") 
+`gnus-select-group-hook'.")
 
 (defvar gnus-auto-select-next t
   "*If non-nil, offer to go to the next group from the end of the previous.
 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
-nor t, Gnus will select the following unread newsgroup.  In
+summary mode and go back to group mode.         If the value is neither nil
+nor t, Gnus will select the following unread newsgroup.         In
 particular, if the value is the symbol `quietly', the next unread
-newsgroup will be selected without any confirmations.")
+newsgroup will be selected without any confirmation, and if it is
+`almost-quietly', the next group will be selected without any
+confirmation if you are located on the last article in the group.
+Finally, if this variable is `slightly-quietly', the `Z n' command
+will go to the next group without confirmation.")
 
 (defvar gnus-auto-select-same nil
   "*If non-nil, select the next article with the same subject.")
@@ -682,7 +796,9 @@ The \"unread\" movement commands will stay on the same line if the
 current article is unread.")
 
 (defvar gnus-auto-center-summary t
-  "*If non-nil, always center the current summary buffer.")
+  "*If non-nil, always center the current summary buffer.
+In particular, if `vertical' do only vertical recentering.  If non-nil
+and non-`vertical', do both horizontal and vertical recentering.")
 
 (defvar gnus-break-pages t
   "*If non-nil, do page breaking on articles.
@@ -700,49 +816,119 @@ beginning of a line.")
 (defvar gnus-window-configuration nil
   "Obsolete variable.  See `gnus-buffer-configuration'.")
 
+(defvar gnus-window-min-width 2
+  "*Minimum width of Gnus buffers.")
+
+(defvar gnus-window-min-height 1
+  "*Minimum height of Gnus buffers.")
+
 (defvar gnus-buffer-configuration
-  '((group ([group 1.0 point] 
-           (if gnus-carpal [group-carpal 4])))
-    (summary ([summary 1.0 point]
-             (if gnus-carpal [summary-carpal 4])))
-    (article ([summary 0.25 point] 
-             (if gnus-carpal [summary-carpal 4]) 
-             [article 1.0]))
-    (server ([server 1.0 point]
-            (if gnus-carpal [server-carpal 2])))
-    (browse ([browse 1.0 point]
-            (if gnus-carpal [browse-carpal 2])))
-    (group-mail ([mail 1.0 point]))
-    (summary-mail ([mail 1.0 point]))
-    (summary-reply ([article 0.5]
-                   [mail 1.0 point]))
-    (info ([nil 1.0 point]))
-    (summary-faq ([summary 0.25]
-                 [faq 1.0 point]))
-    (edit-group ([group 0.5]
-                [edit-group 1.0 point]))
-    (edit-server ([server 0.5]
-                 [edit-server 1.0 point]))
-    (edit-score ([summary 0.25]
-                [edit-score 1.0 point]))
-    (post ([post 1.0 point]))
-    (reply ([article 0.5]
-           [mail 1.0 point]))
-    (mail-forward ([mail 1.0 point]))
-    (post-forward ([post 1.0 point]))
-    (reply-yank ([mail 1.0 point]))
-    (followup ([article 0.5]
-              [post 1.0 point]))
-    (followup-yank ([post 1.0 point])))
+  '((group
+     (vertical 1.0
+              (group 1.0 point)
+              (if gnus-carpal '(group-carpal 4))))
+    (summary
+     (vertical 1.0
+              (summary 1.0 point)
+              (if gnus-carpal '(summary-carpal 4))))
+    (article
+     (cond 
+      (gnus-use-picons
+       '(frame 1.0
+              (vertical 1.0
+                        (summary 0.25 point)
+                        (if gnus-carpal '(summary-carpal 4))
+                        (article 1.0))
+              (vertical ((height . 5) (width . 15)
+                         (user-position . t)
+                         (left . -1) (top . 1))
+                        (picons 1.0))))
+      (gnus-use-trees
+       '(vertical 1.0
+                 (summary 0.25 point)
+                 (tree 0.25)
+                 (article 1.0)))
+      (t
+       '(vertical 1.0
+                (summary 0.25 point)
+                (if gnus-carpal '(summary-carpal 4))
+                (if gnus-use-trees '(tree 0.25))
+                (article 1.0)))))
+    (server
+     (vertical 1.0
+              (server 1.0 point)
+              (if gnus-carpal '(server-carpal 2))))
+    (browse
+     (vertical 1.0
+              (browse 1.0 point)
+              (if gnus-carpal '(browse-carpal 2))))
+    (message
+     (vertical 1.0
+              (message 1.0 point)))
+    (pick
+     (vertical 1.0
+              (article 1.0 point)))
+    (info
+     (vertical 1.0
+              (info 1.0 point)))
+    (summary-faq
+     (vertical 1.0
+              (summary 0.25)
+              (faq 1.0 point)))
+    (edit-group
+     (vertical 1.0
+              (group 0.5)
+              (edit-group 1.0 point)))
+    (edit-server
+     (vertical 1.0
+              (server 0.5)
+              (edit-server 1.0 point)))
+    (edit-score
+     (vertical 1.0
+              (summary 0.25)
+              (edit-score 1.0 point)))
+    (post
+     (vertical 1.0
+              (post 1.0 point)))
+    (reply
+     (vertical 1.0
+              (article-copy 0.5)
+              (message 1.0 point)))
+    (forward
+     (vertical 1.0
+              (message 1.0 point)))
+    (reply-yank
+     (vertical 1.0
+              (message 1.0 point)))
+    (mail-bounce
+     (vertical 1.0
+              (article 0.5)
+              (message 1.0 point)))
+    (draft
+     (vertical 1.0
+              (draft 1.0 point)))
+    (pipe
+     (vertical 1.0
+              (summary 0.25 point)
+              (if gnus-carpal '(summary-carpal 4))
+              ("*Shell Command Output*" 1.0)))
+    (bug
+     (vertical 1.0
+              ("*Gnus Help Bug*" 0.5)
+              ("*Gnus Bug*" 1.0 point)))
+    (compose-bounce
+     (vertical 1.0
+              (article 0.5)
+              (message 1.0 point))))
   "Window configuration for all possible Gnus buffers.
 This variable is a list of lists.  Each of these lists has a NAME and
-a RULE.  The NAMEs are commonsense names like `group', which names a
+a RULE.         The NAMEs are commonsense names like `group', which names a
 rule used when displaying the group buffer; `summary', which names a
 rule for what happens when you enter a group and do not display an
 article buffer; and so on.  See the value of this variable for a
 complete list of NAMEs.
 
-Each RULE is a list of vectors.  The first element in this vector is
+Each RULE is a list of vectors.         The first element in this vector is
 the name of the buffer to be displayed; the second element is the
 percentage of the screen this buffer is to occupy (a number in the
 0.0-0.99 range); the optional third element is `point', which should
@@ -762,9 +948,15 @@ buffer configuration.")
     (server-carpal . gnus-carpal-server-buffer)
     (browse-carpal . gnus-carpal-browse-buffer)
     (edit-score . gnus-score-edit-buffer)
-    (mail . gnus-mail-buffer)
-    (post . gnus-post-news-buffer)
-    (faq . gnus-faq-buffer))
+    (message . gnus-message-buffer)
+    (mail . gnus-message-buffer)
+    (post-news . gnus-message-buffer)
+    (faq . gnus-faq-buffer)
+    (picons . "*Picons*")
+    (tree . gnus-tree-buffer)
+    (info . gnus-info-buffer)
+    (article-copy . gnus-article-copy)
+    (draft . gnus-draft-buffer))
   "Mapping from short symbols to buffer names or buffer variables.")
 
 (defvar gnus-carpal nil
@@ -777,10 +969,11 @@ inserts new groups at the beginning of the list of groups;
 `gnus-subscribe-alphabetically' inserts new groups in strict
 alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
 in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
-for your decision.")
+for your decision; `gnus-subscribe-killed' kills all new groups;
+`gnus-subscribe-zombies' will make all new groups into zombies.")
 
 ;; Suggested by a bug report by Hallvard B Furuseth.
-;; <h.b.furuseth@usit.uio.no>. 
+;; <h.b.furuseth@usit.uio.no>.
 (defvar gnus-subscribe-options-newsgroup-method
   (function gnus-subscribe-alphabetically)
   "*This function is called to subscribe newsgroups mentioned on \"options -n\" lines.
@@ -807,11 +1000,16 @@ hierarchy in its entirety.")
   "*Function used for sorting the group buffer.
 This function will be called with group info entries as the arguments
 for the groups to be sorted.  Pre-made functions include
-`gnus-group-sort-by-alphabet', `gnus-group-sort-by-unread' and
-`gnus-group-sort-by-level'")
+`gnus-group-sort-by-alphabet', `gnus-group-sort-by-unread',
+`gnus-group-sort-by-level', `gnus-group-sort-by-score', and
+`gnus-group-sort-by-rank'.
+
+This variable can also be a list of sorting functions. In that case,
+the most significant sort function should be the last function in the
+list.")
 
 ;; Mark variables suggested by Thomas Michanek
-;; <Thomas.Michanek@telelogic.se>. 
+;; <Thomas.Michanek@telelogic.se>.
 (defvar gnus-unread-mark ? 
   "*Mark used for unread articles.")
 (defvar gnus-ticked-mark ?!
@@ -826,6 +1024,8 @@ for the groups to be sorted.  Pre-made functions include
   "*Mark used for expirable articles.")
 (defvar gnus-killed-mark ?K
   "*Mark used for killed articles.")
+(defvar gnus-souped-mark ?F
+  "*Mark used for killed articles.")
 (defvar gnus-kill-file-mark ?X
   "*Mark used for articles killed by kill files.")
 (defvar gnus-low-score-mark ?Y
@@ -834,10 +1034,16 @@ for the groups to be sorted.  Pre-made functions include
   "*Mark used for articles that are caught up.")
 (defvar gnus-replied-mark ?A
   "*Mark used for articles that have been replied to.")
-(defvar gnus-process-mark ?# 
+(defvar gnus-cached-mark ?*
+  "*Mark used for articles that are in the cache.")
+(defvar gnus-saved-mark ?S
+  "*Mark used for articles that have been saved to.")
+(defvar gnus-process-mark ?#
   "*Process mark.")
 (defvar gnus-ancient-mark ?O
   "*Mark used for ancient articles.")
+(defvar gnus-sparse-mark ?Q
+  "*Mark used for sparsely reffed articles.")
 (defvar gnus-canceled-mark ?G
   "*Mark used for canceled articles.")
 (defvar gnus-score-over-mark ?+
@@ -848,8 +1054,6 @@ for the groups to be sorted.  Pre-made functions include
   "*There is no thread under the article.")
 (defvar gnus-not-empty-thread-mark ?=
   "*There is a thread under the article.")
-(defvar gnus-dummy-mark ?Z
-  "*This is a dummy article.")
 
 (defvar gnus-view-pseudo-asynchronously nil
   "*If non-nil, Gnus will view pseudo-articles asynchronously.")
@@ -864,7 +1068,10 @@ will not be asked to confirm the command.")
 If nil, all files that use the same viewing command will be given as a
 list of parameters to that command.")
 
-(defvar gnus-group-line-format "%M%S%p%5y: %(%g%)\n"
+(defvar gnus-insert-pseudo-articles t
+  "*If non-nil, insert pseudo-articles when decoding articles.")
+
+(defvar gnus-group-line-format "%M%S%p%P%5y: %(%g%)%l\n"
   "*Format of group lines.
 It works along the same lines as a normal formatting string,
 with some simple extensions.
@@ -886,21 +1093,23 @@ with some simple extensions.
 %o    Moderated group (char, \"m\")
 %p    Process mark (char)
 %O    Moderated group (string, \"(m)\" or \"\")
+%P    Topic indentation (string)
+%l    Whether there are GroupLens predictions for this group (string)
 %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
+%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
+      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 buffer just like information from any other
       group 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
+Note that this format specification is not always respected.  For
 reasons of efficiency, when listing killed groups, this specification
-is ignored altogether. If the spec is changed considerably, your
+is ignored altogether. If the spec is changed considerably, your
 output may end up looking strange when listing both alive and killed
 groups.
 
@@ -908,7 +1117,7 @@ If you use %o or %O, reading the active file will be slower and quite
 a bit of extra memory will be used. %D will also worsen performance.
 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.") 
+effect.")
 
 (defvar gnus-summary-line-format "%U%R%z%I%(%[%4L: %-20,20n%]%) %s\n"
   "*The format specification of the lines in the summary buffer.
@@ -933,8 +1142,8 @@ with some simple extensions.
 %I   Indentation based on thread level (a string of spaces)
 %T   A string with two possible values: 80 spaces if the article
      is on thread level two or larger and 0 spaces on level one
-%R   \"R\" if this article has been replied to, \" \" otherwise (character)
-%U   Status of this article (character, \"D\", \"K\", \"-\" or \" \")
+%R   \"A\" if this article has been replied to, \" \" otherwise (character)
+%U   Status of this article (character, \"R\", \"K\", \"-\" or \" \")
 %[   Opening bracket (character, \"[\" or \"<\")
 %]   Closing bracket (character, \"]\" or \">\")
 %>   Spaces of length thread-level (string)
@@ -943,77 +1152,103 @@ with some simple extensions.
 %z   Article zcore (character)
 %t   Number of articles under the current thread (number).
 %e   Whether the thread is empty or not (character).
-%u   User defined specifier. The next character in the format string should
+%l   GroupLens score (string).
+%u   User defined specifier.  The next character in the format string should
      be a letter.  Gnus will call the function gnus-user-format-function-X,
-     where X is the letter following %u. The function will be passed the
-     current header as argument. The function should return a string, which
+     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
+when the mouse point is placed inside the area.         There can only be one
 such area.
 
 The %U (status), %R (replied) and %z (zcore) specs have to be handled
-with care. For reasons of efficiency, Gnus will compute what column
-these characters will end up in, and \"hard-code\" that. This means that
-it is illegal to have these specs after a variable-length spec. Well,
+with care.  For reasons of efficiency, Gnus will compute what column
+these characters will end up in, and \"hard-code\" that.  This means that
+it is illegal to have these specs after a variable-length spec.         Well,
 you might not be arrested, but your summary buffer will look strange,
 which is bad enough.
 
 The smart choice is to have these specs as for to the left as
-possible. 
+possible.
 
 This restriction may disappear in later versions of Gnus.")
 
-(defvar gnus-summary-dummy-line-format "*  :                          : %S\n"
+(defvar gnus-summary-dummy-line-format
+  "*  %(:                          :%) %S\n"
   "*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 "Gnus  %G/%A %Z"
-  "*The format specification for the summary mode line.")
-
-(defvar gnus-article-mode-line-format "Gnus  %G/%A %S"
-  "*The format specification for the article mode line.")
+(defvar gnus-summary-mode-line-format "Gnus: %%b [%A] %Z"
+  "*The format specification for the summary mode line.
+It works along the same lines as a normal formatting string,
+with some simple extensions:
+
+%G  Group name
+%p  Unprefixed group name
+%A  Current article number
+%V  Gnus version
+%U  Number of unread articles in the group
+%e  Number of unselected articles in the group
+%Z  A string with unread/unselected article counts
+%g  Shortish group name
+%S  Subject of the current article
+%u  User-defined spec
+%s  Current score file name
+%d  Number of dormant articles
+%r  Number of articles that have been marked as read in this session
+%E  Number of articles expunged by the score files")
+
+(defvar gnus-article-mode-line-format "Gnus: %%b %S"
+  "*The format specification for the article mode line.
+See `gnus-summary-mode-line-format' for a closer description.")
+
+(defvar gnus-group-mode-line-format "Gnus: %%b {%M%:%S}"
+  "*The format specification for the group mode line.
+It works along the same lines as a normal formatting string,
+with some simple extensions:
 
-(defvar gnus-group-mode-line-format "Gnus  List of groups   {%M:%S}  "
-  "*The format specification for the group mode line.")
+%S   The native news server.
+%M   The native select method.
+%:   \":\" if %S isn't \"\".")
 
 (defvar gnus-valid-select-methods
   '(("nntp" post address prompt-address)
-    ("nnspool" post)
-    ("nnvirtual" none virtual prompt-address) 
-    ("nnmbox" mail respool
-    ("nnml" mail respool)
-    ("nnmh" mail respool
-    ("nndir" none prompt-address address)
-    ("nneething" none prompt-address)
-    ("nndigest" none) 
-    ("nndoc" none prompt-address) 
-    ("nnbabyl" mail respool) 
-    ("nnkiboze" post virtual) 
-    ;;("nnsoup" post)
-    ("nnfolder" mail respool))
+    ("nnspool" post address)
+    ("nnvirtual" post-mail virtual prompt-address)
+    ("nnmbox" mail respool address)
+    ("nnml" mail respool address)
+    ("nnmh" mail respool address)
+    ("nndir" post-mail prompt-address address)
+    ("nneething" none address prompt-address)
+    ("nndoc" none address prompt-address)
+    ("nnbabyl" mail address respool)
+    ("nnkiboze" post address virtual)
+    ("nnsoup" post-mail address)
+    ("nndraft" post-mail)
+    ("nnfolder" mail respool address))
   "An alist of valid select methods.
 The first element of each list lists should be a string with the name
-of the select method. The other elements may be be the category of
+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).
 If you implement a new select method, all you should have to change is
-this variable. I think.")
+this variable. I think.")
 
-(defvar gnus-updated-mode-lines '(group article summary)
+(defvar gnus-updated-mode-lines '(group article summary tree)
   "*List of buffers that should update their mode lines.
-The list may contain the symbols `group', `article' and `summary'. If
+The list may contain the symbols `group', `article' and `summary'.  If
 the corresponding symbol is present, Gnus will keep that mode line
-updated with information that may be pertinent. 
+updated with information that may be pertinent.
 If this variable is nil, screen refresh may be quicker.")
 
 ;; Added by Keinonen Kari <kk85613@cs.tut.fi>.
-(defvar gnus-mode-non-string-length 21
+(defvar gnus-mode-non-string-length nil
   "*Max length of mode-line non-string contents.
 If this is nil, Gnus will take space as is needed, leaving the rest
 of the modeline intact.")
@@ -1026,7 +1261,11 @@ of the modeline intact.")
 (defvar gnus-summary-mark-below nil
   "*Mark all articles with a score below this variable as read.
 This variable is local to each summary buffer and usually set by the
-score file.")  
+score file.")
+
+(defvar gnus-article-sort-functions '(gnus-article-sort-by-number)
+  "*List of functions used for sorting articles in the summary buffer.
+This variable is only used when not using a threaded display.")
 
 (defvar gnus-thread-sort-functions '(gnus-thread-sort-by-number)
   "*List of functions used for sorting threads in the summary buffer.
@@ -1034,7 +1273,9 @@ By default, threads are sorted by article number.
 
 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,
-the primary sort function should be the last.
+the primary sort function should be the last.  You should probably
+always include `gnus-thread-sort-by-number' in the list of sorting
+functions -- preferably first.
 
 Ready-mady functions include `gnus-thread-sort-by-number',
 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
@@ -1049,14 +1290,28 @@ subthread and should then return the score of the thread.
 
 Some functions you can use are `+', `max', or `min'.")
 
+(defvar gnus-summary-expunge-below nil
+  "All articles that have a score less than this variable will be expunged.")
+
+(defvar gnus-thread-expunge-below nil
+  "All threads that have a total score less than this variable will be expunged.
+See `gnus-thread-score-function' for en explanation of what a
+\"thread score\" is.")
+
+(defvar gnus-auto-subscribed-groups
+  "^nnml\\|^nnfolder\\|^nnmbox\\|^nnmh\\|^nnbabyl"
+  "*All new groups that match this regexp will be subscribed automatically.
+Note that this variable only deals with new groups.  It has no effect
+whatsoever on old groups.")
+
 (defvar gnus-options-subscribe nil
   "*All new groups matching this regexp will be subscribed unconditionally.
-Note that this variable deals only with new newsgroups.  This variable
+Note that this variable deals only with new newsgroups.         This variable
 does not affect old newsgroups.")
 
 (defvar gnus-options-not-subscribe nil
   "*All new groups matching this regexp will be ignored.
-Note that this variable deals only with new newsgroups.  This variable
+Note that this variable deals only with new newsgroups.         This variable
 does not affect old (already subscribed) newsgroups.")
 
 (defvar gnus-auto-expirable-newsgroups nil
@@ -1064,12 +1319,23 @@ does not affect old (already subscribed) newsgroups.")
 If non-nil, this should be a regexp that should match all groups in
 which to perform auto-expiry.  This only makes sense for mail groups.")
 
+(defvar gnus-total-expirable-newsgroups nil
+  "*Groups in which to perform expiry of all read articles.
+Use with extreme caution.  All groups that match this regexp will be
+expiring - which means that all read articles will be deleted after
+(say) one week.         (This only goes for mail groups and the like, of
+course.)")
+
+(defvar gnus-group-uncollapsed-levels 1
+  "Number of group name elements to leave alone when making a short group name.")
+
 (defvar gnus-hidden-properties '(invisible t intangible t)
   "Property list to use for hiding text.")
 
 (defvar gnus-modtime-botch nil
-  "*Non-nil means .newsrc should be deleted prior to save.  Its use is
-due to the bogus appearance that .newsrc was modified on disc.")
+  "*Non-nil means .newsrc should be deleted prior to save.  
+Its use is due to the bogus appearance that .newsrc was modified on
+disc.")
 
 ;; Hooks.
 
@@ -1083,14 +1349,17 @@ This hook is run before any variables are set in the summary buffer.")
 (defvar gnus-article-mode-hook nil
   "*A hook for Gnus article mode.")
 
-(defun gnus-summary-prepare-exit-hook nil
+(defvar gnus-summary-prepare-exit-hook nil
   "*A hook called when preparing to exit from the summary buffer.
 It calls `gnus-summary-expire-articles' by default.")
 (add-hook 'gnus-summary-prepare-exit-hook 'gnus-summary-expire-articles)
 
-(defun gnus-summary-exit-hook nil
+(defvar gnus-summary-exit-hook nil
   "*A hook called on exit from the summary buffer.")
 
+(defvar gnus-group-catchup-group-hook nil
+  "*A hook run when catching up a group from the group buffer.")
+
 (defvar gnus-open-server-hook nil
   "*A hook called just before opening connection to the news server.")
 
@@ -1104,12 +1373,15 @@ This hook is called after Gnus is connected to the NNTP server.")
 (defvar gnus-get-new-news-hook nil
   "*A hook run just before Gnus checks for new news.")
 
+(defvar gnus-after-getting-new-news-hook nil
+  "*A hook run after Gnus checks for new news.")
+
 (defvar gnus-group-prepare-function 'gnus-group-prepare-flat
   "*A function that is called to generate the group buffer.
 The function is called with three arguments: The first is a number;
 all group with a level less or equal to that number should be listed,
-if the second is non-nil, empty groups should also be displayed. If
-the third is non-nil, it is a number. No groups with a level lower
+if the second is non-nil, empty groups should also be displayed.  If
+the third is non-nil, it is a number.  No groups with a level lower
 than this number should be displayed.
 
 The only current function implemented is `gnus-group-prepare-flat'.")
@@ -1122,6 +1394,11 @@ If you want to modify the group buffer, you can use this hook.")
   "*A hook called after the summary buffer has been generated.
 If you want to modify the summary buffer, you can use this hook.")
 
+(defvar gnus-summary-generate-hook nil
+  "*A hook run just before generating the summary buffer.
+This hook is commonly used to customize threading variables and the
+like.")
+
 (defvar gnus-article-prepare-hook nil
   "*A hook called after an article has been prepared in the article buffer.
 If you want to run a special decoding program like nkf, use this hook.")
@@ -1129,9 +1406,9 @@ 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
-;buffer. Typical functions that this hook may contain are
+;buffer.  Typical functions that this hook may contain are
 ;`gnus-article-hide-headers' (hide selected headers),
-;`gnus-article-maybe-highlight' (perform fancy article highlighting), 
+;`gnus-article-maybe-highlight' (perform fancy article highlighting),
 ;`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)
@@ -1142,7 +1419,7 @@ If you want to run a special decoding program like nkf, use this hook.")
   "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | xv -quit -"
   "String or function to be executed to display an X-Face header.
 If it is a string, the command will be executed in a sub-shell
-asynchronously. The compressed face will be piped to this command.") 
+asynchronously.         The compressed face will be piped to this command.")
 
 (defvar gnus-article-x-face-too-ugly nil
   "Regexp matching posters whose face shouldn't be shown automatically.")
@@ -1164,11 +1441,8 @@ following hook:
                       (mail-header-subject header) 're-only)))
                  gnus-newsgroup-headers))))")
 
-(defvar gnus-select-article-hook
-  '(gnus-summary-show-thread)
-  "*A hook called when an article is selected.
-The default hook shows conversation thread subtrees of the selected
-article automatically using `gnus-summary-show-thread'.")
+(defvar gnus-select-article-hook nil
+  "*A hook called when an article is selected.")
 
 (defvar gnus-apply-kill-hook '(gnus-apply-kill-file)
   "*A hook called to apply kill files to a group.
@@ -1176,7 +1450,7 @@ 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
-newsgroups, I recommend you to use a lighter hook function. For
+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
 a string `rmgroup' in subject in newsgroup `control', you can use the
 following hook:
@@ -1188,16 +1462,15 @@ following hook:
                 (gnus-kill \"Subject\" \"rmgroup\")
                 (gnus-expunge \"X\"))))))")
 
-(defvar gnus-visual-mark-article-hook 
+(defvar gnus-visual-mark-article-hook
   (list 'gnus-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 'gnus-inews-insert-signature)
-  "*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'.")
+(defvar gnus-parse-headers-hook nil
+  "*A hook called before parsing the headers.")
+(add-hook 'gnus-parse-headers-hook 'gnus-decode-rfc1522)
 
 (defvar gnus-exit-group-hook nil
   "*A hook called when exiting (not quitting) summary mode.")
@@ -1208,10 +1481,21 @@ file specified by the variable `gnus-signature-file'.")
 (defvar gnus-exit-gnus-hook nil
   "*A hook called when exiting Gnus.")
 
+(defvar gnus-after-exiting-gnus-hook nil
+  "*A hook called after exiting Gnus.")
+
 (defvar gnus-save-newsrc-hook nil
-  "*A hook called when saving the newsrc file.")
+  "*A hook called before saving any of the newsrc files.")
+
+(defvar gnus-save-quick-newsrc-hook nil
+  "*A hook called just before saving the quick newsrc file.
+Can be used to turn version control on or off.")
 
-(defvar gnus-summary-update-hook 
+(defvar gnus-save-standard-newsrc-hook nil
+  "*A hook called just before saving the standard newsrc file.
+Can be used to turn version control on or off.")
+
+(defvar gnus-summary-update-hook
   (list 'gnus-summary-highlight-line)
   "*A hook called when a summary line is changed.
 The hook will not be called if `gnus-visual' is nil.
@@ -1220,29 +1504,85 @@ The default function `gnus-summary-highlight-line' will
 highlight the line according to the `gnus-summary-highlight'
 variable.")
 
-(defvar gnus-mark-article-hook (list 'gnus-summary-mark-unread-as-read)
+(defvar gnus-group-update-hook '(gnus-group-highlight-line)
+  "*A hook called when a group line is changed.
+The hook will not be called if `gnus-visual' is nil.
+
+The default function `gnus-group-highlight-line' will
+highlight the line according to the `gnus-group-highlight'
+variable.")
+
+(defvar gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
   "*A hook called when an article is selected for the first time.
 The hook is intended to mark an article as read (or unread)
 automatically when it is selected.")
 
+(defvar gnus-group-change-level-function nil
+  "Function run when a group level is changed.
+It is called with three parameters -- GROUP, LEVEL and OLDLEVEL.")
+
 ;; Remove any hilit infestation.
 (add-hook 'gnus-startup-hook
          (lambda ()
            (remove-hook 'gnus-summary-prepare-hook
                         'hilit-rehighlight-buffer-quietly)
            (remove-hook 'gnus-summary-prepare-hook 'hilit-install-line-hooks)
-           (setq gnus-mark-article-hook '(gnus-summary-mark-unread-as-read))
+           (setq gnus-mark-article-hook
+                 '(gnus-summary-mark-read-and-unread-as-read))
            (remove-hook 'gnus-article-prepare-hook
                         'hilit-rehighlight-buffer-quietly)))
 
-
 \f
 ;; Internal variables
 
+(defvar gnus-tree-buffer "*Tree*"
+  "Buffer where Gnus thread trees are displayed.")
+
+;; Dummy variable.
+(defvar gnus-use-generic-from nil)
+
+(defvar gnus-thread-indent-array nil)
+(defvar gnus-thread-indent-array-level gnus-thread-indent-level)
+
+(defvar gnus-newsrc-file-version nil)
+
+(defvar gnus-method-history nil)
+;; Variable holding the user answers to all method prompts.
+
+(defvar gnus-group-history nil)
+;; Variable holding the user answers to all group prompts.
+
+(defvar gnus-server-alist nil
+  "List of available servers.")
+
+(defvar gnus-group-indentation-function nil)
+
+(defvar gnus-topic-indentation "") ;; Obsolete variable.
+
+(defvar gnus-goto-missing-group-function nil)
+
+(defvar gnus-override-subscribe-method nil)
+
+(defvar gnus-group-goto-next-group-function nil
+  "Function to override finding the next group after listing groups.")
+
+(defconst gnus-article-mark-lists
+  '((marked . tick) (replied . reply)
+    (expirable . expire) (killed . killed)
+    (bookmarks . bookmark) (dormant . dormant)
+    (scored . score) (saved . save)
+    (cached . cache)
+    ))
+
 ;; Avoid highlighting in kill files.
 (defvar gnus-summary-inhibit-highlight nil)
 (defvar gnus-newsgroup-selected-overlay nil)
 
+(defvar gnus-inhibit-hiding nil)
+(defvar gnus-group-indentation "")
+(defvar gnus-inhibit-limiting nil)
+(defvar gnus-created-frames nil)
+
 (defvar gnus-article-mode-map nil)
 (defvar gnus-dribble-buffer nil)
 (defvar gnus-headers-retrieved-by nil)
@@ -1251,102 +1591,129 @@ automatically when it is selected.")
 (defvar gnus-article-check-size nil)
 
 (defvar gnus-current-score-file nil)
-(defvar gnus-internal-global-score-files nil)
-(defvar gnus-score-file-list nil)
+(defvar gnus-newsgroup-adaptive-score-file nil)
+(defvar gnus-scores-exclude-files nil)
 
+(defvar gnus-opened-servers nil)
 
 (defvar gnus-current-move-group nil)
+(defvar gnus-current-copy-group nil)
+(defvar gnus-current-crosspost-group nil)
 
 (defvar gnus-newsgroup-dependencies nil)
-(defvar gnus-newsgroup-threads nil)
 (defvar gnus-newsgroup-async nil)
 (defconst gnus-group-edit-buffer "*Gnus edit newsgroup*")
 
 (defvar gnus-newsgroup-adaptive nil)
 
 (defvar gnus-summary-display-table nil)
-
-(defconst gnus-group-line-format-alist
-  (list (list ?M 'marked ?c)
-       (list ?S 'subscribed ?c)
-       (list ?L 'level ?d)
-       (list ?N 'number ?s)
-       (list ?I 'number-of-dormant ?d)
-       (list ?T 'number-of-ticked ?d)
-       (list ?R 'number-of-read ?s)
-       (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 'qualified-group ?s)
-       (list ?D 'newsgroup-description ?s)
-       (list ?o 'moderated ?c)
-       (list ?O 'moderated-string ?s)
-       (list ?p 'process-marked ?c)
-       (list ?s 'news-server ?s)
-       (list ?n 'news-method ?s)
-       (list ?z 'news-method-string ?s)
-       (list ?u 'user-defined ?s)))
-
-(defconst gnus-summary-line-format-alist 
-  (list (list ?N 'number ?d)
-       (list ?S 'subject ?s)
-       (list ?s 'subject-or-nil ?s)
-       (list ?n 'name ?s)
-       (list ?A '(car (cdr (funcall gnus-extract-address-components from)))
-             ?s)
-       (list ?a '(or (car (funcall gnus-extract-address-components from)) 
-                     from) ?s)
-       (list ?F 'from ?s)
-       (list ?x (macroexpand '(mail-header-xref header)) ?s)
-       (list ?D (macroexpand '(mail-header-date header)) ?s)
-       (list ?d '(gnus-dd-mmm (mail-header-date header)) ?s)
-       (list ?M (macroexpand '(mail-header-id header)) ?s)
-       (list ?r (macroexpand '(mail-header-references header)) ?s)
-       (list ?c '(or (mail-header-chars header) 0) ?d)
-       (list ?L 'lines ?d)
-       (list ?I 'indentation ?s)
-       (list ?T '(if (= level 0) "" (make-string (frame-width) ? )) ?s)
-       (list ?R 'replied ?c)
-       (list ?\[ 'opening-bracket ?c)
-       (list ?\] 'closing-bracket ?c)
-       (list ?\> '(make-string level ? ) ?s)
-       (list ?\< '(make-string (max 0 (- 20 level)) ? ) ?s)
-       (list ?i 'score ?d)
-       (list ?z 'score-char ?c)
-       (list ?U 'unread ?c)
-       (list ?t '(gnus-summary-number-of-articles-in-thread 
-                  (and (boundp 'thread) (car thread)))
-             ?d)
-       (list ?e '(gnus-summary-number-of-articles-in-thread 
-                  (and (boundp 'thread) (car thread)) t)
-             ?c)
-       (list ?u 'user-defined ?s))
+(defvar gnus-summary-display-article-function nil)
+
+(defvar gnus-summary-highlight-line-function nil
+  "Function called after highlighting a summary line.")
+
+(defvar gnus-group-line-format-alist
+  `((?M gnus-tmp-marked-mark ?c)
+    (?S gnus-tmp-subscribed ?c)
+    (?L gnus-tmp-level ?d)
+    (?N (cond ((eq number t) "*" )
+             ((numberp number) 
+              (int-to-string
+               (+ number
+                  (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
+                  (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))))
+             (t number)) ?s)
+    (?R gnus-tmp-number-of-read ?s)
+    (?t gnus-tmp-number-total ?d)
+    (?y gnus-tmp-number-of-unread ?s)
+    (?I (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
+    (?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
+    (?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
+          (gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d)
+    (?g gnus-tmp-group ?s)
+    (?G gnus-tmp-qualified-group ?s)
+    (?c (gnus-short-group-name gnus-tmp-group) ?s)
+    (?D gnus-tmp-newsgroup-description ?s)
+    (?o gnus-tmp-moderated ?c)
+    (?O gnus-tmp-moderated-string ?s)
+    (?p gnus-tmp-process-marked ?c)
+    (?s gnus-tmp-news-server ?s)
+    (?n gnus-tmp-news-method ?s)
+    (?P gnus-group-indentation ?s)
+    (?l gnus-tmp-grouplens ?s)
+    (?z gnus-tmp-news-method-string ?s)
+    (?u gnus-tmp-user-defined ?s)))
+
+(defvar gnus-summary-line-format-alist
+  `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
+    (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
+    (?s gnus-tmp-subject-or-nil ?s)
+    (?n gnus-tmp-name ?s)
+    (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
+       ?s)
+    (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
+           gnus-tmp-from) ?s)
+    (?F gnus-tmp-from ?s)
+    (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
+    (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
+    (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
+    (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
+    (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
+    (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
+    (?L gnus-tmp-lines ?d)
+    (?I gnus-tmp-indentation ?s)
+    (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
+    (?R gnus-tmp-replied ?c)
+    (?\[ gnus-tmp-opening-bracket ?c)
+    (?\] gnus-tmp-closing-bracket ?c)
+    (?\> (make-string gnus-tmp-level ? ) ?s)
+    (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
+    (?i gnus-tmp-score ?d)
+    (?z gnus-tmp-score-char ?c)
+    (?l (bbb-grouplens-score gnus-tmp-header) ?s)
+    (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
+    (?U gnus-tmp-unread ?c)
+    (?t (gnus-summary-number-of-articles-in-thread
+        (and (boundp 'thread) (car thread)) gnus-tmp-level)
+       ?d)
+    (?e (gnus-summary-number-of-articles-in-thread
+        (and (boundp 'thread) (car thread)) gnus-tmp-level t)
+       ?c)
+    (?u gnus-tmp-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).")
 
-(defconst gnus-summary-dummy-line-format-alist
-  (list (list ?S 'subject ?s)
-       (list ?N 'number ?d)
-       (list ?u 'user-defined ?s)))
-
-(defconst gnus-summary-mode-line-format-alist 
-  (list (list ?G 'group-name ?s)
-       (list ?g '(gnus-short-group-name group-name) ?s)
-       (list ?A 'article-number ?d)
-       (list ?Z 'unread-and-unselected ?s)
-       (list ?V 'gnus-version ?s)
-       (list ?U 'unread ?d)
-       (list ?S 'subject ?s)
-       (list ?e 'unselected ?d)
-       (list ?u 'user-defined ?s)
-       (list ?s '(gnus-current-score-file-nondirectory) ?s)))
-
-(defconst gnus-group-mode-line-format-alist 
-  (list (list ?S 'news-server ?s)
-       (list ?M 'news-method ?s)
-       (list ?u 'user-defined ?s)))
+(defvar gnus-summary-dummy-line-format-alist
+  `((?S gnus-tmp-subject ?s)
+    (?N gnus-tmp-number ?d)
+    (?u gnus-tmp-user-defined ?s)))
+
+(defvar gnus-summary-mode-line-format-alist
+  `((?G gnus-tmp-group-name ?s)
+    (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
+    (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
+    (?A gnus-tmp-article-number ?d)
+    (?Z gnus-tmp-unread-and-unselected ?s)
+    (?V gnus-version ?s)
+    (?U gnus-tmp-unread ?d)
+    (?S gnus-tmp-subject ?s)
+    (?e gnus-tmp-unselected ?d)
+    (?u gnus-tmp-user-defined ?s)
+    (?d (length gnus-newsgroup-dormant) ?d)
+    (?t (length gnus-newsgroup-marked) ?d)
+    (?r (length gnus-newsgroup-reads) ?d)
+    (?E gnus-newsgroup-expunged-tally ?d)
+    (?s (gnus-current-score-file-nondirectory) ?s)))
+
+(defvar gnus-article-mode-line-format-alist
+  gnus-summary-mode-line-format-alist)
+
+(defvar gnus-group-mode-line-format-alist
+  `((?S gnus-tmp-news-server ?s)
+    (?M gnus-tmp-news-method ?s)
+    (?u gnus-tmp-user-defined ?s)
+    (?: gnus-tmp-colon ?s)))
 
 (defvar gnus-have-read-active-file nil)
 
@@ -1354,18 +1721,15 @@ variable (string, integer, character, etc).")
   "gnus-bug@ifi.uio.no (The Gnus Bugfixing Girls + Boys)"
   "The mail address of the Gnus maintainers.")
 
-(defconst gnus-version "Gnus v5.0.3"
+(defconst gnus-version "September Gnus v0.90"
   "Version number for this version of Gnus.")
 
 (defvar gnus-info-nodes
-  '((gnus-group-mode           "(gnus)The Group Buffer")
-    (gnus-summary-mode         "(gnus)The Summary Buffer")
-    (gnus-article-mode         "(gnus)The Article Buffer"))
+  '((gnus-group-mode "(gnus)The Group Buffer")
+    (gnus-summary-mode "(gnus)The Summary Buffer")
+    (gnus-article-mode "(gnus)The Article Buffer"))
   "Assoc list of major modes and related Info nodes.")
 
-(defvar gnus-documentation-group-file "~/dgnus/lisp/doc.txt"
-  "The location of the Gnus documentation group.")
-
 (defvar gnus-group-buffer "*Group*")
 (defvar gnus-summary-buffer "*Summary*")
 (defvar gnus-article-buffer "*Article*")
@@ -1373,33 +1737,39 @@ variable (string, integer, character, etc).")
 
 (defvar gnus-work-buffer " *gnus work*")
 
+(defvar gnus-original-article-buffer " *Original Article*")
+(defvar gnus-original-article nil)
+
 (defvar gnus-buffer-list nil
   "Gnus buffers that should be killed on exit.")
 
-(defvar gnus-server-alist nil
-  "List of available servers.")
+(defvar gnus-slave nil
+  "Whether this Gnus is a slave or not.")
 
 (defvar gnus-variable-list
   '(gnus-newsrc-options gnus-newsrc-options-n
-    gnus-newsrc-last-checked-date 
+    gnus-newsrc-last-checked-date
     gnus-newsrc-alist gnus-server-alist
-    gnus-killed-list gnus-zombie-list)
+    gnus-killed-list gnus-zombie-list
+    gnus-topic-topology gnus-topic-alist
+    gnus-format-specs)
   "Gnus variables saved in the quick startup file.")
 
-(defvar gnus-overload-functions
-  '((news-inews gnus-inews-news "rnewspost"))
-  "Functions overloaded by gnus.
-It is a list of `(original overload &optional file)'.")
-
 (defvar gnus-newsrc-options nil
   "Options line in the .newsrc file.")
 
 (defvar gnus-newsrc-options-n nil
-  "List of regexps representing groups to be subscribed/ignored unconditionally.") 
+  "List of regexps representing groups to be subscribed/ignored unconditionally.")
 
 (defvar gnus-newsrc-last-checked-date nil
   "Date Gnus last asked server for new newsgroups.")
 
+(defvar gnus-topic-topology nil
+  "The complete topic hierarchy.")
+
+(defvar gnus-topic-alist nil
+  "The complete topic-group alist.")
+
 (defvar gnus-newsrc-alist nil
   "Assoc list of read articles.
 gnus-newsrc-hashtb should be kept so that both hold the same information.")
@@ -1456,6 +1826,11 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-newsgroup-auto-expire nil)
 (defvar gnus-newsgroup-active nil)
 
+(defvar gnus-newsgroup-data nil)
+(defvar gnus-newsgroup-data-reverse nil)
+(defvar gnus-newsgroup-limit nil)
+(defvar gnus-newsgroup-limits nil)
+
 (defvar gnus-newsgroup-unreads nil
   "List of unread articles in the current newsgroup.")
 
@@ -1465,12 +1840,20 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-newsgroup-reads nil
   "Alist of read articles and article marks in the current newsgroup.")
 
+(defvar gnus-newsgroup-expunged-tally nil)
+
 (defvar gnus-newsgroup-marked nil
   "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 scoring process.")
 
+(defvar gnus-newsgroup-cached nil
+  "List of articles that come from the article cache.")
+
+(defvar gnus-newsgroup-saved nil
+  "List of articles that have been saved.")
+
 (defvar gnus-newsgroup-kill-headers nil)
 
 (defvar gnus-newsgroup-replied nil
@@ -1493,11 +1876,17 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 
 (defvar gnus-newsgroup-headers nil
   "List of article headers in the current newsgroup.")
-(defvar gnus-newsgroup-headers-hashtb-by-number nil)
+
+(defvar gnus-newsgroup-threads nil)
+
+(defvar gnus-newsgroup-prepared nil
+  "Whether the current group has been prepared properly.")
 
 (defvar gnus-newsgroup-ancient nil
   "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
 
+(defvar gnus-newsgroup-sparse nil)
+
 (defvar gnus-current-article nil)
 (defvar gnus-article-current nil)
 (defvar gnus-current-headers nil)
@@ -1509,46 +1898,46 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 ;; Save window configuration.
 (defvar gnus-prev-winconf nil)
 
-;; Format specs
-(defvar gnus-summary-line-format-spec nil)
-(defvar gnus-summary-dummy-line-format-spec nil)
-(defvar gnus-group-line-format-spec nil)
-(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-mark-positions nil)
 (defvar gnus-group-mark-positions nil)
 
-(defvar gnus-summary-expunge-below nil)
 (defvar gnus-reffed-article-number nil)
 
-; Let the byte-compiler know that we know about this variable.
+;;; Let the byte-compiler know that we know about this variable.
 (defvar rmail-default-rmail-file)
 
-(defvar gnus-cache-removeable-articles nil)
+(defvar gnus-cache-removable-articles nil)
+
+(defvar gnus-dead-summary nil)
 
-(defconst gnus-summary-local-variables 
-  '(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 
+(defconst gnus-summary-local-variables
+  '(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
     gnus-newsgroup-unselected gnus-newsgroup-marked
-    gnus-newsgroup-reads
+    gnus-newsgroup-reads gnus-newsgroup-saved
     gnus-newsgroup-replied gnus-newsgroup-expirable
     gnus-newsgroup-processable gnus-newsgroup-killed
     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
-    gnus-newsgroup-headers gnus-newsgroup-headers-hashtb-by-number
+    gnus-newsgroup-headers gnus-newsgroup-threads
+    gnus-newsgroup-prepared gnus-summary-highlight-line-function
     gnus-current-article gnus-current-headers gnus-have-all-headers
     gnus-last-article gnus-article-internal-prepare-hook
     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
     gnus-newsgroup-scored gnus-newsgroup-kill-headers
-    gnus-newsgroup-threads gnus-newsgroup-async
-    gnus-score-alist gnus-current-score-file gnus-summary-expunge-below 
+    gnus-newsgroup-async gnus-thread-expunge-below
+    gnus-score-alist gnus-current-score-file gnus-summary-expunge-below
     gnus-summary-mark-below gnus-newsgroup-active gnus-scores-exclude-files
     gnus-newsgroup-history gnus-newsgroup-ancient
+    gnus-newsgroup-sparse
     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
-    gnus-cache-removeable-articles)
+    gnus-newsgroup-adaptive-score-file
+    (gnus-newsgroup-expunged-tally . 0)
+    gnus-cache-removable-articles gnus-newsgroup-cached
+    gnus-newsgroup-data gnus-newsgroup-data-reverse
+    gnus-newsgroup-limit gnus-newsgroup-limits)
   "Variables that are buffer-local to the summary buffers.")
 
 (defconst gnus-bug-message
@@ -1556,14 +1945,14 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 ========================================
 
 The buffer below is a mail buffer.  When you press `C-c C-c', it will
-be sent to the Gnus Bug Exterminators. 
+be sent to the Gnus Bug Exterminators.
 
 At the bottom of the buffer you'll see lots of variable settings.
 Please do not delete those.  They will tell the Bug People what your
 environment is, so that it will be easier to locate the bugs.
 
 If you have found a bug that makes Emacs go \"beep\", set
-debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET') 
+debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET')
 and include the backtrace in your bug report.
 
 Please describe the bug in annoying, painstaking detail.
@@ -1576,206 +1965,191 @@ Thank you for your help in stamping out bugs.
 ;; Define some autoload functions Gnus might use.
 (eval-and-compile
 
-  ;; Various 
-  (autoload 'metamail-buffer "metamail")
-  (autoload 'Info-goto-node "info")
-  (autoload 'hexl-hex-string-to-integer "hexl")
-  (autoload 'pp "pp")
-  (autoload 'pp-to-string "pp")
-  (autoload 'pp-eval-expression "pp")
-  (autoload 'mail-extract-address-components "mail-extr")
-
-  (autoload 'nnmail-split-fancy "nnmail")
-  (autoload 'nnvirtual-catchup-group "nnvirtual")
-
-  ;; timezone
-  (autoload 'timezone-make-date-arpa-standard "timezone")
-  (autoload 'timezone-fix-time "timezone")
-  (autoload 'timezone-make-sortable-date "timezone")
-  (autoload 'timezone-make-time-string "timezone")
-
-  ;; rmail & friends
-  (autoload 'mail-position-on-field "sendmail")
-  (autoload 'mail-setup "sendmail")
-  (autoload 'rmail-output "rmailout")
-  (autoload 'news-mail-other-window "rnewspost")
-  (autoload 'news-reply-yank-original "rnewspost")
-  (autoload 'news-caesar-buffer-body "rnewspost")
-  (autoload 'rmail-insert-rmail-file-header "rmail")
-  (autoload 'rmail-count-new-messages "rmail")
-  (autoload 'rmail-show-message "rmail")
-
-  ;; gnus-soup
-  ;;(autoload 'gnus-group-brew-soup "gnus-soup" nil t)
-  ;;(autoload 'gnus-brew-soup "gnus-soup" nil t)
-  ;;(autoload 'gnus-soup-add-article "gnus-soup" nil t)
-  ;;(autoload 'gnus-soup-send-replies "gnus-soup" nil t)
-  ;;(autoload 'gnus-soup-save-areas "gnus-soup" nil t)
-  ;;(autoload 'gnus-soup-pack-packet "gnus-soup" nil t)
-  ;;(autoload 'nnsoup-pack-replies "nnsoup" nil t)
-
-  ;; gnus-mh
-  (autoload 'gnus-mail-reply-using-mhe "gnus-mh")
-  (autoload 'gnus-mail-forward-using-mhe "gnus-mh")
-  (autoload 'gnus-mail-other-window-using-mhe "gnus-mh")
-  (autoload 'gnus-summary-save-in-folder "gnus-mh")
-  (autoload 'gnus-summary-save-article-folder "gnus-mh")
-  (autoload 'gnus-Folder-save-name "gnus-mh")
-  (autoload 'gnus-folder-save-name "gnus-mh")
-
-  ;; gnus-vis misc
-  (autoload 'gnus-group-make-menu-bar "gnus-vis")
-  (autoload 'gnus-summary-make-menu-bar "gnus-vis")
-  (autoload 'gnus-server-make-menu-bar "gnus-vis")
-  (autoload 'gnus-article-make-menu-bar "gnus-vis")
-  (autoload 'gnus-browse-make-menu-bar "gnus-vis")
-  (autoload 'gnus-highlight-selected-summary "gnus-vis")
-  (autoload 'gnus-summary-highlight-line "gnus-vis")
-  (autoload 'gnus-carpal-setup-buffer "gnus-vis")
-
-  ;; gnus-vis article
-  (autoload 'gnus-article-push-button "gnus-vis" nil t)
-  (autoload 'gnus-article-press-button "gnus-vis" nil t)
-  (autoload 'gnus-article-highlight "gnus-vis" nil t)
-  (autoload 'gnus-article-highlight-some "gnus-vis" nil t)
-  (autoload 'gnus-article-hide "gnus-vis" nil t)
-  (autoload 'gnus-article-hide-signature "gnus-vis" nil t)
-  (autoload 'gnus-article-highlight-headers "gnus-vis" nil t)
-  (autoload 'gnus-article-highlight-signature "gnus-vis" nil t)
-  (autoload 'gnus-article-add-buttons "gnus-vis" nil t)
-  (autoload 'gnus-article-next-button "gnus-vis" nil t)
-  (autoload 'gnus-article-add-button "gnus-vis")
-
-  ;; gnus-cite
-  (autoload 'gnus-article-highlight-citation "gnus-cite" nil t)
-  (autoload 'gnus-article-hide-citation-maybe "gnus-cite" nil t)
-  (autoload 'gnus-article-hide-citation "gnus-cite" nil t)
-
-  ;; gnus-kill
-  (autoload 'gnus-kill "gnus-kill")
-  (autoload 'gnus-apply-kill-file-internal "gnus-kill")
-  (autoload 'gnus-kill-file-edit-file "gnus-kill")
-  (autoload 'gnus-kill-file-raise-followups-to-author "gnus-kill")
-  (autoload 'gnus-execute "gnus-kill")
-  (autoload 'gnus-expunge "gnus-kill")
-
-  ;; gnus-cache
-  (autoload 'gnus-cache-possibly-enter-article "gnus-cache")
-  (autoload 'gnus-cache-save-buffers "gnus-cache")
-  (autoload 'gnus-cache-possibly-remove-articles "gnus-cache")
-  (autoload 'gnus-cache-request-article "gnus-cache")
-  (autoload 'gnus-cache-retrieve-headers "gnus-cache")
-  (autoload 'gnus-cache-possibly-alter-active "gnus-cache")
-  (autoload 'gnus-jog-cache "gnus-cache" nil t)
-  (autoload 'gnus-cache-enter-remove-article "gnus-cache")
-
-  ;; gnus-score
-  (autoload 'gnus-summary-increase-score "gnus-score" nil t)
-  (autoload 'gnus-summary-lower-score "gnus-score" nil t)
-  (autoload 'gnus-summary-score-map "gnus-score" nil nil 'keymap)
-  (autoload 'gnus-score-save "gnus-score")
-  (autoload 'gnus-score-headers "gnus-score")
-  (autoload 'gnus-current-score-file-nondirectory "gnus-score")
-  (autoload 'gnus-score-adaptive "gnus-score")
-  (autoload 'gnus-score-remove-lines-adaptive "gnus-score")
-  (autoload 'gnus-score-find-trace "gnus-score")
-
-  ;; gnus-edit
-  (autoload 'gnus-score-customize "gnus-edit" nil t)
-
-  ;; gnus-uu
-  (autoload 'gnus-uu-extract-map "gnus-uu" nil nil 'keymap)
-  (autoload 'gnus-uu-mark-map "gnus-uu" nil nil 'keymap)
-  (autoload 'gnus-uu-digest-mail-forward "gnus-uu" nil t)
-  (autoload 'gnus-uu-digest-post-forward "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-series "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-region "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-by-regexp "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-all "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-sparse "gnus-uu" nil t)
-  (autoload 'gnus-uu-mark-thread "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-uu "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-uu-and-save "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-unshar "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-unshar-and-save "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-save "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-binhex "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-uu-view "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-uu-and-save-view "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-unshar-view "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-unshar-and-save-view "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-save-view "gnus-uu" nil t)
-  (autoload 'gnus-uu-decode-binhex-view "gnus-uu" nil t)
-
-  ;; gnus-msg
-  (autoload 'gnus-summary-send-map "gnus-msg" nil nil 'keymap)
-  (autoload 'gnus-group-post-news "gnus-msg" nil t)
-  (autoload 'gnus-group-mail "gnus-msg" nil t)
-  (autoload 'gnus-summary-post-news "gnus-msg" nil t)
-  (autoload 'gnus-summary-followup "gnus-msg" nil t)
-  (autoload 'gnus-summary-followup-with-original "gnus-msg" nil t)
-  (autoload 'gnus-summary-followup-and-reply "gnus-msg" nil t)
-  (autoload 'gnus-summary-followup-and-reply-with-original "gnus-msg" nil t)
-  (autoload 'gnus-summary-cancel-article "gnus-msg" nil t)
-  (autoload 'gnus-summary-supersede-article "gnus-msg" nil t)
-  (autoload 'gnus-post-news "gnus-msg" nil t)
-  (autoload 'gnus-inews-news "gnus-msg" nil t)
-  (autoload 'gnus-cancel-news "gnus-msg" nil t)
-  (autoload 'gnus-summary-reply "gnus-msg" nil t)
-  (autoload 'gnus-summary-reply-with-original "gnus-msg" nil t)
-  (autoload 'gnus-summary-mail-forward "gnus-msg" nil t)
-  (autoload 'gnus-summary-mail-other-window "gnus-msg" nil t)
-  (autoload 'gnus-mail-reply-using-mail "gnus-msg")
-  (autoload 'gnus-mail-yank-original "gnus-msg")
-  (autoload 'gnus-mail-send-and-exit "gnus-msg")
-  (autoload 'gnus-mail-forward-using-mail "gnus-msg")
-  (autoload 'gnus-mail-other-window-using-mail "gnus-msg")
-  (autoload 'gnus-article-mail "gnus-msg")
-  (autoload 'gnus-bug "gnus-msg" nil t)
-
-  ;; gnus-vm
-  (autoload 'gnus-summary-save-in-vm "gnus-vm" nil t)
-  (autoload 'gnus-summary-save-article-vm "gnus-vm" nil t)
-  (autoload 'gnus-mail-forward-using-vm "gnus-vm")
-  (autoload 'gnus-mail-reply-using-vm "gnus-vm")
-  (autoload 'gnus-mail-other-window-using-vm "gnus-vm" nil t)
-  (autoload 'gnus-yank-article "gnus-vm" nil t)
-
-  )
+  ;; This little mapcar goes through the list below and marks the
+  ;; symbols in question as autoloaded functions.
+  (mapcar
+   (lambda (package)
+     (let ((interactive (nth 1 (memq ':interactive package))))
+       (mapcar
+       (lambda (function)
+         (let (keymap)
+           (when (consp function)
+             (setq keymap (car (memq 'keymap function)))
+             (setq function (car function)))
+           (autoload function (car package) nil interactive keymap)))
+       (if (eq (nth 1 package) ':interactive)
+           (cdddr package)
+         (cdr package)))))
+   '(("metamail" metamail-buffer)
+     ("info" Info-goto-node)
+     ("hexl" hexl-hex-string-to-integer)
+     ("pp" pp pp-to-string pp-eval-expression)
+     ("mail-extr" mail-extract-address-components)
+     ("nnmail" nnmail-split-fancy nnmail-article-group)
+     ("nnvirtual" nnvirtual-catchup-group)
+     ("timezone" timezone-make-date-arpa-standard timezone-fix-time
+      timezone-make-sortable-date timezone-make-time-string)
+     ("sendmail" mail-position-on-field mail-setup)
+     ("rmailout" rmail-output)
+     ("rnewspost" news-mail-other-window news-reply-yank-original
+      news-caesar-buffer-body)
+     ("rmail" rmail-insert-rmail-file-header rmail-count-new-messages
+      rmail-show-message)
+     ("gnus-soup" :interactive t
+      gnus-group-brew-soup gnus-brew-soup gnus-soup-add-article
+      gnus-soup-send-replies gnus-soup-save-areas gnus-soup-pack-packet)
+     ("nnsoup" nnsoup-pack-replies)
+     ("gnus-scomo" :interactive t gnus-score-mode)
+     ("gnus-mh" gnus-mh-mail-setup gnus-summary-save-article-folder
+      gnus-Folder-save-name gnus-folder-save-name)
+     ("gnus-mh" :interactive t gnus-summary-save-in-folder)
+     ("gnus-vis" gnus-group-make-menu-bar gnus-summary-make-menu-bar
+      gnus-server-make-menu-bar gnus-article-make-menu-bar
+      gnus-browse-make-menu-bar gnus-highlight-selected-summary
+      gnus-summary-highlight-line gnus-carpal-setup-buffer
+      gnus-group-highlight-line
+      gnus-article-add-button gnus-insert-next-page-button
+      gnus-insert-prev-page-button gnus-visual-turn-off-edit-menu)
+     ("gnus-vis" :interactive t
+      gnus-article-push-button gnus-article-press-button
+      gnus-article-highlight gnus-article-highlight-some
+      gnus-article-highlight-headers gnus-article-highlight-signature
+      gnus-article-add-buttons gnus-article-add-buttons-to-head
+      gnus-article-next-button gnus-article-prev-button)
+     ("gnus-demon" gnus-demon-add-nocem gnus-demon-add-scanmail
+      gnus-demon-add-disconnection gnus-demon-add-handler
+      gnus-demon-remove-handler)
+     ("gnus-demon" :interactive t
+      gnus-demon-init gnus-demon-cancel)
+     ("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
+      gnus-tree-open gnus-tree-close)
+     ("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
+      gnus-nocem-unwanted-article-p)
+     ("gnus-srvr" gnus-enter-server-buffer gnus-server-set-info)
+     ("gnus-srvr" gnus-browse-foreign-server)
+     ("gnus-cite" :interactive t
+      gnus-article-highlight-citation gnus-article-hide-citation-maybe
+      gnus-article-hide-citation gnus-article-fill-cited-article
+      gnus-article-hide-citation-in-followups)
+     ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
+      gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
+      gnus-execute gnus-expunge)
+     ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
+      gnus-cache-possibly-remove-articles gnus-cache-request-article
+      gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
+      gnus-cache-enter-remove-article gnus-cached-article-p
+      gnus-cache-open gnus-cache-close gnus-cache-update-article)
+     ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
+      gnus-cache-remove-article)
+     ("gnus-score" :interactive t
+      gnus-summary-increase-score gnus-summary-lower-score
+      gnus-score-flush-cache gnus-score-close
+      gnus-score-raise-same-subject-and-select
+      gnus-score-raise-same-subject gnus-score-default
+      gnus-score-raise-thread gnus-score-lower-same-subject-and-select
+      gnus-score-lower-same-subject gnus-score-lower-thread
+      gnus-possibly-score-headers)
+     ("gnus-score"
+      (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
+      gnus-current-score-file-nondirectory gnus-score-adaptive
+      gnus-score-find-trace gnus-score-file-name)
+     ("gnus-edit" :interactive t gnus-score-customize)
+     ("gnus-topic" :interactive t gnus-topic-mode)
+     ("gnus-topic" gnus-topic-remove-group)
+     ("gnus-salt" :interactive t gnus-pick-mode gnus-binary-mode)
+     ("gnus-uu" (gnus-uu-extract-map keymap) (gnus-uu-mark-map keymap))
+     ("gnus-uu" :interactive t
+      gnus-uu-digest-mail-forward gnus-uu-digest-post-forward
+      gnus-uu-mark-series gnus-uu-mark-region gnus-uu-mark-buffer
+      gnus-uu-mark-by-regexp gnus-uu-mark-all
+      gnus-uu-mark-sparse gnus-uu-mark-thread gnus-uu-decode-uu
+      gnus-uu-decode-uu-and-save gnus-uu-decode-unshar
+      gnus-uu-decode-unshar-and-save gnus-uu-decode-save
+      gnus-uu-decode-binhex gnus-uu-decode-uu-view
+      gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
+      gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
+      gnus-uu-decode-binhex-view)
+     ("gnus-msg" (gnus-summary-send-map keymap)
+      gnus-mail-yank-original gnus-mail-send-and-exit
+      gnus-sendmail-setup-mail gnus-article-mail
+      gnus-inews-message-id gnus-new-mail gnus-mail-reply)
+     ("gnus-msg" :interactive t
+      gnus-group-post-news gnus-group-mail gnus-summary-post-news
+      gnus-summary-followup gnus-summary-followup-with-original
+      gnus-summary-followup-and-reply
+      gnus-summary-followup-and-reply-with-original
+      gnus-summary-cancel-article gnus-summary-supersede-article
+      gnus-post-news gnus-inews-news gnus-cancel-news
+      gnus-summary-reply gnus-summary-reply-with-original
+      gnus-summary-mail-forward gnus-summary-mail-other-window
+      gnus-bug)
+     ("gnus-picon" :interactive t gnus-article-display-picons
+      gnus-group-display-picons gnus-picons-article-display-x-face)
+     ("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p 
+      gnus-grouplens-mode)
+     ("gnus-vm" gnus-vm-mail-setup)
+     ("gnus-vm" :interactive t gnus-summary-save-in-vm
+      gnus-summary-save-article-vm gnus-yank-article))))
 
 \f
 
 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
 ;; If you want the cursor to go somewhere else, set these two
 ;; functions in some startup hook to whatever you want.
-(defalias 'gnus-summary-position-cursor 'gnus-goto-colon)
-(defalias 'gnus-group-position-cursor 'gnus-goto-colon)
+(defalias 'gnus-summary-position-point 'gnus-goto-colon)
+(defalias 'gnus-group-position-point 'gnus-goto-colon)
 
 ;;; Various macros and substs.
 
+(defun gnus-header-from (header)
+  (mail-header-from header))
+
 (defmacro gnus-eval-in-buffer-window (buffer &rest forms)
-  "Pop to BUFFER, evaluate FORMS, and then returns to original window."
-  (` (let ((GnusStartBufferWindow (selected-window)))
+  "Pop to BUFFER, evaluate FORMS, and then return to the original window."
+  (let ((tempvar (make-symbol "GnusStartBufferWindow"))
+       (w (make-symbol "w"))
+       (buf (make-symbol "buf")))
+    `(let* ((,tempvar (selected-window))
+           (,buf ,buffer)
+           (,w (get-buffer-window ,buf 'visible)))
        (unwind-protect
           (progn
-            (pop-to-buffer (, buffer))
-            (,@ forms))
-        (select-window GnusStartBufferWindow)))))
+            (if ,w
+                (select-window ,w)
+              (pop-to-buffer ,buf))
+            ,@forms)
+        (select-window ,tempvar)))))
 
 (defmacro gnus-gethash (string hashtable)
   "Get hash value of STRING in HASHTABLE."
-  ;;(` (symbol-value (abbrev-symbol (, string) (, hashtable))))
-  ;;(` (abbrev-expansion (, string) (, hashtable)))
-  (` (symbol-value (intern-soft (, string) (, hashtable)))))
+  `(symbol-value (intern-soft ,string ,hashtable)))
 
 (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 hash value.  Arguments are STRING, VALUE, and HASHTABLE."
+  `(set (intern ,string ,hashtable) ,value))
+
+(defmacro gnus-intern-safe (string hashtable)
+  "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
+  `(let ((symbol (intern ,string ,hashtable)))
+     (or (boundp symbol)
+        (set symbol nil))
+     symbol))
 
-(defsubst gnus-buffer-substring (beg end)
-  (buffer-substring (match-beginning beg) (match-end end)))
+(defmacro gnus-group-unread (group)
+  "Get the currently computed number of unread articles in GROUP."
+  `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
+
+(defmacro gnus-group-entry (group)
+  "Get the newsrc entry for GROUP."
+  `(gnus-gethash ,group gnus-newsrc-hashtb))
+
+(defmacro gnus-active (group)
+  "Get active info on GROUP."
+  `(gnus-gethash ,group gnus-active-hashtb))
+
+(defmacro gnus-set-active (group active)
+  "Set GROUP's active info."
+  `(gnus-sethash ,group ,active gnus-active-hashtb))
 
 ;; modified by MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;;   function `substring' might cut on a middle of multi-octet
@@ -1783,8 +2157,8 @@ Thank you for your help in stamping out bugs.
 (defun gnus-truncate-string (str width)
   (substring str 0 width))
 
-;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>. A safe way
-;; to limit the length of a string. This function is necessary since
+;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>.  A safe way
+;; to limit the length of a string.  This function is necessary since
 ;; `(substr "abc" 0 30)' pukes with "Args out of range".
 (defsubst gnus-limit-string (str width)
   (if (> (length str) width)
@@ -1793,25 +2167,31 @@ Thank you for your help in stamping out bugs.
 
 (defsubst gnus-simplify-subject-re (subject)
   "Remove \"Re:\" from subject lines."
-  (let ((case-fold-search t))
-    (if (string-match "^re: *" subject)
-       (substring subject (match-end 0))
-      subject)))
+  (if (string-match "^[Rr][Ee]: *" subject)
+      (substring subject (match-end 0))
+    subject))
+
+(defsubst gnus-functionp (form)
+  "Return non-nil if FORM is funcallable."
+  (or (and (symbolp form) (fboundp form))
+      (and (listp form) (eq (car form) 'lambda))))
 
 (defsubst gnus-goto-char (point)
   (and point (goto-char point)))
 
 (defmacro gnus-buffer-exists-p (buffer)
-  (` (and (, buffer)
-         (funcall (if (stringp (, buffer)) 'get-buffer 'buffer-name)
-                  (, buffer)))))
+  `(let ((buffer ,buffer))
+     (and buffer
+         (funcall (if (stringp buffer) 'get-buffer 'buffer-name)
+                  buffer))))
 
 (defmacro gnus-kill-buffer (buffer)
-  (` (if (gnus-buffer-exists-p (, buffer))
-        (kill-buffer (, buffer)))))
+  `(let ((buf ,buffer))
+     (if (gnus-buffer-exists-p buf)
+        (kill-buffer buf))))
 
 (defsubst gnus-point-at-bol ()
-  "Return point at the beginning of line."
+  "Return point at the beginning of the line."
   (let ((p (point)))
     (beginning-of-line)
     (prog1
@@ -1819,17 +2199,22 @@ Thank you for your help in stamping out bugs.
       (goto-char p))))
 
 (defsubst gnus-point-at-eol ()
-  "Return point at the beginning of line."
+  "Return point at the end of the line."
   (let ((p (point)))
     (end-of-line)
     (prog1
        (point)
       (goto-char p))))
 
+(defun gnus-alive-p ()
+  "Say whether Gnus is running or not."
+  (and gnus-group-buffer
+       (get-buffer gnus-group-buffer)))
+
 ;; Delete the current line (and the next N lines.);
 (defmacro gnus-delete-line (&optional n)
-  (` (delete-region (progn (beginning-of-line) (point))
-                   (progn (forward-line (, (or n 1))) (point)))))
+  `(delete-region (progn (beginning-of-line) (point))
+                 (progn (forward-line ,(or n 1)) (point))))
 
 ;; Suggested by Brian Edmonds <edmonds@cs.ubc.ca>.
 (defvar gnus-init-inhibit nil)
@@ -1838,21 +2223,197 @@ Thank you for your help in stamping out bugs.
       (setq gnus-init-inhibit nil)
     (setq gnus-init-inhibit inhibit-next)
     (and gnus-init-file
-        (or (and (file-exists-p gnus-init-file) 
+        (or (and (file-exists-p gnus-init-file)
                  ;; Don't try to load a directory.
                  (not (file-directory-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))))
-
-;;; Load the user startup file.
-;; (eval '(gnus-read-init-file 'inhibit))
-
-;;; Load the compatability functions. 
+        (condition-case var
+            (load gnus-init-file nil t)
+          (error
+           (error "Error in %s: %s" gnus-init-file var))))))
+
+;; Info access macros.
+
+(defmacro gnus-info-group (info)
+  `(nth 0 ,info))
+(defmacro gnus-info-rank (info)
+  `(nth 1 ,info))
+(defmacro gnus-info-read (info)
+  `(nth 2 ,info))
+(defmacro gnus-info-marks (info)
+  `(nth 3 ,info))
+(defmacro gnus-info-method (info)
+  `(nth 4 ,info))
+(defmacro gnus-info-params (info)
+  `(nth 5 ,info))
+
+(defmacro gnus-info-level (info)
+  `(let ((rank (gnus-info-rank ,info)))
+     (if (consp rank)
+        (car rank)
+       rank)))
+(defmacro gnus-info-score (info)
+  `(let ((rank (gnus-info-rank ,info)))
+     (or (and (consp rank) (cdr rank)) 0)))
+
+(defmacro gnus-info-set-group (info group)
+  `(setcar ,info ,group))
+(defmacro gnus-info-set-rank (info rank)
+  `(setcar (nthcdr 1 ,info) ,rank))
+(defmacro gnus-info-set-read (info read)
+  `(setcar (nthcdr 2 ,info) ,read))
+(defmacro gnus-info-set-marks (info marks)
+  `(setcar (nthcdr 3 ,info) ,marks))
+(defmacro gnus-info-set-method (info method)
+  `(setcar (nthcdr 4 ,info) ,method))
+(defmacro gnus-info-set-params (info params)
+  `(setcar (nthcdr 5 ,info) ,params))
+
+(defmacro gnus-info-set-level (info level)
+  `(let ((rank (cdr ,info)))
+     (if (consp (car rank))
+        (setcar (car rank) ,level)
+       (setcar rank ,level))))
+(defmacro gnus-info-set-score (info score)
+  `(let ((rank (cdr ,info)))
+     (if (consp (car rank))
+        (setcdr (car rank) ,score)
+       (setcar rank (cons (car rank) ,score)))))
+
+(defmacro gnus-get-info (group)
+  `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
+
+(defun gnus-byte-code (func)
+  "Return a form that can be `eval'ed based on FUNC."
+  (let ((fval (symbol-function func)))
+    (if (byte-code-function-p fval)
+       (let ((flist (append fval nil)))
+         (setcar flist 'byte-code)
+         flist)
+      (cons 'progn (cddr fval)))))
+
+;;; Load the compatability functions.
 
 (require 'gnus-cus)
 (require 'gnus-ems)
 
+\f
+;;;
+;;; Shutdown
+;;;
+
+(defvar gnus-shutdown-alist nil)
+
+(defun gnus-add-shutdown (function &rest symbols)
+  "Run FUNCTION whenever one of SYMBOLS is shut down."
+  (push (cons function symbols) gnus-shutdown-alist))
+
+(defun gnus-shutdown (symbol)
+  "Shut down everything that waits for SYMBOL."
+  (let ((alist gnus-shutdown-alist)
+       entry)
+    (while (setq entry (pop alist))
+      (when (memq symbol (cdr entry))
+       (funcall (car entry))))))
+
+\f
+
+;; Format specs.  The chunks below are the machine-generated forms
+;; that are to be evaled as the result of the default format strings.
+;; We write them in here to get them byte-compiled.  That way the
+;; default actions will be quite fast, while still retaining the full
+;; flexibility of the user-defined format specs.
+
+;; First we have lots of dummy defvars to let the compiler know these
+;; are really dynamic variables.
+
+(defvar gnus-tmp-unread)
+(defvar gnus-tmp-replied)
+(defvar gnus-tmp-score-char)
+(defvar gnus-tmp-indentation)
+(defvar gnus-tmp-opening-bracket)
+(defvar gnus-tmp-lines)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-closing-bracket)
+(defvar gnus-tmp-subject-or-nil)
+(defvar gnus-tmp-subject)
+(defvar gnus-tmp-marked)
+(defvar gnus-tmp-marked-mark)
+(defvar gnus-tmp-subscribed)
+(defvar gnus-tmp-process-marked)
+(defvar gnus-tmp-number-of-unread)
+(defvar gnus-tmp-group-name)
+(defvar gnus-tmp-group)
+(defvar gnus-tmp-article-number)
+(defvar gnus-tmp-unread-and-unselected)
+(defvar gnus-tmp-news-method)
+(defvar gnus-tmp-news-server)
+(defvar gnus-tmp-article-number)
+(defvar gnus-mouse-face)
+(defvar gnus-mouse-face-prop)
+
+(defun gnus-summary-line-format-spec ()
+  (insert gnus-tmp-unread gnus-tmp-replied
+         gnus-tmp-score-char gnus-tmp-indentation)
+  (gnus-put-text-property
+   (point)
+   (progn
+     (insert
+      gnus-tmp-opening-bracket
+      (format "%4d: %-20s"
+             gnus-tmp-lines
+             (if (> (length gnus-tmp-name) 20)
+                 (substring gnus-tmp-name 0 20)
+               gnus-tmp-name))
+      gnus-tmp-closing-bracket)
+     (point))
+   gnus-mouse-face-prop gnus-mouse-face)
+  (insert " " gnus-tmp-subject-or-nil "\n"))
+
+(defvar gnus-summary-line-format-spec
+  (gnus-byte-code 'gnus-summary-line-format-spec))
+
+(defun gnus-summary-dummy-line-format-spec ()
+  (insert "*  ")
+  (gnus-put-text-property
+   (point)
+   (progn
+     (insert ":                                 :")
+     (point))
+   gnus-mouse-face-prop gnus-mouse-face)
+  (insert " " gnus-tmp-subject "\n"))
+
+(defvar gnus-summary-dummy-line-format-spec
+  (gnus-byte-code 'gnus-summary-dummy-line-format-spec))
+
+(defun gnus-group-line-format-spec ()
+  (insert gnus-tmp-marked-mark gnus-tmp-subscribed
+         gnus-tmp-process-marked
+         gnus-group-indentation
+         (format "%5s: " gnus-tmp-number-of-unread))
+  (gnus-put-text-property
+   (point)
+   (progn
+     (insert gnus-tmp-group "\n")
+     (1- (point)))
+   gnus-mouse-face-prop gnus-mouse-face))
+(defvar gnus-group-line-format-spec
+  (gnus-byte-code 'gnus-group-line-format-spec))
+
+(defvar gnus-format-specs
+  `((version . ,emacs-version)
+    (group ,gnus-group-line-format ,gnus-group-line-format-spec)
+    (summary-dummy ,gnus-summary-dummy-line-format
+                  ,gnus-summary-dummy-line-format-spec)
+    (summary ,gnus-summary-line-format ,gnus-summary-line-format-spec)))
+
+(defvar gnus-article-mode-line-format-spec nil)
+(defvar gnus-summary-mode-line-format-spec nil)
+(defvar gnus-group-mode-line-format-spec nil)
+
+;;; Phew.  All that gruft is over, fortunately.
+
 \f
 ;;;
 ;;; Gnus Utility Functions
@@ -1867,22 +2428,24 @@ Thank you for your help in stamping out bugs.
        (setq address (substring from (match-beginning 0) (match-end 0))))
     ;; Then we check whether the "name <address>" format is used.
     (and address
-        (string-match (concat "<" (regexp-quote address) ">") from)
-        (and (setq name (substring from 0 (1- (match-beginning 0))))
+        ;; Fix by MORIOKA Tomohiko <morioka@jaist.ac.jp>
+        ;; Linear white space is not required.
+        (string-match (concat "[ \t]*<" (regexp-quote address) ">") from)
+        (and (setq name (substring from 0 (match-beginning 0)))
              ;; Strip any quotes from the name.
              (string-match "\".*\"" name)
              (setq name (substring name 1 (1- (match-end 0))))))
     ;; If not, then "address (name)" is used.
     (or name
        (and (string-match "(.+)" from)
-            (setq name (substring from (1+ (match-beginning 0)) 
+            (setq name (substring from (1+ (match-beginning 0))
                                   (1- (match-end 0)))))
        (and (string-match "()" from)
             (setq name address))
        ;; Fix by MORIOKA Tomohiko <morioka@jaist.ac.jp>.
        ;; XOVER might not support folded From headers.
        (and (string-match "(.*" from)
-            (setq name (substring from (1+ (match-beginning 0)) 
+            (setq name (substring from (1+ (match-beginning 0))
                                   (match-end 0)))))
     ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
     (list (or name from) (or address from))))
@@ -1891,180 +2454,354 @@ Thank you for your help in stamping out bugs.
   "Return the value of the header FIELD of current article."
   (save-excursion
     (save-restriction
-      (let ((case-fold-search t))
-       (gnus-narrow-to-headers)
-       (mail-fetch-field field)))))
+      (let ((case-fold-search t)
+           (inhibit-point-motion-hooks t))
+       (nnheader-narrow-to-headers)
+       (message-fetch-field field)))))
 
 (defun gnus-goto-colon ()
   (beginning-of-line)
   (search-forward ":" (gnus-point-at-eol) t))
 
-(defun gnus-narrow-to-headers ()
-  (widen)
-  (save-excursion
-    (narrow-to-region
-     (goto-char (point-min))
-     (if (search-forward "\n\n" nil t)
-        (1- (point))
-       (point-max)))))
-
-(defvar gnus-old-specs nil)
+;;;###autoload
+(defun gnus-update-format (var)
+  "Update the format specification near point."
+  (interactive
+   (list
+    (save-excursion
+      (eval-defun nil)
+      ;; Find the end of the current word.
+      (re-search-forward "[ \t\n]" nil t)
+      ;; Search backward.
+      (when (re-search-backward "\\(gnus-[-a-z]+-line-format\\)" nil t)
+       (match-string 1)))))
+  (let* ((type (intern (progn (string-match "gnus-\\([-a-z]+\\)-line" var)
+                             (match-string 1 var))))
+        (entry (assq type gnus-format-specs))
+        value spec)
+    (when entry
+      (setq gnus-format-specs (delq entry gnus-format-specs)))
+    (set
+     (intern (format "%s-spec" var))
+     (gnus-parse-format (setq value (symbol-value (intern var)))
+                       (symbol-value (intern (format "%s-alist" var)))
+                       (not (string-match "mode" var))))
+    (setq spec (symbol-value (intern (format "%s-spec" var))))
+    (push (list type value spec) gnus-format-specs)
+
+    (pop-to-buffer "*Gnus Format*")
+    (erase-buffer)
+    (lisp-interaction-mode)
+    (insert (pp-to-string spec))))
 
-(defun gnus-update-format-specifications ()
+(defun gnus-update-format-specifications (&optional force)
+  "Update all (necessary) format specifications."
+  ;; Make the indentation array.
   (gnus-make-thread-indent-array)
 
-  (let ((formats '(summary summary-dummy group 
-                          summary-mode group-mode article-mode))
-       old-format new-format)
-    (while formats
-      (setq new-format (symbol-value
-                       (intern (format "gnus-%s-line-format" (car formats)))))
-      (or (and (setq old-format (cdr (assq (car formats) gnus-old-specs)))
-              (equal old-format new-format))
-         (set (intern (format "gnus-%s-line-format-spec" (car formats)))
-              (gnus-parse-format
-               new-format
-               (symbol-value 
-                (intern (format "gnus-%s-line-format-alist"
-                                (if (eq (car formats) 'article-mode)
-                                    'summary-mode (car formats))))))))
-      (setq gnus-old-specs (cons (cons (car formats) new-format)
-                                (delq (car formats) gnus-old-specs)))
-      (setq formats (cdr formats))))
-      
-  (gnus-update-group-mark-positions)
-  (gnus-update-summary-mark-positions)
+  ;; See whether all the stored info needs to be flushed.
+  (when (or force
+           (not (equal emacs-version
+                       (cdr (assq 'version gnus-format-specs)))))
+    (setq gnus-format-specs nil))
+
+  ;; Go through all the formats and see whether they need updating.
+  (let ((types '(summary summary-dummy group
+                        summary-mode group-mode article-mode))
+       new-format entry type val)
+    (while (setq type (pop types))
+      ;; Jump to the proper buffer to find out the value of
+      ;; the variable, if possible.  (It may be buffer-local.)
+      (save-excursion
+       (let ((buffer (intern (format "gnus-%s-buffer" type)))
+             val)
+         (when (and (boundp buffer)
+                    (setq val (symbol-value buffer))
+                    (get-buffer val)
+                    (buffer-name (get-buffer val)))
+           (set-buffer (get-buffer val)))
+         (setq new-format (symbol-value
+                           (intern (format "gnus-%s-line-format" type))))))
+      (setq entry (cdr (assq type gnus-format-specs)))
+      (if (and entry
+              (equal (car entry) new-format))
+         ;; Use the old format.
+         (set (intern (format "gnus-%s-line-format-spec" type))
+              (cadr entry))
+       ;; This is a new format.
+       (setq val
+             (if (not (stringp new-format))
+                 ;; This is a function call or something.
+                 new-format
+               ;; This is a "real" format.
+               (gnus-parse-format
+                new-format
+                (symbol-value
+                 (intern (format "gnus-%s-line-format-alist"
+                                 (if (eq type 'article-mode)
+                                     'summary-mode type))))
+                (not (string-match "mode$" (symbol-name type))))))
+       ;; Enter the new format spec into the list.
+       (if entry
+           (progn
+             (setcar (cdr entry) val)
+             (setcar entry new-format))
+         (push (list type new-format val) gnus-format-specs))
+       (set (intern (format "gnus-%s-line-format-spec" type)) val))))
+
+  (unless (assq 'version gnus-format-specs)
+    (push (cons 'version emacs-version) gnus-format-specs))
 
-  (if (and (string-match "%D" gnus-group-line-format)
-          (not gnus-description-hashtb)
-          gnus-read-active-file)
-      (gnus-read-all-descriptions-files)))
+  (gnus-update-group-mark-positions)
+  (gnus-update-summary-mark-positions))
 
 (defun gnus-update-summary-mark-positions ()
+  "Compute where the summary marks are to go."
   (save-excursion
+    (when (and gnus-summary-buffer
+              (get-buffer gnus-summary-buffer)
+              (buffer-name (get-buffer gnus-summary-buffer)))
+      (set-buffer gnus-summary-buffer))
     (let ((gnus-replied-mark 129)
          (gnus-score-below-mark 130)
          (gnus-score-over-mark 130)
          (thread nil)
+         (gnus-visual nil)
+         (spec gnus-summary-line-format-spec)
          pos)
-      (gnus-set-work-buffer)
-      (gnus-summary-insert-line 
-       nil [0 "" "" "" "" "" 0 0 ""]  0 nil 128 t nil "" nil 1)
-      (goto-char (point-min))
-      (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
-                                        (- (point) 2)))))
-      (goto-char (point-min))
-      (setq pos (cons (cons 'replied (and (search-forward "\201" nil t)
-                                         (- (point) 2))) pos))
-      (goto-char (point-min))
-      (setq pos (cons (cons 'score (and (search-forward "\202" nil t)
-                                       (- (point) 2))) pos))
+      (save-excursion
+       (gnus-set-work-buffer)
+       (let ((gnus-summary-line-format-spec spec))
+         (gnus-summary-insert-line
+          [0 "" "" "" "" "" 0 0 ""]  0 nil 128 t nil "" nil 1)
+         (goto-char (point-min))
+         (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
+                                            (- (point) 2)))))
+         (goto-char (point-min))
+         (push (cons 'replied (and (search-forward "\201" nil t) 
+                                   (- (point) 2)))
+               pos)
+         (goto-char (point-min))
+         (push (cons 'score (and (search-forward "\202" nil t) (- (point) 2)))
+               pos)))
       (setq gnus-summary-mark-positions pos))))
 
 (defun gnus-update-group-mark-positions ()
   (save-excursion
     (let ((gnus-process-mark 128)
-         (gnus-group-marked '("dummy.group")))
-      (gnus-sethash "dummy.group" '(0 . 0) gnus-active-hashtb)
+         (gnus-group-marked '("dummy.group"))
+         (gnus-active-hashtb (make-vector 10 0)))
+      (gnus-set-active "dummy.group" '(0 . 0))
       (gnus-set-work-buffer)
-      (gnus-group-insert-group-line nil "dummy.group" 0 nil 0 nil)
+      (gnus-group-insert-group-line "dummy.group" 0 nil 0 nil)
       (goto-char (point-min))
       (setq gnus-group-mark-positions
            (list (cons 'process (and (search-forward "\200" nil t)
                                      (- (point) 2))))))))
 
-(defun gnus-mouse-face-function (form)
-  (` (let ((string (, form)))
-       (put-text-property 0 (length string) 'mouse-face gnus-mouse-face string)
-       string)))
+(defvar gnus-mouse-face-0 'highlight)
+(defvar gnus-mouse-face-1 'highlight)
+(defvar gnus-mouse-face-2 'highlight)
+(defvar gnus-mouse-face-3 'highlight)
+(defvar gnus-mouse-face-4 'highlight)
+
+(defun gnus-mouse-face-function (form type)
+  `(gnus-put-text-property
+    (point) (progn ,@form (point))
+    gnus-mouse-face-prop
+    ,(if (equal type 0)
+        'gnus-mouse-face
+       `(quote ,(symbol-value (intern (format "gnus-mouse-face-%d" type)))))))
+
+(defvar gnus-face-0 'bold)
+(defvar gnus-face-1 'italic)
+(defvar gnus-face-2 'bold-italic)
+(defvar gnus-face-3 'bold)
+(defvar gnus-face-4 'bold)
+
+(defun gnus-face-face-function (form type)
+  `(gnus-put-text-property
+    (point) (progn ,@form (point))
+    'face ',(symbol-value (intern (format "gnus-face-%d" type)))))
 
 (defun gnus-max-width-function (el max-width)
   (or (numberp max-width) (signal 'wrong-type-argument '(numberp max-width)))
-  (` (let* ((val (eval (, el)))
-           (valstr (if (numberp val)
-                       (int-to-string val) val)))
-       (if (> (length valstr) (, max-width))
-          (substring valstr 0 (, max-width))
-        valstr))))
-
-(defun gnus-parse-format (format spec-alist)
+  (if (symbolp el)
+      `(if (> (length ,el) ,max-width)
+          (substring ,el 0 ,max-width)
+        ,el)
+    `(let ((val (eval ,el)))
+       (if (numberp val)
+          (setq val (int-to-string val)))
+       (if (> (length val) ,max-width)
+          (substring val 0 ,max-width)
+        val))))
+
+(defun gnus-parse-format (format spec-alist &optional insert)
   ;; 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)
-                 (gnus-mouse-face-function 
-                  (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)
+  (if (string-match
+       "\\`\\(.*\\)%[0-9]?[{(]\\(.*\\)%[0-9]?[})]\\(.*\n?\\)\\'"
+       format)
+      (gnus-parse-complex-format format spec-alist)
+    ;; This is a simple format.
+    (gnus-parse-simple-format format spec-alist insert)))
+
+(defun gnus-parse-complex-format (format spec-alist)
+  (save-excursion
+    (gnus-set-work-buffer)
+    (insert format)
+    (goto-char (point-min))
+    (while (re-search-forward "\"" nil t)
+      (replace-match "\\\"" nil t))
+    (goto-char (point-min))
+    (insert "(\"")
+    (while (re-search-forward "%\\([0-9]+\\)?\\([{}()]\\)" nil t)
+      (let ((number (if (match-beginning 1)
+                       (match-string 1) "0"))
+           (delim (aref (match-string 2) 0)))
+       (if (or (= delim ?\() (= delim ?\{))
+           (replace-match (concat "\"(" (if (= delim ?\() "mouse" "face")
+                                  " " number " \""))
+         (replace-match "\")\""))))
+    (goto-char (point-max))
+    (insert "\")")
+    (goto-char (point-min))
+    (let ((form (read (current-buffer))))
+      (cons 'progn (gnus-complex-form-to-spec form spec-alist)))))
+
+(defun gnus-complex-form-to-spec (form spec-alist)
+  (delq nil
+       (mapcar
+        (lambda (sform)
+          (if (stringp sform)
+              (gnus-parse-simple-format sform spec-alist t)
+            (funcall (intern (format "gnus-%s-face-function" (car sform)))
+                     (gnus-complex-form-to-spec (cddr sform) spec-alist)
+                     (nth 1 sform))))
+        form)))
+
+(defun gnus-parse-simple-format (format spec-alist &optional insert)
   ;; 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.
+  ;; SPEC-ALIST and returns a list that can be eval'ed to return a
+  ;; string.
   (let ((max-width 0)
-       spec flist fstring newspec elem beg)
+       spec flist fstring newspec elem beg result dontinsert)
     (save-excursion
       (gnus-set-work-buffer)
       (insert format)
       (goto-char (point-min))
-      (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
-       ;; "%12,12A", ie. with a "max width specification". These have
-       ;; to be treated specially.
-       (if (setq beg (match-beginning 1))
-           (setq max-width 
-                 (string-to-int 
-                  (buffer-substring (1+ (match-beginning 1)) (match-end 1))))
-         (setq max-width 0)
-         (setq beg (match-beginning 2)))
-       ;; Find the specification from `spec-alist'.
-       (if (not (setq elem (cdr (assq spec spec-alist))))
+      (while (re-search-forward "%[-0-9]*\\(,[0-9]+\\)?\\([^0-9]\\)\\(.\\)?"
+                               nil t)
+       (if (= (setq spec (string-to-char (match-string 2))) ?%)
+             (setq newspec "%"
+                   beg (1+ (match-beginning 0)))
+         ;; First check if there are any specs that look anything like
+         ;; "%12,12A", ie. with a "max width specification".  These have
+         ;; to be treated specially.
+         (if (setq beg (match-beginning 1))
+             (setq max-width
+                   (string-to-int
+                    (buffer-substring
+                     (1+ (match-beginning 1)) (match-end 1))))
+           (setq max-width 0)
+           (setq beg (match-beginning 2)))
+         ;; Find the specification from `spec-alist'.
+         (unless (setq elem (cdr (assq spec spec-alist)))
            (setq elem '("*" ?s)))
-       ;; 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))
-           (let ((el (car elem)))
-             (cond ((= (car (cdr elem)) ?c) 
-                    (setq el (list 'char-to-string el)))
-                   ((= (car (cdr elem)) ?d)
-                    (numberp el) (setq el (list 'int-to-string el))))
-             (setq flist (cons (gnus-max-width-function el max-width)
-                               flist))
-             (setq newspec ?s))
-         (setq flist (cons (car elem) flist))
-         (setq newspec (car (cdr elem))))
+         ;; Treat user defined format specifiers specially.
+         (when (eq (car elem) 'gnus-tmp-user-defined)
+           (setq elem
+                 (list
+                  (list (intern (concat "gnus-user-format-function-"
+                                        (match-string 3)))
+                        'gnus-tmp-header) ?s))
+           (delete-region (match-beginning 3) (match-end 3)))
+         (if (not (zerop max-width))
+             (let ((el (car elem)))
+               (cond ((= (cadr elem) ?c)
+                      (setq el (list 'char-to-string el)))
+                     ((= (cadr elem) ?d)
+                      (setq el (list 'int-to-string el))))
+               (setq flist (cons (gnus-max-width-function el max-width)
+                                 flist))
+               (setq newspec ?s))
+           (progn
+             (setq flist (cons (car elem) flist))
+             (setq newspec (cadr elem)))))
        ;; Remove the old specification (and possibly a ",12" string).
        (delete-region beg (match-end 2))
        ;; Insert the new specification.
        (goto-char beg)
        (insert newspec))
       (setq fstring (buffer-substring 1 (point-max))))
-    (cons 'format (cons fstring (nreverse flist)))))
+    ;; Do some postprocessing to increase efficiency.
+    (setq
+     result
+     (cond
+      ;; Emptyness.
+      ((string= fstring "")
+       nil)
+      ;; Not a format string.
+      ((not (string-match "%" fstring))
+       (list fstring))
+      ;; A format string with just a single string spec.
+      ((string= fstring "%s")
+       (list (car flist)))
+      ;; A single character.
+      ((string= fstring "%c")
+       (list (car flist)))
+      ;; A single number.
+      ((string= fstring "%d")
+       (setq dontinsert)
+       (if insert
+          (list `(princ ,(car flist)))
+        (list `(int-to-string ,(car flist)))))
+      ;; Just lots of chars and strings.
+      ((string-match "\\`\\(%[cs]\\)+\\'" fstring)
+       (nreverse flist))
+      ;; A single string spec at the beginning of the spec.
+      ((string-match "\\`%[sc][^%]+\\'" fstring)
+       (list (car flist) (substring fstring 2)))
+      ;; A single string spec in the middle of the spec.
+      ((string-match "\\`\\([^%]+\\)%[sc]\\([^%]+\\)\\'" fstring)
+       (list (match-string 1 fstring) (car flist) (match-string 2 fstring)))
+      ;; A single string spec in the end of the spec.
+      ((string-match "\\`\\([^%]+\\)%[sc]\\'" fstring)
+       (list (match-string 1 fstring) (car flist)))
+      ;; A more complex spec.
+      (t
+       (list (cons 'format (cons fstring (nreverse flist)))))))
+
+    (if insert
+       (when result
+         (if dontinsert
+             result
+           (cons 'insert result)))
+      (cond ((stringp result)
+            result)
+           ((consp result)
+            (cons 'concat result))
+           (t "")))))
+
+(defun gnus-eval-format (format &optional alist props)
+  "Eval the format variable FORMAT, using ALIST.
+If PROPS, insert the result."
+  (let ((form (gnus-parse-format format alist props)))
+    (if props
+       (gnus-add-text-properties (point) (progn (eval form) (point)) props)
+      (eval form))))
+
+(defun gnus-remove-text-with-property (prop)
+  "Delete all text in the current buffer with text property PROP."
+  (save-excursion
+    (goto-char (point-min))
+    (while (not (eobp))
+      (while (get-text-property (point) prop)
+       (delete-char 1))
+      (goto-char (next-single-property-change (point) prop nil (point-max))))))
 
 (defun gnus-set-work-buffer ()
   (if (get-buffer gnus-work-buffer)
@@ -2088,7 +2825,7 @@ Otherwise, it is like ~/News/news/group/num."
                       (gnus-capitalize-newsgroup newsgroup)
                     (gnus-newsgroup-directory-form newsgroup))
                   "/" (int-to-string (mail-header-number headers)))
-          (or gnus-article-save-directory "~/News"))))
+          gnus-article-save-directory)))
     (if (and last-file
             (string-equal (file-name-directory default)
                           (file-name-directory last-file))
@@ -2099,14 +2836,14 @@ Otherwise, it is like ~/News/news/group/num."
 (defun gnus-numeric-save-name (newsgroup headers &optional last-file)
   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
 If variable `gnus-use-long-file-name' is non-nil, it is
-~/News/news.group/num.  Otherwise, it is like ~/News/news/group/num."
+~/News/news.group/num. Otherwise, it is like ~/News/news/group/num."
   (let ((default
          (expand-file-name
           (concat (if (gnus-use-long-file-name 'not-save)
                       newsgroup
                     (gnus-newsgroup-directory-form newsgroup))
                   "/" (int-to-string (mail-header-number headers)))
-          (or gnus-article-save-directory "~/News"))))
+          gnus-article-save-directory)))
     (if (and last-file
             (string-equal (file-name-directory default)
                           (file-name-directory last-file))
@@ -2123,7 +2860,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        (if (gnus-use-long-file-name 'not-save)
           (gnus-capitalize-newsgroup newsgroup)
         (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
-       (or gnus-article-save-directory "~/News"))))
+       gnus-article-save-directory)))
 
 (defun gnus-plain-save-name (newsgroup headers &optional last-file)
   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
@@ -2134,7 +2871,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        (if (gnus-use-long-file-name 'not-save)
           newsgroup
         (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
-       (or gnus-article-save-directory "~/News"))))
+       gnus-article-save-directory)))
 
 ;; For subscribing new newsgroup
 
@@ -2150,26 +2887,26 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        (setq start (1- (length prefix)))
        (if (and (string-match "[^\\.]\\." (car groups) start)
                 (cdr groups)
-                (setq prefix 
+                (setq prefix
                       (concat "^" (substring (car groups) 0 (match-end 0))))
-                (string-match prefix (car (cdr groups))))
+                (string-match prefix (cadr 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)
-                    (while (and groups 
-                                (string-match prefix 
+                    (while (and groups
+                                (string-match prefix
                                               (setq group (car groups))))
-                      (setq gnus-killed-list 
+                      (setq gnus-killed-list
                             (cons group gnus-killed-list))
                       (gnus-sethash group group gnus-killed-hashtb)
                       (setq groups (cdr groups)))
                     (setq starts (cdr starts)))
                    ((= ans ?s)
-                    (while (and groups 
-                                (string-match prefix 
+                    (while (and groups
+                                (string-match prefix
                                               (setq group (car groups))))
                       (gnus-sethash group group gnus-killed-hashtb)
                       (gnus-subscribe-alphabetically (car groups))
@@ -2194,7 +2931,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
                   (setq gnus-killed-list (cons group gnus-killed-list))
                   (gnus-sethash group group gnus-killed-hashtb)
                   (setq groups (cdr groups))))
-               (t 
+               (t
                 (setq gnus-killed-list (cons group gnus-killed-list))
                 (gnus-sethash group group gnus-killed-hashtb)))
          (setq groups (cdr groups)))))))
@@ -2205,12 +2942,11 @@ If variable `gnus-use-long-file-name' is non-nil, it is
 
 (defun gnus-subscribe-alphabetically (newgroup)
   "Subscribe new NEWSGROUP and insert it in alphabetical order."
-  ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
   (let ((groups (cdr gnus-newsrc-alist))
        before)
     (while (and (not before) groups)
-      (if (string< newgroup (car (car groups)))
-         (setq before (car (car groups)))
+      (if (string< newgroup (caar groups))
+         (setq before (caar groups))
        (setq groups (cdr groups))))
     (gnus-subscribe-newsgroup newgroup before)))
 
@@ -2227,8 +2963,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
               (concat "^\\(" (regexp-quote groupkey) ".*\\)[!:]")))
          (while (and (re-search-forward groupkey-re nil t)
                      (progn
-                       (setq before (buffer-substring
-                                     (match-beginning 1) (match-end 1)))
+                       (setq before (match-string 1))
                        (string< before newgroup)))))
        ;; Remove tail of newsgroup name (eg. a.b.c -> a.b)
        (setq groupkey
@@ -2236,24 +2971,28 @@ If variable `gnus-use-long-file-name' is non-nil, it is
                  (substring groupkey (match-beginning 1) (match-end 1)))))
       (gnus-subscribe-newsgroup newgroup before))))
 
-(defun gnus-subscribe-interactively (newsgroup)
-  "Subscribe new NEWSGROUP interactively.
-It is inserted in hierarchical newsgroup order if subscribed. If not,
+(defun gnus-subscribe-interactively (group)
+  "Subscribe the new GROUP interactively.
+It is inserted in hierarchical newsgroup order if subscribed.  If not,
 it is killed."
-  (if (gnus-y-or-n-p (format "Subscribe new newsgroup: %s " newsgroup))
-      (gnus-subscribe-hierarchically newsgroup)
-    (setq gnus-killed-list (cons newsgroup gnus-killed-list))))
+  (if (gnus-y-or-n-p (format "Subscribe new newsgroup: %s " group))
+      (gnus-subscribe-hierarchically group)
+    (push group gnus-killed-list)))
 
-(defun gnus-subscribe-zombies (newsgroup)
-  "Make new NEWSGROUP a zombie group."
-  (setq gnus-zombie-list (cons newsgroup gnus-zombie-list)))
+(defun gnus-subscribe-zombies (group)
+  "Make the new GROUP into a zombie group."
+  (push group gnus-zombie-list))
+
+(defun gnus-subscribe-killed (group)
+  "Make the new GROUP a killed group."
+  (push group gnus-killed-list))
 
 (defun gnus-subscribe-newsgroup (newsgroup &optional next)
   "Subscribe new NEWSGROUP.
-If NEXT is non-nil, it is inserted before NEXT. Otherwise it is made
+If NEXT is non-nil, it is inserted before NEXT.         Otherwise it is made
 the first newsgroup."
   ;; We subscribe the group by changing its level to `subscribed'.
-  (gnus-group-change-level 
+  (gnus-group-change-level
    newsgroup gnus-level-default-subscribed
    gnus-level-killed (gnus-gethash (or next "dummy.group") gnus-newsrc-hashtb))
   (gnus-message 5 "Subscribe newsgroup: %s" newsgroup))
@@ -2262,11 +3001,11 @@ the first newsgroup."
 
 (defun gnus-newsgroup-directory-form (newsgroup)
   "Make hierarchical directory name from NEWSGROUP name."
-  (let ((newsgroup (gnus-newsgroup-saveable-name newsgroup))
+  (let ((newsgroup (gnus-newsgroup-savable-name newsgroup))
        (len (length newsgroup))
        idx)
     ;; If this is a foreign group, we don't want to translate the
-    ;; entire name.  
+    ;; entire name.
     (if (setq idx (string-match ":" newsgroup))
        (aset newsgroup idx ?/)
       (setq idx 0))
@@ -2277,14 +3016,14 @@ the first newsgroup."
       (setq idx (1+ idx)))
     newsgroup))
 
-(defun gnus-newsgroup-saveable-name (group)
+(defun gnus-newsgroup-savable-name (group)
   ;; Replace any slashes in a group name (eg. an ange-ftp nndoc group)
   ;; with dots.
-  (gnus-replace-chars-in-string group ?/ ?.))
+  (nnheader-replace-chars-in-string group ?/ ?.))
 
 (defun gnus-make-directory (dir)
   "Make DIRECTORY recursively."
-  ;; Why don't we use `(make-directory dir 'parents)'? That's just one
+  ;; Why don't we use `(make-directory dir 'parents)'?  That's just one
   ;; of the many mysteries of the universe.
   (let* ((dir (expand-file-name dir default-directory))
         dirs err)
@@ -2301,7 +3040,7 @@ the first newsgroup."
          (make-directory (car dirs))
        (error (setq err t)))
       (setq dirs (cdr dirs)))
-    ;; We return whether we were successful or not. 
+    ;; We return whether we were successful or not.
     (not dirs)))
 
 (defun gnus-capitalize-newsgroup (newsgroup)
@@ -2310,55 +3049,85 @@ the first newsgroup."
        (concat (char-to-string (upcase (aref newsgroup 0)))
               (substring newsgroup 1))))
 
-;; Var
+;; Various... things.
 
 (defun gnus-simplify-subject (subject &optional re-only)
   "Remove `Re:' and words in parentheses.
-If optional argument RE-ONLY is non-nil, strip `Re:' only."
+If RE-ONLY is non-nil, strip leading `Re:'s only."
   (let ((case-fold-search t))          ;Ignore case.
-    ;; Remove `Re:' and `Re^N:'.
-    (if (string-match "^re:[ \t]*" subject)
+    ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
+    (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
+      (setq subject (substring subject (match-end 0))))
+    ;; Remove uninteresting prefixes.
+    (if (and (not re-only)
+            gnus-simplify-ignored-prefixes
+            (string-match gnus-simplify-ignored-prefixes subject))
        (setq subject (substring subject (match-end 0))))
     ;; Remove words in parentheses from end.
-    (or re-only
-       (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
-         (setq subject (substring subject 0 (match-beginning 0)))))
+    (unless re-only
+      (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
+       (setq subject (substring subject 0 (match-beginning 0)))))
     ;; Return subject string.
     subject))
 
 ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
 ;; all whitespace.
-(defun gnus-simplify-subject-fuzzy (subject)
-  (let ((case-fold-search t))
-    (save-excursion
-      (gnus-set-work-buffer)
-      (insert subject)
-      (inline (gnus-simplify-buffer-fuzzy))
-      (buffer-string))))
-
+;; Written by Stainless Steel Rat <ratinox@ccs.neu.edu>.
 (defun gnus-simplify-buffer-fuzzy ()
   (goto-char (point-min))
-  ;; Fix by Stainless Steel Rat <ratinox@ccs.neu.edu>.
-  (while (re-search-forward "^[ \t]*\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;][ \t]*"
-                           nil t)
-    (replace-match "" t t))
+  (while (search-forward "\t" nil t)
+    (replace-match " " t t))
+  (goto-char (point-min))
+  (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *" nil t)
+  (goto-char (match-beginning 0))
+  (while (or
+         (looking-at "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
+         (looking-at "^[[].*: .*[]]$"))
+    (goto-char (point-min))
+    (while (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *"
+                             nil t)
+      (replace-match "" t t))
+    (goto-char (point-min))
+    (while (re-search-forward "^[[].*: .*[]]$" nil t)
+      (goto-char (match-end 0))
+      (delete-char -1)
+      (delete-region
+       (progn (goto-char (match-beginning 0)))
+       (re-search-forward ":"))))
   (goto-char (point-min))
-  (while (re-search-forward "[ \t\n]*([^()]*)[ \t\n]*$" nil t)
+  (while (re-search-forward " *[[{(][^()\n]*[]})] *$" nil t)
     (replace-match "" t t))
   (goto-char (point-min))
-  (while (re-search-forward "[ \t]+" nil t)
+  (while (re-search-forward "  +" nil t)
     (replace-match " " t t))
   (goto-char (point-min))
-  (while (re-search-forward "[ \t]+$" nil t)
+  (while (re-search-forward " $" nil t)
     (replace-match "" t t))
   (goto-char (point-min))
-  (while (re-search-forward "^[ \t]+" nil t)
+  (while (re-search-forward "^ +" nil t)
     (replace-match "" t t))
-  (if gnus-simplify-subject-fuzzy-regexp
+  (goto-char (point-min))
+  (when gnus-simplify-subject-fuzzy-regexp
+    (if (listp gnus-simplify-subject-fuzzy-regexp)
+       (let ((list gnus-simplify-subject-fuzzy-regexp))
+         (while list
+           (goto-char (point-min))
+           (while (re-search-forward (car list) nil t)
+             (replace-match "" t t))
+           (setq list (cdr list))))
       (while (re-search-forward gnus-simplify-subject-fuzzy-regexp nil t)
-       (replace-match "" t t))))
+       (replace-match "" t t)))))
+
+(defun gnus-simplify-subject-fuzzy (subject)
+  "Siplify a subject string fuzzily."
+  (save-excursion
+    (gnus-set-work-buffer)
+    (let ((case-fold-search t))
+      (insert subject)
+      (inline (gnus-simplify-buffer-fuzzy))
+      (buffer-string))))
 
-;; Add the current buffer to the list of buffers to be killed on exit. 
+;; Add the current buffer to the list of buffers to be killed on exit.
 (defun gnus-add-current-to-buffer-list ()
   (or (memq (current-buffer) gnus-buffer-list)
       (setq gnus-buffer-list (cons (current-buffer) gnus-buffer-list))))
@@ -2367,38 +3136,9 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
   (not (or (string< s1 s2)
           (string= s1 s2))))
 
-;; Functions accessing headers.
-;; Functions are more convenient than macros in some cases.
-
-(defun gnus-header-number (header)
-  (mail-header-number header))
-
-(defun gnus-header-subject (header)
-  (mail-header-subject header))
-
-(defun gnus-header-from (header)
-  (mail-header-from header))
-
-(defun gnus-header-xref (header)
-  (mail-header-xref header))
-
-(defun gnus-header-lines (header)
-  (mail-header-lines header))
-
-(defun gnus-header-date (header)
-  (mail-header-date header))
-
-(defun gnus-header-id (header)
-  (mail-header-id header))
-
-(defun gnus-header-message-id (header)
-  (mail-header-id header))
-
-(defun gnus-header-chars (header)
-  (mail-header-chars header))
-
-(defun gnus-header-references (header)
-  (mail-header-references header))
+(defun gnus-read-active-file-p ()
+  "Say whether the active file has been read from `gnus-select-method'."
+  (memq gnus-select-method gnus-have-read-active-file))
 
 ;;; General various misc type functions.
 
@@ -2420,52 +3160,56 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
        gnus-active-hashtb nil
        gnus-moderated-list nil
        gnus-description-hashtb nil
+       gnus-current-headers nil
+       gnus-thread-indent-array nil
        gnus-newsgroup-headers nil
-       gnus-newsgroup-headers-hashtb-by-number nil
        gnus-newsgroup-name nil
        gnus-server-alist nil
+       gnus-group-list-mode nil
+       gnus-opened-servers nil
        gnus-current-select-method nil)
-  ;; Reset any score variables.
-  (and (boundp 'gnus-score-cache)
-       (set 'gnus-score-cache nil))
-  (and (boundp 'gnus-internal-global-score-files)
-       (set 'gnus-internal-global-score-files nil))
+  (gnus-shutdown 'gnus)
   ;; Kill the startup file.
   (and gnus-current-startup-file
        (get-file-buffer gnus-current-startup-file)
        (kill-buffer (get-file-buffer gnus-current-startup-file)))
-  ;; Save any cache buffers.
-  (and gnus-use-cache (gnus-cache-save-buffers))
   ;; Clear the dribble buffer.
   (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))))
+  (when (get-file-buffer (gnus-newsgroup-kill-file nil))
+    (kill-buffer (get-file-buffer (gnus-newsgroup-kill-file nil))))
   (gnus-kill-buffer nntp-server-buffer)
   ;; Kill Gnus buffers.
   (while gnus-buffer-list
-    (gnus-kill-buffer (car gnus-buffer-list))
-    (setq gnus-buffer-list (cdr gnus-buffer-list))))
+    (gnus-kill-buffer (pop gnus-buffer-list)))
+  ;; Remove Gnus frames.
+  (while gnus-created-frames
+    (when (frame-live-p (car gnus-created-frames))
+      ;; We slap a condition-case around this `delete-frame' to ensure 
+      ;; agains errors if we try do delete the single frame that's left.
+      (condition-case ()
+         (delete-frame (car gnus-created-frames))
+       (error nil)))
+    (pop gnus-created-frames)))
 
 (defun gnus-windows-old-to-new (setting)
-  (if (symbolp setting)
-      (setq setting 
-           (cond ((eq setting 'SelectArticle)
-                  'article)
-                 ((eq setting 'SelectSubject)
-                  'summary)
-                 ((eq setting 'SelectNewsgroup)
-                  'group)
-                 (t setting))))
+  ;; First we take care of the really, really old Gnus 3 actions.
+  (when (symbolp setting)
+    (setq setting
+         ;; Take care of ooold GNUS 3.x values.
+         (cond ((eq setting 'SelectArticle) 'article)
+               ((memq setting '(SelectSubject ExpandSubject)) 'summary)
+               ((memq setting '(SelectNewsgroup ExitNewsgroup)) 'group)
+               (t setting))))
   (if (or (listp setting)
          (not (and gnus-window-configuration
                    (memq setting '(group summary article)))))
       setting
-    (let* ((setting (if (eq setting 'group) 
+    (let* ((setting (if (eq setting 'group)
                        (if (assq 'newsgroup gnus-window-configuration)
                            'newsgroup
                          'newsgroups) setting))
-          (elem (car (cdr (assq setting gnus-window-configuration))))
+          (elem (cadr (assq setting gnus-window-configuration)))
           (total (apply '+ elem))
           (types '(group summary article))
           (pbuf (if (eq setting 'newsgroups) 'group 'summary))
@@ -2473,152 +3217,243 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
           perc
           out)
       (while (< i 3)
-       (or (zerop (nth i elem))
+       (or (not (numberp (nth i elem)))
+           (zerop (nth i elem))
            (progn
-             (setq perc  (/ (* 1.0 (nth 0 elem)) total))
+             (setq perc  (/ (float (nth 0 elem)) total))
              (setq out (cons (if (eq pbuf (nth i types))
                                  (vector (nth i types) perc 'point)
                                (vector (nth i types) perc))
                              out))))
        (setq i (1+ i)))
       (list (nreverse out)))))
-          
+
+;;;###autoload
 (defun gnus-add-configuration (conf)
-  (setq gnus-buffer-configuration 
+  "Add the window configuration CONF to `gnus-buffer-configuration'."
+  (setq gnus-buffer-configuration
        (cons conf (delq (assq (car conf) gnus-buffer-configuration)
                         gnus-buffer-configuration))))
 
+(defvar gnus-frame-list nil)
+
+(defun gnus-configure-frame (split &optional window)
+  "Split WINDOW according to SPLIT."
+  (unless window
+    (setq window (get-buffer-window (current-buffer))))
+  (select-window window)
+  ;; This might be an old-stylee buffer config.
+  (when (vectorp split)
+    (setq split (append split nil)))
+  (when (or (consp (car split))
+           (vectorp (car split)))
+    (push 1.0 split)
+    (push 'vertical split))
+  ;; The SPLIT might be something that is to be evaled to
+  ;; return a new SPLIT.
+  (while (and (not (assq (car split) gnus-window-to-buffer))
+             (gnus-functionp (car split)))
+    (setq split (eval split)))
+  (let* ((type (car split))
+        (subs (cddr split))
+        (len (if (eq type 'horizontal) (window-width) (window-height)))
+        (total 0)
+        (window-min-width (or gnus-window-min-width window-min-width))
+        (window-min-height (or gnus-window-min-height window-min-height))
+        s result new-win rest comp-subs size sub)
+    (cond
+     ;; Nothing to do here.
+     ((null split))
+     ;; Don't switch buffers.
+     ((null type)
+      (and (memq 'point split) window))
+     ;; This is a buffer to be selected.
+     ((not (memq type '(frame horizontal vertical)))
+      (let ((buffer (cond ((stringp type) type)
+                         (t (cdr (assq type gnus-window-to-buffer)))))
+           buf)
+       (unless buffer
+         (error "Illegal buffer type: %s" type))
+       (unless (setq buf (get-buffer (if (symbolp buffer)
+                                         (symbol-value buffer) buffer)))
+         (setq buf (get-buffer-create (if (symbolp buffer)
+                                          (symbol-value buffer) buffer))))
+       (switch-to-buffer buf)
+       ;; We return the window if it has the `point' spec.
+       (and (memq 'point split) window)))
+     ;; This is a frame split.
+     ((eq type 'frame)
+      (unless gnus-frame-list
+       (setq gnus-frame-list (list (window-frame
+                                    (get-buffer-window (current-buffer))))))
+      (let ((i 0)
+           params frame fresult)
+       (while (< i (length subs))
+         ;; Frame parameter is gotten from the sub-split.
+         (setq params (cadr (elt subs i)))
+         ;; It should be a list.
+         (unless (listp params)
+           (setq params nil))
+         ;; Create a new frame?
+         (unless (setq frame (elt gnus-frame-list i))
+           (nconc gnus-frame-list (list (setq frame (make-frame params))))
+           (push frame gnus-created-frames))
+         ;; Is the old frame still alive?
+         (unless (frame-live-p frame)
+           (setcar (nthcdr i gnus-frame-list)
+                   (setq frame (make-frame params))))
+         ;; Select the frame in question and do more splits there.
+         (select-frame frame)
+         (setq fresult (or (gnus-configure-frame (elt subs i)) fresult))
+         (incf i))
+       ;; Select the frame that has the selected buffer.
+       (when fresult
+         (select-frame (window-frame fresult)))))
+     ;; This is a normal split.
+     (t
+      (when (> (length subs) 0)
+       ;; First we have to compute the sizes of all new windows.
+       (while subs
+         (setq sub (append (pop subs) nil))
+         (while (and (not (assq (car sub) gnus-window-to-buffer))
+                     (gnus-functionp (car sub)))
+           (setq sub (eval sub)))
+         (when sub
+           (push sub comp-subs)
+           (setq size (cadar comp-subs))
+           (cond ((equal size 1.0)
+                  (setq rest (car comp-subs))
+                  (setq s 0))
+                 ((floatp size)
+                  (setq s (floor (* size len))))
+                 ((integerp size)
+                  (setq s size))
+                 (t
+                  (error "Illegal size: %s" size)))
+           ;; Try to make sure that we are inside the safe limits.
+           (cond ((zerop s))
+                 ((eq type 'horizontal)
+                  (setq s (max s window-min-width)))
+                 ((eq type 'vertical)
+                  (setq s (max s window-min-height))))
+           (setcar (cdar comp-subs) s)
+           (incf total s)))
+       ;; Take care of the "1.0" spec.
+       (if rest
+           (setcar (cdr rest) (- len total))
+         (error "No 1.0 specs in %s" split))
+       ;; The we do the actual splitting in a nice recursive
+       ;; fashion.
+       (setq comp-subs (nreverse comp-subs))
+       (while comp-subs
+         (if (null (cdr comp-subs))
+             (setq new-win window)
+           (setq new-win
+                 (split-window window (cadar comp-subs)
+                               (eq type 'horizontal))))
+         (setq result (or (gnus-configure-frame
+                           (car comp-subs) window) result))
+         (select-window new-win)
+         (setq window new-win)
+         (setq comp-subs (cdr comp-subs))))
+      ;; Return the proper window, if any.
+      (when result
+       (select-window result))))))
+
+(defvar gnus-frame-split-p nil)
+
 (defun gnus-configure-windows (setting &optional force)
   (setq setting (gnus-windows-old-to-new setting))
-  (let ((r (if (symbolp setting)
-              (cdr (assq setting gnus-buffer-configuration))
-            setting))
-       (in-buf (current-buffer))
-       rule val w height hor ohor heights sub jump-buffer
-       rel total to-buf all-visible)
-    (or r (error "No such setting: %s" setting))
-
-    (if (and (not force) (setq all-visible (gnus-all-windows-visible-p r)))
-       ;; All the windows mentioned are already visibe, so we just
+  (let ((split (if (symbolp setting)
+                  (cadr (assq setting gnus-buffer-configuration))
+                setting))
+       all-visible)
+
+    (setq gnus-frame-split-p nil)
+
+    (unless split
+      (error "No such setting: %s" setting))
+
+    (if (and (setq all-visible (gnus-all-windows-visible-p split))
+            (not force))
+       ;; All the windows mentioned are already visible, so we just
        ;; put point in the assigned buffer, and do not touch the
-       ;; winconf. 
-       (select-window (get-buffer-window all-visible))
+       ;; winconf.
+       (select-window all-visible)
 
       ;; Either remove all windows or just remove all Gnus windows.
-      (if gnus-use-full-window
-         (delete-other-windows)
-       (gnus-remove-some-windows)
-       (switch-to-buffer nntp-server-buffer))
-
-      (while r
-       (setq hor (car r)
-             ohor nil)
-
-       ;; We have to do the (possible) horizontal splitting before the
-       ;; vertical. 
-       (if (and (listp (car hor)) 
-                (eq (car (car hor)) 'horizontal))
-           (progn
-             (split-window 
-              nil
-              (if (integerp (nth 1 (car hor)))
-                  (nth 1 (car hor))
-                (- (frame-width) (floor (* (frame-width) (nth 1 (car hor))))))
-              t)
-             (setq hor (cdr hor))))
-
-       ;; Go through the rules and eval the elements that are to be
-       ;; evaled.  
-       (while hor
-         (if (setq val (if (vectorp (car hor)) (car hor) (eval (car hor))))
-             (progn
-               ;; Expand short buffer name.
-               (setq w (aref val 0))
-               (and (setq w (cdr (assq w gnus-window-to-buffer)))
-                    (progn
-                      (setq val (apply 'vector (mapcar 'identity val)))
-                      (aset val 0 w)))
-               (setq ohor (cons val ohor))))
-         (setq hor (cdr hor)))
-       (setq rule (cons (nreverse ohor) rule))
-       (setq r (cdr r)))
-      (setq rule (nreverse rule))
-
-      ;; We tally the window sizes.
-      (setq total (window-height))
-      (while rule
-       (setq hor (car rule))
-       (if (and (listp (car hor)) (eq (car (car hor)) 'horizontal))
-           (setq hor (cdr hor)))
-       (setq sub 0)
-       (while hor
-         (setq rel (aref (car hor) 1)
-               heights (cons
-                        (cond ((and (floatp rel) (= 1.0 rel))
-                               'x)
-                              ((integerp rel)
-                               rel)
-                              (t
-                               (max (floor (* total rel)) 4)))
-                        heights)
-               sub (+ sub (if (numberp (car heights)) (car heights) 0))
-               hor (cdr hor)))
-       (setq heights (nreverse heights)
-             hor (car rule))
-
-       ;; We then go through these heighs and create windows for them.
-       (while heights
-         (setq height (car heights)
-               heights (cdr heights))
-         (and (eq height 'x)
-              (setq height (- total sub)))
-         (and heights
-              (split-window nil height))
-         (setq to-buf (aref (car hor) 0))
-         (switch-to-buffer 
-          (cond ((not to-buf)
-                 in-buf)
-                ((symbolp to-buf)
-                 (symbol-value (aref (car hor) 0)))
-                (t
-                 (aref (car hor) 0))))
-         (and (> (length (car hor)) 2)
-              (eq (aref (car hor) 2) 'point)
-              (setq jump-buffer (current-buffer)))
-         (other-window 1)
-         (setq hor (cdr hor)))
-      
-       (setq rule (cdr rule)))
-
-      ;; Finally, we pop to the buffer that's supposed to have point. 
-      (or jump-buffer (error "Missing `point' in spec for %s" setting))
-
-      (select-window (get-buffer-window jump-buffer))
-      (set-buffer jump-buffer))))
-
-(defun gnus-all-windows-visible-p (rule)
-  (let (invisible hor jump-buffer val buffer)
-    ;; Go through the rules and eval the elements that are to be
-    ;; evaled.  
-    (while (and rule (not invisible))
-      (setq hor (car rule)
-           rule (cdr rule))
-      (while (and hor (not invisible))
-       (if (setq val (if (vectorp (car hor)) 
-                         (car hor)
-                       (if (not (eq (car (car hor)) 'horizontal))
-                           (eval (car hor)))))
-           (progn
-             ;; Expand short buffer name.
-             (setq buffer (or (cdr (assq (aref val 0) gnus-window-to-buffer))
-                              (aref val 0)))
-             (setq buffer (if (symbolp buffer) (symbol-value buffer)
-                            buffer))
-             (and (> (length val) 2) (eq 'point (aref val 2))
-                  (setq jump-buffer buffer))
-             (setq invisible (not (and buffer (get-buffer-window buffer))))))
-       (setq hor (cdr hor))))
-    (and (not invisible) jump-buffer)))
+      (let ((frame (selected-frame)))
+       (unwind-protect
+           (if gnus-use-full-window
+               ;; We want to remove all other windows.
+               (if (not gnus-frame-split-p)
+                   ;; This is not a `frame' split, so we ignore the
+                   ;; other frames.  
+                   (delete-other-windows)
+                 ;; This is a `frame' split, so we delete all windows
+                 ;; on all frames.
+                 (mapcar 
+                  (lambda (frame)
+                    (unless (eq (cdr (assq 'minibuffer
+                                           (frame-parameters frame)))
+                                'only)
+                      (select-frame frame)
+                      (delete-other-windows)))
+                  (frame-list)))
+             ;; Just remove some windows.
+             (gnus-remove-some-windows)
+             (switch-to-buffer nntp-server-buffer))
+         (select-frame frame)))
+
+      (switch-to-buffer nntp-server-buffer)
+      (gnus-configure-frame split (get-buffer-window (current-buffer))))))
+
+(defun gnus-all-windows-visible-p (split)
+  "Say whether all buffers in SPLIT are currently visible.
+In particular, the value returned will be the window that
+should have point."
+  (let ((stack (list split))
+       (all-visible t)
+       type buffer win buf)
+    (while (and (setq split (pop stack))
+               all-visible)
+      ;; Be backwards compatible.
+      (when (vectorp split)
+       (setq split (append split nil)))
+      (when (or (consp (car split))
+               (vectorp (car split)))
+       (push 1.0 split)
+       (push 'vertical split))
+      ;; The SPLIT might be something that is to be evaled to
+      ;; return a new SPLIT.
+      (while (and (not (assq (car split) gnus-window-to-buffer))
+                 (gnus-functionp (car split)))
+       (setq split (eval split)))
+
+      (setq type (elt split 0))
+      (cond
+       ;; Nothing here.
+       ((null split) t)
+       ;; A buffer.
+       ((not (memq type '(horizontal vertical frame)))
+       (setq buffer (cond ((stringp type) type)
+                          (t (cdr (assq type gnus-window-to-buffer)))))
+       (unless buffer
+         (error "Illegal buffer type: %s" type))
+       (when (setq buf (get-buffer (if (symbolp buffer)
+                                       (symbol-value buffer)
+                                     buffer)))
+         (setq win (get-buffer-window buf t)))
+       (if win
+           (when (memq 'point split)
+               (setq all-visible win))
+         (setq all-visible nil)))
+       (t
+       (when (eq type 'frame)
+         (setq gnus-frame-split-p t))
+       (setq stack (append (cddr split) stack)))))
+    (unless (eq all-visible t)
+      all-visible)))
 
 (defun gnus-window-top-edge (&optional window)
   (nth 1 (window-edges window)))
@@ -2629,10 +3464,10 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
     (save-excursion
       ;; Remove windows on all known Gnus buffers.
       (while buffers
-       (setq buf (cdr (car buffers)))
+       (setq buf (cdar buffers))
        (if (symbolp buf)
            (setq buf (and (boundp buf) (symbol-value buf))))
-       (and buf 
+       (and buf
             (get-buffer-window buf)
             (progn
               (setq bufs (cons buf bufs))
@@ -2644,20 +3479,19 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
                     (setq lowest-buf buf)))))
        (setq buffers (cdr buffers)))
       ;; Remove windows on *all* summary buffers.
-      (let (wins)
-       (walk-windows
-        (lambda (win)
-          (let ((buf (window-buffer win)))
-            (if (string-match  "^\\*Summary" (buffer-name buf))
-                (progn
-                  (setq bufs (cons buf bufs))
-                  (pop-to-buffer buf)
-                  (if (or (not lowest)
-                          (< (gnus-window-top-edge) lowest))
-                      (progn
-                        (setq lowest-buf buf)
-                        (setq lowest (gnus-window-top-edge))))))))))
-      (and lowest-buf 
+      (walk-windows
+       (lambda (win)
+        (let ((buf (window-buffer win)))
+          (if (string-match    "^\\*Summary" (buffer-name buf))
+              (progn
+                (setq bufs (cons buf bufs))
+                (pop-to-buffer buf)
+                (if (or (not lowest)
+                        (< (gnus-window-top-edge) lowest))
+                    (progn
+                      (setq lowest-buf buf)
+                      (setq lowest (gnus-window-top-edge)))))))))
+      (and lowest-buf
           (progn
             (pop-to-buffer lowest-buf)
             (switch-to-buffer nntp-server-buffer)))
@@ -2665,7 +3499,7 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
        (and (not (eq (car bufs) lowest-buf))
             (delete-windows-on (car bufs)))
        (setq bufs (cdr bufs))))))
-                         
+
 (defun gnus-version ()
   "Version numbers of this version of Gnus."
   (interactive)
@@ -2673,11 +3507,11 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
        (mess gnus-version)
        meth)
     ;; Go through all the legal select methods and add their version
-    ;; numbers to the total version string. Only the backends that are
+    ;; numbers to the total version string.  Only the backends that are
     ;; currently in use will have their message numbers taken into
-    ;; consideration. 
+    ;; consideration.
     (while methods
-      (setq meth (intern (concat (car (car methods)) "-version")))
+      (setq meth (intern (concat (caar methods) "-version")))
       (and (boundp meth)
           (stringp (symbol-value meth))
           (setq mess (concat mess "; " (symbol-value meth))))
@@ -2688,40 +3522,11 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only."
   "Find Info documentation of Gnus."
   (interactive)
   ;; Enlarge info window if needed.
-  (let ((mode major-mode))
-    (gnus-configure-windows 'info)
-    (Info-goto-node (car (cdr (assq mode gnus-info-nodes))))))
-
-(defun gnus-overload-functions (&optional overloads)
-  "Overload functions specified by optional argument OVERLOADS.
-If nothing is specified, use the variable gnus-overload-functions."
-  (let ((defs nil)
-       (overloads (or overloads gnus-overload-functions)))
-    (while overloads
-      (setq defs (car overloads))
-      (setq overloads (cdr overloads))
-      ;; Load file before overloading function if necessary.  Make
-      ;; sure we cannot use `require' always.
-      (and (not (fboundp (car defs)))
-          (car (cdr (cdr defs)))
-          (load (car (cdr (cdr defs))) nil 'nomessage))
-      (fset (car defs) (car (cdr defs))))))
-
-(defun gnus-replace-chars-in-string (string &rest pairs)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))  ;Copy string.
-       (len (length string))
-       (idx 0)
-       sym to)
-    (or (zerop (% (length pairs) 2)) 
-       (error "Odd number of translation pairs"))
-    (setplist 'sym pairs)
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (if (setq to (get 'sym (aref string idx)))
-         (aset string idx to))
-      (setq idx (1+ idx)))
-    string))
+  (let ((mode major-mode)
+       gnus-info-buffer)
+    (Info-goto-node (cadr (assq mode gnus-info-nodes)))
+    (setq gnus-info-buffer (current-buffer))
+    (gnus-configure-windows 'info)))
 
 (defun gnus-days-between (date1 date2)
   ;; Return the number of days between date1 and date2.
@@ -2730,27 +3535,22 @@ If nothing is specified, use the variable gnus-overload-functions."
 (defun gnus-day-number (date)
   (let ((dat (mapcar (lambda (s) (and s (string-to-int s)) )
                     (timezone-parse-date date))))
-    (timezone-absolute-from-gregorian 
+    (timezone-absolute-from-gregorian
      (nth 1 dat) (nth 2 dat) (car dat))))
 
-;; Returns a floating point number that says how many seconds have
-;; lapsed between Jan 1 12:00:00 1970 and DATE.
-(defun gnus-seconds-since-epoch (date)
-  (let* ((tdate (mapcar (lambda (ti) (and ti (string-to-int ti)))
-                       (timezone-parse-date date)))
-        (ttime (mapcar (lambda (ti) (and ti (string-to-int ti)))
-                       (timezone-parse-time
-                        (aref (timezone-parse-date date) 3))))
-        (edate (mapcar (lambda (ti) (and ti (string-to-int ti)))
-                       (timezone-parse-date "Jan 1 12:00:00 1970")))
-        (tday (- (timezone-absolute-from-gregorian 
-                  (nth 1 tdate) (nth 2 tdate) (nth 0 tdate))
-                 (timezone-absolute-from-gregorian 
-                  (nth 1 edate) (nth 2 edate) (nth 0 edate)))))
-    (+ (nth 2 ttime)
-       (* (nth 1 ttime) 60)
-       (* 1.0 (nth 0 ttime) 60 60)
-       (* 1.0 tday 60 60 24))))
+(defun gnus-encode-date (date)
+  "Convert DATE to internal time."
+  (let* ((parse (timezone-parse-date date))
+        (date (mapcar (lambda (d) (and d (string-to-int d))) parse))
+        (time (mapcar 'string-to-int (timezone-parse-time (aref parse 3)))))
+    (encode-time (caddr time) (cadr time) (car time)
+                (caddr date) (cadr date) (car date) (nth 4 date))))
+
+(defun gnus-time-minus (t1 t2)
+  "Subtract two internal times."
+  (let ((borrow (< (cadr t1) (cadr t2))))
+    (list (- (car t1) (car t2) (if borrow 1 0))
+         (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
 
 (defun gnus-file-newer-than (file date)
   (let ((fdate (nth 5 (file-attributes file))))
@@ -2758,9 +3558,120 @@ If nothing is specified, use the variable gnus-overload-functions."
        (and (= (car fdate) (car date))
             (> (nth 1 fdate) (nth 1 date))))))
 
-;; Two silly functions to ensure that all `y-or-n-p' questions clear
-;; the echo area.
-(defun gnus-y-or-n-p (prompt)
+(defmacro gnus-local-set-keys (&rest plist)
+  "Set the keys in PLIST in the current keymap."
+  `(gnus-define-keys-1 (current-local-map) ',plist))
+
+(defmacro gnus-define-keys (keymap &rest plist)
+  "Define all keys in PLIST in KEYMAP."
+  `(gnus-define-keys-1 (quote ,keymap) (quote ,plist)))
+
+(put 'gnus-define-keys 'lisp-indent-function 1)
+(put 'gnus-define-keys 'lisp-indent-hook 1)
+(put 'gnus-define-keymap 'lisp-indent-function 1)
+(put 'gnus-define-keymap 'lisp-indent-hook 1)
+
+(defmacro gnus-define-keymap (keymap &rest plist)
+  "Define all keys in PLIST in KEYMAP."
+  `(gnus-define-keys-1 ,keymap (quote ,plist)))
+
+(defun gnus-define-keys-1 (keymap plist)
+  (when (null keymap)
+    (error "Can't set keys in a null keymap"))
+  (cond ((symbolp keymap)
+        (setq keymap (symbol-value keymap)))
+       ((keymapp keymap))
+       ((listp keymap)
+        (set (car keymap) nil)
+        (define-prefix-command (car keymap))
+        (define-key (symbol-value (caddr keymap)) (cadr keymap) (car keymap))
+        (setq keymap (symbol-value (car keymap)))))
+  (let (key)
+    (while plist
+      (when (symbolp (setq key (pop plist)))
+       (setq key (symbol-value key)))
+      (define-key keymap key (pop plist)))))
+
+(defun gnus-group-read-only-p (&optional group)
+  "Check whether GROUP supports editing or not.
+If GROUP is nil, `gnus-newsgroup-name' will be checked instead.         Note
+that that variable is buffer-local to the summary buffers."
+  (let ((group (or group gnus-newsgroup-name)))
+    (not (gnus-check-backend-function 'request-replace-article group))))
+
+(defun gnus-group-total-expirable-p (group)
+  "Check whether GROUP is total-expirable or not."
+  (let ((params (gnus-info-params (gnus-get-info group))))
+    (or (memq 'total-expire params)
+       (cdr (assq 'total-expire params)) ; (total-expire . t)
+       (and gnus-total-expirable-newsgroups ; Check var.
+            (string-match gnus-total-expirable-newsgroups group)))))
+
+(defun gnus-group-auto-expirable-p (group)
+  "Check whether GROUP is total-expirable or not."
+  (let ((params (gnus-info-params (gnus-get-info group))))
+    (or (memq 'auto-expire params)
+       (cdr (assq 'auto-expire params)) ; (auto-expire . t)
+       (and gnus-auto-expirable-newsgroups ; Check var.
+            (string-match gnus-auto-expirable-newsgroups group)))))
+
+(defun gnus-virtual-group-p (group)
+  "Say whether GROUP is virtual or not."
+  (memq 'virtual (assoc (symbol-name (car (gnus-find-method-for-group group)))
+                       gnus-valid-select-methods)))
+
+(defun gnus-news-group-p (group &optional article)
+  "Return non-nil if GROUP (and ARTICLE) come from a news server."
+  (or (gnus-member-of-valid 'post group) ; Ordinary news group.
+      (and (gnus-member-of-valid 'post-mail group) ; Combined group.
+          (eq (gnus-request-type group article) 'news))))
+
+(defsubst gnus-simplify-subject-fully (subject)
+  "Simplify a subject string according to the user's wishes."
+  (cond
+   ((null gnus-summary-gather-subject-limit)
+    (gnus-simplify-subject-re subject))
+   ((eq gnus-summary-gather-subject-limit 'fuzzy)
+    (gnus-simplify-subject-fuzzy subject))
+   ((numberp gnus-summary-gather-subject-limit)
+    (gnus-limit-string (gnus-simplify-subject-re subject)
+                      gnus-summary-gather-subject-limit))
+   (t
+    subject)))
+
+(defsubst gnus-subject-equal (s1 s2 &optional simple-first)
+  "Check whether two subjects are equal.  If optional argument
+simple-first is t, first argument is already simplified."
+  (cond
+   ((null simple-first)
+    (equal (gnus-simplify-subject-fully s1)
+          (gnus-simplify-subject-fully s2)))
+   (t
+    (equal s1
+          (gnus-simplify-subject-fully s2)))))
+
+;; Returns a list of writable groups.
+(defun gnus-writable-groups ()
+  (let ((alist gnus-newsrc-alist)
+       groups group)
+    (while (setq group (car (pop alist)))
+      (unless (gnus-group-read-only-p group)
+       (push group groups)))
+    (nreverse groups)))
+
+(defun gnus-completing-read (default prompt &rest args)
+  ;; Like `completing-read', except that DEFAULT is the default argument.
+  (let* ((prompt (if default 
+                    (concat prompt " (default " default ") ")
+                  (concat prompt " ")))
+        (answer (apply 'completing-read prompt args)))
+    (if (or (null answer) (zerop (length answer)))
+       default
+      answer)))
+
+;; Two silly functions to ensure that all `y-or-n-p' questions clear
+;; the echo area.
+(defun gnus-y-or-n-p (prompt)
   (prog1
       (y-or-n-p prompt)
     (message "")))
@@ -2777,21 +3688,37 @@ If nothing is specified, use the variable gnus-overload-functions."
        ;; If it isn't a list, then we return t.
        (or (not (listp gnus-use-long-file-name))
           ;; If it is a list, and the list contains `symbol', we
-          ;; return nil.  
+          ;; return nil.
           (not (memq symbol gnus-use-long-file-name)))))
 
 ;; I suspect there's a better way, but I haven't taken the time to do
 ;; it yet. -erik selberg@cs.washington.edu
 (defun gnus-dd-mmm (messy-date)
   "Return a string like DD-MMM from a big messy string"
-  (let ((datevec (timezone-parse-date messy-date)))
-    (format "%2s-%s"
-           (or (aref datevec 2) "??")
-           (capitalize
-            (or (car 
-                 (nth (1- (string-to-number (aref datevec 1)))
-                      timezone-months-assoc))
-                "???")))))
+  (let ((datevec (condition-case () (timezone-parse-date messy-date) 
+                  (error nil))))
+    (if (not datevec)
+       "??-???"
+      (format "%2s-%s"
+             (condition-case ()
+                 ;; Make sure leading zeroes are stripped.
+                 (number-to-string (string-to-number (aref datevec 2)))
+               (error "??"))
+             (capitalize
+              (or (car
+                   (nth (1- (string-to-number (aref datevec 1)))
+                        timezone-months-assoc))
+                  "???"))))))
+
+(defun gnus-mode-string-quote (string)
+  "Quote all \"%\" in STRING."
+  (save-excursion
+    (gnus-set-work-buffer)
+    (insert string)
+    (goto-char (point-min))
+    (while (search-forward "%" nil t)
+      (insert "%"))
+    (buffer-string)))
 
 ;; Make a hash table (default and minimum size is 255).
 ;; Optional argument HASHSIZE specifies the table size.
@@ -2806,19 +3733,30 @@ If nothing is specified, use the variable gnus-overload-functions."
       (setq i (* 2 i)))
     (1- i)))
 
-;; Show message if message has a lower level than `gnus-verbose'. 
-;; Guide-line for numbers:
+;; Show message if message has a lower level than `gnus-verbose'.
+;; Guideline for numbers:
 ;; 1 - error messages, 3 - non-serious error messages, 5 - messages
 ;; for things that take a long time, 7 - not very important messages
 ;; on stuff, 9 - messages inside loops.
 (defun gnus-message (level &rest args)
   (if (<= level gnus-verbose)
       (apply 'message args)
-    ;; We have to do this format thingie here even if the result isn't
+    ;; We have to do this format thingy here even if the result isn't
     ;; shown - the return value has to be the same as the return value
     ;; from `message'.
     (apply 'format args)))
 
+(defun gnus-error (level &rest args)
+  "Beep an error if `gnus-verbose' is on LEVEL or less."
+  (when (<= (floor level) gnus-verbose)
+    (apply 'message args)
+    (ding)
+    (let (duration)
+      (when (and (floatp level)
+                (not (zerop (setq duration (* 10 (- level (floor level)))))))
+       (sit-for duration))))
+  nil)
+
 ;; Generate a unique new group name.
 (defun gnus-generate-new-group-name (leaf)
   (let ((name leaf)
@@ -2827,6 +3765,85 @@ If nothing is specified, use the variable gnus-overload-functions."
       (setq name (concat leaf "<" (int-to-string (setq num (1+ num))) ">")))
     name))
 
+(defsubst gnus-hide-text (b e props)
+  "Set text PROPS on the B to E region, extending `intangible' 1 past B."
+  (gnus-add-text-properties b e props)
+  (when (memq 'intangible props)
+    (gnus-put-text-property (max (1- b) (point-min))
+                      b 'intangible (cddr (memq 'intangible props)))))
+
+(defsubst gnus-unhide-text (b e)
+  "Remove hidden text properties from region between B and E."
+  (remove-text-properties b e gnus-hidden-properties)
+  (when (memq 'intangible gnus-hidden-properties)
+    (gnus-put-text-property (max (1- b) (point-min))
+                      b 'intangible nil)))
+
+(defun gnus-hide-text-type (b e type)
+  "Hide text of TYPE between B and E."
+  (gnus-hide-text b e (cons 'gnus-type (cons type gnus-hidden-properties))))
+
+;; Find out whether the gnus-visual TYPE is wanted.
+(defun gnus-visual-p (&optional type class)
+  (and gnus-visual                     ; Has to be non-nil, at least.
+       (if (not type)                  ; We don't care about type.
+          gnus-visual
+        (if (listp gnus-visual)        ; It's a list, so we check it.
+            (or (memq type gnus-visual)
+                (memq class gnus-visual))
+          t))))
+
+(defun gnus-parent-headers (headers &optional generation)
+  "Return the headers of the GENERATIONeth parent of HEADERS."
+  (unless generation 
+    (setq generation 1))
+  (let (references parent)
+    (while (and headers (not (zerop generation)))
+      (setq references (mail-header-references headers))
+      (when (and references
+                (setq parent (gnus-parent-id references))
+                (setq headers (car (gnus-id-to-thread parent))))
+       (decf generation)))
+    headers))
+
+(defun gnus-parent-id (references)
+  "Return the last Message-ID in REFERENCES."
+  (when (and references
+            (string-match "\\(<[^\n<>]+>\\)[ \t\n]*\\'" references))
+    (substring references (match-beginning 1) (match-end 1))))
+
+(defun gnus-split-references (references)
+  "Return a list of Message-IDs in REFERENCES."
+  (let ((beg 0)
+       ids)
+    (while (string-match "<[^>]+>" references beg)
+      (push (substring references (match-beginning 0) (setq beg (match-end 0)))
+           ids))
+    (nreverse ids)))
+
+(defun gnus-buffer-live-p (buffer)
+  "Say whether BUFFER is alive or not."
+  (and buffer
+       (get-buffer buffer)
+       (buffer-name (get-buffer buffer))))
+
+(defun gnus-ephemeral-group-p (group)
+  "Say whether GROUP is ephemeral or not."
+  (gnus-group-get-parameter group 'quit-config))
+
+(defun gnus-group-quit-config (group)
+  "Return the quit-config of GROUP."
+  (gnus-group-get-parameter group 'quit-config))
+
+(defun gnus-simplify-mode-line ()
+  "Make mode lines a bit simpler."
+  (setq mode-line-modified "-- ")
+  (when (listp mode-line-format)
+    (make-local-variable 'mode-line-format)
+    (setq mode-line-format (copy-sequence mode-line-format))
+    (when (equal (nth 3 mode-line-format) "   ")
+      (setcar (nthcdr 3 mode-line-format) " "))))
+
 ;;; List and range functions
 
 (defun gnus-last-element (list)
@@ -2839,7 +3856,7 @@ If nothing is specified, use the variable gnus-overload-functions."
   "Do a complete, total copy of a list."
   (if (and (consp list) (not (consp (cdr list))))
       (cons (car list) (cdr list))
-    (mapcar (lambda (elem) (if (consp elem) 
+    (mapcar (lambda (elem) (if (consp elem)
                               (if (consp (cdr elem))
                                   (gnus-copy-sequence elem)
                                 (cons (car elem) (cdr elem)))
@@ -2872,7 +3889,7 @@ Both lists have to be sorted over <."
               (setq list2 (cdr list2)))))
       (nconc (nreverse out) (or list1 list2)))))
 
-(defun gnus-intersection (list1 list2)      
+(defun gnus-intersection (list1 list2)
   (let ((result nil))
     (while list2
       (if (memq (car list2) list1)
@@ -2928,7 +3945,7 @@ ranges."
                ((= (1+ last) (car numbers)) ;Still in sequence
                 (setq last (car numbers)))
                (t                      ;End of one sequence
-                (setq result 
+                (setq result
                       (cons (if (= first last) first
                               (cons first last)) result))
                 (setq first (car numbers))
@@ -2945,7 +3962,7 @@ ranges."
 RANGES is either a single range on the form `(num . num)' or a list of
 these ranges."
   (let (first last result)
-    (cond 
+    (cond
      ((null ranges)
       nil)
      ((not (listp (cdr ranges)))
@@ -2960,8 +3977,8 @@ these ranges."
        (if (atom (car ranges))
            (if (numberp (car ranges))
                (setq result (cons (car ranges) result)))
-         (setq first (car (car ranges)))
-         (setq last  (cdr (car ranges)))
+         (setq first (caar ranges))
+         (setq last  (cdar ranges))
          (while (<= first last)
            (setq result (cons first result))
            (setq first (1+ first))))
@@ -2981,8 +3998,8 @@ Note: LIST has to be sorted over `<'."
       (while (and ranges list)
        (setq ilist list)
        (setq lowest (or (and (atom (car ranges)) (car ranges))
-                        (car (car ranges))))
-       (while (and list (cdr list) (< (car (cdr list)) lowest))
+                        (caar ranges)))
+       (while (and list (cdr list) (< (cadr list) lowest))
          (setq list (cdr list)))
        (if (< (car ilist) lowest)
            (progn
@@ -2991,40 +4008,40 @@ Note: LIST has to be sorted over `<'."
              (setcdr temp nil)
              (setq out (nconc (gnus-compress-sequence ilist t) out))))
        (setq highest (or (and (atom (car ranges)) (car ranges))
-                         (cdr (car ranges))))
+                         (cdar ranges)))
        (while (and list (<= (car list) highest))
          (setq list (cdr list)))
        (setq ranges (cdr ranges)))
       (if list
          (setq out (nconc (gnus-compress-sequence list t) out)))
-      (setq out (sort out (lambda (r1 r2) 
+      (setq out (sort out (lambda (r1 r2)
                            (< (or (and (atom r1) r1) (car r1))
                               (or (and (atom r2) r2) (car r2))))))
       (setq ranges out)
       (while ranges
        (if (atom (car ranges))
            (if (cdr ranges)
-               (if (atom (car (cdr ranges)))
-                   (if (= (1+ (car ranges)) (car (cdr ranges)))
+               (if (atom (cadr ranges))
+                   (if (= (1+ (car ranges)) (cadr ranges))
                        (progn
-                         (setcar ranges (cons (car ranges) 
-                                              (car (cdr ranges))))
-                         (setcdr ranges (cdr (cdr ranges)))))
-                 (if (= (1+ (car ranges)) (car (car (cdr ranges))))
+                         (setcar ranges (cons (car ranges)
+                                              (cadr ranges)))
+                         (setcdr ranges (cddr ranges))))
+                 (if (= (1+ (car ranges)) (caadr ranges))
                      (progn
-                       (setcar (car (cdr ranges)) (car ranges))
-                       (setcar ranges (car (cdr ranges)))
-                       (setcdr ranges (cdr (cdr ranges)))))))
+                       (setcar (cadr ranges) (car ranges))
+                       (setcar ranges (cadr ranges))
+                       (setcdr ranges (cddr ranges))))))
          (if (cdr ranges)
-             (if (atom (car (cdr ranges)))
-                 (if (= (1+ (cdr (car ranges))) (car (cdr ranges)))
+             (if (atom (cadr ranges))
+                 (if (= (1+ (cdar ranges)) (cadr ranges))
                      (progn
-                       (setcdr (car ranges) (car (cdr ranges)))
-                       (setcdr ranges (cdr (cdr ranges)))))
-               (if (= (1+ (cdr (car ranges))) (car (car (cdr ranges))))
+                       (setcdr (car ranges) (cadr ranges))
+                       (setcdr ranges (cddr ranges))))
+               (if (= (1+ (cdar ranges)) (caadr ranges))
                    (progn
-                     (setcdr (car ranges) (cdr (car (cdr ranges))))
-                     (setcdr ranges (cdr (cdr ranges))))))))
+                     (setcdr (car ranges) (cdadr ranges))
+                     (setcdr ranges (cddr ranges)))))))
        (setq ranges (cdr ranges)))
       out)))
 
@@ -3032,178 +4049,210 @@ Note: LIST has to be sorted over `<'."
   "Return a list of ranges that has all articles from LIST removed from RANGES.
 Note: LIST has to be sorted over `<'."
   ;; !!! This function shouldn't look like this, but I've got a headache.
-  (gnus-compress-sequence 
+  (gnus-compress-sequence
    (gnus-sorted-complement
     (gnus-uncompress-range ranges) list)))
 
 (defun gnus-member-of-range (number ranges)
   (if (not (listp (cdr ranges)))
-      (and (>= number (car ranges)) 
+      (and (>= number (car ranges))
           (<= number (cdr ranges)))
     (let ((not-stop t))
-      (while (and ranges 
+      (while (and ranges
                  (if (numberp (car ranges))
                      (>= number (car ranges))
-                   (>= number (car (car ranges))))
+                   (>= number (caar ranges)))
                  not-stop)
        (if (if (numberp (car ranges))
                (= number (car ranges))
-             (and (>= number (car (car ranges)))
-                  (<= number (cdr (car ranges)))))
+             (and (>= number (caar ranges))
+                  (<= number (cdar ranges))))
            (setq not-stop nil))
        (setq ranges (cdr ranges)))
       (not not-stop))))
 
+(defun gnus-range-length (range)
+  "Return the length RANGE would have if uncompressed."
+  (length (gnus-uncompress-range range)))
+
+(defun gnus-sublist-p (list sublist)
+  "Test whether all elements in SUBLIST are members of LIST."
+  (let ((sublistp t))
+    (while sublist
+      (unless (memq (pop sublist) list)
+       (setq sublistp nil
+             sublist nil)))
+    sublistp))
+
 \f
 ;;;
 ;;; Gnus group mode
 ;;;
 
 (defvar gnus-group-mode-map nil)
-(defvar gnus-group-group-map nil)
-(defvar gnus-group-mark-map nil)
-(defvar gnus-group-list-map nil)
-(defvar gnus-group-sub-map nil)
 (put 'gnus-group-mode 'mode-class 'special)
 
-(if gnus-group-mode-map
-    nil
+(unless gnus-group-mode-map
   (setq gnus-group-mode-map (make-keymap))
   (suppress-keymap gnus-group-mode-map)
-  (define-key gnus-group-mode-map " " 'gnus-group-read-group)
-  (define-key gnus-group-mode-map "=" 'gnus-group-select-group)
-  (define-key gnus-group-mode-map "\r" 'gnus-group-select-group)
-  (define-key gnus-group-mode-map "j" 'gnus-group-jump-to-group)
-  (define-key gnus-group-mode-map "n" 'gnus-group-next-unread-group)
-  (define-key gnus-group-mode-map "p" 'gnus-group-prev-unread-group)
-  (define-key gnus-group-mode-map "\177" 'gnus-group-prev-unread-group)
-  (define-key gnus-group-mode-map "N" 'gnus-group-next-group)
-  (define-key gnus-group-mode-map "P" 'gnus-group-prev-group)
-  (define-key gnus-group-mode-map
-    "\M-n" 'gnus-group-next-unread-group-same-level)
-  (define-key gnus-group-mode-map 
-    "\M-p" 'gnus-group-prev-unread-group-same-level)
-  (define-key gnus-group-mode-map "," 'gnus-group-best-unread-group)
-  (define-key gnus-group-mode-map "." 'gnus-group-first-unread-group)
-  (define-key gnus-group-mode-map "u" 'gnus-group-unsubscribe-current-group)
-  (define-key gnus-group-mode-map "U" 'gnus-group-unsubscribe-group)
-  (define-key gnus-group-mode-map "c" 'gnus-group-catchup-current)
-  (define-key gnus-group-mode-map "C" 'gnus-group-catchup-current-all)
-  (define-key gnus-group-mode-map "l" 'gnus-group-list-groups)
-  (define-key gnus-group-mode-map "L" 'gnus-group-list-all-groups)
-  (define-key gnus-group-mode-map "m" 'gnus-group-mail)
-  (define-key gnus-group-mode-map "g" 'gnus-group-get-new-news)
-  (define-key gnus-group-mode-map "\M-g" 'gnus-group-get-new-news-this-group)
-  (define-key gnus-group-mode-map "R" 'gnus-group-restart)
-  (define-key gnus-group-mode-map "r" 'gnus-group-read-init-file)
-  (define-key gnus-group-mode-map "B" 'gnus-group-browse-foreign-server)
-  (define-key gnus-group-mode-map "b" 'gnus-group-check-bogus-groups)
-  (define-key gnus-group-mode-map "F" 'gnus-find-new-newsgroups)
-  (define-key gnus-group-mode-map "\C-c\C-d" 'gnus-group-describe-group)
-  (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 "a" 'gnus-group-post-news)
-  (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)
-  (define-key gnus-group-mode-map "\C-y" 'gnus-group-yank-group)
-  (define-key gnus-group-mode-map "\C-w" 'gnus-group-kill-region)
-  (define-key gnus-group-mode-map "\C-x\C-t" 'gnus-group-transpose-groups)
-  (define-key gnus-group-mode-map "\C-c\C-l" 'gnus-group-list-killed)
-  (define-key gnus-group-mode-map "\C-c\C-x" 'gnus-group-expire-articles)
-  (define-key gnus-group-mode-map "\C-c\M-\C-x" 'gnus-group-expire-all-groups)
-  (define-key gnus-group-mode-map "V" 'gnus-version)
-  (define-key gnus-group-mode-map "s" 'gnus-group-save-newsrc)
-  (define-key gnus-group-mode-map "z" 'gnus-group-suspend)
-  (define-key gnus-group-mode-map "Z" 'gnus-group-clear-dribble)
-  (define-key gnus-group-mode-map "q" 'gnus-group-exit)
-  (define-key gnus-group-mode-map "Q" 'gnus-group-quit)
-  (define-key gnus-group-mode-map "\M-f" 'gnus-group-fetch-faq)
-  (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 "\M-e" 'gnus-group-edit-group-method)
-  (define-key gnus-group-mode-map "^" 'gnus-group-enter-server-mode)
-  (define-key gnus-group-mode-map gnus-mouse-2 'gnus-mouse-pick-group)
-  (define-key gnus-group-mode-map "<" 'beginning-of-buffer)
-  (define-key gnus-group-mode-map ">" 'end-of-buffer)
-  (define-key gnus-group-mode-map "\C-c\C-b" 'gnus-bug)
-  (define-key gnus-group-mode-map "\C-c\C-s" 'gnus-group-sort-groups)
-
-  (define-key gnus-group-mode-map "#" 'gnus-group-mark-group)
-  (define-key gnus-group-mode-map "\M-#" 'gnus-group-unmark-group)
-  (define-prefix-command 'gnus-group-mark-map)
-  (define-key gnus-group-mode-map "M" 'gnus-group-mark-map)
-  (define-key gnus-group-mark-map "m" 'gnus-group-mark-group)
-  (define-key gnus-group-mark-map "u" 'gnus-group-unmark-group)
-  (define-key gnus-group-mark-map "w" 'gnus-group-mark-region)
-
-  (define-prefix-command 'gnus-group-group-map)
-  (define-key gnus-group-mode-map "G" 'gnus-group-group-map)
-  (define-key gnus-group-group-map "d" 'gnus-group-make-directory-group)
-  (define-key gnus-group-group-map "h" 'gnus-group-make-help-group)
-  (define-key gnus-group-group-map "a" 'gnus-group-make-archive-group)
-  (define-key gnus-group-group-map "k" 'gnus-group-make-kiboze-group)
-  (define-key gnus-group-group-map "m" 'gnus-group-make-group)
-  (define-key gnus-group-group-map "E" 'gnus-group-edit-group)
-  (define-key gnus-group-group-map "e" 'gnus-group-edit-group-method)
-  (define-key gnus-group-group-map "p" 'gnus-group-edit-group-parameters)
-  (define-key gnus-group-group-map "v" 'gnus-group-add-to-virtual)
-  (define-key gnus-group-group-map "V" 'gnus-group-make-empty-virtual)
-  (define-key gnus-group-group-map "D" 'gnus-group-enter-directory)
-  (define-key gnus-group-group-map "f" 'gnus-group-make-doc-group)
-  ;;(define-key gnus-group-group-map "sb" 'gnus-group-brew-soup)
-  ;;(define-key gnus-group-group-map "sw" 'gnus-soup-save-areas)
-  ;;(define-key gnus-group-group-map "ss" 'gnus-soup-send-replies)
-  ;;(define-key gnus-group-group-map "sp" 'gnus-soup-pack-packet)
-  ;;(define-key gnus-group-group-map "sr" 'nnsoup-pack-replies)
-
-  (define-prefix-command 'gnus-group-list-map)
-  (define-key gnus-group-mode-map "A" 'gnus-group-list-map)
-  (define-key gnus-group-list-map "k" 'gnus-group-list-killed)
-  (define-key gnus-group-list-map "z" 'gnus-group-list-zombies)
-  (define-key gnus-group-list-map "s" 'gnus-group-list-groups)
-  (define-key gnus-group-list-map "u" 'gnus-group-list-all-groups)
-  (define-key gnus-group-list-map "a" 'gnus-group-apropos)
-  (define-key gnus-group-list-map "d" 'gnus-group-description-apropos)
-  (define-key gnus-group-list-map "m" 'gnus-group-list-matching)
-  (define-key gnus-group-list-map "M" 'gnus-group-list-all-matching)
-
-  (define-prefix-command 'gnus-group-sub-map)
-  (define-key gnus-group-mode-map "S" 'gnus-group-sub-map)
-  (define-key gnus-group-sub-map "l" 'gnus-group-set-current-level)
-  (define-key gnus-group-sub-map "t" 'gnus-group-unsubscribe-current-group)
-  (define-key gnus-group-sub-map "s" 'gnus-group-unsubscribe-group)
-  (define-key gnus-group-sub-map "k" 'gnus-group-kill-group)
-  (define-key gnus-group-sub-map "y" 'gnus-group-yank-group)
-  (define-key gnus-group-sub-map "w" 'gnus-group-kill-region)
-  (define-key gnus-group-sub-map "z" 'gnus-group-kill-all-zombies))
+
+  (gnus-define-keys gnus-group-mode-map
+    " " gnus-group-read-group
+    "=" gnus-group-select-group
+    "\r" gnus-group-select-group
+    "\M-\r" gnus-group-quick-select-group
+    "j" gnus-group-jump-to-group
+    "n" gnus-group-next-unread-group
+    "p" gnus-group-prev-unread-group
+    "\177" gnus-group-prev-unread-group
+    [delete] gnus-group-prev-unread-group
+    "N" gnus-group-next-group
+    "P" gnus-group-prev-group
+    "\M-n" gnus-group-next-unread-group-same-level
+    "\M-p" gnus-group-prev-unread-group-same-level
+    "," gnus-group-best-unread-group
+    "." gnus-group-first-unread-group
+    "u" gnus-group-unsubscribe-current-group
+    "U" gnus-group-unsubscribe-group
+    "c" gnus-group-catchup-current
+    "C" gnus-group-catchup-current-all
+    "l" gnus-group-list-groups
+    "L" gnus-group-list-all-groups
+    "m" gnus-group-mail
+    "g" gnus-group-get-new-news
+    "\M-g" gnus-group-get-new-news-this-group
+    "R" gnus-group-restart
+    "r" gnus-group-read-init-file
+    "B" gnus-group-browse-foreign-server
+    "b" gnus-group-check-bogus-groups
+    "F" gnus-find-new-newsgroups
+    "\C-c\C-d" gnus-group-describe-group
+    "\M-d" gnus-group-describe-all-groups
+    "\C-c\C-a" gnus-group-apropos
+    "\C-c\M-\C-a" gnus-group-description-apropos
+    "a" gnus-group-post-news
+    "\ek" gnus-group-edit-local-kill
+    "\eK" gnus-group-edit-global-kill
+    "\C-k" gnus-group-kill-group
+    "\C-y" gnus-group-yank-group
+    "\C-w" gnus-group-kill-region
+    "\C-x\C-t" gnus-group-transpose-groups
+    "\C-c\C-l" gnus-group-list-killed
+    "\C-c\C-x" gnus-group-expire-articles
+    "\C-c\M-\C-x" gnus-group-expire-all-groups
+    "V" gnus-version
+    "s" gnus-group-save-newsrc
+    "z" gnus-group-suspend
+    "Z" gnus-group-clear-dribble
+    "q" gnus-group-exit
+    "Q" gnus-group-quit
+    "?" gnus-group-describe-briefly
+    "\C-c\C-i" gnus-info-find-node
+    "\M-e" gnus-group-edit-group-method
+    "^" gnus-group-enter-server-mode
+    gnus-mouse-2 gnus-mouse-pick-group
+    "<" beginning-of-buffer
+    ">" end-of-buffer
+    "\C-c\C-b" gnus-bug
+    "\C-c\C-s" gnus-group-sort-groups
+    "t" gnus-topic-mode
+    "\C-c\M-g" gnus-activate-all-groups
+    "\M-&" gnus-group-universal-argument
+    "#" gnus-group-mark-group
+    "\M-#" gnus-group-unmark-group)
+
+  (gnus-define-keys (gnus-group-mark-map "M" gnus-group-mode-map)
+    "m" gnus-group-mark-group
+    "u" gnus-group-unmark-group
+    "w" gnus-group-mark-region
+    "m" gnus-group-mark-buffer
+    "r" gnus-group-mark-regexp
+    "U" gnus-group-unmark-all-groups)
+
+  (gnus-define-keys (gnus-group-group-map "G" gnus-group-mode-map)
+    "d" gnus-group-make-directory-group
+    "h" gnus-group-make-help-group
+    "a" gnus-group-make-archive-group
+    "k" gnus-group-make-kiboze-group
+    "m" gnus-group-make-group
+    "E" gnus-group-edit-group
+    "e" gnus-group-edit-group-method
+    "p" gnus-group-edit-group-parameters
+    "v" gnus-group-add-to-virtual
+    "V" gnus-group-make-empty-virtual
+    "D" gnus-group-enter-directory
+    "f" gnus-group-make-doc-group
+    "r" gnus-group-rename-group
+    "\177" gnus-group-delete-group
+    [delete] gnus-group-delete-group)
+
+   (gnus-define-keys (gnus-group-soup-map "s" gnus-group-group-map)
+     "b" gnus-group-brew-soup
+     "w" gnus-soup-save-areas
+     "s" gnus-soup-send-replies
+     "p" gnus-soup-pack-packet
+     "r" nnsoup-pack-replies)
+
+   (gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
+     "s" gnus-group-sort-groups
+     "a" gnus-group-sort-groups-by-alphabet
+     "u" gnus-group-sort-groups-by-unread
+     "l" gnus-group-sort-groups-by-level
+     "v" gnus-group-sort-groups-by-score
+     "r" gnus-group-sort-groups-by-rank
+     "m" gnus-group-sort-groups-by-method)
+
+   (gnus-define-keys (gnus-group-list-map "A" gnus-group-mode-map)
+     "k" gnus-group-list-killed
+     "z" gnus-group-list-zombies
+     "s" gnus-group-list-groups
+     "u" gnus-group-list-all-groups
+     "A" gnus-group-list-active
+     "a" gnus-group-apropos
+     "d" gnus-group-description-apropos
+     "m" gnus-group-list-matching
+     "M" gnus-group-list-all-matching
+     "l" gnus-group-list-level)
+
+   (gnus-define-keys (gnus-group-score-map "W" gnus-group-mode-map)
+     "f" gnus-score-flush-cache)
+
+   (gnus-define-keys (gnus-group-help-map "H" gnus-group-mode-map)
+     "f" gnus-group-fetch-faq)
+
+   (gnus-define-keys (gnus-group-sub-map "S" gnus-group-mode-map)
+     "l" gnus-group-set-current-level
+     "t" gnus-group-unsubscribe-current-group
+     "s" gnus-group-unsubscribe-group
+     "k" gnus-group-kill-group
+     "y" gnus-group-yank-group
+     "w" gnus-group-kill-region
+     "\C-k" gnus-group-kill-level
+     "z" gnus-group-kill-all-zombies))
 
 (defun gnus-group-mode ()
   "Major mode for reading news.
 
 All normal editing commands are switched off.
 \\<gnus-group-mode-map>
-The group buffer lists (some of) the groups available.  For instance,
+The group buffer lists (some of) the groups available. For instance,
 `\\[gnus-group-list-groups]' will list all subscribed groups with unread articles, while `\\[gnus-group-list-zombies]'
-lists all zombie groups. 
+lists all zombie groups.
 
-Groups that are displayed can be entered with `\\[gnus-group-read-group]'.  To subscribe 
-to a group not displayed, type `\\[gnus-group-unsubscribe-group]'. 
+Groups that are displayed can be entered with `\\[gnus-group-read-group]'.  To subscribe
+to a group not displayed, type `\\[gnus-group-unsubscribe-group]'.
 
-For more in-depth information on this mode, read the manual (`\\[gnus-info-find-node]'). 
+For more in-depth information on this mode, read the manual (`\\[gnus-info-find-node]').
 
 The following commands are available:
 
 \\{gnus-group-mode-map}"
   (interactive)
-  (if gnus-visual (gnus-group-make-menu-bar))
+  (when (and menu-bar-mode
+            (gnus-visual-p 'group-menu 'menu))
+    (gnus-group-make-menu-bar))
   (kill-all-local-variables)
-  (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) ""))
+  (gnus-simplify-mode-line)
   (setq major-mode 'gnus-group-mode)
   (setq mode-name "Group")
   (gnus-group-set-mode-line)
@@ -3215,6 +4264,7 @@ The following commands are available:
   (run-hooks 'gnus-group-mode-hook))
 
 (defun gnus-mouse-pick-group (e)
+  "Enter the group under the mouse pointer."
   (interactive "e")
   (mouse-set-point e)
   (gnus-group-read-group nil))
@@ -3223,45 +4273,72 @@ The following commands are available:
 ;; If LEVEL is non-nil, LEVEL will be returned, if not, what happens
 ;; will depend on whether `gnus-group-use-permanent-levels' is used.
 (defun gnus-group-default-level (&optional level number-or-nil)
-  (cond  
+  (cond
    (gnus-group-use-permanent-levels
-    (setq gnus-group-default-list-level 
-         (or level gnus-group-default-list-level))
-    (or gnus-group-default-list-level gnus-level-subscribed))
+    (or (setq gnus-group-use-permanent-levels
+             (or level (if (numberp gnus-group-use-permanent-levels)
+                           gnus-group-use-permanent-levels
+                         (or gnus-group-default-list-level
+                             gnus-level-subscribed))))
+       gnus-group-default-list-level gnus-level-subscribed))
    (number-or-nil
     level)
    (t
     (or level gnus-group-default-list-level gnus-level-subscribed))))
-  
 
 ;;;###autoload
-(defun gnus-no-server (&optional arg)
+(defun gnus-slave-no-server (&optional arg)
+  "Read network news as a slave, without connecting to local server"
+  (interactive "P")
+  (gnus-no-server arg t))
+
+;;;###autoload
+(defun gnus-no-server (&optional arg slave)
   "Read network news.
 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. 
+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")
-  (setq gnus-group-use-permanent-levels t)
-  (gnus (or arg (1- gnus-level-default-subscribed)) t))
+  (let ((val (or arg (1- gnus-level-default-subscribed))))
+    (gnus val t slave)
+    (make-local-variable 'gnus-group-use-permanent-levels)
+    (setq gnus-group-use-permanent-levels val)))
+
+;;;###autoload
+(defun gnus-slave (&optional arg)
+  "Read news as a slave."
+  (interactive "P")
+  (gnus arg nil 'slave))
+
+;;;###autoload
+(defun gnus-other-frame (&optional arg)
+  "Pop up a frame to read news."
+  (interactive "P")
+  (if (get-buffer gnus-group-buffer)
+      (let ((pop-up-frames t))
+       (gnus arg))
+    (select-frame (make-frame))
+    (gnus arg)))
 
 ;;;###autoload
-(defun gnus (&optional arg dont-connect)
+(defun gnus (&optional arg dont-connect slave)
   "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
+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")
+
   (if (get-buffer gnus-group-buffer)
       (progn
        (switch-to-buffer gnus-group-buffer)
        (gnus-group-get-new-news))
 
     (gnus-clear-system)
-
     (nnheader-init-server-buffer)
     (gnus-read-init-file)
+    (setq gnus-slave slave)
 
     (gnus-group-setup-buffer)
     (let ((buffer-read-only nil))
@@ -3270,31 +4347,40 @@ prompt the user for the name of an NNTP server to use."
          (progn
            (gnus-group-startup-message)
            (sit-for 0))))
-    
-    (let ((level (and arg (numberp arg) (> arg 0) arg))
+
+    (let ((level (and (numberp arg) (> arg 0) arg))
          did-connect)
       (unwind-protect
          (progn
-           (or dont-connect 
+           (or dont-connect
                (setq did-connect
                      (gnus-start-news-server (and arg (not level))))))
-       (if (and (not dont-connect) 
+       (if (and (not dont-connect)
                 (not did-connect))
            (gnus-group-quit)
          (run-hooks 'gnus-startup-hook)
-         ;; NNTP server is successfully open. 
+         ;; NNTP server is successfully open.
 
          ;; Find the current startup file name.
-         (setq gnus-current-startup-file 
+         (setq gnus-current-startup-file
                (gnus-make-newsrc-file gnus-startup-file))
 
          ;; Read the dribble file.
-         (and gnus-use-dribble-file (gnus-dribble-read-file))
+         (and (or gnus-slave gnus-use-dribble-file) (gnus-dribble-read-file))
+
+         ;; Allow using GroupLens predictions.
+         (when gnus-use-grouplens
+           (bbb-login)
+           (add-hook 'gnus-summary-mode-hook 'gnus-grouplens-mode))
 
          (gnus-summary-make-display-table)
-         (gnus-setup-news nil level)
+         ;; Do the actual startup.
+         (gnus-setup-news nil level dont-connect)
+         ;; Generate the group buffer.
          (gnus-group-list-groups level)
-         (gnus-configure-windows 'group))))))
+         (gnus-group-first-unread-group)
+         (gnus-configure-windows 'group)
+         (gnus-group-set-mode-line))))))
 
 (defun gnus-unload ()
   "Unload all Gnus features."
@@ -3304,89 +4390,88 @@ prompt the user for the name of an NNTP server to use."
   (let ((history load-history)
        feature)
     (while history
-      (and (string-match "^gnus" (car (car history)))
+      (and (string-match "^\\(gnus\\|nn\\)" (caar history))
           (setq feature (cdr (assq 'provide (car history))))
           (unload-feature feature 'force))
       (setq history (cdr history)))))
 
+(defun gnus-compile ()
+  "Byte-compile the user-defined format specs."
+  (interactive)
+  (let ((entries gnus-format-specs)
+       entry gnus-tmp-func)
+    (save-excursion
+      (gnus-message 7 "Compiling format specs...")
+
+      (while entries
+       (setq entry (pop entries))
+       (if (eq (car entry) 'version)
+           (setq gnus-format-specs (delq entry gnus-format-specs))
+         (when (and (listp (caddr entry))
+                    (not (eq 'byte-code (caaddr entry))))
+           (fset 'gnus-tmp-func
+                 `(lambda () ,(caddr entry)))
+           (byte-compile 'gnus-tmp-func)
+           (setcar (cddr entry) (gnus-byte-code 'gnus-tmp-func)))))
+
+      (push (cons 'version emacs-version) gnus-format-specs)
+
+      (gnus-message 7 "Compiling user specs...done"))))
+
+(defun gnus-indent-rigidly (start end arg)
+  "Indent rigidly using only spaces and no tabs."
+  (save-excursion
+    (save-restriction
+      (narrow-to-region start end)
+      (indent-rigidly start end arg)
+      (goto-char (point-min))
+      (while (search-forward "\t" nil t)
+       (replace-match "        " t t)))))
+
 (defun gnus-group-startup-message (&optional x y)
   "Insert startup message in current buffer."
   ;; Insert the message.
   (erase-buffer)
   (insert
-   (format "
-          _    ___ _             _      
-          _ ___ __ ___  __    _ ___     
-          __   _     ___    __  ___     
-              _           ___     _     
-             _  _ __             _      
-             ___   __            _      
-                   __           _       
-                    _      _   _        
-                   _      _    _        
-                      _  _    _         
-                  __  ___               
-                 _   _ _     _          
-                _   _                   
-              _    _                    
-             _    _                     
-            _                         
-          __                             
-
-
-      Gnus * A newsreader for Emacsen
-    A Praxis release * larsi@ifi.uio.no
-" 
-          gnus-version))
+   (format "              %s
+          _    ___ _             _
+          _ ___ __ ___  __    _ ___
+          __   _     ___    __  ___
+              _           ___     _
+             _  _ __             _
+             ___   __            _
+                   __           _
+                    _      _   _
+                   _      _    _
+                      _  _    _
+                  __  ___
+                 _   _ _     _
+                _   _
+              _    _
+             _    _
+            _
+          __
+
+"
+           ""))
   ;; And then hack it.
-  ;; 18 is the longest line.
-  (indent-rigidly (point-min) (point-max) 
-                 (/ (max (- (window-width) (or x 46)) 0) 2))
+  (gnus-indent-rigidly (point-min) (point-max)
+                      (/ (max (- (window-width) (or x 46)) 0) 2))
   (goto-char (point-min))
+  (forward-line 1)
   (let* ((pheight (count-lines (point-min) (point-max)))
         (wheight (window-height))
-        (rest (- wheight  pheight)))
+        (rest (- wheight pheight)))
     (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
-    
-    
-
   ;; Fontify some.
   (goto-char (point-min))
-  (search-forward "Praxis")
-  (put-text-property (match-beginning 0) (match-end 0) 'face 'bold)
-  (goto-char (point-min)))
-
-(defun gnus-group-startup-message-old (&optional x y)
-  "Insert startup message in current buffer."
-  ;; Insert the message.
-  (erase-buffer)
-  (insert
-   (format "
-     %s
-           A newsreader 
-      for GNU Emacs
-
-        Based on GNUS 
-             written by 
-     Masanobu UMEDA
-
-       A Praxis Release
-      larsi@ifi.uio.no
-" 
-          gnus-version))
-  ;; And then hack it.
-  ;; 18 is the longest line.
-  (indent-rigidly (point-min) (point-max) 
-                 (/ (max (- (window-width) (or x 28)) 0) 2))
-  (goto-char (point-min))
-  ;; +4 is fuzzy factor.
-  (insert-char ?\n (/ (max (- (window-height) (or y 12)) 0) 2))
-
-  ;; Fontify some.
+  (and (search-forward "Praxis" nil t)
+       (gnus-put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
   (goto-char (point-min))
-  (search-forward "Praxis")
-  (put-text-property (match-beginning 0) (match-end 0) 'face 'bold)
-  (goto-char (point-min)))
+  (let* ((mode-string (gnus-group-set-mode-line)))
+    (setq mode-line-buffer-identification
+         (list (concat gnus-version (substring (car mode-string) 4))))
+    (set-buffer-modified-p t)))
 
 (defun gnus-group-setup-buffer ()
   (or (get-buffer gnus-group-buffer)
@@ -3396,11 +4481,11 @@ prompt the user for the name of an NNTP server to use."
        (gnus-group-mode)
        (and gnus-carpal (gnus-carpal-setup-buffer 'group)))))
 
-(defun gnus-group-list-groups (&optional level unread)
+(defun gnus-group-list-groups (&optional level unread lowest)
   "List newsgroups with level LEVEL or lower that have unread articles.
 Default is all subscribed groups.
 If argument UNREAD is non-nil, groups with no unread articles are also
-listed." 
+listed."
   (interactive (list (if current-prefix-arg
                         (prefix-numeric-value current-prefix-arg)
                       (or
@@ -3412,35 +4497,49 @@ listed."
            unread (cdr gnus-group-list-mode)))
   (setq level (gnus-group-default-level level))
   (gnus-group-setup-buffer)            ;May call from out of group buffer
+  (gnus-update-format-specifications)
   (let ((case-fold-search nil)
+       (props (text-properties-at (gnus-point-at-bol)))
        (group (gnus-group-group-name)))
-    (funcall gnus-group-prepare-function level unread nil)
+    (set-buffer gnus-group-buffer)
+    (funcall gnus-group-prepare-function level unread lowest)
     (if (zerop (buffer-size))
        (gnus-message 5 gnus-no-groups-message)
-      (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 (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 (gnus-goto-char 
-                               (text-property-any 
-                                (point-min) (point-max) 'gnus-group 
-                                (intern (car (car newsrc)))))))
-               (setq newsrc (cdr newsrc)))
-             (or newsrc (progn (goto-char (point-max))
-                               (forward-line -1))))))
+      (goto-char (point-max))
+      (when (or (not gnus-group-goto-next-group-function)
+               (not (funcall gnus-group-goto-next-group-function 
+                             group props)))
+       (if (not group)
+           ;; Go to the first group with unread articles.
+           (gnus-group-search-forward t)
+         ;; Find the right group to put point on.  If the current group
+         ;; has disappeared 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 (gnus-goto-char
+                   (text-property-any
+                    (point-min) (point-max)
+                    'gnus-group (gnus-intern-safe group gnus-active-hashtb))))
+             (let ((newsrc (cdddr (gnus-gethash group gnus-newsrc-hashtb))))
+               (while (and newsrc
+                           (not (gnus-goto-char
+                                 (text-property-any
+                                  (point-min) (point-max) 'gnus-group
+                                  (gnus-intern-safe
+                                   (caar newsrc) gnus-active-hashtb)))))
+                 (setq newsrc (cdr newsrc)))
+               (or newsrc (progn (goto-char (point-max))
+                                 (forward-line -1)))))))
       ;; Adjust cursor point.
-      (gnus-group-position-cursor))))
+      (gnus-group-position-point))))
 
-(defun gnus-group-prepare-flat (level &optional all lowest regexp) 
+(defun gnus-group-list-level (level &optional all)
+  "List groups on LEVEL.
+If ALL (the prefix), also list groups that have no unread articles."
+  (interactive "nList groups on level: \nP")
+  (gnus-group-list-groups level all level))
+
+(defun gnus-group-prepare-flat (level &optional all lowest regexp)
   "List all newsgroups with unread articles of level LEVEL or lower.
 If ALL is non-nil, list groups that have no unread articles.
 If LOWEST is non-nil, list all newsgroups of level LOWEST or higher.
@@ -3449,36 +4548,47 @@ If REGEXP, only list groups matching REGEXP."
   (let ((buffer-read-only nil)
        (newsrc (cdr gnus-newsrc-alist))
        (lowest (or lowest 1))
-       info clevel unread group)
+       info clevel unread group params)
     (erase-buffer)
     (if (< lowest gnus-level-zombie)
        ;; List living groups.
        (while newsrc
          (setq info (car newsrc)
-               group (car info)
+               group (gnus-info-group info)
+               params (gnus-info-params info)
                newsrc (cdr newsrc)
                unread (car (gnus-gethash group gnus-newsrc-hashtb)))
          (and unread                   ; This group might be bogus
               (or (not regexp)
                   (string-match regexp group))
-              (<= (setq clevel (car (cdr info))) level) 
+              (<= (setq clevel (gnus-info-level info)) level)
               (>= clevel lowest)
               (or all                  ; We list all groups?
-                  (eq unread t)        ; We list unactivated groups
-                  (> unread 0)         ; We list groups with unread articles
-                  (cdr (assq 'tick (nth 3 info)))) ; And groups with tickeds
-              (gnus-group-insert-group-line 
-               nil group (car (cdr info)) (nth 3 info) unread (nth 4 info)))))
+                  (if (eq unread t)    ; Unactivated?
+                      gnus-group-list-inactive-groups ; We list unactivated 
+                    (> unread 0))      ; We list groups with unread articles
+                  (and gnus-list-groups-with-ticked-articles
+                       (cdr (assq 'tick (gnus-info-marks info))))
+                                       ; And groups with tickeds
+                  ;; Check for permanent visibility.
+                  (and gnus-permanently-visible-groups
+                       (string-match gnus-permanently-visible-groups
+                                     group))
+                  (memq 'visible params)
+                  (cdr (assq 'visible params)))
+              (gnus-group-insert-group-line
+               group (gnus-info-level info)
+               (gnus-info-marks info) unread (gnus-info-method info)))))
 
     ;; List dead groups.
     (and (>= level gnus-level-zombie) (<= lowest gnus-level-zombie)
-        (gnus-group-prepare-flat-list-dead 
-         (setq gnus-zombie-list (sort gnus-zombie-list 'string<)) 
+        (gnus-group-prepare-flat-list-dead
+         (setq gnus-zombie-list (sort gnus-zombie-list 'string<))
          gnus-level-zombie ?Z
          regexp))
     (and (>= level gnus-level-killed) (<= lowest gnus-level-killed)
-        (gnus-group-prepare-flat-list-dead 
-         (setq gnus-killed-list (sort gnus-killed-list 'string<)) 
+        (gnus-group-prepare-flat-list-dead
+         (setq gnus-killed-list (sort gnus-killed-list 'string<))
          gnus-level-killed ?K regexp))
 
     (gnus-group-set-mode-line)
@@ -3486,36 +4596,120 @@ If REGEXP, only list groups matching REGEXP."
     (run-hooks 'gnus-group-prepare-hook)))
 
 (defun gnus-group-prepare-flat-list-dead (groups level mark regexp)
-  ;; List zombies and killed lists somehwat faster, which was
-  ;; suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>. It does
+  ;; List zombies and killed lists somewhat faster, which was
+  ;; suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.  It does
   ;; this by ignoring the group format specification altogether.
-  (let (group beg)
-    (while groups
-      (setq group (car groups)
-           groups (cdr groups))
-      (if (or (not regexp)
-             (string-match regexp group))
-         (progn
-           (setq beg (point))
-           (insert (format " %c     *: %s\n" mark group))
-           (add-text-properties 
-            beg (1+ beg) 
-            (list 'gnus-group (intern group)
+  (let (group)
+    (if regexp
+       ;; This loop is used when listing groups that match some
+       ;; regexp.
+       (while groups
+         (setq group (pop groups))
+         (when (string-match regexp group)
+           (gnus-add-text-properties
+            (point) (prog1 (1+ (point))
+                      (insert " " mark "     *: " group "\n"))
+            (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
                   'gnus-unread t
-                  'gnus-level level)))))))
-
-(defun gnus-group-real-name (group)
+                  'gnus-level level))))
+      ;; This loop is used when listing all groups.
+      (while groups
+       (gnus-add-text-properties
+        (point) (prog1 (1+ (point))
+                  (insert " " mark "     *: "
+                          (setq group (pop groups)) "\n"))
+        (list 'gnus-group (gnus-intern-safe group gnus-active-hashtb)
+              'gnus-unread t
+              'gnus-level level))))))
+
+(defmacro gnus-group-real-name (group)
   "Find the real name of a foreign newsgroup."
-  (if (string-match ":[^:]+$" group)
-      (substring group (1+ (match-beginning 0)))
-    group))
+  `(let ((gname ,group))
+     (if (string-match ":[^:]+$" gname)
+        (substring gname (1+ (match-beginning 0)))
+       gname)))
+
+(defsubst gnus-server-add-address (method)
+  (let ((method-name (symbol-name (car method))))
+    (if (and (memq 'address (assoc method-name gnus-valid-select-methods))
+            (not (assq (intern (concat method-name "-address")) method)))
+       (append method (list (list (intern (concat method-name "-address"))
+                                  (nth 1 method))))
+      method)))
+
+(defsubst gnus-server-get-method (group method)
+  ;; Input either a server name, and extended server name, or a
+  ;; select method, and return a select method.
+  (cond ((stringp method)
+        (gnus-server-to-method method))
+       ((equal method gnus-select-method)
+        gnus-select-method)
+       ((and (stringp (car method)) group)
+        (gnus-server-extend-method group method))
+       ((and method (not group)
+             (equal (cadr method) ""))
+        method)
+       (t
+        (gnus-server-add-address method))))
+
+(defun gnus-server-to-method (server)
+  "Map virtual server names to select methods."
+  (or 
+   ;; Is this a method, perhaps?
+   (and server (listp server) server)
+   ;; Perhaps this is the native server?
+   (and (equal server "native") gnus-select-method)
+   ;; It should be in the server alist.
+   (cdr (assoc server gnus-server-alist))
+   ;; If not, we look through all the opened server
+   ;; to see whether we can find it there.
+   (let ((opened gnus-opened-servers))
+     (while (and opened
+                (not (equal server (format "%s:%s" (caaar opened)
+                                           (cadaar opened)))))
+       (pop opened))
+     (caar opened))))
+
+(defmacro gnus-method-equal (ss1 ss2)
+  "Say whether two servers are equal."
+  `(let ((s1 ,ss1)
+        (s2 ,ss2))
+     (or (equal s1 s2)
+        (and (= (length s1) (length s2))
+             (progn
+               (while (and s1 (member (car s1) s2))
+                 (setq s1 (cdr s1)))
+               (null s1))))))
+
+(defun gnus-server-equal (m1 m2)
+  "Say whether two methods are equal."
+  (let ((m1 (cond ((null m1) gnus-select-method)
+                 ((stringp m1) (gnus-server-to-method m1))
+                 (t m1)))
+       (m2 (cond ((null m2) gnus-select-method)
+                 ((stringp m2) (gnus-server-to-method m2))
+                 (t m2))))
+    (gnus-method-equal m1 m2)))
+
+(defun gnus-servers-using-backend (backend)
+  "Return a list of known servers using BACKEND."
+  (let ((opened gnus-opened-servers)
+       out)
+    (while opened
+      (when (eq backend (caaar opened))
+       (push (caar opened) out))
+      (pop opened))
+    out))
 
 (defun gnus-group-prefixed-name (group method)
   "Return the whole name from GROUP and METHOD."
   (and (stringp method) (setq method (gnus-server-to-method method)))
   (concat (format "%s" (car method))
-         (if (and 
-              (assoc (format "%s" (car method)) (gnus-methods-using 'address))
+         (if (and
+              (or (assoc (format "%s" (car method)) 
+                         (gnus-methods-using 'address))
+                  (gnus-server-equal method gnus-message-archive-method))
+              (nth 1 method)
               (not (string= (nth 1 method) "")))
              (concat "+" (nth 1 method)))
          ":" group))
@@ -3526,86 +4720,156 @@ If REGEXP, only list groups matching REGEXP."
       (substring group 0 (match-end 0))
     ""))
 
-(defun gnus-group-method-name (group)
-  "Return the method used for selecting GROUP."
+(defun gnus-group-method (group)
+  "Return the server or 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)))) "")))))
+      (let ((servers gnus-opened-servers)
+           (server "")
+           backend possible found)
+       (if (string-match "^[^\\+]+\\+" prefix)
+           (setq backend (intern (substring prefix 0 (1- (match-end 0))))
+                 server (substring prefix (match-end 0) (1- (length prefix))))
+         (setq backend (intern (substring prefix 0 (1- (length prefix))))))
+       (while servers
+         (when (eq (caaar servers) backend)
+           (setq possible (caar servers))
+           (when (equal (cadaar servers) server)
+             (setq found (caar servers))))
+         (pop servers))
+       (or (car (rassoc found gnus-server-alist))
+           found
+           (car (rassoc possible gnus-server-alist))
+           possible
+           (list backend server))))))
+
+(defsubst gnus-secondary-method-p (method)
+  "Return whether METHOD is a secondary select method."
+  (let ((methods gnus-secondary-select-methods)
+       (gmethod (gnus-server-get-method nil method)))
+    (while (and methods
+               (not (equal (gnus-server-get-method nil (car methods))
+                           gmethod)))
+      (setq methods (cdr methods)))
+    methods))
 
 (defun gnus-group-foreign-p (group)
-  "Return nil if GROUP is native, non-nil if it is foreign."
-  (string-match ":" group))
+  "Say whether a group is foreign or not."
+  (and (not (gnus-group-native-p group))
+       (not (gnus-group-secondary-p group))))
+
+(defun gnus-group-native-p (group)
+  "Say whether the group is native or not."
+  (not (string-match ":" group)))
+
+(defun gnus-group-secondary-p (group)
+  "Say whether the group is secondary or not."
+  (gnus-secondary-method-p (gnus-find-method-for-group group)))
+
+(defun gnus-group-get-parameter (group &optional symbol)
+  "Returns the group parameters for GROUP.
+If SYMBOL, return the value of that symbol in the group parameters."
+  (let ((params (gnus-info-params (gnus-get-info group))))
+    (if symbol
+       (gnus-group-parameter-value params symbol)
+      params)))
+
+(defun gnus-group-parameter-value (params symbol)
+  "Return the value of SYMBOL in group PARAMS."
+  (or (car (memq symbol params))       ; It's either a simple symbol
+      (cdr (assq symbol params))))     ; or a cons.
+
+(defun gnus-group-add-parameter (group param)
+  "Add parameter PARAM to GROUP."
+  (let ((info (gnus-get-info group)))
+    (if (not info)
+       () ; This is a dead group.  We just ignore it.
+      ;; Cons the new param to the old one and update.
+      (gnus-group-set-info (cons param (gnus-info-params info))
+                          group 'params))))
+
+(defun gnus-group-set-parameter (group name value)
+  "Set parameter NAME to VALUE in GROUP."
+  (let ((info (gnus-get-info group)))
+    (if (not info)
+       () ; This is a dead group.  We just ignore it.
+      (let ((old-params (gnus-info-params info))
+           (new-params (list (cons name value))))
+       (while old-params
+         (if (or (not (listp (car old-params)))
+                 (not (eq (caar old-params) name)))
+             (setq new-params (append new-params (list (car old-params)))))
+         (setq old-params (cdr old-params)))
+       (gnus-group-set-info new-params group 'params)))))
+
+(defun gnus-group-add-score (group &optional score)
+  "Add SCORE to the GROUP score.
+If SCORE is nil, add 1 to the score of GROUP."
+  (let ((info (gnus-get-info group)))
+    (when info
+      (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
+
+(defun gnus-summary-bubble-group ()
+  "Increase the score of the current group.
+This is a handy function to add to `gnus-summary-exit-hook' to
+increase the score of each group you read."
+  (gnus-group-add-score gnus-newsgroup-name))
 
 (defun gnus-group-set-info (info &optional method-only-group part)
   (let* ((entry (gnus-gethash
-                (or method-only-group (car info)) gnus-newsrc-hashtb))
+                (or method-only-group (gnus-info-group info))
+                gnus-newsrc-hashtb))
         (part-info info)
-        (info (if method-only-group (nth 2 entry) info)))
-    (if (not method-only-group)
-       ()
-      (or entry
-         (error "Trying to change non-existent group %s" method-only-group))
-      ;; We have recevied parts of the actual group info - either the
-      ;; select method or the group parameters.  We first check
+        (info (if method-only-group (nth 2 entry) info))
+        method)
+    (when method-only-group
+      (unless entry
+       (error "Trying to change non-existent group %s" method-only-group))
+      ;; We have received parts of the actual group info - either the
+      ;; select method or the group parameters.         We first check
       ;; whether we have to extend the info, and if so, do that.
       (let ((len (length info))
            (total (if (eq part 'method) 5 6)))
-       (and (< len total)
-            (setcdr (nthcdr (1- len) info)
-                    (make-list (- total len) nil)))
+       (when (< len total)
+         (setcdr (nthcdr (1- len) info)
+                 (make-list (- total len) nil)))
        ;; Then we enter the new info.
        (setcar (nthcdr (1- total) info) part-info)))
-    ;; We uncompress some lists of marked articles.
-    (let (marked)
-      (if (not (setq marked (nth 3 info)))
-         ()
-       (while marked
-         (or (eq 'score (car (car marked)))
-             (eq 'bookmark (car (car marked)))
-             (eq 'killed (car (car marked)))
-             (setcdr (car marked) 
-                     (gnus-uncompress-range (cdr (car marked)))))
-         (setq marked (cdr marked)))))
-    (if entry
-       ()
+    (unless entry
       ;; This is a new group, so we just create it.
       (save-excursion
        (set-buffer gnus-group-buffer)
-       (if (nth 4 info)
-           ;; It's a foreign group...
-           (gnus-group-make-group 
-            (gnus-group-real-name (car info))
-            (prin1-to-string (car (nth 4 info)))
-            (nth 1 (nth 4 info)))
-         ;; It's a native group.
-         (gnus-group-make-group
-          (car info)
-          (prin1-to-string (car gnus-select-method))
-          (nth 1 gnus-select-method)))
+       (setq method (gnus-info-method info))
+       (when (gnus-server-equal method "native")
+         (setq method nil))
+       (save-excursion
+         (set-buffer gnus-group-buffer)
+         (if method
+             ;; It's a foreign group...
+             (gnus-group-make-group
+              (gnus-group-real-name (gnus-info-group info))
+              (if (stringp method) method
+                (prin1-to-string (car method)))
+              (and (consp method)
+                   (nth 1 (gnus-info-method info))))
+           ;; It's a native group.
+           (gnus-group-make-group (gnus-info-group info))))
        (gnus-message 6 "Note: New group created")
-       (setq entry 
-             (gnus-gethash (gnus-group-prefixed-name 
-                            (gnus-group-real-name (car info))
-                            (or (nth 4 info) gnus-select-method))
+       (setq entry
+             (gnus-gethash (gnus-group-prefixed-name
+                            (gnus-group-real-name (gnus-info-group info))
+                            (or (gnus-info-method info) gnus-select-method))
                            gnus-newsrc-hashtb))))
     ;; Whether it was a new group or not, we now have the entry, so we
     ;; can do the update.
     (if entry
        (progn
          (setcar (nthcdr 2 entry) info)
-         (if (and (not (eq (car entry) t)) 
-                  (gnus-gethash (car info) gnus-active-hashtb))
-             (let ((marked (nth 3 info)))
-               (setcar entry 
-                       (max 0 (- (length (gnus-list-of-unread-articles 
-                                          (car info)))
-                                 (length (cdr (assq 'tick marked)))
-                                 (length (cdr (assq 'dormant marked)))))))))
-      (error "No such group: %s" (car info)))))
+         (when (and (not (eq (car entry) t))
+                    (gnus-active (gnus-info-group info)))
+           (setcar entry (length (gnus-list-of-unread-articles (car info))))))
+      (error "No such group: %s" (gnus-info-group info)))))
 
 (defun gnus-group-set-method-info (group select-method)
   (gnus-group-set-info select-method group 'method))
@@ -3614,157 +4878,196 @@ If REGEXP, only list groups matching REGEXP."
   (gnus-group-set-info params group 'params))
 
 (defun gnus-group-update-group-line ()
-  "This function updates the current line in the newsgroup buffer and
-moves the point to the colon."
+  "Update the current line in the group buffer."
   (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) (progn (forward-line 1) (point)))
+        (entry (and group (gnus-gethash group gnus-newsrc-hashtb)))
+        gnus-group-indentation)
+    (and entry
+        (not (gnus-ephemeral-group-p group))
+        (gnus-dribble-enter
+         (concat "(gnus-group-set-info '"
+                 (prin1-to-string (nth 2 entry)) ")")))
+    (setq gnus-group-indentation (gnus-group-group-indentation))
+    (gnus-delete-line)
     (gnus-group-insert-group-line-info group)
     (forward-line -1)
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 (defun gnus-group-insert-group-line-info (group)
-  (let ((entry (gnus-gethash group gnus-newsrc-hashtb)) 
+  "Insert GROUP on the current line."
+  (let ((entry (gnus-gethash group gnus-newsrc-hashtb))
        active info)
     (if entry
        (progn
+         ;; (Un)subscribed group.
          (setq info (nth 2 entry))
-         (gnus-group-insert-group-line 
-          nil group (nth 1 info) (nth 3 info) (car entry) (nth 4 info)))
-      (setq active (gnus-gethash group gnus-active-hashtb))
-      (gnus-group-insert-group-line 
-       nil group 
+         (gnus-group-insert-group-line
+          group (gnus-info-level info) (gnus-info-marks info)
+          (or (car entry) t) (gnus-info-method info)))
+      ;; This group is dead.
+      (gnus-group-insert-group-line
+       group
        (if (member group gnus-zombie-list) gnus-level-zombie gnus-level-killed)
-       nil (if active (- (1+ (cdr active)) (car active)) 0) nil))))
-
-(defun gnus-group-insert-group-line (gformat group level marked number method)
-  (let* ((gformat (or gformat gnus-group-line-format-spec))
-        (active (gnus-gethash group gnus-active-hashtb))
-        (number-total (if active (1+ (- (cdr active) (car active))) 0))
-        (number-of-dormant (length (cdr (assq 'dormant marked))))
-        (number-of-ticked (length (cdr (assq 'tick marked))))
-        (number-of-ticked-and-dormant
-         (+ number-of-ticked number-of-dormant))
-        (number-of-unread-unticked 
+       nil
+       (if (setq active (gnus-active group))
+          (- (1+ (cdr active)) (car active)) 0)
+       nil))))
+
+(defun gnus-group-insert-group-line (gnus-tmp-group gnus-tmp-level 
+                                                   gnus-tmp-marked number
+                                                   gnus-tmp-method)
+  "Insert a group line in the group buffer."
+  (let* ((gnus-tmp-active (gnus-active gnus-tmp-group))
+        (gnus-tmp-number-total
+         (if gnus-tmp-active
+             (1+ (- (cdr gnus-tmp-active) (car gnus-tmp-active)))
+           0))
+        (gnus-tmp-number-of-unread
          (if (numberp number) (int-to-string (max 0 number))
            "*"))
-        (number-of-read
+        (gnus-tmp-number-of-read
          (if (numberp number)
-             (max 0 (- number-total number))
+             (int-to-string (max 0 (- gnus-tmp-number-total number)))
            "*"))
-        (subscribed (cond ((<= level gnus-level-subscribed) ? )
-                          ((<= level gnus-level-unsubscribed) ?U)
-                          ((= level gnus-level-zombie) ?Z)
-                          (t ?K)))
-        (qualified-group (gnus-group-real-name group))
-        (newsgroup-description 
+        (gnus-tmp-subscribed
+         (cond ((<= gnus-tmp-level gnus-level-subscribed) ? )
+               ((<= gnus-tmp-level gnus-level-unsubscribed) ?U)
+               ((= gnus-tmp-level gnus-level-zombie) ?Z)
+               (t ?K)))
+        (gnus-tmp-qualified-group (gnus-group-real-name gnus-tmp-group))
+        (gnus-tmp-newsgroup-description
          (if gnus-description-hashtb
-             (or (gnus-gethash group gnus-description-hashtb) "")
+             (or (gnus-gethash gnus-tmp-group gnus-description-hashtb) "")
            ""))
-        (moderated (if (member group gnus-moderated-list) ?m ? ))
-        (moderated-string (if (eq moderated ?m) "(m)" ""))
-        (method (gnus-server-get-method group method))
-        (news-server (or (car (cdr method)) ""))
-        (news-method (or (car method) ""))
-        (news-method-string 
-         (if method (format "(%s:%s)" (car method) (car (cdr method))) ""))
-        (marked (if (and 
-                     (numberp number) 
-                     (zerop number)
-                     (> number-of-ticked 0))
-                    ?* ? ))
-        (number (if (eq number t) "*" (+ number number-of-dormant 
-                                         number-of-ticked)))
-        (process-marked (if (member group gnus-group-marked)
-                            gnus-process-mark ? ))
+        (gnus-tmp-moderated
+         (if (member gnus-tmp-group gnus-moderated-list) ?m ? ))
+        (gnus-tmp-moderated-string
+         (if (eq gnus-tmp-moderated ?m) "(m)" ""))
+        (gnus-tmp-method
+         (gnus-server-get-method gnus-tmp-group gnus-tmp-method))
+        (gnus-tmp-news-server (or (cadr gnus-tmp-method) ""))
+        (gnus-tmp-news-method (or (car gnus-tmp-method) ""))
+        (gnus-tmp-news-method-string
+         (if gnus-tmp-method
+             (format "(%s:%s)" (car gnus-tmp-method)
+                     (cadr gnus-tmp-method)) ""))
+        (gnus-tmp-marked-mark
+         (if (and (numberp number)
+                  (zerop number)
+                  (cdr (assq 'tick gnus-tmp-marked)))
+             ?* ? ))
+        (gnus-tmp-process-marked
+         (if (member gnus-tmp-group gnus-group-marked)
+             gnus-process-mark ? ))
+        (gnus-tmp-grouplens
+         (or (and gnus-use-grouplens
+                  (bbb-grouplens-group-p gnus-tmp-group))
+             ""))
         (buffer-read-only nil)
-        header                         ; passed as parameter to user-funcs.
-        b)
+        header gnus-tmp-header)        ; passed as parameter to user-funcs.
     (beginning-of-line)
-    (setq b (point))
-    ;; Insert the text.
-    (insert (eval gformat))
-
-    (add-text-properties 
-     b (1+ b) (list 'gnus-group (intern group)
-                   'gnus-unread (if (numberp number)
-                                    (string-to-int number-of-unread-unticked)
-                                  t)
-                   'gnus-marked marked
-                   'gnus-level level))))
+    (gnus-add-text-properties
+     (point)
+     (prog1 (1+ (point))
+       ;; Insert the text.
+       (eval gnus-group-line-format-spec))
+     `(gnus-group ,(gnus-intern-safe gnus-tmp-group gnus-active-hashtb)
+       gnus-unread ,(if (numberp number)
+                       (string-to-int gnus-tmp-number-of-unread)
+                     t)
+       gnus-marked ,gnus-tmp-marked-mark
+       gnus-indentation ,gnus-group-indentation
+       gnus-level ,gnus-tmp-level))
+    (when (inline (gnus-visual-p 'group-highlight 'highlight))
+      (forward-line -1)
+      (run-hooks 'gnus-group-update-hook)
+      (forward-line))
+    ;; Allow XEmacs to remove front-sticky text properties.
+    (gnus-group-remove-excess-properties)))
 
 (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."
+  "Update all lines where GROUP appear.
+If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't
+already."
   (save-excursion
     (set-buffer gnus-group-buffer)
-    (let ((buffer-read-only nil)
-         visible)
-      (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))))
+    ;; The buffer may be narrowed.
+    (save-restriction
+      (widen)
+      (let ((ident (gnus-intern-safe group gnus-active-hashtb))
+           (loc (point-min))
+           found buffer-read-only)
+       ;; Enter the current status into the dribble buffer.
+       (let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
+         (if (and entry (not (gnus-ephemeral-group-p group)))
+             (gnus-dribble-enter
+              (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
+                      ")"))))
+       ;; Find all group instances.  If topics are in use, each group
+       ;; may be listed in more than once.
+       (while (setq loc (text-property-any
+                         loc (point-max) 'gnus-group ident))
+         (setq found t)
+         (goto-char loc)
+         (let ((gnus-group-indentation (gnus-group-group-indentation)))
+           (gnus-delete-line)
+           (gnus-group-insert-group-line-info group))
+         (setq loc (1+ loc)))
+       (unless (or found visible-only)
          ;; 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 (cdr (gnus-gethash group gnus-newsrc-hashtb)))))
-               (while (and entry
-                           (car 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))
-         (gnus-group-insert-group-line-info group))
-      (gnus-group-set-mode-line))))
+         (if gnus-goto-missing-group-function
+             (funcall gnus-goto-missing-group-function group)
+           (let ((entry (cddr (gnus-gethash group gnus-newsrc-hashtb))))
+             (while (and entry (car entry)
+                         (not
+                          (gnus-goto-char
+                           (text-property-any
+                            (point-min) (point-max)
+                            'gnus-group (gnus-intern-safe
+                                         (caar entry) gnus-active-hashtb)))))
+               (setq entry (cdr entry)))
+             (or entry (goto-char (point-max)))))
+         ;; Finally insert the line.
+         (let ((gnus-group-indentation (gnus-group-group-indentation)))
+           (gnus-group-insert-group-line-info group)))
+       (gnus-group-set-mode-line)))))
 
 (defun gnus-group-set-mode-line ()
-  (if (memq 'group gnus-updated-mode-lines)
+  "Update the mode line in the group buffer."
+  (when (memq 'group gnus-updated-mode-lines)
+    ;; Yes, we want to keep this mode line updated.
+    (save-excursion
+      (set-buffer gnus-group-buffer)
       (let* ((gformat (or gnus-group-mode-line-format-spec
                          (setq gnus-group-mode-line-format-spec
-                               (gnus-parse-format 
-                                gnus-group-mode-line-format 
+                               (gnus-parse-format
+                                gnus-group-mode-line-format
                                 gnus-group-mode-line-format-alist))))
-            (news-server (car (cdr gnus-select-method)))
-            (news-method (car gnus-select-method))
+            (gnus-tmp-news-server (cadr gnus-select-method))
+            (gnus-tmp-news-method (car gnus-select-method))
+            (gnus-tmp-colon (if (equal gnus-tmp-news-server "") "" ":"))
             (max-len 60)
+            gnus-tmp-header            ;Dummy binding for user-defined formats
+            ;; Get the resulting string.
             (mode-string (eval gformat)))
-       (setq mode-string (eval gformat))
-       (if (> (length mode-string) max-len) 
-           (setq mode-string (substring mode-string 0 (- max-len 4))))
-       (setq mode-line-buffer-identification mode-string)
-       (set-buffer-modified-p t))))
+       ;; Say whether the dribble buffer has been modified.
+       (setq mode-line-modified
+             (if (and gnus-dribble-buffer
+                      (buffer-name gnus-dribble-buffer)
+                      (buffer-modified-p gnus-dribble-buffer)
+                      (save-excursion
+                        (set-buffer gnus-dribble-buffer)
+                        (not (zerop (buffer-size)))))
+                 "---*- " "----- "))
+       ;; If the line is too long, we chop it off.
+       (when (> (length mode-string) max-len)
+         (setq mode-string (substring mode-string 0 (- max-len 4))))
+       (prog1
+           (setq mode-line-buffer-identification 
+                 (list mode-string))
+         (set-buffer-modified-p t))))))
 
 (defun gnus-group-group-name ()
   "Get the name of the newsgroup on the current line."
@@ -3775,6 +5078,13 @@ If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't already."
   "Get the level of the newsgroup on the current line."
   (get-text-property (gnus-point-at-bol) 'gnus-level))
 
+(defun gnus-group-group-indentation ()
+  "Get the indentation of the newsgroup on the current line."
+  (or (get-text-property (gnus-point-at-bol) 'gnus-indentation)
+      (and gnus-group-indentation-function
+          (funcall gnus-group-indentation-function))
+      ""))
+
 (defun gnus-group-group-unread ()
   "Get the number of unread articles of the newsgroup on the current line."
   (get-text-property (gnus-point-at-bol) 'gnus-unread))
@@ -3793,15 +5103,15 @@ If FIRST-TOO, the current line is also eligible as a target."
     (if (and backward (progn (beginning-of-line)) (bobp))
        nil
       (or first-too (forward-line way))
-      (while (and 
+      (while (and
              (not (eobp))
-             (not (setq 
-                   found 
+             (not (setq
+                   found
                    (and (or all
                             (and
-                             (let ((unread 
+                             (let ((unread
                                     (get-text-property (point) 'gnus-unread)))
-                               (or (eq unread t) (and unread (> unread 0))))
+                               (and (numberp unread) (> unread 0)))
                              (setq lev (get-text-property (point)
                                                           'gnus-level))
                              (<= lev gnus-level-subscribed)))
@@ -3816,8 +5126,8 @@ If FIRST-TOO, the current line is also eligible as a target."
                                             (setq pos (point))
                                             nil))))))))
              (zerop (forward-line way)))))
-    (if found 
-       (progn (gnus-group-position-cursor) t)
+    (if found
+       (progn (gnus-group-position-point) t)
       (goto-char (or pos beg))
       (and pos t))))
 
@@ -3830,31 +5140,40 @@ If FIRST-TOO, the current line is also eligible as a target."
   (interactive "p")
   (let ((buffer-read-only nil)
        group)
-    (while 
-       (and (> n 0) 
-            (setq group (gnus-group-group-name))
-            (progn
-              (beginning-of-line)
-              (forward-char 
-               (or (cdr (assq 'process gnus-group-mark-positions)) 2))
-              (delete-char 1)
-              (if unmark
-                  (progn
-                    (insert " ")
-                    (setq gnus-group-marked (delete group gnus-group-marked)))
-                (insert "#")
-                (setq gnus-group-marked
-                      (cons group (delete group gnus-group-marked))))
-              t)
-            (or no-advance (zerop (gnus-group-next-group 1))))
-      (setq n (1- n)))
-    (gnus-summary-position-cursor)
+    (while (and (> n 0)
+               (not (eobp)))
+      (when (setq group (gnus-group-group-name))
+       ;; Update the mark.
+       (beginning-of-line)
+       (forward-char
+        (or (cdr (assq 'process gnus-group-mark-positions)) 2))
+       (delete-char 1)
+       (if unmark
+           (progn
+             (insert " ")
+             (setq gnus-group-marked (delete group gnus-group-marked)))
+         (insert "#")
+         (setq gnus-group-marked
+               (cons group (delete group gnus-group-marked)))))
+      (or no-advance (gnus-group-next-group 1))
+      (decf n))
+    (gnus-summary-position-point)
     n))
 
 (defun gnus-group-unmark-group (n)
   "Remove the mark from the current group."
   (interactive "p")
-  (gnus-group-mark-group n 'unmark))
+  (gnus-group-mark-group n 'unmark)
+  (gnus-group-position-point))
+
+(defun gnus-group-unmark-all-groups ()
+  "Unmark all groups."
+  (interactive)
+  (let ((groups gnus-group-marked))
+    (save-excursion
+      (while groups
+       (gnus-group-remove-mark (pop groups)))))
+  (gnus-group-position-point))
 
 (defun gnus-group-mark-region (unmark beg end)
   "Mark all groups between point and mark.
@@ -3865,58 +5184,123 @@ If UNMARK, remove the mark instead."
       (goto-char beg)
       (- num (gnus-group-mark-group num unmark)))))
 
+(defun gnus-group-mark-buffer (&optional unmark)
+  "Mark all groups in the buffer.
+If UNMARK, remove the mark instead."
+  (interactive "P")
+  (gnus-group-mark-region unmark (point-min) (point-max)))
+
+(defun gnus-group-mark-regexp (regexp)
+  "Mark all groups that match some regexp."
+  (interactive "sMark (regexp): ")
+  (let ((alist (cdr gnus-newsrc-alist))
+       group)
+    (while alist
+      (when (string-match regexp (setq group (gnus-info-group (pop alist))))
+       (gnus-group-set-mark group))))
+  (gnus-group-position-point))
+
 (defun gnus-group-remove-mark (group)
-  (and (gnus-group-goto-group group)
-       (save-excursion
-        (gnus-group-mark-group 1 'unmark t))))
+  "Remove the process mark from GROUP and move point there.
+Return nil if the group isn't displayed."
+  (if (gnus-group-goto-group group)
+      (save-excursion
+       (gnus-group-mark-group 1 'unmark t)
+       t)
+    (setq gnus-group-marked
+         (delete group gnus-group-marked))
+    nil))
+
+(defun gnus-group-set-mark (group)
+  "Set the process mark on GROUP."
+  (if (gnus-group-goto-group group) 
+      (save-excursion
+       (gnus-group-mark-group 1 nil t))
+    (setq gnus-group-marked (cons group (delete group gnus-group-marked)))))
+
+(defun gnus-group-universal-argument (arg &optional groups func)
+  "Perform any command on all groups accoring to the process/prefix convention."
+  (interactive "P")
+  (let ((groups (or groups (gnus-group-process-prefix arg)))
+       group func)
+    (if (eq (setq func (or func
+                          (key-binding
+                           (read-key-sequence
+                            (substitute-command-keys
+                             "\\<gnus-group-mode-map>\\[gnus-group-universal-argument]")))))
+           'undefined)
+       (gnus-error 1 "Undefined key")
+      (while groups
+       (gnus-group-remove-mark (setq group (pop groups)))
+       (command-execute func))))
+  (gnus-group-position-point))
 
-;; Return a list of groups to work on.  Take into consideration N (the
-;; prefix) and the list of marked groups.
 (defun gnus-group-process-prefix (n)
-  (cond (n
-        (setq n (prefix-numeric-value n))
-        ;; There is a prefix, so we return a list of the N next
-        ;; groups. 
-        (let ((way (if (< n 0) -1 1))
-              (n (abs n))
-              group groups)
-          (save-excursion
-            (while (and (> n 0)
-                        (setq group (gnus-group-group-name)))
-              (setq groups (cons group groups))
-              (setq n (1- n))
-              (forward-line way)))
-          (nreverse groups)))
-       (gnus-group-marked
-        ;; No prefix, but a list of marked articles.
-        (reverse gnus-group-marked))
-       (t
-        ;; Neither marked articles or a prefix, so we return the
-        ;; current group.
-        (let ((group (gnus-group-group-name)))
-          (and group (list group))))))
+  "Return a list of groups to work on.
+Take into consideration N (the prefix) and the list of marked groups."
+  (cond
+   (n
+    (setq n (prefix-numeric-value n))
+    ;; There is a prefix, so we return a list of the N next
+    ;; groups.
+    (let ((way (if (< n 0) -1 1))
+         (n (abs n))
+         group groups)
+      (save-excursion
+       (while (and (> n 0)
+                   (setq group (gnus-group-group-name)))
+         (setq groups (cons group groups))
+         (setq n (1- n))
+         (gnus-group-next-group way)))
+      (nreverse groups)))
+   ((and (boundp 'transient-mark-mode)
+        transient-mark-mode
+        (boundp 'mark-active)
+        mark-active)
+    ;; Work on the region between point and mark.
+    (let ((max (max (point) (mark)))
+         groups)
+      (save-excursion
+       (goto-char (min (point) (mark)))
+       (while
+           (and
+            (push (gnus-group-group-name) groups)
+            (zerop (gnus-group-next-group 1))
+            (< (point) max)))
+       (nreverse groups))))
+   (gnus-group-marked
+    ;; No prefix, but a list of marked articles.
+    (reverse gnus-group-marked))
+   (t
+    ;; Neither marked articles or a prefix, so we return the
+    ;; current group.
+    (let ((group (gnus-group-group-name)))
+      (and group (list group))))))
 
 ;; Selecting groups.
 
 (defun gnus-group-read-group (&optional all no-article group)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
-readable. If the optional argument NO-ARTICLE is non-nil, no article
-will be auto-selected upon group entry."
+readable.  IF ALL is a number, fetch this number of articles.  If the
+optional argument NO-ARTICLE is non-nil, no article will be
+auto-selected upon group entry.         If GROUP is non-nil, fetch that
+group."
   (interactive "P")
   (let ((group (or group (gnus-group-group-name)))
        number active marked entry)
     (or group (error "No group on current line"))
-    (setq marked 
-         (nth 3 (nth 2 (setq entry (gnus-gethash group gnus-newsrc-hashtb)))))
-    ;; This group might be a dead group. In that case we have to get
+    (setq marked (nth 3 (nth 2 (setq entry (gnus-gethash
+                                           group gnus-newsrc-hashtb)))))
+    ;; This group might be a dead group.  In that case we have to get
     ;; the number of unread articles from `gnus-active-hashtb'.
-    (if entry
-       (setq number (car entry))
-      (if (setq active (gnus-gethash group gnus-active-hashtb))
-         (setq number (- (1+ (cdr active)) (car active)))))
-    (gnus-summary-read-group 
-     group (or all (and (numberp number) 
+    (setq number
+         (cond ((numberp all) all)
+               (entry (car entry))
+               ((setq active (gnus-active group))
+                (- (1+ (cdr active)) (car active)))))
+    (gnus-summary-read-group
+     group (or all (and (numberp number)
                        (zerop (+ number (length (cdr (assq 'tick marked)))
                                  (length (cdr (assq 'dormant marked)))))))
      no-article)))
@@ -3924,29 +5308,47 @@ will be auto-selected upon group entry."
 (defun gnus-group-select-group (&optional all)
   "Select this newsgroup.
 No article is selected automatically.
-If argument ALL is non-nil, already read articles become readable."
+If ALL is non-nil, already read articles become readable.
+If ALL is a number, fetch this number of articles."
   (interactive "P")
   (gnus-group-read-group all t))
 
-(defun gnus-group-select-group-all ()
-  "Select the current group and display all articles in it."
-  (interactive)
-  (gnus-group-select-group 'all))
+(defun gnus-group-quick-select-group (&optional all)
+  "Select the current group \"quickly\".
+This means that no highlighting or scoring will be performed."
+  (interactive "P")
+  (let (gnus-visual
+       gnus-score-find-score-files-function
+       gnus-apply-kill-hook
+       gnus-summary-expunge-below)
+    (gnus-group-read-group all t)))
+
+(defun gnus-group-visible-select-group (&optional all)
+  "Select the current group without hiding any articles."
+  (interactive "P")
+  (let ((gnus-inhibit-limiting t))
+    (gnus-group-read-group all t)))
+
+;;;###autoload
+(defun gnus-fetch-group (group)
+  "Start Gnus if necessary and enter GROUP.
+Returns whether the fetching was successful or not."
+  (interactive "sGroup name: ")
+  (or (get-buffer gnus-group-buffer)
+      (gnus))
+  (gnus-group-read-group nil nil group))
 
-;; Enter a group that is not in the group buffer. Non-nil is returned
+;; Enter a group that is not in the group buffer.  Non-nil is returned
 ;; if selection was successful.
-(defun gnus-group-read-ephemeral-group 
+(defun gnus-group-read-ephemeral-group
   (group method &optional activate quit-config)
   (let ((group (if (gnus-group-foreign-p group) group
                 (gnus-group-prefixed-name group method))))
-    (gnus-sethash 
+    (gnus-sethash
      group
-     (list t nil (list group gnus-level-default-subscribed nil nil 
-                      (append method
-                              (list
-                               (list 'quit-config 
-                                     (if quit-config quit-config
-                                       (cons (current-buffer) 'summary)))))))
+     `(t nil (,group ,gnus-level-default-subscribed nil nil ,method
+                    ((quit-config . ,(if quit-config quit-config
+                                       (cons (current-buffer) 'summary))))))
      gnus-newsrc-hashtb)
     (set-buffer gnus-group-buffer)
     (or (gnus-check-server method)
@@ -3956,41 +5358,50 @@ If argument ALL is non-nil, already read articles become readable."
     (condition-case ()
        (gnus-group-read-group t t group)
       (error nil)
-      (quit nil))
-    (not (equal major-mode 'gnus-group-mode))))
-  
+      (quit nil))))
+
 (defun gnus-group-jump-to-group (group)
   "Jump to newsgroup GROUP."
-  (interactive 
-   (list (completing-read 
-         "Group: " gnus-active-hashtb nil 
-         (memq gnus-select-method gnus-have-read-active-file))))
-
-  (if (equal group "")
-      (error "Empty group name"))
-
-  (let ((b (text-property-any 
-           (point-min) (point-max) 'gnus-group (intern group))))
-    (if b
-       ;; Either go to the line in the group buffer...
-       (goto-char b)
-      ;; ... or insert the line.
-      (or
-       (gnus-gethash group gnus-active-hashtb)
-       (gnus-activate-group group)
-       (error "%s error: %s" group (gnus-status-message group)))
-
-      (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))
+  (interactive
+   (list (completing-read
+         "Group: " gnus-active-hashtb nil
+         (gnus-read-active-file-p)
+         nil
+         'gnus-group-history)))
+
+  (when (equal group "")
+    (error "Empty group name"))
+
+  (when (string-match "[\000-\032]" group)
+    (error "Control characters in group: %s" group))
+
+  (let ((b (text-property-any
+           (point-min) (point-max)
+           'gnus-group (gnus-intern-safe group gnus-active-hashtb))))
+    (unless (gnus-ephemeral-group-p group)
+      (if b
+         ;; Either go to the line in the group buffer...
+         (goto-char b)
+       ;; ... or insert the line.
+       (or
+        (gnus-active group)
+        (gnus-activate-group group)
+        (error "%s error: %s" group (gnus-status-message group)))
+
+       (gnus-group-update-group group)
+       (goto-char (text-property-any
+                   (point-min) (point-max)
+                   'gnus-group (gnus-intern-safe group gnus-active-hashtb)))))
+    ;; Adjust cursor point.
+    (gnus-group-position-point)))
 
 (defun gnus-group-goto-group (group)
   "Goto to newsgroup GROUP."
-  (let ((b (text-property-any (point-min) (point-max) 
-                             'gnus-group (intern group))))
-    (and b (goto-char b))))
+  (when group
+    (let ((b (text-property-any (point-min) (point-max)
+                               'gnus-group (gnus-intern-safe
+                                            group gnus-active-hashtb))))
+      (and b (goto-char b)))))
 
 (defun gnus-group-next-group (n)
   "Go to next N'th newsgroup.
@@ -4013,7 +5424,7 @@ made."
   (let ((backward (< n 0))
        (n (abs n)))
     (while (and (> n 0)
-               (gnus-group-search-forward 
+               (gnus-group-search-forward
                 backward (or (not gnus-group-goto-unread) all) level))
       (setq n (1- n)))
     (if (/= 0 n) (gnus-message 7 "No more%s newsgroups%s" (if all "" " unread")
@@ -4030,7 +5441,7 @@ done."
 (defun gnus-group-prev-unread-group (n)
   "Go to previous N'th unread newsgroup.
 Returns the difference between N and the number of skips actually
-done."  
+done."
   (interactive "p")
   (gnus-group-next-unread-group (- n)))
 
@@ -4041,7 +5452,7 @@ Returns the difference between N and the number of skips actually
 done."
   (interactive "p")
   (gnus-group-next-unread-group n t (gnus-group-group-level))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
 (defun gnus-group-prev-unread-group-same-level (n)
   "Go to next N'th unread newsgroup on the same level.
@@ -4049,7 +5460,7 @@ Returns the difference between N and the number of skips actually
 done."
   (interactive "p")
   (gnus-group-next-unread-group (- n) t (gnus-group-group-level))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
 (defun gnus-group-best-unread-group (&optional exclude-group)
   "Go to the group with the highest level.
@@ -4058,18 +5469,20 @@ If EXCLUDE-GROUP, do not go to that group."
   (goto-char (point-min))
   (let ((best 100000)
        unread best-point)
-    (while (setq unread (get-text-property (point) 'gnus-unread))
+    (while (not (eobp))
+      (setq unread (get-text-property (point) 'gnus-unread))
       (if (and (numberp unread) (> unread 0))
          (progn
-           (if (and (< (get-text-property (point) 'gnus-level) best)
+           (if (and (get-text-property (point) 'gnus-level)
+                    (< (get-text-property (point) 'gnus-level) best)
                     (or (not exclude-group)
                         (not (equal exclude-group (gnus-group-group-name)))))
-               (progn 
+               (progn
                  (setq best (get-text-property (point) 'gnus-level))
                  (setq best-point (point))))))
       (forward-line 1))
     (if best-point (goto-char best-point))
-    (gnus-summary-position-cursor)
+    (gnus-summary-position-point)
     (and best-point (gnus-group-group-name))))
 
 (defun gnus-group-first-unread-group ()
@@ -4080,73 +5493,154 @@ If EXCLUDE-GROUP, do not go to that group."
            unread)
        (goto-char (point-min))
        (if (or (eq (setq unread (gnus-group-group-unread)) t) ; Not active.
-               (not (zerop unread))    ; Has unread articles.
+               (and (numberp unread)   ; Not a topic.
+                    (not (zerop unread))) ; Has unread articles.
                (zerop (gnus-group-next-unread-group 1))) ; Next unread group.
            (point)                     ; Success.
          (goto-char opoint)
          nil))                         ; Not success.
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 (defun gnus-group-enter-server-mode ()
   "Jump to the server buffer."
   (interactive)
-  (gnus-server-setup-buffer)
-  (gnus-configure-windows 'server)
-  (gnus-server-prepare))
+  (gnus-enter-server-buffer))
 
-(defun gnus-group-make-group (name method &optional address)
+(defun gnus-group-make-group (name &optional method address)
   "Add a new newsgroup.
 The user will be prompted for a NAME, for a select METHOD, and an
 ADDRESS."
   (interactive
-   (cons 
+   (cons
     (read-string "Group name: ")
     (let ((method
-          (completing-read 
+          (completing-read
            "Method: " (append gnus-valid-select-methods gnus-server-alist)
-           nil t)))
-      (if (assoc method gnus-valid-select-methods)
-         (list method
-               (if (memq 'prompt-address
-                         (assoc method gnus-valid-select-methods))
-                   (read-string "Address: ")
-                 ""))
-       (list method nil)))))
-  
-  (let* ((meth (if address (list (intern method) address) method))
-        (nname (gnus-group-prefixed-name name meth))
-        info)
-    (and (gnus-gethash nname gnus-newsrc-hashtb)
-        (error "Group %s already exists" nname))
-    (gnus-group-change-level 
+           nil t nil 'gnus-method-history)))
+      (cond ((assoc method gnus-valid-select-methods)
+            (list method
+                  (if (memq 'prompt-address
+                            (assoc method gnus-valid-select-methods))
+                      (read-string "Address: ")
+                    "")))
+           ((assoc method gnus-server-alist)
+            (list method))
+           (t
+            (list method ""))))))
+
+  (let* ((meth (and method (if address (list (intern method) address)
+                            method)))
+        (nname (if method (gnus-group-prefixed-name name meth) name))
+        backend info)
+    (when (gnus-gethash nname gnus-newsrc-hashtb)
+      (error "Group %s already exists" nname))
+    ;; Subscribe to the new group.
+    (gnus-group-change-level
      (setq info (list t nname gnus-level-default-subscribed nil nil meth))
-     gnus-level-default-subscribed gnus-level-killed 
+     gnus-level-default-subscribed gnus-level-killed
      (and (gnus-group-group-name)
          (gnus-gethash (gnus-group-group-name)
                        gnus-newsrc-hashtb))
      t)
-    (gnus-sethash nname (cons 1 0) gnus-active-hashtb)
-    (gnus-dribble-enter 
-     (concat "(gnus-group-set-info '" (prin1-to-string (cdr info)) ")"))
+    ;; Make it active.
+    (gnus-set-active nname (cons 1 0))
+    (or (gnus-ephemeral-group-p name)
+       (gnus-dribble-enter
+        (concat "(gnus-group-set-info '" (prin1-to-string (cdr info)) ")")))
+    ;; Insert the line.
     (gnus-group-insert-group-line-info nname)
-
-    (if (assoc method gnus-valid-select-methods)
-       (require (intern method)))
+    (forward-line -1)
+    (gnus-group-position-point)
+
+    ;; Load the backend and try to make the backend create
+    ;; the group as well.
+    (when (assoc (symbol-name (setq backend (car (gnus-server-get-method
+                                                 nil meth))))
+                gnus-valid-select-methods)
+      (require backend))
+    (gnus-check-server meth)
     (and (gnus-check-backend-function 'request-create-group nname)
-        (gnus-request-create-group nname))))
+        (gnus-request-create-group nname))
+    t))
+
+(defun gnus-group-delete-group (group &optional force)
+  "Delete the current group.
+If FORCE (the prefix) is non-nil, all the articles in the group will
+be deleted.  This is \"deleted\" as in \"removed forever from the face
+of the Earth\".         There is no undo."
+  (interactive
+   (list (gnus-group-group-name)
+        current-prefix-arg))
+  (or group (error "No group to rename"))
+  (or (gnus-check-backend-function 'request-delete-group group)
+      (error "This backend does not support group deletion"))
+  (prog1
+      (if (not (gnus-yes-or-no-p
+               (format
+                "Do you really want to delete %s%s? "
+                group (if force " and all its contents" ""))))
+         () ; Whew!
+       (gnus-message 6 "Deleting group %s..." group)
+       (if (not (gnus-request-delete-group group force))
+           (gnus-error 3 "Couldn't delete group %s" group)
+         (gnus-message 6 "Deleting group %s...done" group)
+         (gnus-group-goto-group group)
+         (gnus-group-kill-group 1 t)
+         (gnus-sethash group nil gnus-active-hashtb)
+         t))
+    (gnus-group-position-point)))
+
+(defun gnus-group-rename-group (group new-name)
+  (interactive
+   (list
+    (gnus-group-group-name)
+    (progn
+      (or (gnus-check-backend-function
+          'request-rename-group (gnus-group-group-name))
+         (error "This backend does not support renaming groups"))
+      (read-string "New group name: "))))
+
+  (or (gnus-check-backend-function 'request-rename-group group)
+      (error "This backend does not support renaming groups"))
+
+  (or group (error "No group to rename"))
+  (and (string-match "^[ \t]*$" new-name)
+       (error "Not a valid group name"))
+
+  ;; We find the proper prefixed name.
+  (setq new-name
+       (gnus-group-prefixed-name
+        (gnus-group-real-name new-name)
+        (gnus-info-method (gnus-get-info group))))
+
+  (gnus-message 6 "Renaming group %s to %s..." group new-name)
+  (prog1
+      (if (not (gnus-request-rename-group group new-name))
+         (gnus-error 3 "Couldn't rename group %s to %s" group new-name)
+       ;; We rename the group internally by killing it...
+       (gnus-group-goto-group group)
+       (gnus-group-kill-group)
+       ;; ... changing its name ...
+       (setcar (cdar gnus-list-of-killed-groups) new-name)
+       ;; ... and then yanking it.  Magic!
+       (gnus-group-yank-group)
+       (gnus-set-active new-name (gnus-active group))
+       (gnus-message 6 "Renaming group %s to %s...done" group new-name)
+       new-name)
+    (gnus-group-position-point)))
 
 (defun gnus-group-edit-group (group &optional part)
   "Edit the group on the current line."
   (interactive (list (gnus-group-group-name)))
-  (let ((done-func '(lambda () 
-                     "Exit editing mode and update the information."
-                     (interactive)
-                     (gnus-group-edit-group-done 'part 'group)))
-       (part (or part 'info))
-       (winconf (current-window-configuration))
-       info)
+  (let* ((part (or part 'info))
+        (done-func `(lambda ()
+                      "Exit editing mode and update the information."
+                      (interactive)
+                      (gnus-group-edit-group-done ',part ,group)))
+        (winconf (current-window-configuration))
+        info)
     (or group (error "No group on current line"))
-    (or (setq info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
+    (or (setq info (gnus-get-info group))
        (error "Killed group; can't be edited"))
     (set-buffer (get-buffer-create gnus-group-edit-buffer))
     (gnus-configure-windows 'edit-group)
@@ -4157,39 +5651,23 @@ ADDRESS."
     (local-set-key "\C-c\C-c" done-func)
     (make-local-variable 'gnus-prev-winconf)
     (setq gnus-prev-winconf winconf)
-    ;; We modify the func to let it know what part it is editing.
-    (setcar (cdr (nth 4 done-func)) (list 'quote part))
-    (setcar (cdr (cdr (nth 4 done-func))) group)
     (erase-buffer)
     (insert
-     (cond 
+     (cond
       ((eq part 'method)
        ";; Type `C-c C-c' after editing the select method.\n\n")
       ((eq part 'params)
        ";; Type `C-c C-c' after editing the group parameters.\n\n")
       ((eq part 'info)
        ";; Type `C-c C-c' after editing the group info.\n\n")))
-    (let ((cinfo (gnus-copy-sequence info))
-         marked)
-      (if (not (setq marked (nth 3 cinfo)))
-         ()
-       (while marked
-         (or (eq 'score (car (car marked)))
-             (eq 'bookmark (car (car marked)))
-             (eq 'killed (car (car marked)))
-             (not (numberp (car (cdr (car marked)))))
-             (setcdr (car marked) 
-                     (gnus-compress-sequence (sort (cdr (car marked)) '<) t)))
-         (setq marked (cdr marked))))
-      (insert 
-       (pp-to-string
-       (cond ((eq part 'method)
-              (or (nth 4 info) "native"))
-             ((eq part 'params)
-              (nth 5 info))
-             (t
-              cinfo)))
-       "\n"))))
+    (insert
+     (pp-to-string
+      (cond ((eq part 'method)
+            (or (gnus-info-method info) "native"))
+           ((eq part 'params)
+            (gnus-info-params info))
+           (t info)))
+     "\n")))
 
 (defun gnus-group-edit-group-method (group)
   "Edit the select method of GROUP."
@@ -4205,89 +5683,139 @@ ADDRESS."
   "Get info from buffer, update variables and jump to the group buffer."
   (set-buffer (get-buffer-create gnus-group-edit-buffer))
   (goto-char (point-min))
-  (let ((form (read (current-buffer)))
-       (winconf gnus-prev-winconf))
-    (if (eq part 'info) 
-       (gnus-group-set-info form)
-      (gnus-group-set-info form group part))
+  (let* ((form (read (current-buffer)))
+        (winconf gnus-prev-winconf)
+        (method (cond ((eq part 'info) (nth 4 form))
+                      ((eq part 'method) form)
+                      (t nil)))
+        (info (cond ((eq part 'info) form)
+                    ((eq part 'method) (gnus-get-info group))
+                    (t nil)))
+        (new-group (if info
+                     (if (or (not method)
+                             (gnus-server-equal
+                              gnus-select-method method))
+                         (gnus-group-real-name (car info))
+                       (gnus-group-prefixed-name
+                        (gnus-group-real-name (car info)) method))
+                     nil)))
+    (when (and new-group
+              (not (equal new-group group)))
+      (when (gnus-group-goto-group group)
+       (gnus-group-kill-group 1))
+      (gnus-activate-group new-group))
+    ;; Set the info.
+    (if (and info new-group)
+       (progn
+         (setq info (gnus-copy-sequence info))
+         (setcar info new-group)
+         (unless (gnus-server-equal method "native")
+           (unless (nthcdr 3 info)
+             (nconc info (list nil nil)))
+           (unless (nthcdr 4 info)
+             (nconc info (list nil)))
+           (gnus-info-set-method info method))
+         (gnus-group-set-info info))
+      (gnus-group-set-info form (or new-group group) part))
     (kill-buffer (current-buffer))
     (and winconf (set-window-configuration winconf))
     (set-buffer gnus-group-buffer)
-    (gnus-group-update-group (gnus-group-group-name))
-    (gnus-group-position-cursor)))
+    (gnus-group-update-group (or new-group group))
+    (gnus-group-position-point)))
 
 (defun gnus-group-make-help-group ()
   "Create the Gnus documentation group."
   (interactive)
   (let ((path load-path)
-       name)
-    (and (gnus-gethash (setq name (gnus-group-prefixed-name
-                                  "gnus-help" '(nndoc "gnus-help")))
-                      gnus-newsrc-hashtb)
+       (name (gnus-group-prefixed-name "gnus-help" '(nndoc "gnus-help")))
+       file dir)
+    (and (gnus-gethash name gnus-newsrc-hashtb)
         (error "Documentation group already exists"))
-    (while (and path
-               (not (file-exists-p (concat (file-name-as-directory (car path))
-                                           "doc.txt"))))
-      (setq path (cdr path)))
-    (or path (error "Couldn't find doc group"))
-    (gnus-group-make-group 
-     (gnus-group-real-name name)
-     (list 'nndoc name
-          (list 'nndoc-address 
-                (concat (file-name-as-directory (car path)) "doc.txt"))
-          (list 'nndoc-article-type 'mbox))))
-  (gnus-group-position-cursor))
+    (while path
+      (setq dir (file-name-as-directory (expand-file-name (pop path)))
+           file nil)
+      (when (or (file-exists-p (setq file (concat dir "gnus-tut.txt")))
+               (file-exists-p
+                (setq file (concat (file-name-directory
+                                    (directory-file-name dir))
+                                   "etc/gnus-tut.txt"))))
+       (setq path nil)))
+    (if (not file)
+       (gnus-message 1 "Couldn't find doc group")
+      (gnus-group-make-group
+       (gnus-group-real-name name)
+       (list 'nndoc "gnus-help"
+            (list 'nndoc-address file)
+            (list 'nndoc-article-type 'mbox)))))
+  (gnus-group-position-point))
 
 (defun gnus-group-make-doc-group (file type)
   "Create a group that uses a single file as the source."
-  (interactive 
-   (list (read-file-name "File name: ") 
-        (let ((err "")
-              found char)
-          (while (not found)
-            (message "%sFile type (mbox, babyl, digest) [mbd]: " err)
-            (setq found (cond ((= (setq char (read-char)) ?m) 'mbox)
-                              ((= char ?b) 'babyl)
-                              ((= char ?d) 'digest)
-                              (t (setq err (format "%c unknown. " char))
-                                 nil))))
-          found)))
+  (interactive
+   (list (read-file-name "File name: ")
+        (and current-prefix-arg 'ask)))
+  (when (eq type 'ask)
+    (let ((err "")
+         char found)
+      (while (not found)
+       (message
+        "%sFile type (mbox, babyl, digest, forward, mmfd, guess) [mbdfag]: "
+        err)
+       (setq found (cond ((= (setq char (read-char)) ?m) 'mbox)
+                         ((= char ?b) 'babyl)
+                         ((= char ?d) 'digest)
+                         ((= char ?f) 'forward)
+                         ((= char ?a) 'mmfd)
+                         (t (setq err (format "%c unknown. " char))
+                            nil))))
+      (setq type found)))
   (let* ((file (expand-file-name file))
         (name (gnus-generate-new-group-name
                (gnus-group-prefixed-name
                 (file-name-nondirectory file) '(nndoc "")))))
-    (gnus-group-make-group 
+    (gnus-group-make-group
      (gnus-group-real-name name)
-     (list 'nndoc name
+     (list 'nndoc (file-name-nondirectory file)
           (list 'nndoc-address file)
-          (list 'nndoc-article-type type)))))
+          (list 'nndoc-article-type (or type 'guess))))))
 
 (defun gnus-group-make-archive-group (&optional all)
   "Create the (ding) Gnus archive group of the most recent articles.
 Given a prefix, create a full group."
   (interactive "P")
-  (let ((group (gnus-group-prefixed-name 
+  (let ((group (gnus-group-prefixed-name
                (if all "ding.archives" "ding.recent") '(nndir ""))))
     (and (gnus-gethash group gnus-newsrc-hashtb)
         (error "Archive group already exists"))
     (gnus-group-make-group
      (gnus-group-real-name group)
-     "nndir" 
-     (if all gnus-group-archive-directory 
-       gnus-group-recent-archive-directory)))
-  (gnus-group-position-cursor))
+     (list 'nndir (if all "hpc" "edu")
+          (list 'nndir-directory
+                (if all gnus-group-archive-directory
+                  gnus-group-recent-archive-directory))))))
 
 (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
+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 (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-make-group dir "nndir" dir)
-  (gnus-group-position-cursor))
+  (let ((ext "")
+       (i 0)
+       group)
+    (while (or (not group) (gnus-gethash group gnus-newsrc-hashtb))
+      (setq group
+           (gnus-group-prefixed-name
+            (concat (file-name-as-directory (directory-file-name dir))
+                    ext)
+            '(nndir "")))
+      (setq ext (format "<%d>" (setq i (1+ i)))))
+    (gnus-group-make-group
+     (gnus-group-real-name group)
+     (list 'nndir group (list 'nndir-directory dir)))))
 
 (defun gnus-group-make-kiboze-group (group address scores)
   "Create an nnkiboze group.
@@ -4299,26 +5827,22 @@ score file entries for articles to include in the group."
     (read-string "Source groups (regexp): ")
     (let ((headers (mapcar (lambda (group) (list group))
                           '("subject" "from" "number" "date" "message-id"
-                            "references" "chars" "lines" "xref")))
+                            "references" "chars" "lines" "xref"
+                            "followup" "all" "body" "head")))
          scores header regexp regexps)
-      (while (not (equal "" (setq header (completing-read 
+      (while (not (equal "" (setq header (completing-read
                                          "Match on header: " headers nil t))))
        (setq regexps nil)
-       (while (not (equal "" (setq regexp (read-string 
+       (while (not (equal "" (setq regexp (read-string
                                            (format "Match on %s (string): "
                                                    header)))))
          (setq regexps (cons (list regexp nil nil 'r) regexps)))
        (setq scores (cons (cons header regexps) scores)))
       scores)))
   (gnus-group-make-group group "nnkiboze" address)
-  (save-excursion
-    (gnus-set-work-buffer)
+  (nnheader-temp-write (gnus-score-file-name (concat "nnkiboze:" group))
     (let (emacs-lisp-mode-hook)
-      (pp scores (current-buffer)))
-    (write-region (point-min) (point-max) 
-                 (concat (or gnus-kill-files-directory "~/News")
-                         "nnkiboze:" group "." gnus-score-file-suffix)))
-  (gnus-group-position-cursor))
+      (pp scores (current-buffer)))))
 
 (defun gnus-group-add-to-virtual (n vgroup)
   "Add the current group to a virtual group."
@@ -4329,16 +5853,16 @@ score file entries for articles to include in the group."
   (or (eq (car (gnus-find-method-for-group vgroup)) 'nnvirtual)
       (error "%s is not an nnvirtual group" vgroup))
   (let* ((groups (gnus-group-process-prefix n))
-        (method (nth 4 (nth 2 (gnus-gethash vgroup gnus-newsrc-hashtb)))))
+        (method (gnus-info-method (gnus-get-info vgroup))))
     (setcar (cdr method)
-           (concat 
+           (concat
             (nth 1 method) "\\|"
-            (mapconcat 
-             (lambda (s) 
+            (mapconcat
+             (lambda (s)
                (gnus-group-remove-mark s)
                (concat "\\(^" (regexp-quote s) "$\\)"))
              groups "\\|"))))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
 (defun gnus-group-make-empty-virtual (group)
   "Create a new, fresh, empty virtual group."
@@ -4352,7 +5876,7 @@ score file entries for articles to include in the group."
     (gnus-subscribe-group pgroup (gnus-group-group-name) method)
     (gnus-group-update-group pgroup)
     (forward-line -1)
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 (defun gnus-group-enter-directory (dir)
   "Enter an ephemeral nneething group."
@@ -4363,7 +5887,7 @@ score file entries for articles to include in the group."
                method))
         (name (gnus-generate-new-group-name leaf)))
     (let ((nneething-read-only t))
-      (or (gnus-group-read-ephemeral-group 
+      (or (gnus-group-read-ephemeral-group
           name method t
           (cons (current-buffer) (if (eq major-mode 'gnus-summary-mode)
                                      'summary 'group)))
@@ -4372,33 +5896,123 @@ score file entries for articles to include in the group."
 ;; Group sorting commands
 ;; Suggested by Joe Hildebrand <hildjj@idaho.fuentez.com>.
 
-(defun gnus-group-sort-groups ()
-  "Sort the group buffer using `gnus-group-sort-function'."
-  (interactive)
-  (setq gnus-newsrc-alist 
-       (sort (cdr gnus-newsrc-alist) gnus-group-sort-function))
-  (gnus-make-hashtable-from-newsrc-alist)
-  (gnus-group-list-groups))
+(defun gnus-group-sort-groups (func &optional reverse)
+  "Sort the group buffer according to FUNC.
+If REVERSE, reverse the sorting order."
+  (interactive (list gnus-group-sort-function
+                    current-prefix-arg))
+  (let ((func (cond 
+              ((not (listp func)) func)
+              ((null func) func)
+              ((= 1 (length func)) (car func))
+              (t `(lambda (t1 t2)
+                    ,(gnus-make-sort-function 
+                      (reverse func)))))))
+    ;; We peel off the dummy group from the alist.
+    (when func
+      (when (equal (car (gnus-info-group gnus-newsrc-alist)) "dummy.group")
+       (pop gnus-newsrc-alist))
+      ;; Do the sorting.
+      (setq gnus-newsrc-alist
+           (sort gnus-newsrc-alist func))
+      (when reverse
+       (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist)))
+      ;; Regenerate the hash table.
+      (gnus-make-hashtable-from-newsrc-alist)
+      (gnus-group-list-groups))))
+
+(defun gnus-group-sort-groups-by-alphabet (&optional reverse)
+  "Sort the group buffer alphabetically by group name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-group-sort-groups-by-unread (&optional reverse)
+  "Sort the group buffer by number of unread articles.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-group-sort-groups-by-level (&optional reverse)
+  "Sort the group buffer by group level.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-level reverse))
+
+(defun gnus-group-sort-groups-by-score (&optional reverse)
+  "Sort the group buffer by group score.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-score reverse))
+
+(defun gnus-group-sort-groups-by-rank (&optional reverse)
+  "Sort the group buffer by group rank.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-group-sort-groups-by-method (&optional reverse)
+  "Sort the group buffer alphabetically by backend name.
+If REVERSE, sort in reverse order."
+  (interactive "P")
+  (gnus-group-sort-groups 'gnus-group-sort-by-method reverse))
 
 (defun gnus-group-sort-by-alphabet (info1 info2)
-  (string< (car info1) (car info2)))
+  "Sort alphabetically."
+  (string< (gnus-info-group info1) (gnus-info-group info2)))
 
 (defun gnus-group-sort-by-unread (info1 info2)
-  (let ((n1 (car (gnus-gethash (car info1) gnus-newsrc-hashtb)))
-       (n2 (car (gnus-gethash (car info2) gnus-newsrc-hashtb))))
+  "Sort by number of unread articles."
+  (let ((n1 (car (gnus-gethash (gnus-info-group info1) gnus-newsrc-hashtb)))
+       (n2 (car (gnus-gethash (gnus-info-group info2) gnus-newsrc-hashtb))))
     (< (or (and (numberp n1) n1) 0)
        (or (and (numberp n2) n2) 0))))
 
 (defun gnus-group-sort-by-level (info1 info2)
-  (< (nth 1 info1) (nth 1 info2)))
+  "Sort by level."
+  (< (gnus-info-level info1) (gnus-info-level info2)))
+
+(defun gnus-group-sort-by-method (info1 info2)
+  "Sort alphabetically by backend name."
+  (string< (symbol-name (car (gnus-find-method-for-group
+                             (gnus-info-group info1) info1)))
+          (symbol-name (car (gnus-find-method-for-group
+                             (gnus-info-group info2) info2)))))
+
+(defun gnus-group-sort-by-score (info1 info2)
+  "Sort by group score."
+  (< (gnus-info-score info1) (gnus-info-score info2)))
+
+(defun gnus-group-sort-by-rank (info1 info2)
+  "Sort by level and score."
+  (let ((level1 (gnus-info-level info1))
+       (level2 (gnus-info-level info2)))
+    (or (< level1 level2)
+       (and (= level1 level2)
+            (> (gnus-info-score info1) (gnus-info-score info2))))))
 
 ;; Group catching up.
 
+(defun gnus-group-clear-data (n)
+  "Clear all marks and read ranges from the current group."
+  (interactive "P")
+  (let ((groups (gnus-group-process-prefix n))
+       group info)
+    (while (setq group (pop groups))
+      (setq info (gnus-get-info group))
+      (gnus-info-set-read info nil)
+      (when (gnus-info-marks info)
+       (gnus-info-set-marks info nil))
+      (gnus-get-unread-articles-in-group info (gnus-active group) t)
+      (when (gnus-group-goto-group group)
+       (gnus-group-remove-mark group)
+       (gnus-group-update-group-line)))))
+
 (defun gnus-group-catchup-current (&optional n 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: header) of articles are ignored.
+caught up.  If ALL is non-nil, marked articles will also be marked as
+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")
@@ -4412,17 +6026,19 @@ caught up is returned."
     (let ((groups (gnus-group-process-prefix n))
          (ret 0))
       (while groups
-       ;; Virtual groups have to be given special treatment. 
+       ;; Virtual groups have to be given special treatment.
        (let ((method (gnus-find-method-for-group (car groups))))
          (if (eq 'nnvirtual (car method))
              (nnvirtual-catchup-group
               (gnus-group-real-name (car groups)) (nth 1 method) all)))
        (gnus-group-remove-mark (car groups))
-       (if (prog1
-               (gnus-group-goto-group (car groups))
-             (gnus-group-catchup (car groups) all))
-           (gnus-group-update-group-line)
-         (setq ret (1+ ret)))
+       (if (>= (gnus-group-group-level) gnus-level-zombie)
+           (gnus-message 2 "Dead groups can't be caught up")
+         (if (prog1
+                 (gnus-group-goto-group (car groups))
+               (gnus-group-catchup (car groups) all))
+             (gnus-group-update-group-line)
+           (setq ret (1+ ret))))
        (setq groups (cdr groups)))
       (gnus-group-next-unread-group 1)
       ret)))
@@ -4439,73 +6055,100 @@ If ALL is non-nil, all articles are marked as read.
 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))))
+        (num (car entry)))
+    ;; Do the updating only if the newsgroup isn't killed.
     (if (not (numberp (car entry)))
        (gnus-message 1 "Can't catch up; non-active group")
-      ;; Do the updating only if the newsgroup isn't killed.
-      (if (not entry)
-         ()
-       (gnus-update-read-articles 
-        group (and (not all) (append (cdr (assq 'tick marked))
-                                     (cdr (assq 'dormant marked))))
-        nil (and (not all) (cdr (assq 'tick marked))))
-       (and all 
-            (setq marked (nth 3 (nth 2 entry)))
-            (setcar (nthcdr 3 (nth 2 entry)) 
-                    (delq (assq 'dormant marked) 
-                          (nth 3 (nth 2 entry)))))))
-    num))
+      ;; Do auto-expirable marks if that's required.
+      (when (gnus-group-auto-expirable-p group)
+       (gnus-add-marked-articles
+        group 'expire (gnus-list-of-unread-articles group))
+       (when all
+         (let ((marks (nth 3 (nth 2 entry))))
+           (gnus-add-marked-articles
+            group 'expire (gnus-uncompress-range (cdr (assq 'tick marks))))
+           (gnus-add-marked-articles
+            group 'expire (gnus-uncompress-range (cdr (assq 'tick marks)))))))
+      (when entry
+       (gnus-update-read-articles group nil)
+       ;; Also nix out the lists of marks and dormants.
+       (when all
+         (gnus-add-marked-articles group 'tick nil nil 'force)
+         (gnus-add-marked-articles group 'dormant nil nil 'force))
+       (run-hooks 'gnus-group-catchup-group-hook)
+       num))))
 
 (defun gnus-group-expire-articles (&optional n)
   "Expire all expirable articles in the current newsgroup."
   (interactive "P")
   (let ((groups (gnus-group-process-prefix n))
        group)
-    (or groups (error "No groups to expire"))
-    (while groups
-      (setq group (car groups)
-           groups (cdr groups))
+    (unless groups
+      (error "No groups to expire"))
+    (while (setq group (pop groups))
       (gnus-group-remove-mark group)
-      (if (not (gnus-check-backend-function 'request-expire-articles group))
-         ()
-       (let* ((info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
-              (expirable (if (memq 'total-expire (nth 5 info))
+      (when (gnus-check-backend-function 'request-expire-articles group)
+       (gnus-message 6 "Expiring articles in %s..." group)
+       (let* ((info (gnus-get-info group))
+              (expirable (if (gnus-group-total-expirable-p group)
                              (cons nil (gnus-list-of-read-articles group))
-                           (assq 'expire (nth 3 info)))))
-         (and expirable 
-              (setcdr expirable
-                      (gnus-request-expire-articles 
-                       (cdr expirable) group))))))))
+                           (assq 'expire (gnus-info-marks info))))
+              (expiry-wait (gnus-group-get-parameter group 'expiry-wait)))
+         (when expirable
+           (setcdr
+            expirable
+            (gnus-compress-sequence
+             (if expiry-wait
+                 ;; We set the expiry variables to the groupp
+                 ;; parameter. 
+                 (let ((nnmail-expiry-wait-function nil)
+                       (nnmail-expiry-wait expiry-wait))
+                   (gnus-request-expire-articles
+                    (gnus-uncompress-sequence (cdr expirable)) group))
+               ;; Just expire using the normal expiry values.
+               (gnus-request-expire-articles
+                (gnus-uncompress-sequence (cdr expirable)) group)))))
+         (gnus-message 6 "Expiring articles in %s...done" group)))
+      (gnus-group-position-point))))
 
 (defun gnus-group-expire-all-groups ()
   "Expire all expirable articles in all newsgroups."
   (interactive)
   (save-excursion
     (gnus-message 5 "Expiring...")
-    (let ((gnus-group-marked (mapcar (lambda (info) (car info))
+    (let ((gnus-group-marked (mapcar (lambda (info) (gnus-info-group info))
                                     (cdr gnus-newsrc-alist))))
       (gnus-group-expire-articles nil)))
-  (gnus-group-position-cursor)
+  (gnus-group-position-point)
   (gnus-message 5 "Expiring...done"))
 
 (defun gnus-group-set-current-level (n level)
   "Set the level of the next N groups to LEVEL."
-  (interactive "P\nnLevel: ")
+  (interactive
+   (list
+    current-prefix-arg
+    (string-to-int
+     (let ((s (read-string
+              (format "Level (default %s): "
+                      (or (gnus-group-group-level) 
+                          gnus-level-default-subscribed)))))
+       (if (string-match "^\\s-*$" s)
+          (int-to-string (or (gnus-group-group-level) 
+                             gnus-level-default-subscribed))
+        s)))))
   (or (and (>= level 1) (<= level gnus-level-killed))
       (error "Illegal level: %d" level))
   (let ((groups (gnus-group-process-prefix n))
        group)
-    (while groups
-      (setq group (car groups)
-           groups (cdr groups))
+    (while (setq group (pop groups))
       (gnus-group-remove-mark group)
-      (gnus-message 6 "Changed level of %s from %d to %d" 
-                   group (gnus-group-group-level) level)
-      (gnus-group-change-level group level
-                              (gnus-group-group-level))
+      (gnus-message 6 "Changed level of %s from %d to %d"
+                   group (or (gnus-group-group-level) gnus-level-killed)
+                   level)
+      (gnus-group-change-level
+       group level (or (gnus-group-group-level) gnus-level-killed))
       (gnus-group-update-group-line)))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
 (defun gnus-group-unsubscribe-current-group (&optional n)
   "Toggle subscription of the current group.
@@ -4520,49 +6163,54 @@ If given numerical prefix, toggle the N next groups."
       (gnus-group-unsubscribe-group
        group (if (<= (gnus-group-group-level) gnus-level-subscribed)
                 gnus-level-default-unsubscribed
-              gnus-level-default-subscribed))
+              gnus-level-default-subscribed) t)
       (gnus-group-update-group-line))
     (gnus-group-next-group 1)))
 
-(defun gnus-group-unsubscribe-group (group &optional level)
-  "Toggle subscribe from/to unsubscribe GROUP.
-New newsgroup is added to .newsrc automatically."
+(defun gnus-group-unsubscribe-group (group &optional level silent)
+  "Toggle subscription to GROUP.
+Killed newsgroups are subscribed.  If SILENT, don't try to update the
+group line."
   (interactive
    (list (completing-read
-         "Group: " gnus-active-hashtb nil 
-         (memq gnus-select-method gnus-have-read-active-file))))
+         "Group: " gnus-active-hashtb nil
+         (gnus-read-active-file-p)
+         nil 
+         'gnus-group-history)))
   (let ((newsrc (gnus-gethash group gnus-newsrc-hashtb)))
     (cond
      ((string-match "^[ \t]$" group)
       (error "Empty group name"))
      (newsrc
       ;; Toggle subscription flag.
-      (gnus-group-change-level 
-       newsrc (if level level (if (<= (nth 1 (nth 2 newsrc)) 
-                                     gnus-level-subscribed) 
+      (gnus-group-change-level
+       newsrc (if level level (if (<= (nth 1 (nth 2 newsrc))
+                                     gnus-level-subscribed)
                                  (1+ gnus-level-subscribed)
                                gnus-level-default-subscribed)))
-      (gnus-group-update-group group))
+      (unless silent
+       (gnus-group-update-group group)))
      ((and (stringp group)
-          (or (not (memq gnus-select-method gnus-have-read-active-file))
-              (gnus-gethash group gnus-active-hashtb)))
+          (or (not (gnus-read-active-file-p))
+              (gnus-active group)))
       ;; Add new newsgroup.
-      (gnus-group-change-level 
-       group 
-       (if level level gnus-level-default-subscribed) 
-       (or (and (member group gnus-zombie-list) 
-               gnus-level-zombie) 
+      (gnus-group-change-level
+       group
+       (if level level gnus-level-default-subscribed)
+       (or (and (member group gnus-zombie-list)
+               gnus-level-zombie)
           gnus-level-killed)
        (and (gnus-group-group-name)
            (gnus-gethash (gnus-group-group-name) gnus-newsrc-hashtb)))
-      (gnus-group-update-group group))
+      (unless silent
+       (gnus-group-update-group group)))
      (t (error "No such newsgroup: %s" group)))
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 (defun gnus-group-transpose-groups (n)
   "Move the current newsgroup up N places.
-If given a negative prefix, move down instead. The difference between
-N and the number of steps taken is returned." 
+If given a negative prefix, move down instead. The difference between
+N and the number of steps taken is returned."
   (interactive "p")
   (or (gnus-group-group-name)
       (error "No group on current line"))
@@ -4570,7 +6218,7 @@ N and the number of steps taken is returned."
   (prog1
       (forward-line (- n))
     (gnus-group-yank-group)
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 (defun gnus-group-kill-all-zombies ()
   "Kill all zombie newsgroups."
@@ -4599,59 +6247,103 @@ The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
     (beginning-of-line)                        ;Important when LINES < 1
     (gnus-group-kill-group lines)))
 
-(defun gnus-group-kill-group (&optional n)
-  "The the next N groups.
+(defun gnus-group-kill-group (&optional n discard)
+  "Kill 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 
+However, only groups that were alive can be yanked; already killed
 groups or zombie groups can't be yanked.
-The return value is the name of the (last) group that was killed."
+The return value is the name of the group that was killed, or a list
+of groups killed."
   (interactive "P")
   (let ((buffer-read-only nil)
        (groups (gnus-group-process-prefix n))
-       group entry level)
-    (while groups
-      (setq group (car groups)
-           groups (cdr groups))
-      (gnus-group-remove-mark group)
-      (setq level (gnus-group-group-level))
-      (gnus-delete-line)
-      (if (setq entry (gnus-gethash group gnus-newsrc-hashtb))
-         (setq gnus-list-of-killed-groups 
-               (cons (cons (car entry) (nth 2 entry)) 
-                     gnus-list-of-killed-groups)))
-      (gnus-group-change-level 
-       (if entry entry group) gnus-level-killed (if entry nil level)))
-    (gnus-group-position-cursor)
-    group))
+       group entry level out)
+    (if (< (length groups) 10)
+       ;; This is faster when there are few groups.
+       (while groups
+         (push (setq group (pop groups)) out)
+         (gnus-group-remove-mark group)
+         (setq level (gnus-group-group-level))
+         (gnus-delete-line)
+         (when (and (not discard)
+                    (setq entry (gnus-gethash group gnus-newsrc-hashtb)))
+           (push (cons (car entry) (nth 2 entry))
+                 gnus-list-of-killed-groups))
+         (gnus-group-change-level
+          (if entry entry group) gnus-level-killed (if entry nil level)))
+      ;; If there are lots and lots of groups to be killed, we use
+      ;; this thing instead.
+      (let (entry)
+       (setq groups (nreverse groups))
+       (while groups
+         (gnus-group-remove-mark (setq group (pop groups)))
+         (gnus-delete-line)
+         (cond
+          ((setq entry (gnus-gethash group gnus-newsrc-hashtb))
+           (push (cons (car entry) (nth 2 entry))
+                 gnus-list-of-killed-groups)
+           (setcdr (cdr entry) (cdddr entry)))
+          ((member group gnus-zombie-list)
+           (setq gnus-zombie-list (delete group gnus-zombie-list)))))
+       (gnus-make-hashtable-from-newsrc-alist)))
+
+    (gnus-group-position-point)
+    (if (< (length out) 2) (car out) (nreverse out))))
 
 (defun gnus-group-yank-group (&optional arg)
   "Yank the last newsgroups killed with \\[gnus-group-kill-group],
 inserting it before the current newsgroup.  The numeric ARG specifies
-how many newsgroups are to be yanked.  The name of the (last)
-newsgroup yanked is returned."
+how many newsgroups are to be yanked.  The name of the newsgroup yanked
+is returned, or (if several groups are yanked) a list of yanked groups
+is returned."
   (interactive "p")
-  (if (not arg) (setq arg 1))
-  (let (info group prev)
-    (while (>= (setq arg (1- arg)) 0)
-      (if (not (setq info (car gnus-list-of-killed-groups)))
+  (setq arg (or arg 1))
+  (let (info group prev out)
+    (while (>= (decf arg) 0)
+      (if (not (setq info (pop gnus-list-of-killed-groups)))
          (error "No more newsgroups to yank"))
-      (setq group (nth 2 info))
+      (push (setq group (nth 1 info)) out)
       ;; Find which newsgroup to insert this one before - search
-      ;; backward until something suitable is found. If there are no
+      ;; backward until something suitable is found.  If there are no
       ;; other newsgroups in this buffer, just make this newsgroup the
       ;; first newsgroup.
       (setq prev (gnus-group-group-name))
-      (gnus-group-change-level 
-       info (nth 2 info) gnus-level-killed 
+      (gnus-group-change-level
+       info (gnus-info-level (cdr info)) gnus-level-killed
        (and prev (gnus-gethash prev gnus-newsrc-hashtb))
        t)
-      (gnus-group-insert-group-line-info (nth 1 info))
-      (setq gnus-list-of-killed-groups 
-           (cdr gnus-list-of-killed-groups)))
+      (gnus-group-insert-group-line-info group))
     (forward-line -1)
-    (gnus-group-position-cursor)
-    group))
-      
+    (gnus-group-position-point)
+    (if (< (length out) 2) (car out) (nreverse out))))
+
+(defun gnus-group-kill-level (level)
+  "Kill all groups that is on a certain LEVEL."
+  (interactive "nKill all groups on level: ")
+  (cond
+   ((= level gnus-level-zombie)
+    (setq gnus-killed-list
+         (nconc gnus-zombie-list gnus-killed-list))
+    (setq gnus-zombie-list nil))
+   ((and (< level gnus-level-zombie)
+        (> level 0)
+        (or gnus-expert-user
+            (gnus-yes-or-no-p
+             (format
+              "Do you really want to kill all groups on level %d? "
+              level))))
+    (let* ((prev gnus-newsrc-alist)
+          (alist (cdr prev)))
+      (while alist
+       (if (= (gnus-info-level level) level)
+           (setcdr prev (cdr alist))
+         (setq prev alist))
+       (setq alist (cdr alist)))
+      (gnus-make-hashtable-from-newsrc-alist)
+      (gnus-group-list-groups)))
+   (t
+    (error "Can't kill; illegal level: %d" level))))
+
 (defun gnus-group-list-all-groups (&optional arg)
   "List all newsgroups with level ARG or lower.
 Default is gnus-level-unsubscribed, which lists all subscribed and most
@@ -4659,16 +6351,23 @@ unsubscribed groups."
   (interactive "P")
   (gnus-group-list-groups (or arg gnus-level-unsubscribed) t))
 
-(defun gnus-group-list-killed ()
-  "List all killed newsgroups in the group buffer."
-  (interactive)
+;; Redefine this to list ALL killed groups if prefix arg used.
+;; Rewritten by engstrom@src.honeywell.com (Eric Engstrom).
+(defun gnus-group-list-killed (&optional arg)
+  "List all killed newsgroups in the group buffer.
+If ARG is non-nil, list ALL killed groups known to Gnus.  This may
+entail asking the server for the groups."
+  (interactive "P")
+  ;; Find all possible killed newsgroups if arg.
+  (when arg
+    (gnus-get-killed-groups))
   (if (not gnus-killed-list)
       (gnus-message 6 "No killed groups")
     (let (gnus-group-list-mode)
-      (funcall gnus-group-prepare-function 
+      (funcall gnus-group-prepare-function
               gnus-level-killed t gnus-level-killed))
     (goto-char (point-min)))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
 (defun gnus-group-list-zombies ()
   "List all zombie newsgroups in the group buffer."
@@ -4679,23 +6378,65 @@ unsubscribed groups."
       (funcall gnus-group-prepare-function
               gnus-level-zombie t gnus-level-zombie))
     (goto-char (point-min)))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
+
+(defun gnus-group-list-active ()
+  "List all groups that are available from the server(s)."
+  (interactive)
+  ;; First we make sure that we have really read the active file.
+  (unless (gnus-read-active-file-p)
+    (let ((gnus-read-active-file t))
+      (gnus-read-active-file)))
+  ;; Find all groups and sort them.
+  (let ((groups
+        (sort
+         (let (list)
+           (mapatoms
+            (lambda (sym)
+              (and (boundp sym)
+                   (symbol-value sym)
+                   (setq list (cons (symbol-name sym) list))))
+            gnus-active-hashtb)
+           list)
+         'string<))
+       (buffer-read-only nil))
+    (erase-buffer)
+    (while groups
+      (gnus-group-insert-group-line-info (pop groups)))
+    (goto-char (point-min))))
+
+(defun gnus-activate-all-groups (level)
+  "Activate absolutely all groups."
+  (interactive (list 7))
+  (let ((gnus-activate-level level)
+       (gnus-activate-foreign-newsgroups level))
+    (gnus-group-get-new-news)))
 
 (defun gnus-group-get-new-news (&optional arg)
   "Get newly arrived articles.
-If ARG is non-nil, it should be a number between one and nine to
-specify which levels you are interested in re-scanning."
+If ARG is a number, it specifies which levels you are interested in
+re-scanning.  If ARG is non-nil and not a number, this will force
+\"hard\" re-reading of the active files from all servers."
   (interactive "P")
   (run-hooks 'gnus-get-new-news-hook)
+  ;; We might read in new NoCeM messages here.
+  (when (and gnus-use-nocem 
+            (null arg))
+    (gnus-nocem-scan-groups))
+  ;; If ARG is not a number, then we read the active file.
+  (when (and arg (not (numberp arg)))
+    (let ((gnus-read-active-file t))
+      (gnus-read-active-file))
+    (setq arg nil))
+
   (setq arg (gnus-group-default-level arg t))
   (if (and gnus-read-active-file (not arg))
       (progn
        (gnus-read-active-file)
-       (gnus-get-unread-articles (or arg (1+ gnus-level-subscribed))))
-    (let ((gnus-read-active-file (not arg))
-         (gnus-have-read-active-file 
-          (and (not arg) gnus-have-read-active-file)))
-      (gnus-get-unread-articles (or arg (1+ gnus-level-subscribed)))))
+       (gnus-get-unread-articles arg))
+    (let ((gnus-read-active-file (if arg nil gnus-read-active-file)))
+      (gnus-get-unread-articles arg)))
+  (run-hooks 'gnus-after-getting-new-news-hook)
   (gnus-group-list-groups))
 
 (defun gnus-group-get-new-news-this-group (&optional n)
@@ -4705,39 +6446,44 @@ If N is negative, this group and the N-1 previous groups will be checked."
   (interactive "P")
   (let* ((groups (gnus-group-process-prefix n))
         (ret (if (numberp n) (- n (length groups)) 0))
+        (beg (unless n (point)))
         group)
-    (while groups
-      (setq group (car groups)
-           groups (cdr groups))
+    (while (setq group (pop groups))
       (gnus-group-remove-mark group)
-      (or (gnus-get-new-news-in-group group)
-         (progn 
-           (ding) 
-           (message "%s error: %s" group (gnus-status-message group))
-           (sit-for 2))))
-    (gnus-group-next-unread-group 1 t)
-    (gnus-summary-position-cursor)
+      (if (gnus-activate-group group 'scan)
+         (progn
+           (gnus-get-unread-articles-in-group
+            (gnus-get-info group) (gnus-active group) t)
+           (unless (gnus-virtual-group-p group)
+             (gnus-close-group group))
+           (gnus-group-update-group group))
+       (gnus-error 3 "%s error: %s" group (gnus-status-message group))))
+    (when beg (goto-char beg))
+    (when gnus-goto-next-group-when-activating
+      (gnus-group-next-unread-group 1 t))
+    (gnus-summary-position-point)
     ret))
 
-(defun gnus-get-new-news-in-group (group)
-  (and group 
-       (gnus-activate-group 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-fetch-faq (group)
+(defun gnus-group-fetch-faq (group &optional faq-dir)
   "Fetch the FAQ for the current group."
-  (interactive (list (gnus-group-real-name (gnus-group-group-name))))
+  (interactive
+   (list
+    (gnus-group-real-name (gnus-group-group-name))
+    (cond (current-prefix-arg
+          (completing-read
+           "Faq dir: " (and (listp gnus-group-faq-directory)
+                            gnus-group-faq-directory))))))
+  (or faq-dir
+      (setq faq-dir (if (listp gnus-group-faq-directory)
+                       (car gnus-group-faq-directory)
+                     gnus-group-faq-directory)))
   (or group (error "No group name given"))
-  (let ((file (concat gnus-group-faq-directory (gnus-group-real-name group))))
+  (let ((file (concat (file-name-as-directory faq-dir)
+                     (gnus-group-real-name group))))
     (if (not (file-exists-p file))
        (error "No such file: %s" file)
       (find-file file))))
-  
+
 (defun gnus-group-describe-group (force &optional group)
   "Display a description of the current newsgroup."
   (interactive (list current-prefix-arg (gnus-group-group-name)))
@@ -4747,13 +6493,13 @@ If N is negative, this group and the N-1 previous groups will be checked."
     (or group (error "No group name given"))
     (and (or (and gnus-description-hashtb
                  ;; We check whether this group's method has been
-                 ;; queried for a description file.  
-                 (gnus-gethash 
-                  (gnus-group-prefixed-name "" method) 
+                 ;; queried for a description file.
+                 (gnus-gethash
+                  (gnus-group-prefixed-name "" method)
                   gnus-description-hashtb))
             (setq desc (gnus-group-get-description group))
             (gnus-read-descriptions-file method))
-        (message
+        (gnus-message 1
          (or desc (gnus-gethash group gnus-description-hashtb)
              "No description available")))))
 
@@ -4773,13 +6519,13 @@ If N is negative, this group and the N-1 previous groups will be checked."
        (setq b (point))
        (insert (format "      *: %-20s %s\n" (symbol-name group)
                       (symbol-value group)))
-       (add-text-properties 
+       (gnus-add-text-properties
        b (1+ b) (list 'gnus-group group
                       'gnus-unread t 'gnus-marked nil
                       'gnus-level (1+ gnus-level-subscribed))))
      gnus-description-hashtb)
     (goto-char (point-min))
-    (gnus-group-position-cursor)))
+    (gnus-group-position-point)))
 
 ;; Suggested by by Daniel Quinlan <quinlan@best.com>.
 (defun gnus-group-apropos (regexp &optional search-description)
@@ -4789,20 +6535,20 @@ If N is negative, this group and the N-1 previous groups will be checked."
        (obuf (current-buffer))
        groups des)
     ;; Go through all newsgroups that are known to Gnus.
-    (mapatoms 
+    (mapatoms
      (lambda (group)
        (and (symbol-name group)
            (string-match regexp (symbol-name group))
            (setq groups (cons (symbol-name group) groups))))
      gnus-active-hashtb)
-    ;; Go through all descriptions that are known to Gnus. 
-    (if search-description
-       (mapatoms 
-        (lambda (group)
-          (and (string-match regexp (symbol-value group))
-               (gnus-gethash (symbol-name group) gnus-active-hashtb)
-               (setq groups (cons (symbol-name group) groups))))
-        gnus-description-hashtb))
+    ;; Also go through all descriptions that are known to Gnus.
+    (when search-description
+      (mapatoms
+       (lambda (group)
+        (and (string-match regexp (symbol-value group))
+             (gnus-active (symbol-name group))
+             (setq groups (cons (symbol-name group) groups))))
+       gnus-description-hashtb))
     (if (not groups)
        (gnus-message 3 "No groups matched \"%s\"." regexp)
       ;; Print out all the groups.
@@ -4817,7 +6563,7 @@ If N is negative, this group and the N-1 previous groups will be checked."
              (progn
                (insert (setq prev (car groups)) "\n")
                (if (and gnus-description-hashtb
-                        (setq des (gnus-gethash (car groups) 
+                        (setq des (gnus-gethash (car groups)
                                                 gnus-description-hashtb)))
                    (insert "  " des "\n"))))
          (setq groups (cdr groups)))
@@ -4833,38 +6579,48 @@ If N is negative, this group and the N-1 previous groups will be checked."
   (gnus-group-apropos regexp t))
 
 ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
-(defun gnus-group-list-matching (level regexp &optional all lowest) 
+(defun gnus-group-list-matching (level regexp &optional all lowest)
   "List all groups with unread articles that match REGEXP.
 If the prefix LEVEL is non-nil, it should be a number that says which
-level to cut off listing groups. 
+level to cut off listing groups.
 If ALL, also list groups with no unread articles.
-If LOWEST, don't list groups with level lower than LOWEST."
+If LOWEST, don't list groups with level lower than LOWEST.
+
+This command may read the active file."
   (interactive "P\nsList newsgroups matching: ")
+  ;; First make sure active file has been read.
+  (when (and level
+            (>= (prefix-numeric-value level) gnus-level-killed))
+    (gnus-get-killed-groups))
   (gnus-group-prepare-flat (or level gnus-level-subscribed)
                           all (or lowest 1) regexp)
   (goto-char (point-min))
-  (gnus-group-position-cursor))
+  (gnus-group-position-point))
 
-(defun gnus-group-list-all-matching (level regexp &optional lowest) 
+(defun gnus-group-list-all-matching (level regexp &optional lowest)
   "List all groups that match REGEXP.
 If the prefix LEVEL is non-nil, it should be a number that says which
-level to cut off listing groups. 
+level to cut off listing groups.
 If LOWEST, don't list groups with level lower than LOWEST."
   (interactive "P\nsList newsgroups matching: ")
   (gnus-group-list-matching (or level gnus-level-killed) regexp t lowest))
 
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
-(defun gnus-group-save-newsrc ()
-  "Save the Gnus startup files."
-  (interactive)
-  (gnus-save-newsrc-file))
+(defun gnus-group-save-newsrc (&optional force)
+  "Save the Gnus startup files.
+If FORCE, force saving whether it is necessary or not."
+  (interactive "P")
+  (gnus-save-newsrc-file force))
 
 (defun gnus-group-restart (&optional arg)
   "Force Gnus to read the .newsrc file."
   (interactive "P")
-  (gnus-save-newsrc-file)
-  (gnus-setup-news 'force)
-  (gnus-group-list-groups arg))
+  (when (gnus-yes-or-no-p
+        (format "Are you sure you want to read %s? "
+                gnus-current-startup-file))
+    (gnus-save-newsrc-file)
+    (gnus-setup-news 'force)
+    (gnus-group-list-groups arg)))
 
 (defun gnus-group-read-init-file ()
   "Read the Gnus elisp init file."
@@ -4885,10 +6641,11 @@ If GROUP, edit that local kill file instead."
   (interactive "P")
   (setq gnus-current-kill-article article)
   (gnus-kill-file-edit-file group)
-  (gnus-message 
+  (gnus-message
    6
    (substitute-command-keys
-    "Editing a global kill file (Type \\[gnus-kill-file-exit] to exit)")))
+    (format "Editing a %s kill file (Type \\[gnus-kill-file-exit] to exit)"
+           (if group "local" "global")))))
 
 (defun gnus-group-edit-local-kill (article group)
   "Edit a local kill file."
@@ -4924,34 +6681,37 @@ The hook gnus-suspend-gnus-hook is called before actually suspending."
 (defun gnus-group-clear-dribble ()
   "Clear all information from the dribble buffer."
   (interactive)
-  (gnus-dribble-clear))
+  (gnus-dribble-clear)
+  (gnus-message 7 "Cleared dribble buffer"))
 
 (defun gnus-group-exit ()
   "Quit reading news after updating .newsrc.eld and .newsrc.
 The hook `gnus-exit-gnus-hook' is called before actually exiting."
   (interactive)
-  (if (or noninteractive               ;For gnus-batch-kill
+  (when 
+      (or noninteractive               ;For gnus-batch-kill
          (not (gnus-server-opened gnus-select-method)) ;NNTP connection closed
          (not gnus-interactive-exit)   ;Without confirmation
          gnus-expert-user
          (gnus-y-or-n-p "Are you sure you want to quit reading news? "))
-      (progn
-       (run-hooks 'gnus-exit-gnus-hook)
-       ;; Offer to save data from non-quitted summary buffers.
-       (gnus-offer-save-summaries)
-       ;; Save the newsrc file(s).
-       (gnus-save-newsrc-file)
-       ;; Kill-em-all.
-       (gnus-close-backends)
-       ;; Reset everything.
-       (gnus-clear-system))))
+    (run-hooks 'gnus-exit-gnus-hook)
+    ;; Offer to save data from non-quitted summary buffers.
+    (gnus-offer-save-summaries)
+    ;; Save the newsrc file(s).
+    (gnus-save-newsrc-file)
+    ;; Kill-em-all.
+    (gnus-close-backends)
+    ;; Reset everything.
+    (gnus-clear-system)
+    ;; Allow the user to do things after cleaning up.
+    (run-hooks 'gnus-after-exiting-gnus-hook)))
 
 (defun gnus-close-backends ()
-  ;; Send a close request to all backends that support such a request. 
+  ;; Send a close request to all backends that support such a request.
   (let ((methods gnus-valid-select-methods)
        func)
     (while methods
-      (if (fboundp (setq func (intern (concat (car (car methods))
+      (if (fboundp (setq func (intern (concat (caar methods)
                                              "-request-close"))))
          (funcall func))
       (setq methods (cdr methods)))))
@@ -4960,43 +6720,47 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
   "Quit reading news without updating .newsrc.eld or .newsrc.
 The hook `gnus-exit-gnus-hook' is called before actually exiting."
   (interactive)
-  (if (or noninteractive               ;For gnus-batch-kill
-         (zerop (buffer-size))
-         (not (gnus-server-opened gnus-select-method))
-         gnus-expert-user
-         (not gnus-current-startup-file)
-         (gnus-yes-or-no-p
-          (format "Quit reading news without saving %s? "
-                  (file-name-nondirectory gnus-current-startup-file))))
-      (progn
-       (run-hooks 'gnus-exit-gnus-hook)
-       (if gnus-use-full-window
-           (delete-other-windows)
-         (gnus-remove-some-windows))
-       (gnus-dribble-save)
-       (gnus-close-backends)
-       (gnus-clear-system))))
+  (when (or noninteractive             ;For gnus-batch-kill
+           (zerop (buffer-size))
+           (not (gnus-server-opened gnus-select-method))
+           gnus-expert-user
+           (not gnus-current-startup-file)
+           (gnus-yes-or-no-p
+            (format "Quit reading news without saving %s? "
+                    (file-name-nondirectory gnus-current-startup-file))))
+