(undigestify-rmail-message): Better error messages.
[bpt/emacs.git] / lisp / gnus.el
index 139dfe4..f9e1f73 100644 (file)
@@ -1,6 +1,8 @@
-;;; GNUS: an NNTP-based News Reader for GNU Emacs
-;; Copyright (C) 1987, 1988, 1989, 1990, 1993 Free Software Foundation, Inc.
-;; $Header: /gd/gnu/emacs/19.0/lisp/RCS/gnus.el,v 1.18 1993/06/05 09:17:34 rms Exp jimb $
+;;; gnus.el --- NNTP-based News Reader for GNU Emacs
+;; Copyright (C) 1987,88,89,90,93,94,95 Free Software Foundation, Inc.
+
+;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
+;; Keywords: news
 
 ;; This file is part of GNU Emacs.
 
@@ -49,8 +51,7 @@
 ;;     (setq gnus-nntp-service 119)
 ;;
 ;;     Or, if you'd like to use a local news spool directly in stead
-;;     of NNTP, install nnspool.el and set the variable to nil as
-;;     follows:
+;;     of NNTP, set the variable to nil as follows:
 ;;
 ;;     (setq gnus-nntp-service nil)
 ;;
 ;;     If you are not allowed to create the Info file to the standard
 ;;     Info-directory, create it in your private directory and set the
 ;;     variable gnus-info-directory to that directory.
-
-;; GNUS Mailing List:
-;; There are two mailing lists for GNUS lovers in the world:
-;;
-;;     info-gnus@flab.fujitsu.co.jp, and
-;;     info-gnus-english@tut.cis.ohio-state.edu.
-;;
-;; They are intended to exchange useful information about GNUS, such
-;; as bug fixes, useful hooks, and extensions.  The major difference
-;; between the lists is what the official language is.  Both Japanese
-;; and English are available in info-gnus, while English is only
-;; available in info-gnus-english. There is no need to subscribe to
-;; info-gnus if you cannot read Japanese messages, because most of the
-;; discussion and important announcements will be sent to
-;; info-gnus-english. Moreover, if you can read gnu.emacs.gnus
-;; newsgroup of USENET, you need not, either. info-gnus-english and
-;; gnu.emacs.gnus are linked each other.
 ;;
-;; Please send subscription request to:
-;;
-;;     info-gnus-request@flab.fujitsu.co.jp, or
-;;     info-gnus-english-request@cis.ohio-state.edu
+;; For getting more information about GNUS, consult USENET newsgorup
+;; gnu.emacs.gnus.
 
 ;; TO DO:
 ;; (1) Incremental update of active info.
-;; (2) GNUS own poster.
-;; (3) Multi-GNUS (Talking to many hosts same time).
-;; (4) Asynchronous transmission of large messages.
+;; (2) Asynchronous transmission of large messages.
+
+;;; Code:
 
-(provide 'gnus)
 (require 'nntp)
 (require 'mail-utils)
+(require 'timezone)
+
+(defvar gnus-default-nntp-server nil
+  "*Specify default NNTP server.
+This variable should be defined in `site-init.el'.")
 
 (defvar gnus-nntp-server (or (getenv "NNTPSERVER") gnus-default-nntp-server)
   "*The name of the host running NNTP server.
-If it is a string such as `:DIRECTORY', the user's private DIRECTORY
-is used as a news spool.
-Initialized from the NNTPSERVER environment variable.")
+If it is a string starting with a colon, as in as `:DIRECTORY', then the
+directory ~/DIRECTORY is used as the news spool.
+This variable is initialized from the NNTPSERVER environment variable
+or from `gnus-default-nntp-server'.")
 
 (defvar gnus-nntp-service "nntp"
   "*NNTP service name (\"nntp\" or 119).
 Go to a local news spool if its value is nil.")
 
 (defvar gnus-startup-file "~/.newsrc"
-  "*Your .newsrc file. Use `.newsrc-SERVER' instead if exists.")
+  "*Your `.newsrc' file.  Use `.newsrc-SERVER' instead if exists.")
 
 (defvar gnus-signature-file "~/.signature"
-  "*Your .signature file. Use `.signature-DISTRIBUTION' instead if exists.")
+  "*Your `.signature' file.  Use `.signature-DISTRIBUTION' instead if exists.")
 
 (defvar gnus-use-cross-reference t
   "*Specifies what to do with cross references (Xref: field).
@@ -137,7 +124,7 @@ read in all newsgroups.")
 
 (defvar gnus-use-followup-to t
   "*Specifies what to do with Followup-To: field.
-If nil, ignore followup-to: field.  If t, use its value except for
+If nil, ignore `Followup-to:' field.  If t, use its value except for
 `poster'.  Otherwise, if not nil nor t, always use its value.")
 
 (defvar gnus-large-newsgroup 50
@@ -150,25 +137,29 @@ confirmation is required for selecting the newsgroup.")
 Initialized from the AUTHORCOPY environment variable.
 
 Articles are saved using a function specified by the the variable
-gnus-author-copy-saver (rmail-output is default) if a file name is
+`gnus-author-copy-saver' (`rmail-output' is default) if a file name is
 given.  Instead, if the first character of the name is `|', the
-contents of the article is piped out to the named program. It is
+contents of the article is piped out to the named program.  It is
 possible to save an article in an MH folder as follows:
 
-(setq gnus-author-copy \"|/usr/local/lib/mh/rcvstore +Article\")")
+\(setq gnus-author-copy \"|/usr/local/lib/mh/rcvstore +Article\")")
 
 (defvar gnus-author-copy-saver (function rmail-output)
   "*A function called with a file name to save an author copy to.
-The default function is `rmail-output' which saves in Unix mailbox format.")
+The default function is `rmail-output' which saves in  inbox format.")
 
 (defvar gnus-use-long-file-name
   (not (memq system-type '(usg-unix-v xenix)))
   "*Non-nil means that a newsgroup name is used as a default file name
-to save articles to. If it's nil, the directory form of a newsgroup is
+to save articles to.  If it's nil, the directory form of a newsgroup is
 used instead.")
 
 (defvar gnus-article-save-directory (getenv "SAVEDIR")
-  "*A directory name to save articles to (default to ~/News).
+  "*A directory name to save articles to (default is `~/News').
+Initialized from the SAVEDIR environment variable.")
+
+(defvar gnus-kill-files-directory (getenv "SAVEDIR")
+  "*A directory name to save kill files to (default to ~/News).
 Initialized from the SAVEDIR environment variable.")
 
 (defvar gnus-default-article-saver (function gnus-summary-save-in-rmail)
@@ -202,8 +193,9 @@ The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
   "*File name of a KILL file.")
 
 (defvar gnus-novice-user t
-  "*Non-nil means that you are a novice to USENET.  If non-nil,
-verbose messages may be displayed or your confirmations may be required.")
+  "*Non-nil means that you are a novice to USENET.
+If non-nil, verbose messages may be displayed
+or your confirmations may be required.")
 
 (defvar gnus-interactive-catchup t
   "*Require your confirmation when catching up a newsgroup if non-nil.")
@@ -212,11 +204,11 @@ verbose messages may be displayed or your confirmations may be required.")
   "*Newsgroup, subject, and distribution will be asked for if non-nil.")
 
 (defvar gnus-interactive-exit t
-  "*Require your confirmation when exiting gnus if non-nil.")
+  "*Require your confirmation when exiting GNUS if non-nil.")
 
 (defvar gnus-user-login-name nil
   "*The login name of the user.
-Got from the USER and LOGNAME environment variable if undefined.")
+Got from the function `user-login-name' if undefined.")
 
 (defvar gnus-user-full-name nil
   "*The full name of the user.
@@ -233,8 +225,8 @@ Got from the NAME environment variable if undefined.")
 
 (defvar gnus-thread-hide-subtree nil
   "*Non-nil means hide thread subtrees initially.
-If non-nil, you have to run the command gnus-summary-show-thread by
-hand or by using gnus-select-article-hook to show hidden threads.")
+If non-nil, you have to run the command `gnus-summary-show-thread' by
+hand or by using `gnus-select-article-hook' to show hidden threads.")
 
 (defvar gnus-thread-hide-killed t
   "*Non-nil means hide killed thread subtrees automatically.")
@@ -247,22 +239,24 @@ If it is non-nil, some commands work with subjects do not work properly.")
   "*Indentation of thread subtrees.")
 
 (defvar gnus-ignored-newsgroups "^to\\..*$"
-  "*A regular expression used to ignore uninterested newsgroups in the active file.
+  "*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,
 thus making them effectively invisible.")
 
 (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:"
-  "*All random fields within the header of a message.")
+  "*Header fields not worth displaying.
+Ordinarily GNUS excludes these when displaying an article.
+If you want to see them, ask to see the message with \"the full header\"
+\(also known as \"the original header\").")
 
 (defvar gnus-required-headers
   '(From Date Newsgroups Subject Message-ID Path Organization Distribution)
   "*All required fields for articles you post.
 RFC977 and RFC1036 require From, Date, Newsgroups, Subject, Message-ID
 and Path fields.  Organization, Distribution and Lines are optional.
-If you want GNUS not to insert some field, remove it from the
-variable.")
+If you want GNUS not to insert some field, remove it from this list.")
 
 (defvar gnus-show-all-headers nil
   "*Show all headers of an article if non-nil.")
@@ -272,7 +266,7 @@ variable.")
 
 (defvar gnus-optional-headers (function gnus-optional-lines-and-from)
   "*A function generating a optional string displayed in GNUS Summary
-mode buffer.  The function is called with an article HEADER. The
+mode buffer.  The function is called with an article HEADER.  The
 result must be a string excluding `[' and `]'.")
 
 (defvar gnus-auto-extend-newsgroup t
@@ -281,14 +275,14 @@ result must be a string excluding `[' and `]'.")
 (defvar gnus-auto-select-first t
   "*Select the first unread article automagically if non-nil.
 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
-or gnus-apply-kill-hook.")
+in some newsgroups, set the variable to nil in `gnus-select-group-hook'
+or `gnus-apply-kill-hook'.")
 
 (defvar gnus-auto-select-next t
   "*Select the next newsgroup automagically if non-nil.
 If the value is t and the next newsgroup is empty, GNUS will exit
 Summary mode and go back to Group mode.  If the value is neither nil
-nor t, GNUS will select the following unread newsgroup. Especially, if
+nor t, GNUS will select the following unread newsgroup.  Especially, if
 the value is the symbol `quietly', the next unread newsgroup will be
 selected without any confirmations.")
 
@@ -301,7 +295,7 @@ selected without any confirmations.")
 (defvar gnus-auto-mail-to-author nil
   "*Insert `To: author' of the article when following up if non-nil.
 Mail is sent using the function specified by the variable
-gnus-mail-send-method.")
+`gnus-mail-send-method'.")
 
 (defvar gnus-break-pages t
   "*Break an article into pages if non-nil.
@@ -335,37 +329,36 @@ The function is expected to process current buffer as a MIME message.")
 (defvar gnus-mail-reply-method
   (function gnus-mail-reply-using-mail)
   "*Function to compose reply mail.
-The function gnus-mail-reply-using-mail uses usual sendmail mail
-program.  The function gnus-mail-reply-using-mhe uses mh-e mail
+The function `gnus-mail-reply-using-mail' uses usual sendmail mail
+program.  The function `gnus-mail-reply-using-mhe' uses the MH-E mail
 program.  You can use yet another program by customizing this variable.")
 
 (defvar gnus-mail-forward-method
   (function gnus-mail-forward-using-mail)
   "*Function to forward current message to another user.
-The function gnus-mail-reply-using-mail uses usual sendmail mail
-program. You can use yet another program by customizing this variable.")
+The function `gnus-mail-reply-using-mail' uses usual sendmail mail
+program.  You can use yet another program by customizing this variable.")
 
 (defvar gnus-mail-other-window-method
   (function gnus-mail-other-window-using-mail)
   "*Function to compose mail in other window.
-The function gnus-mail-other-window-using-mail uses usual sendmail
-mail program.  The function gnus-mail-other-window-using-mhe uses mh-e
+The function `gnus-mail-other-window-using-mail' uses the usual sendmail
+mail program.  The function `gnus-mail-other-window-using-mhe' uses the MH-E
 mail program.  You can use yet another program by customizing this variable.")
 
 (defvar gnus-mail-send-method send-mail-function
   "*Function to mail a message too which is being posted as an article.
-The message must have To: or Cc: field.  The value of the variable
-send-mail-function is the default function which uses sendmail mail
-program.")
+The message must have To: or Cc: field.  The default is copied from
+the variable `send-mail-function'.")
 
 (defvar gnus-subscribe-newsgroup-method
   (function gnus-subscribe-alphabetically)
   "*Function called with a newsgroup name when new newsgroup is found.
-The function gnus-subscribe-randomly inserts a new newsgroup a the
-beginning of newsgroups.  The function gnus-subscribe-alphabetically
+The function `gnus-subscribe-randomly' inserts a new newsgroup a the
+beginning of newsgroups.  The function `gnus-subscribe-alphabetically'
 inserts it in strict alphabetic order.  The function
-gnus-subscribe-hierarchically inserts it in hierarchical newsgroup
-order.  The function gnus-subscribe-interactively asks for your decision.")
+`gnus-subscribe-hierarchically' inserts it in hierarchical newsgroup
+order.  The function `gnus-subscribe-interactively' asks for your decision.")
 
 (defvar gnus-group-mode-hook nil
   "*A hook for GNUS Group Mode.")
@@ -384,7 +377,7 @@ order.  The function gnus-subscribe-interactively asks for your decision.")
 
 (defvar gnus-startup-hook nil
   "*A hook called at start up time.
-This hook is called after GNUS is connected to the NNTP server. So, it
+This hook is called after GNUS is connected to the NNTP server.  So, it
 is possible to change the behavior of GNUS according to the selected
 NNTP server.")
 
@@ -405,140 +398,139 @@ If you want to run a special decoding program like nkf, use this hook.")
 If you want to sort Summary buffer by date and then by subject, you
 can use the following hook:
 
-(setq gnus-select-group-hook
-      (function
-       (lambda ()
-        ;; First of all, sort by date.
-        (gnus-keysort-headers
-         (function string-lessp)
-         (function
-          (lambda (a)
-            (gnus-sortable-date (gnus-header-date a)))))
-        ;; Then sort by subject string ignoring `Re:'.
-        ;; If case-fold-search is non-nil, case of letters is ignored.
-        (gnus-keysort-headers
-         (function string-lessp)
-         (function
-          (lambda (a)
-            (if case-fold-search
-                (downcase (gnus-simplify-subject (gnus-header-subject a) t))
-              (gnus-simplify-subject (gnus-header-subject a) t)))))
-        )))
+\(add-hook 'gnus-select-group-hook
+       (function
+       (lambda ()
+         ;; First of all, sort by date.
+         (gnus-keysort-headers
+          (function string-lessp)
+          (function
+           (lambda (a)
+             (gnus-sortable-date (gnus-header-date a)))))
+         ;; Then sort by subject string ignoring `Re:'.
+         ;; If case-fold-search is non-nil, case of letters is ignored.
+         (gnus-keysort-headers
+          (function string-lessp)
+          (function
+           (lambda (a)
+             (if case-fold-search
+                 (downcase (gnus-simplify-subject (gnus-header-subject a) t))
+               (gnus-simplify-subject (gnus-header-subject a) t)))))
+         )))
 
 If you'd like to simplify subjects like the
 `gnus-summary-next-same-subject' command does, you can use the
 following hook:
 
-(setq gnus-select-group-hook
-      (function
-       (lambda ()
-        (mapcar (function
-                 (lambda (header)
-                   (nntp-set-header-subject
-                    header
-                    (gnus-simplify-subject
-                     (gnus-header-subject header) 're-only))))
-                gnus-newsgroup-headers))))
-
-In some newsgroups author name is meaningless. It is possible to
+\(add-hook 'gnus-select-group-hook
+       (function
+       (lambda ()
+         (mapcar (function
+                  (lambda (header)
+                    (nntp-set-header-subject
+                     header
+                     (gnus-simplify-subject
+                      (gnus-header-subject header) 're-only))))
+                 gnus-newsgroup-headers))))
+
+In some newsgroups author name is meaningless.  It is possible to
 prevent listing author names in GNUS Summary buffer as follows:
 
-(setq gnus-select-group-hook
-      (function
-       (lambda ()
-        (cond ((string-equal \"comp.sources.unix\" gnus-newsgroup-name)
-               (setq gnus-optional-headers
-                     (function gnus-optional-lines)))
-              (t
-               (setq gnus-optional-headers
-                     (function gnus-optional-lines-and-from)))))))")
+\(add-hook 'gnus-select-group-hook
+       (function
+       (lambda ()
+         (cond ((string-equal \"comp.sources.unix\" gnus-newsgroup-name)
+                (setq gnus-optional-headers
+                      (function gnus-optional-lines)))
+               (t
+                (setq gnus-optional-headers
+                      (function gnus-optional-lines-and-from)))))))")
 
 (defvar gnus-select-article-hook
-  (function (lambda () (gnus-summary-show-thread)))
+  '(gnus-summary-show-thread)
   "*A hook called when an article is selected.
 The default hook shows conversation thread subtrees of the selected
-article automatically as follows:
-
-(setq gnus-select-article-hook
-      (function 
-       (lambda ()
-        (gnus-summary-show-thread))))
+article automatically using `gnus-summary-show-thread'.
 
-If you'd like to run RMAIL on a digest article automagically, you can
+If you'd like to run Rmail on a digest article automagically, you can
 use the following hook:
 
-(setq gnus-select-article-hook
-      (function
-       (lambda ()
-        (gnus-summary-show-thread)
-        (cond ((string-equal \"comp.sys.sun\" gnus-newsgroup-name)
-               (gnus-summary-rmail-digest))
-              ((and (string-equal \"comp.text\" gnus-newsgroup-name)
-                    (string-match \"^TeXhax Digest\"
-                                  (gnus-header-subject gnus-current-headers)))
-               (gnus-summary-rmail-digest)
-               )))))")
+\(add-hook 'gnus-select-article-hook
+       (function
+       (lambda ()
+         (cond ((string-equal \"comp.sys.sun\" gnus-newsgroup-name)
+                (gnus-summary-rmail-digest))
+               ((and (string-equal \"comp.text\" gnus-newsgroup-name)
+                     (string-match \"^TeXhax Digest\"
+                                   (gnus-header-subject gnus-current-headers)))
+                (gnus-summary-rmail-digest)
+                ))))
+       t)")
 
 (defvar gnus-select-digest-hook
-  (function
-   (lambda ()
-     ;; Reply-To: is required by `undigestify-rmail-message'.
-     (or (mail-position-on-field "Reply-to" t)
-        (progn
-          (mail-position-on-field "Reply-to")
-          (insert (gnus-fetch-field "From"))))))
+  (list
+   (function
+    (lambda ()
+      ;; Reply-To: is required by `undigestify-rmail-message'.
+      (or (mail-position-on-field "Reply-to" t)
+         (progn
+           (mail-position-on-field "Reply-to")
+           (insert (gnus-fetch-field "From")))))))
   "*A hook called when reading digest messages using Rmail.
 This hook can be used to modify incomplete digest articles as follows
-(this is the default):
+\(this is the default):
 
-(setq gnus-select-digest-hook
-      (function
-       (lambda ()
-        ;; Reply-To: is required by `undigestify-rmail-message'.
-        (or (mail-position-on-field \"Reply-to\" t)
-            (progn
-              (mail-position-on-field \"Reply-to\")
-              (insert (gnus-fetch-field \"From\")))))))")
+\(add-hook 'gnus-select-digest-hook
+       (function
+       (lambda ()
+         ;; Reply-To: is required by `undigestify-rmail-message'.
+         (or (mail-position-on-field \"Reply-to\" t)
+             (progn
+               (mail-position-on-field \"Reply-to\")
+               (insert (gnus-fetch-field \"From\")))))))")
 
 (defvar gnus-rmail-digest-hook nil
   "*A hook called when reading digest messages using Rmail.
 This hook is intended to customize Rmail mode for reading digest articles.")
 
-(defvar gnus-apply-kill-hook (function gnus-apply-kill-file)
+(defvar gnus-apply-kill-hook '(gnus-apply-kill-file)
   "*A hook called when a newsgroup is selected and summary list is prepared.
 This hook is intended to apply a KILL file to the selected newsgroup.
-The function `gnus-apply-kill-file' is called defaultly.
+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:
 
-(setq gnus-apply-kill-hook
-      (function
-       (lambda ()
-        (cond ((string-match \"control\" gnus-newsgroup-name)
-               (gnus-kill \"Subject\" \"rmgroup\")
-               (gnus-expunge \"X\"))))))")
+\(setq gnus-apply-kill-hook
+      (list
+       (function
+       (lambda ()
+         (cond ((string-match \"control\" gnus-newsgroup-name)
+                (gnus-kill \"Subject\" \"rmgroup\")
+                (gnus-expunge \"X\")))))))")
 
 (defvar gnus-mark-article-hook
-  (function
-   (lambda ()
-     (or (memq gnus-current-article gnus-newsgroup-marked)
-        (gnus-summary-mark-as-read gnus-current-article))
-     (gnus-summary-set-current-mark "+")))
+  (list
+   (function
+    (lambda ()
+      (or (memq gnus-current-article gnus-newsgroup-marked)
+         (gnus-summary-mark-as-read gnus-current-article))
+      (gnus-summary-set-current-mark "+"))))
   "*A hook called when an article is selected at the first time.
 The hook is intended to mark an article as read (or unread)
 automatically when it is selected.
 
 If you'd like to mark as unread (-) instead, use the following hook:
 
-(setq gnus-mark-article-hook
-      (function
-       (lambda ()
-        (gnus-summary-mark-as-unread gnus-current-article)
-        (gnus-summary-set-current-mark \"+\"))))")
+\(setq gnus-mark-article-hook
+      (list
+       (function
+        (lambda ()
+         (gnus-summary-mark-as-unread gnus-current-article)
+         (gnus-summary-set-current-mark \"+\")))))")
 
 (defvar gnus-prepare-article-hook (list (function gnus-inews-insert-signature))
   "*A hook called after preparing body, but before preparing header fields.
@@ -553,7 +545,7 @@ to a file).")
 (defvar gnus-exit-group-hook nil
   "*A hook called when exiting (not quitting) Summary mode.
 If your machine is so slow that exiting from Summary mode takes very
-long time, set the variable `gnus-use-cross-reference' to nil. This
+long time, set the variable `gnus-use-cross-reference' to nil.  This
 inhibits marking articles as read using cross-reference information.")
 
 (defvar gnus-suspend-gnus-hook nil
@@ -567,7 +559,7 @@ inhibits marking articles as read using cross-reference information.")
 This hook is called before saving the `.newsrc' file.")
 
 \f
-;; Site dependent variables. You have to define these variables in
+;; Site dependent variables.  You have to define these variables in
 ;;  site-init.el, default.el or your .emacs.
 
 (defvar gnus-local-timezone nil
@@ -597,23 +589,49 @@ file is available, its content is also used.")
 
 (defvar gnus-use-generic-from nil
   "*If nil, prepend local host name to the defined domain in the From:
-field; if stringp, use this; if non-nil, strip of the local host name.")
+field; if a string, use this; if non-nil, strip off the local host name.")
 
 (defvar gnus-use-generic-path nil
   "*If nil, use the NNTP server name in the Path: field; if stringp,
 use this; if non-nil, use no host name (user name only)")
+
+(defvar gnus-newsgroups-regex "^\\([^ \t\n]+\\)[ \t]+\\(.*\\)$"
+  "Regex to retrieve the group name and the group description from
+the output of the newsgroups listing.
+
+If you have ^M at the end of lines try \"^\\([^ \t\n]+\\)[ \t]+\\([^\r]+\\)[\r]*$\"")
+
+(defvar gnus-newsgroups-display t
+  "*display the newsgroup description in *Newsgroup* buffer if not nil")
+
+(defvar gnus-newsgroups-alist nil
+  "alist (groupname . description)")
+
+(defvar gnus-newsgroups-hashtb nil
+  "hashtable of gnus-newsgroups-alist")
+
+(defvar gnus-newsgroups-showall nil
+  "non nil if we display all the groups")
+
 \f
 ;; Internal variables.
 
-(defconst gnus-version "GNUS 3.15"
+(defconst gnus-version "GNUS 4.1"
   "Version numbers of this version of GNUS.")
 
+(defconst gnus-emacs-version
+  (progn
+    (string-match "[0-9]*" emacs-version)
+    (string-to-int (substring emacs-version
+                             (match-beginning 0) (match-end 0))))
+  "Major version number of this emacs.")
+
 (defvar gnus-info-nodes
   '((gnus-group-mode           "(gnus)Newsgroup Commands")
     (gnus-summary-mode         "(gnus)Summary Commands")
     (gnus-article-mode         "(gnus)Article Commands")
-    (gnus-kill-file-mode       "(gnus)KILL File")
-    (gnus-browse-killed-mode   "(gnus)Maintenance"))
+    (gnus-kill-file-mode       "(gnus)Kill File")
+    (gnus-browse-killed-mode   "(gnus)Maintaining Subscriptions"))
   "Assoc list of major modes and related Info nodes.")
 
 ;; Alist syntax is different from that of 3.14.3.
@@ -682,7 +700,7 @@ It is a list of `(original overload &optional file)'.")
 (defvar gnus-distribution-list nil)
 
 (defvar gnus-newsrc-options nil
-  "Options line in the .newsrc file.")
+  "Options line in the `.newsrc' file.")
 
 (defvar gnus-newsrc-options-n-yes nil
   "Regexp representing subscribed newsgroups.")
@@ -692,24 +710,24 @@ It is a list of `(original overload &optional file)'.")
 
 (defvar gnus-newsrc-assoc nil
   "Assoc list of read articles.
-gnus-newsrc-hashtb should be kept so that both hold the same information.")
+`gnus-newsrc-hashtb' should be kept so that both hold the same information.")
 
 (defvar gnus-newsrc-hashtb nil
-  "Hashtable of gnus-newsrc-assoc.")
+  "Hashtable of `gnus-newsrc-assoc'.")
 
 (defvar gnus-killed-assoc nil
-  "Assoc list of newsgroups removed from gnus-newsrc-assoc.
-gnus-killed-hashtb should be kept so that both hold the same information.")
+  "Assoc list of newsgroups removed from `gnus-newsrc-assoc'.
+`gnus-killed-hashtb' should be kept so that both hold the same information.")
 
 (defvar gnus-killed-hashtb nil
-  "Hashtable of gnus-killed-assoc.")
+  "Hashtable of `gnus-killed-assoc'.")
 
 (defvar gnus-marked-assoc nil
   "Assoc list of articles marked as unread.
-gnus-marked-hashtb should be kept so that both hold the same information.")
+`gnus-marked-hashtb' should be kept so that both hold the same information.")
 
 (defvar gnus-marked-hashtb nil
-  "Hashtable of gnus-marked-assoc.")
+  "Hashtable of `gnus-marked-assoc'.")
 
 (defvar gnus-unread-hashtb nil
   "Hashtable of unread articles.")
@@ -750,9 +768,8 @@ gnus-marked-hashtb should be kept so that both hold the same information.")
 
 (defvar gnus-newsgroup-headers nil
   "List of article headers in the current newsgroup.
-If the variable is modified (added or deleted), the function
-gnus-clear-hashtables-for-newsgroup-headers must be called to clear
-the hash tables.")
+If you modify the variable, you must call the function
+`gnus-clear-hashtables-for-newsgroup-headers' to clear the hash tables.")
 (defvar gnus-newsgroup-headers-hashtb-by-id nil)
 (defvar gnus-newsgroup-headers-hashtb-by-number nil)
 
@@ -771,8 +788,8 @@ the hash tables.")
 (defvar gnus-article-mode-map nil)
 (defvar gnus-kill-file-mode-map nil)
 
-(defvar rmail-last-file (expand-file-name "~/XMBOX"))
-(defvar rmail-last-rmail-file (expand-file-name "~/XNEWS"))
+(defvar rmail-default-file (expand-file-name "~/XMBOX"))
+(defvar rmail-default-rmail-file (expand-file-name "~/XNEWS"))
 
 ;; Define GNUS Subsystems.
 (autoload 'gnus-group-post-news "gnuspost"
@@ -809,10 +826,7 @@ the hash tables.")
          "Rewrite Date field in GMT to local in current buffer.")
 
 (autoload 'metamail-buffer "metamail"
-         "Process current buffer through 'metamail'." t)
-
-(autoload 'timezone-make-sortable-date "timezone")
-(autoload 'timezone-parse-date "timezone")
+         "Process current buffer through `metamail'." t)
 
 (autoload 'rmail-output "rmailout"
          "Append this message to Unix mail file named FILE-NAME." t)
@@ -824,6 +838,8 @@ the hash tables.")
 (put 'gnus-summary-mode 'mode-class 'special)
 (put 'gnus-article-mode 'mode-class 'special)
 
+(autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap)
+(autoload 'gnus-uu-mark-article "gnus-uu" nil t)
 \f
 ;;(put 'gnus-eval-in-buffer-window 'lisp-indent-hook 1)
 
@@ -848,13 +864,13 @@ Optional argument HASHSIZE specifies the table size."
   (` (symbol-value (intern-soft (, string) (, hashtable)))))
 
 (defmacro gnus-sethash (string value hashtable)
-  "Set hash value. Arguments are STRING, VALUE, and 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))))
 
-;; Note: Macros defined here are also defined in nntp.el. I don't like
+;; Note: Macros defined here are also defined in nntp.el.  I don't like
 ;; to put them here, but many users got troubled with the old
-;; definitions in nntp.elc. These codes are NNTP 3.10 version.
+;; definitions in nntp.elc.  These codes are NNTP 3.10 version.
 
 (defmacro nntp-header-number (header)
   "Return article number in HEADER."
@@ -939,6 +955,8 @@ Optional argument HASHSIZE specifies the table size."
   (define-key gnus-group-mode-map "P" 'gnus-group-prev-group)
   (define-key gnus-group-mode-map "\C-n" 'gnus-group-next-group)
   (define-key gnus-group-mode-map "\C-p" 'gnus-group-prev-group)
+  (define-key gnus-group-mode-map [down] 'gnus-group-next-group)
+  (define-key gnus-group-mode-map [up] 'gnus-group-prev-group)
   (define-key gnus-group-mode-map "\r" 'next-line)
   ;;(define-key gnus-group-mode-map "/" 'isearch-forward)
   (define-key gnus-group-mode-map "<" 'beginning-of-buffer)
@@ -968,7 +986,60 @@ Optional argument HASHSIZE specifies the table size."
   (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 "?" 'gnus-group-describe-briefly)
-  (define-key gnus-group-mode-map "\C-c\C-i" 'gnus-info-find-node))
+  (define-key gnus-group-mode-map "\C-c\C-i" 'gnus-info-find-node)
+  (define-key gnus-group-mode-map   [mouse-2] 'gnus-mouse-pick-group)
+  (define-key gnus-group-mode-map "t" 'gnus-newsgroups-display-toggle)
+
+  ;; Make a menu bar item.
+  (define-key gnus-group-mode-map [menu-bar GNUS]
+       (cons "GNUS" (make-sparse-keymap "GNUS")))
+
+  (define-key gnus-group-mode-map [menu-bar GNUS force-update]
+       '("Force Update" . gnus-group-force-update))
+  (define-key gnus-group-mode-map [menu-bar GNUS quit]
+       '("Quit" . gnus-group-quit))
+  (define-key gnus-group-mode-map [menu-bar GNUS exit]
+       '("Exit" . gnus-group-exit))
+  (define-key gnus-group-mode-map [menu-bar GNUS restart]
+       '("Restart" . gnus-group-restart))
+  (define-key gnus-group-mode-map [menu-bar GNUS suspend]
+       '("Suspend" . gnus-group-suspend))
+  (define-key gnus-group-mode-map [menu-bar GNUS get-new-news]
+       '("Get New News" . gnus-group-get-new-news))
+
+  ;; Make a menu bar item.
+  (define-key gnus-group-mode-map [menu-bar groups]
+       (cons "Groups" (make-sparse-keymap "Groups")))
+
+  (define-key gnus-group-mode-map [menu-bar groups catchup]
+       '("Catchup" . gnus-group-catchup))
+  (define-key gnus-group-mode-map [menu-bar groups edit-global-kill]
+       '("Edit Kill File" . gnus-group-edit-global-kill))
+
+  (define-key gnus-group-mode-map [menu-bar groups separator-2]
+       '("--"))
+
+  (define-key gnus-group-mode-map [menu-bar groups yank-group]
+       '("Yank Group" . gnus-group-yank-group))
+  (define-key gnus-group-mode-map [menu-bar groups kill-group]
+       '("Kill Group" . gnus-group-kill-group))
+
+  (define-key gnus-group-mode-map [menu-bar groups separator-1]
+       '("--"))
+
+  (define-key gnus-group-mode-map [menu-bar groups newsgroups-update-description]
+        '("Update descriptions" . gnus-newsgroups-update-description))
+  (define-key gnus-group-mode-map [menu-bar groups newsgroups-display-toggle]
+        '("Toggle descriptions" . gnus-newsgroups-display-toggle))
+  (define-key gnus-group-mode-map [menu-bar groups jump-to-group]
+       '("Jump to Group..." . gnus-group-jump-to-group))
+  (define-key gnus-group-mode-map [menu-bar groups list-all-groups]
+       '("List All Groups" . gnus-group-list-all-groups))
+  (define-key gnus-group-mode-map [menu-bar groups list-groups]
+       '("List Groups" . gnus-group-list-groups))
+  (define-key gnus-group-mode-map [menu-bar groups unsub-current-group]
+       '("Unsubscribe Group" . gnus-group-unsubscribe-current-group))
+  )
 
 (defun gnus-group-mode ()
   "Major mode for reading network news.
@@ -1010,17 +1081,18 @@ V       Show the version number of this GNUS.
 ?      Describe Group Mode commands briefly.
 C-h m  Describe Group Mode.
 C-c C-i        Read Info about Group Mode.
+t       Toggle displaying newsgroup descriptions.
 
   The name of the host running NNTP server is asked for if no default
-host is specified. It is also possible to choose another NNTP server
+host is specified.  It is also possible to choose another NNTP server
 even when the default server is defined by giving a prefix argument to
 the command `\\[gnus]'.
 
-  If an NNTP server is preceded by a colon such as `:Mail', the user's
-private directory `~/Mail' is used as a news spool. This makes it
+  If the NNTP server name starts with a colon, as in `:Mail', the user's
+own directory `~/Mail' is used as a news spool.  This makes it
 possible to read mail stored in MH folders or articles saved by GNUS.
 File names of mail or articles must consist of only numeric
-characters. Otherwise, they are ignored.
+characters.  Otherwise, they are ignored.
 
   If there is a file named `~/.newsrc-SERVER', it is used as the
 startup file instead of standard one when talking to SERVER.  It is
@@ -1028,7 +1100,7 @@ possible to talk to many hosts by using different startup files for
 each.
 
   Option `-n' of the options line in the startup file is recognized
-properly the same as the Bnews system. For example, if the options
+properly the same as the Bnews system.  For example, if the options
 line is `options -n !talk talk.rumors', newsgroups under the `talk'
 hierarchy except for `talk.rumors' are ignored while checking new
 newsgroups.
@@ -1047,7 +1119,7 @@ nntp.el, nnspool.el, and mhspoo.el, respectively.
 
 User customizable variables:
  gnus-nntp-server
-    Specifies the name of the host running the NNTP server. If its
+    Specifies the name of the host running the NNTP server.  If its
     value is a string such as `:DIRECTORY', the user's private
     DIRECTORY is used as a news spool.  The variable is initialized
     from the NNTPSERVER environment variable.
@@ -1128,12 +1200,12 @@ User customizable variables:
 Various hooks for customization:
  gnus-group-mode-hook
     Entry to this mode calls the value with no arguments, if that
-    value is non-nil. This hook is called before GNUS is connected to
-    the NNTP server. So, you can change or define the NNTP server in
+    value is non-nil.  This hook is called before GNUS is connected to
+    the NNTP server.  So, you can change or define the NNTP server in
     this hook.
 
  gnus-startup-hook
-    Called with no arguments after the NNTP server is selected. It is
+    Called with no arguments after the NNTP server is selected.  It is
     possible to change the behavior of GNUS or initialize the
     variables according to the selected NNTP server.
 
@@ -1181,8 +1253,14 @@ Various hooks for customization:
   (use-local-map gnus-group-mode-map)
   (buffer-flush-undo (current-buffer))
   (setq buffer-read-only t)            ;Disable modification
+  (setq truncate-lines t)              ;In case descriptions are too long.
   (run-hooks 'gnus-group-mode-hook))
 
+(defun gnus-mouse-pick-group (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-group-read-group nil))
+
 ;;;###autoload
 (defun gnus (&optional confirm)
   "Read network news.
@@ -1211,19 +1289,20 @@ If optional argument CONFIRM is non-nil, ask NNTP server."
 (defun gnus-group-startup-message ()
   "Insert startup message in current buffer."
   ;; Insert the message.
-  (insert "
-                   GNUS Version 3.15
+  (insert
+   (format "
+                   %s
 
          NNTP-based News Reader for GNU Emacs
 
 
 If you have any trouble with this software, please let me
-know. I will fix your problems in the next release.
+know.  I will fix your problems in the next release.
 
 Comments, suggestions, and bug fixes are welcome.
 
 Masanobu UMEDA
-umerin@mse.kyutech.ac.jp")
+umerin@mse.kyutech.ac.jp" gnus-version))
   ;; And then hack it.
   ;; 57 is the longest line.
   (indent-rigidly (point-min) (point-max) (/ (max (- (window-width) 57) 0) 2))
@@ -1235,6 +1314,7 @@ umerin@mse.kyutech.ac.jp")
   "List newsgroups in the Newsgroup buffer.
 If argument SHOW-ALL is non-nil, unsubscribed groups are also listed."
   (interactive "P")
+  (setq gnus-newsgroups-showall show-all)
   (let ((case-fold-search nil)
        (last-group                     ;Current newsgroup.
         (gnus-group-group-name))
@@ -1272,21 +1352,27 @@ If optional argument ALL is non-nil, unsubscribed groups are also listed."
        (newsrc gnus-newsrc-assoc)
        (group-info nil)
        (group-name nil)
+       (group-description nil)
        (unread-count 0)
+       (nb-tab 0)
        ;; This specifies the format of Group buffer.
-       (cntl "%s%s%5d: %s\n"))
+       (cntl "%s%s%5d: %s"))
     (erase-buffer)
     ;; List newsgroups.
     (while newsrc
       (setq group-info (car newsrc))
       (setq group-name (car group-info))
+      (if gnus-newsgroups-display
+         (progn (setq group-description (gnus-gethash group-name gnus-newsgroups-hashtb))
+                (setq nb-tab (/ (- 38 (length group-name)) tab-width))))
       (setq unread-count (nth 1 (gnus-gethash group-name gnus-unread-hashtb)))
       (if (or all
              (and (nth 1 group-info)   ;Subscribed.
                   (> unread-count 0))) ;There are unread articles.
          ;; Yes, I can use gnus-group-prepare-line, but this is faster.
          (insert
-          (format cntl
+          (format (concat cntl (make-string (if (> nb-tab 0) nb-tab 1) ?\t)
+                          "%s\n")
                   ;; Subscribed or not.
                   (if (nth 1 group-info) " " "U")
                   ;; Has new news?
@@ -1300,7 +1386,10 @@ If optional argument ALL is non-nil, unsubscribed groups are also listed."
                   ;; Number of unread articles.
                   unread-count
                   ;; Newsgroup name.
-                  group-name))
+                  group-name
+                  ;; Newsgroup description
+                  (if group-description (cdr group-description) "")
+                  ))
        )
       (setq newsrc (cdr newsrc))
       )
@@ -1311,8 +1400,10 @@ If optional argument ALL is non-nil, unsubscribed groups are also listed."
 
 (defun gnus-group-prepare-line (info)
   "Return a string for the Newsgroup buffer from INFO.
-INFO is an element of gnus-newsrc-assoc or gnus-killed-assoc."
+INFO is an element of `gnus-newsrc-assoc' or `gnus-killed-assoc'."
   (let* ((group-name (car info))
+        (group-description nil)
+        (nb-tab 0)
         (unread-count
          (or (nth 1 (gnus-gethash group-name gnus-unread-hashtb))
              ;; Not in hash table, so compute it now.
@@ -1321,8 +1412,13 @@ INFO is an element of gnus-newsrc-assoc or gnus-killed-assoc."
                (nth 2 (gnus-gethash group-name gnus-active-hashtb))
                (nthcdr 2 info)))))
         ;; This specifies the format of Group buffer.
-        (cntl "%s%s%5d: %s\n"))
-    (format cntl
+        (cntl "%s%s%5d: %s"))
+    (if gnus-newsgroups-display
+       (progn
+         (setq group-description (gnus-gethash group-name gnus-newsgroups-hashtb))
+         (setq nb-tab (/ (- 38 (length group-name)) tab-width))))
+    (format (concat cntl (make-string (if (> nb-tab 0) nb-tab 1) ?\t)
+                   "%s\n")
            ;; Subscribed or not.
            (if (nth 1 info) " " "U")
            ;; Has new news?
@@ -1337,6 +1433,8 @@ INFO is an element of gnus-newsrc-assoc or gnus-killed-assoc."
            unread-count
            ;; Newsgroup name.
            group-name
+           ;; Newsgroup description
+           (if group-description (cdr group-description) "")
            )))
 
 (defun gnus-group-update-group (group &optional visible-only)
@@ -1364,7 +1462,7 @@ If optional argument VISIBLE-ONLY is non-nil, non displayed group is ignored."
                ((progn
                   (goto-char (point-max))
                   (re-search-backward regexp nil t))))
-         ;; GROUP is listed in current buffer. So, delete old line.
+         ;; GROUP is listed in current buffer.  So, delete old line.
          (progn
            (setq visible t)
            (beginning-of-line)
@@ -1384,9 +1482,10 @@ If optional argument VISIBLE-ONLY is non-nil, non displayed group is ignored."
   "Get newsgroup name around point."
   (save-excursion
     (beginning-of-line)
-    (if (looking-at "^.+:[ \t]+\\([^ \t\n]+\\)\\([ \t].*\\|$\\)")
-       (buffer-substring (match-beginning 1) (match-end 1))
-      )))
+    (if (looking-at "^..[0-9 \t]+:[ \t]+\\([^ \t\n]+\\)\\([ \t].*\\|$\\)")
+        (let ((group-name (buffer-substring (match-beginning 1) (match-end 1))))
+          (set-text-properties 0 (length group-name) nil group-name)
+          group-name))))
 
 (defun gnus-group-make-regexp (newsgroup)
   "Return regexp that matches for a line of NEWSGROUP."
@@ -1463,7 +1562,7 @@ If argument ALL is non-nil, already read articles become readable."
     ))
 
 (defun gnus-group-next-group (n)
-  "Go to next N'th newsgroup."
+  "Go to Nth following newsgroup."
   (interactive "p")
   (while (and (> n 1)
              (gnus-group-search-forward nil t))
@@ -1472,7 +1571,7 @@ If argument ALL is non-nil, already read articles become readable."
       (message "No more newsgroups")))
 
 (defun gnus-group-next-unread-group (n)
-  "Go to next N'th unread newsgroup."
+  "Go to Nth following unread newsgroup."
   (interactive "p")
   (while (and (> n 1)
              (gnus-group-search-forward nil nil))
@@ -1481,7 +1580,7 @@ If argument ALL is non-nil, already read articles become readable."
       (message "No more unread newsgroups")))
 
 (defun gnus-group-prev-group (n)
-  "Go to previous N'th newsgroup."
+  "Go to Nth previous newsgroup."
   (interactive "p")
   (while (and (> n 1)
              (gnus-group-search-forward t t))
@@ -1490,7 +1589,7 @@ If argument ALL is non-nil, already read articles become readable."
       (message "No more newsgroups")))
 
 (defun gnus-group-prev-unread-group (n)
-  "Go to previous N'th unread newsgroup."
+  "Go to Nth previous unread newsgroup."
   (interactive "p")
   (while (and (> n 1)
              (gnus-group-search-forward t nil))              
@@ -1529,12 +1628,16 @@ Cross references (Xref: field) of articles are ignored."
 (defun gnus-group-unsubscribe-current-group ()
   "Toggle subscribe from/to unsubscribe current group."
   (interactive)
-  (gnus-group-unsubscribe-group (gnus-group-group-name))
-  (gnus-group-next-group 1))
+  (let ((group (gnus-group-group-name)))
+    (if group
+        (progn
+          (gnus-group-unsubscribe-group group)
+          (gnus-group-next-group 1))
+      (message "No Newsgroup found to \(un\)subscribe"))))
 
 (defun gnus-group-unsubscribe-group (group)
   "Toggle subscribe from/to unsubscribe GROUP.
-New newsgroup is added to .newsrc automatically."
+\(If GROUP is new, it is added to `.newsrc' automatically.)"
   (interactive
    (list (completing-read "Newsgroup: "
                          gnus-active-hashtb nil 'require-match)))
@@ -1561,10 +1664,12 @@ New newsgroup is added to .newsrc automatically."
 (defun gnus-group-list-all-groups ()
   "List all of newsgroups in the Newsgroup buffer."
   (interactive)
-  (gnus-group-list-groups t))
+  (message "Listing all groups...")
+  (gnus-group-list-groups t)
+  (message "Listing all groups...done"))
 
 (defun gnus-group-get-new-news ()
-  "Get newly arrived articles. In fact, read the active file again."
+  "Get newly arrived articles.  In fact, read the active file again."
   (interactive)
   (gnus-setup-news)
   (gnus-group-list-groups gnus-have-all-newsgroups))
@@ -1616,29 +1721,31 @@ Type \\[widen] to remove restriction."
     "Editing a local KILL file (Type \\[gnus-kill-file-exit] to exit)")))
 
 (defun gnus-group-force-update ()
-  "Update .newsrc file."
+  "Update `.newsrc' file."
   (interactive)
   (gnus-save-newsrc-file))
 
 (defun gnus-group-suspend ()
   "Suspend the current GNUS session.
 In fact, cleanup buffers except for Group Mode buffer.
-The hook gnus-suspend-gnus-hook is called before actually suspending."
+The hook `gnus-suspend-gnus-hook' is called before actually suspending."
   (interactive)
   (run-hooks 'gnus-suspend-gnus-hook)
   ;; Kill GNUS buffers except for Group Mode buffer.
-  (let ((buffers gnus-buffer-list))
+  (let ((buffers gnus-buffer-list)
+       (group-buf (get-buffer gnus-group-buffer)))
     (while buffers
       (and (not (eq (car buffers) gnus-group-buffer))
           (get-buffer (car buffers))
           (kill-buffer (car buffers)))
       (setq buffers (cdr buffers))
-      ))
-  (bury-buffer))
+      )
+    (bury-buffer group-buf)
+    (delete-windows-on group-buf t)))
 
 (defun gnus-group-exit ()
-  "Quit reading news after updating .newsrc.
-The hook gnus-exit-gnus-hook is called before actually quitting."
+  "Quit reading news after updating `.newsrc'.
+The hook `gnus-exit-gnus-hook' is called before actually quitting."
   (interactive)
   (if (or noninteractive               ;For gnus-batch-kill
          (zerop (buffer-size))         ;No news is good news.
@@ -1654,8 +1761,8 @@ The hook gnus-exit-gnus-hook is called before actually quitting."
     ))
 
 (defun gnus-group-quit ()
-  "Quit reading news without updating .newsrc.
-The hook gnus-exit-gnus-hook is called before actually quitting."
+  "Quit reading news without updating `.newsrc'.
+The hook `gnus-exit-gnus-hook' is called before actually quitting."
   (interactive)
   (if (or noninteractive               ;For gnus-batch-kill
          (zerop (buffer-size))
@@ -1692,6 +1799,8 @@ The hook gnus-exit-gnus-hook is called before actually quitting."
     nil
   (setq gnus-summary-mode-map (make-keymap))
   (suppress-keymap gnus-summary-mode-map)
+  (define-key gnus-summary-mode-map "\C-c\C-v" 'gnus-uu-ctl-map)
+  (define-key gnus-summary-mode-map "#" 'gnus-uu-mark-article)
   (define-key gnus-summary-mode-map " " 'gnus-summary-next-page)
   (define-key gnus-summary-mode-map "\177" 'gnus-summary-prev-page)
   (define-key gnus-summary-mode-map "\r" 'gnus-summary-scroll-up)
@@ -1707,6 +1816,8 @@ The hook gnus-exit-gnus-hook is called before actually quitting."
   (define-key gnus-summary-mode-map "\C-c\C-p" 'gnus-summary-prev-digest)
   (define-key gnus-summary-mode-map "\C-n" 'gnus-summary-next-subject)
   (define-key gnus-summary-mode-map "\C-p" 'gnus-summary-prev-subject)
+  (define-key gnus-summary-mode-map [down] 'gnus-summary-next-subject)
+  (define-key gnus-summary-mode-map [up] 'gnus-summary-prev-subject)
   (define-key gnus-summary-mode-map "\en" 'gnus-summary-next-unread-subject)
   (define-key gnus-summary-mode-map "\ep" 'gnus-summary-prev-unread-subject)
   ;;(define-key gnus-summary-mode-map "\C-cn" 'gnus-summary-next-group)
@@ -1784,7 +1895,128 @@ The hook gnus-exit-gnus-hook is called before actually quitting."
   (define-key gnus-summary-mode-map "q" 'gnus-summary-exit)
   (define-key gnus-summary-mode-map "Q" 'gnus-summary-quit)
   (define-key gnus-summary-mode-map "?" 'gnus-summary-describe-briefly)
-  (define-key gnus-summary-mode-map "\C-c\C-i" 'gnus-info-find-node))
+  (define-key gnus-summary-mode-map "\C-c\C-i" 'gnus-info-find-node)
+  (define-key gnus-summary-mode-map [mouse-2] 'gnus-mouse-pick-article)
+
+  (define-key gnus-summary-mode-map [menu-bar misc]
+       (cons "Misc" (make-sparse-keymap "misc")))
+
+  (define-key gnus-summary-mode-map [menu-bar misc caesar-message]
+       '("Caesar Message" . gnus-summary-caesar-message))
+  (define-key gnus-summary-mode-map [menu-bar misc cancel-article]
+       '("Cancel Article" . gnus-summary-cancel-article))
+  (define-key gnus-summary-mode-map [menu-bar misc edit-local-kill]
+       '("Edit Kill File" . gnus-summary-edit-local-kill))
+
+  (define-key gnus-summary-mode-map [menu-bar misc mark-as-unread]
+       '("Mark as Unread" . gnus-summary-mark-as-unread-forward))
+  (define-key gnus-summary-mode-map [menu-bar misc mark-as-read]
+       '("Mark as Read" . gnus-summary-mark-as-read))
+
+  (define-key gnus-summary-mode-map [menu-bar misc quit]
+       '("Quit Group" . gnus-summary-quit))
+  (define-key gnus-summary-mode-map [menu-bar misc exit]
+       '("Exit Group" . gnus-summary-exit))
+
+  (define-key gnus-summary-mode-map [menu-bar sort]
+       (cons "Sort" (make-sparse-keymap "sort")))
+
+  (define-key gnus-summary-mode-map [menu-bar sort sort-by-author]
+       '("Sort by Author" . gnus-summary-sort-by-author))
+  (define-key gnus-summary-mode-map [menu-bar sort sort-by-date]
+       '("Sort by Date" . gnus-summary-sort-by-date))
+  (define-key gnus-summary-mode-map [menu-bar sort sort-by-number]
+       '("Sort by Number" . gnus-summary-sort-by-number))
+  (define-key gnus-summary-mode-map [menu-bar sort sort-by-subject]
+       '("Sort by Subject" . gnus-summary-sort-by-subject))
+
+  (define-key gnus-summary-mode-map [menu-bar show/hide]
+       (cons "Show/Hide" (make-sparse-keymap "show/hide")))
+
+  (define-key gnus-summary-mode-map [menu-bar show/hide hide-all-threads]
+       '("Hide All Threads" . gnus-summary-hide-all-threads))
+  (define-key gnus-summary-mode-map [menu-bar show/hide hide-thread]
+       '("Hide Thread" . gnus-summary-hide-thread))
+  (define-key gnus-summary-mode-map [menu-bar show/hide show-all-threads]
+       '("Show All Threads" . gnus-summary-show-all-threads))
+  (define-key gnus-summary-mode-map [menu-bar show/hide show-all-headers]
+       '("Show All Headers" . gnus-summary-show-all-headers))
+  (define-key gnus-summary-mode-map [menu-bar show/hide show-thread]
+       '("Show Thread" . gnus-summary-show-thread))
+  (define-key gnus-summary-mode-map [menu-bar show/hide show-article]
+       '("Show Article" . gnus-summary-show-article))
+  (define-key gnus-summary-mode-map [menu-bar show/hide toggle-truncation]
+       '("Toggle Truncation" . gnus-summary-toggle-truncation))
+  (define-key gnus-summary-mode-map [menu-bar show/hide toggle-mime]
+       '("Toggle Mime" . gnus-summary-toggle-mime))
+  (define-key gnus-summary-mode-map [menu-bar show/hide toggle-header]
+       '("Toggle Header" . gnus-summary-toggle-header))
+
+  (define-key gnus-summary-mode-map [menu-bar action]
+       (cons "Action" (make-sparse-keymap "action")))
+
+  (define-key gnus-summary-mode-map [menu-bar action kill-same-subject]
+       '("Kill Same Subject" . gnus-summary-kill-same-subject))
+  (define-key gnus-summary-mode-map [menu-bar action kill-thread]
+       '("Kill Thread" . gnus-summary-kill-thread))
+  (define-key gnus-summary-mode-map [menu-bar action delete-marked-with]
+       '("Delete Marked With" . gnus-summary-delete-marked-with))
+  (define-key gnus-summary-mode-map [menu-bar action delete-marked-as-read]
+       '("Delete Marked As Read" . gnus-summary-delete-marked-as-read))
+  (define-key gnus-summary-mode-map [menu-bar action catchup-and-exit]
+       '("Catchup And Exit" . gnus-summary-catchup-and-exit))
+  (define-key gnus-summary-mode-map [menu-bar action catchup-to-here]
+       '("Catchup to Here" . gnus-summary-catchup-to-here))
+
+  (define-key gnus-summary-mode-map [menu-bar action ignore]
+    '("---"))
+
+  (define-key gnus-summary-mode-map [menu-bar action save-in-file]
+       '("Save in File" . gnus-summary-save-in-file))
+  (define-key gnus-summary-mode-map [menu-bar action save-article]
+       '("Save Article" . gnus-summary-save-article))
+
+  (define-key gnus-summary-mode-map [menu-bar action lambda]
+    '("---"))
+
+  (define-key gnus-summary-mode-map [menu-bar action forward]
+       '("Forward" . gnus-summary-mail-forward))
+  (define-key gnus-summary-mode-map [menu-bar action followup-with-original]
+       '("Followup with Original" . gnus-summary-followup-with-original))
+  (define-key gnus-summary-mode-map [menu-bar action followup]
+       '("Followup" . gnus-summary-followup))
+  (define-key gnus-summary-mode-map [menu-bar action reply-with-original]
+       '("Reply with Original" . gnus-summary-reply-with-original))
+  (define-key gnus-summary-mode-map [menu-bar action reply]
+       '("Reply" . gnus-summary-reply))
+  (define-key gnus-summary-mode-map [menu-bar action post]
+       '("Post News" . gnus-summary-post-news))
+
+  (define-key gnus-summary-mode-map [menu-bar move]
+       (cons "Move" (make-sparse-keymap "move")))
+
+  (define-key gnus-summary-mode-map [menu-bar move isearch-article]
+       '("Search in Article" . gnus-summary-isearch-article))
+  (define-key gnus-summary-mode-map [menu-bar move search-through-articles]
+       '("Search through Articles" . gnus-summary-search-article-forward))
+  (define-key gnus-summary-mode-map [menu-bar move down-thread]
+       '("Down Thread" . gnus-summary-down-thread))
+  (define-key gnus-summary-mode-map [menu-bar move prev-same-subject]
+       '("Prev Same Subject" . gnus-summary-prev-same-subject))
+  (define-key gnus-summary-mode-map [menu-bar move prev-group]
+       '("Prev Group" . gnus-summary-prev-group))
+  (define-key gnus-summary-mode-map [menu-bar move next-unread-same-subject]
+       '("Next Unread Same Subject" . gnus-summary-next-unread-same-subject))
+  (define-key gnus-summary-mode-map [menu-bar move next-unread-article]
+       '("Next Unread Article" . gnus-summary-next-unread-article))
+  (define-key gnus-summary-mode-map [menu-bar move next-thread]
+       '("Next Thread" . gnus-summary-next-thread))
+  (define-key gnus-summary-mode-map [menu-bar move next-group]
+       '("Next Group" . gnus-summary-next-group))
+  (define-key gnus-summary-mode-map [menu-bar move first-unread-article]
+       '("First Unread Article" . gnus-summary-first-unread-article))
+  )
+\f
 
 (defun gnus-summary-mode ()
   "Major mode for reading articles in this newsgroup.
@@ -1870,7 +2102,7 @@ C-c C-s C-a       Sort subjects by article author.
 C-c C-s C-s    Sort subjects alphabetically.
 C-c C-s C-d    Sort subjects by date.
 =      Expand Summary window to show headers full window.
-C-x C-s        Reselect the current newsgroup. Prefix argument means to select all.
+C-x C-s        Reselect the current newsgroup.  Prefix argument means to select all.
 w      Stop page breaking by linefeed.
 C-c C-r        Caesar rotates letters by 13/47 places.
 g      Force to show the current article.
@@ -1898,21 +2130,21 @@ C-c C-i Read Info about Summary mode.
 
 User customizable variables:
  gnus-large-newsgroup
-    The number of articles which indicates a large newsgroup. If the
+    The number of articles which indicates a large newsgroup.  If the
     number of articles in a newsgroup is greater than the value, the
-    number of articles to be selected is asked for. If the given value
-    N is positive, the last N articles is selected. If N is negative,
-    the first N articles are selected. An empty string means to select
+    number of articles to be selected is asked for.  If the given value
+    N is positive, the last N articles is selected.  If N is negative,
+    the first N articles are selected.  An empty string means to select
     all articles.
 
  gnus-use-long-file-name
     Non-nil means that a newsgroup name is used as a default file name
-    to save articles to. If it's nil, the directory form of a
+    to save articles to.  If it's nil, the directory form of a
     newsgroup is used instead.
 
  gnus-default-article-saver
     Specifies your favorite article saver which is interactively
-    funcallable. Following functions are available:
+    funcallable.  Following functions are available:
 
        gnus-summary-save-in-rmail (in Rmail format)
        gnus-summary-save-in-mail (in Unix mail format)
@@ -1926,15 +2158,20 @@ User customizable variables:
     Specifies a function generating a file name to save articles in
     specified format.  The function is called with NEWSGROUP, HEADERS,
     and optional LAST-FILE.  Access macros to the headers are defined
-    as nntp-header-FIELD, and functions are defined as
-    gnus-header-FIELD.
+    as `nntp-header-FIELD', and functions are defined as
+    `gnus-header-FIELD'.
 
  gnus-article-save-directory
     Specifies a directory name to save articles to using the commands
-    gnus-summary-save-in-rmail, gnus-summary-save-in-mail and
-    gnus-summary-save-in-file. The variable is initialized from the
+    `gnus-summary-save-in-rmail', `gnus-summary-save-in-mail' and
+    `gnus-summary-save-in-file'.  The variable is initialized from the
     SAVEDIR environment variable.
 
+ gnus-kill-files-directory
+    Specifies a directory name to save KILL files to using the commands
+    `gnus-edit-global-kill', and `gnus-edit-local-kill'.  The variable is
+    initialized from the SAVEDIR environment variable.
+
  gnus-show-all-headers
     Non-nil means that all headers of an article are shown.
 
@@ -1965,7 +2202,7 @@ User customizable variables:
 
  gnus-optional-headers
     Specifies a function which generates an optional string displayed
-    in the Summary buffer. The function is called with an article
+    in the Summary buffer.  The function is called with an article
     HEADERS.  The result must be a string excluding `[' and `]'.  The
     default function returns a string like NNN:AUTHOR, where NNN is
     the number of lines in an article and AUTHOR is the name of the
@@ -1977,16 +2214,16 @@ User customizable variables:
 
  gnus-auto-select-first
     Non-nil means the first unread article is selected automagically
-    when a newsgroup is selected normally (by gnus-group-read-group).
+    when a newsgroup is selected normally (by `gnus-group-read-group').
     If you'd like to prevent automatic selection of the first unread
     article in some newsgroups, set the variable to nil in
-    gnus-select-group-hook or gnus-apply-kill-hook.
+    `gnus-select-group-hook' or `gnus-apply-kill-hook'.
 
  gnus-auto-select-next
     Non-nil means the next newsgroup is selected automagically at the
-    end of the newsgroup. If the value is t and the next newsgroup is
+    end of the newsgroup.  If the value is t and the next newsgroup is
     empty (no unread articles), GNUS will exit Summary mode and go
-    back to Group mode. If the value is neither nil nor t, GNUS won't
+    back to Group mode.  If the value is neither nil nor t, GNUS won't
     exit Summary mode but select the following unread newsgroup.
     Especially, if the value is the symbol `quietly', the next unread
     newsgroup will be selected without any confirmations.
@@ -2008,9 +2245,6 @@ User customizable variables:
     Specifies a regexp describing line-beginnings that separate pages
     of news article.
 
- [gnus-more-message is obsolete.  overlay-arrow-string interfares
-    with other subsystems, such as dbx mode.]
-
  gnus-digest-show-summary
     Non-nil means that a summary of digest messages is shown when
     reading a digest article using `gnus-summary-rmail-digest'
@@ -2022,17 +2256,17 @@ User customizable variables:
  gnus-mail-reply-method
  gnus-mail-other-window-method
     Specifies a function to begin composing mail message using
-    commands gnus-summary-reply and gnus-summary-mail-other-window.
-    Functions gnus-mail-reply-using-mail and gnus-mail-reply-using-mhe
-    are available for the value of gnus-mail-reply-method.  And
-    functions gnus-mail-other-window-using-mail and
-    gnus-mail-other-window-using-mhe are available for the value of
-    gnus-mail-other-window-method.
+    commands `gnus-summary-reply' and `gnus-summary-mail-other-window'.
+    Functions `gnus-mail-reply-using-mail' and `gnus-mail-reply-using-mhe'
+    are available for the value of `gnus-mail-reply-method'.  And
+    functions `gnus-mail-other-window-using-mail' and
+    `gnus-mail-other-window-using-mhe' are available for the value of
+    `gnus-mail-other-window-method'.
 
  gnus-mail-send-method
     Specifies a function to mail a message too which is being posted
     as an article.  The message must have To: or Cc: field.  The value
-    of the variable send-mail-function is the default function which
+    of the variable `send-mail-function' is the default function, which
     uses sendmail mail program.
 
 Various hooks for customization:
@@ -2042,47 +2276,47 @@ Various hooks for customization:
 
  gnus-select-group-hook
     Called with no arguments when newsgroup is selected, if that value
-    is non-nil. It is possible to sort subjects in this hook. See the
+    is non-nil.  It is possible to sort subjects in this hook.  See the
     documentation of this variable for more information.
 
  gnus-summary-prepare-hook
     Called with no arguments after a summary list is created in the
-    Summary buffer, if that value is non-nil. If you'd like to modify
+    Summary buffer, if that value is non-nil.  If you'd like to modify
     the buffer, you can use this hook.
 
  gnus-select-article-hook
     Called with no arguments when an article is selected, if that
-    value is non-nil. See the documentation of this variable for more
+    value is non-nil.  See the documentation of this variable for more
     information.
 
  gnus-select-digest-hook
     Called with no arguments when reading digest messages using Rmail,
-    if that value is non-nil. This hook can be used to modify an
-    article so that Rmail can work with it. See the documentation of
+    if that value is non-nil.  This hook can be used to modify an
+    article so that Rmail can work with it.  See the documentation of
     the variable for more information.
 
  gnus-rmail-digest-hook
     Called with no arguments when reading digest messages using Rmail,
-    if that value is non-nil. This hook is intended to customize Rmail
+    if that value is non-nil.  This hook is intended to customize Rmail
     mode.
 
  gnus-apply-kill-hook
     Called with no arguments when a newsgroup is selected and the
-    Summary buffer is prepared. This hook is intended to apply a KILL
-    file to the selected newsgroup. The format of KILL file is
-    completely different from that of version 3.8. You have to rewrite
-    them in the new format. See the documentation of Kill file mode
+    Summary buffer is prepared.  This hook is intended to apply a KILL
+    file to the selected newsgroup.  The format of KILL file is
+    completely different from that of version 3.8.  You have to rewrite
+    them in the new format.  See the documentation of Kill file mode
     for more information.
 
  gnus-mark-article-hook
     Called with no arguments when an article is selected at the first
-    time. The hook is intended to mark an article as read (or unread)
+    time.  The hook is intended to mark an article as read (or unread)
     automatically when it is selected.  See the documentation of the
     variable for more information.
 
  gnus-exit-group-hook
     Called with no arguments when exiting the current newsgroup, if
-    that value is non-nil. If your machine is so slow that exiting
+    that value is non-nil.  If your machine is so slow that exiting
     from Summary mode takes very long time, inhibit marking articles
     as read using cross-references by setting the variable
     gnus-use-cross-reference to nil in this hook."
@@ -2114,6 +2348,11 @@ Various hooks for customization:
   ;;(setq case-fold-search t)
   (run-hooks 'gnus-summary-mode-hook))
 
+(defun gnus-mouse-pick-article (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (gnus-summary-next-page nil))
+
 (defun gnus-summary-setup-buffer ()
   "Initialize Summary buffer."
   (if (get-buffer gnus-summary-buffer)
@@ -2295,7 +2534,7 @@ Optional PARENT-SUBJECT specifies the subject of the parent."
 
 (defun gnus-summary-set-mode-line ()
   "Set Summary mode line string.
-If you don't like it, define your own gnus-summary-set-mode-line."
+If you don't like it, define your own `gnus-summary-set-mode-line'."
   (let ((unmarked
         (- (length gnus-newsgroup-unreads)
            (length (gnus-intersection
@@ -2348,7 +2587,7 @@ the same subject will be searched for."
        (regexp 
         (format "^%s[ \t]+\\([0-9]+\\):.\\[[^]\r\n]*\\][ \t]+%s"
                 ;;(if unread " " ".")
-                (cond ((eq unread t) " ") (unread "[ ---]") (t "."))
+                (cond ((eq unread t) " ") (unread "[]") (t "."))
                 (if subject
                     (concat "\\([Rr][Ee]:[ \t]+\\)*"
                             (regexp-quote (gnus-simplify-subject subject))
@@ -2385,7 +2624,8 @@ the same subject will be searched for."
   (gnus-summary-search-subject t unread subject))
 
 (defun gnus-summary-article-number ()
-  "Article number around point. If nothing, return current number."
+  "Return the Article number around point.
+If none, return current article number."
   (save-excursion
     (beginning-of-line)
     (if (looking-at ".[ \t]+\\([0-9]+\\):")
@@ -2479,8 +2719,8 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
              (get-buffer gnus-summary-buffer))
          (eq gnus-auto-select-next t)
          ;; Expected newsgroup has nothing to read since the articles
-         ;; are marked as read by cross-referencing. So, try next
-         ;; newsgroup. (Make sure we are in Group mode buffer now.)
+         ;; are marked as read by cross-referencing.  So, try next
+         ;; newsgroup.  (Make sure we are in Group mode buffer now.)
          (and (eq (current-buffer)
                   (get-buffer gnus-group-buffer))
               (gnus-group-group-name)
@@ -2512,8 +2752,8 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
              (get-buffer gnus-summary-buffer))
          (eq gnus-auto-select-next t)
          ;; Expected newsgroup has nothing to read since the articles
-         ;; are marked as read by cross-referencing. So, try next
-         ;; newsgroup. (Make sure we are in Group mode buffer now.)
+         ;; are marked as read by cross-referencing.  So, try next
+         ;; newsgroup.  (Make sure we are in Group mode buffer now.)
          (and (eq (current-buffer)
                   (get-buffer gnus-group-buffer))
               (gnus-summary-search-group t)
@@ -2525,7 +2765,7 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
 ;; Walking around summary lines.
 
 (defun gnus-summary-next-subject (n &optional unread)
-  "Go to next N'th summary line.
+  "Go to Nth following summary line.
 If optional argument UNREAD is non-nil, only unread article is selected."
   (interactive "p")
   (while (and (> n 1)
@@ -2540,12 +2780,12 @@ If optional argument UNREAD is non-nil, only unread article is selected."
        ))
 
 (defun gnus-summary-next-unread-subject (n)
-  "Go to next N'th unread summary line."
+  "Go to Nth following unread summary line."
   (interactive "p")
   (gnus-summary-next-subject n t))
 
 (defun gnus-summary-prev-subject (n &optional unread)
-  "Go to previous N'th summary line.
+  "Go to Nth previous summary line.
 If optional argument UNREAD is non-nil, only unread article is selected."
   (interactive "p")
   (while (and (> n 1)
@@ -2560,7 +2800,7 @@ If optional argument UNREAD is non-nil, only unread article is selected."
        ))
 
 (defun gnus-summary-prev-unread-subject (n)
-  "Go to previous N'th unread summary line."
+  "Go to Nth previous unread summary line."
   (interactive "p")
   (gnus-summary-prev-subject n t))
 
@@ -2682,7 +2922,7 @@ If argument UNREAD is non-nil, only unread article is selected."
           (gnus-summary-goto-article gnus-newsgroup-end))
          (t
           ;; Select next newsgroup automatically if requested.
-          (let ((cmd (string-to-char (this-command-keys)))
+          (let ((cmd (aref (this-command-keys) 0))
                 (group (gnus-summary-search-group))
                 (auto-select
                  (and gnus-auto-select-next
@@ -2700,20 +2940,22 @@ If argument UNREAD is non-nil, only unread article is selected."
                       ;; Ignore characters typed ahead.
                       (not (input-pending-p))
                       )))
+            ;; Keep just the event type of CMD.
+            (if (listp cmd)
+                (setq cmd (car cmd)))
             (message "No more%s articles%s"
                      (if unread " unread" "")
                      (if (and auto-select
                               (not (eq gnus-auto-select-next 'quietly)))
                          (if group
                              (format " (Type %s for %s [%d])"
-                                     (key-description (char-to-string cmd))
+                                     (single-key-description cmd)
                                      group
                                      (nth 1 (gnus-gethash group
                                                           gnus-unread-hashtb)))
                            (format " (Type %s to exit %s)"
-                                   (key-description (char-to-string cmd))
-                                   gnus-newsgroup-name
-                                   ))
+                                   (single-key-description cmd)
+                                   gnus-newsgroup-name))
                        ""))
             ;; Select next unread newsgroup automagically.
             (cond ((and auto-select
@@ -2722,10 +2964,14 @@ If argument UNREAD is non-nil, only unread article is selected."
                    (gnus-summary-next-group nil))
                   (auto-select
                    ;; Confirm auto selection.
-                   (let ((char (read-char)))
-                     (if (= char cmd)
+                   (let* ((event (read-event))
+                          (type
+                           (if (listp event)
+                               (car event)
+                             event)))
+                     (if (and (eq event type) (eq event cmd))
                          (gnus-summary-next-group nil)
-                       (setq unread-command-char char))))
+                       (setq unread-command-events (list event)))))
                   )
             ))
          )))
@@ -2773,7 +3019,7 @@ If argument UNREAD is non-nil, only unread article is selected."
          )))
 
 (defun gnus-summary-prev-unread-article ()
-  "Select unred article before current one."
+  "Select unread article before current one."
   (interactive)
   (gnus-summary-prev-article t (and gnus-auto-select-same
                                    (gnus-summary-subject-string))))
@@ -2851,7 +3097,7 @@ Argument LINES specifies lines to be scrolled up (or down if negative)."
   "Refer parent article of current article.
 If a prefix argument CHILD is non-nil, go back to the child article
 using internally maintained articles history.
-NOTE: This command may not work with nnspool.el."
+NOTE: This command may not work with `nnspool.el'."
   (interactive "P")
   (gnus-summary-select-article t t)    ;Request all headers.
   (let ((referenced-id nil))           ;Message-id of parent or child article.
@@ -2879,7 +3125,7 @@ NOTE: This command may not work with nnspool.el."
   "Refer article specified by MESSAGE-ID.
 If the MESSAGE-ID is nil or an empty string, Message-ID is poped from
 internally maintained articles history.
-NOTE: This command may not work with nnspool.el nor mhspool.el."
+NOTE: This command may not work with `nnspool.el' nor `mhspool.el'."
   (interactive "sMessage-ID: ")
   ;; Make sure that this command depends on the fact that article
   ;; related information is not updated when an article is retrieved
@@ -2914,24 +3160,23 @@ NOTE: This command may not work with nnspool.el nor mhspool.el."
     (error "No such references"))
   )
 
-(defun gnus-summary-next-digest (nth)
-  "Move to head of NTH next digested message."
+(defun gnus-summary-next-digest (n)
+  "Move to head of Nth next digested message."
   (interactive "p")
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
-    (gnus-article-next-digest (or nth 1))
+    (gnus-article-next-digest (or n 1))
     ))
 
-(defun gnus-summary-prev-digest (nth)
-  "Move to head of NTH previous digested message."
+(defun gnus-summary-prev-digest (n)
+  "Move to head of Nth previous digested message."
   (interactive "p")
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
-    (gnus-article-prev-digest (or nth 1))
-    ))
+    (gnus-article-prev-digest (or n 1))))
 
 (defun gnus-summary-first-unread-article ()
-  "Select first unread article. Return non-nil if successfully selected."
+  "Select first unread article.  Return non-nil if successfully selected."
   (interactive)
   (let ((begin (point)))
     (goto-char (point-min))
@@ -2954,7 +3199,8 @@ NOTE: This command may not work with nnspool.el nor mhspool.el."
 
 (defun gnus-summary-search-article-forward (regexp)
   "Search for an article containing REGEXP forward.
-gnus-select-article-hook is not called during the search."
+`gnus-select-article-hook' is not called for articles examined
+by searching search."
   (interactive
    (list (read-string
          (concat "Search forward (regexp): "
@@ -2973,7 +3219,8 @@ gnus-select-article-hook is not called during the search."
 
 (defun gnus-summary-search-article-backward (regexp)
   "Search for an article containing REGEXP backward.
-gnus-select-article-hook is not called during the search."
+`gnus-select-article-hook' is not called for articles examined
+by searching search."
   (interactive
    (list (read-string
          (concat "Search backward (regexp): "
@@ -2993,7 +3240,8 @@ gnus-select-article-hook is not called during the search."
 (defun gnus-summary-search-article (regexp &optional backward)
   "Search for an article containing REGEXP.
 Optional argument BACKWARD means do search for backward.
-gnus-select-article-hook is not called during the search."
+`gnus-select-article-hook' is not called for articles examined
+by searching search."
   (let ((gnus-select-article-hook nil) ;Disable hook.
        (gnus-mark-article-hook nil)    ;Inhibit marking as read.
        (re-search
@@ -3058,10 +3306,10 @@ If optional (prefix) argument BACKWARD is non-nil, do backward instead."
                    (` (lambda ()
                         (call-interactively '(, (key-binding command)))))
                    backward)
-      (message "Executing %s... done" (key-description command)))))
+      (message "Executing %s...done" (key-description command)))))
 
 (defun gnus-summary-beginning-of-article ()
-  "Go to beginning of article body"
+  "Go to beginning of article body."
   (interactive)
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
@@ -3072,7 +3320,7 @@ If optional (prefix) argument BACKWARD is non-nil, do backward instead."
     ))
 
 (defun gnus-summary-end-of-article ()
-  "Go to end of article body"
+  "Go to end of article body."
   (interactive)
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
@@ -3083,8 +3331,8 @@ If optional (prefix) argument BACKWARD is non-nil, do backward instead."
     ))
 
 (defun gnus-summary-goto-article (article &optional all-headers)
-  "Read ARTICLE if exists.
-Optional argument ALL-HEADERS means all headers are shown."
+  "Read article number ARTICLE if it exists.
+Optional argument ALL-HEADERS means show the full header."
   (interactive
    (list
     (string-to-int
@@ -3140,7 +3388,7 @@ With arg, turn MIME processing on iff arg is positive."
   (gnus-summary-select-article (not gnus-have-all-headers) t))
 
 (defun gnus-summary-stop-page-breaking ()
-  "Stop page breaking by linefeed temporary (Widen article buffer)."
+  "Stop page breaking by linefeed temporary (widen article buffer)."
   (interactive)
   (gnus-summary-select-article)
   (gnus-eval-in-buffer-window gnus-article-buffer
@@ -3157,7 +3405,7 @@ If argument UNMARK is negative, mark articles as unread instead."
   (let ((count
         (gnus-summary-mark-same-subject
          (gnus-summary-subject-string) unmark)))
-    ;; Select next unread article. If auto-select-same mode, should
+    ;; Select next unread article.  If auto-select-same mode, should
     ;; select the first unread article.
     (gnus-summary-next-article t (and gnus-auto-select-same
                                      (gnus-summary-subject-string)))
@@ -3253,7 +3501,7 @@ Optional 2nd argument CLEAR-MARK remove any kinds of mark."
 
 (defun gnus-summary-mark-as-read-forward (count)
   "Mark current article as read, and then go forward.
-Argument COUNT specifies number of articles marked as read"
+Argument COUNT specifies number of articles marked as read."
   (interactive "p")
   (while (> count 0)
     (gnus-summary-mark-as-read)
@@ -3262,7 +3510,7 @@ Argument COUNT specifies number of articles marked as read"
 
 (defun gnus-summary-mark-as-read-backward (count)
   "Mark current article as read, and then go backward.
-Argument COUNT specifies number of articles marked as read"
+Argument COUNT specifies number of articles marked as read."
   (interactive "p")
   (while (> count 0)
     (gnus-summary-mark-as-read)
@@ -3293,7 +3541,7 @@ Any kind of string (length 1) except for a space and `-' is ok."
 
 (defun gnus-summary-clear-mark-forward (count)
   "Remove current article's mark, and go forward.
-Argument COUNT specifies number of articles unmarked"
+Argument COUNT specifies number of articles unmarked."
   (interactive "p")
   (while (> count 0)
     (gnus-summary-mark-as-unread nil t)
@@ -3302,7 +3550,7 @@ Argument COUNT specifies number of articles unmarked"
 
 (defun gnus-summary-clear-mark-backward (count)
   "Remove current article's mark, and go backward.
-Argument COUNT specifies number of articles unmarked"
+Argument COUNT specifies number of articles unmarked."
   (interactive "p")
   (while (> count 0)
     (gnus-summary-mark-as-unread nil t)
@@ -3310,13 +3558,13 @@ Argument COUNT specifies number of articles unmarked"
     (setq count (1- count))))
 
 (defun gnus-summary-delete-marked-as-read ()
-  "Delete lines which is marked as read."
+  "Delete summary lines for articles that are marked as read."
   (interactive)
   (if gnus-newsgroup-unreads
       (let ((buffer-read-only nil))
        (save-excursion
          (goto-char (point-min))
-         (delete-non-matching-lines "^[ ---]"))
+         (delete-non-matching-lines "^[]"))
        ;; Adjust point.
        (if (eobp)
            (gnus-summary-prev-subject 1)
@@ -3588,7 +3836,7 @@ Argument REVERSE means reverse order."
    ))
 
 (defun gnus-summary-sort-by-subject (reverse)
-  "Sort Summary buffer by subject alphabetically. `Re:'s are ignored.
+  "Sort Summary buffer by subject alphabetically.  `Re:'s are ignored.
 If case-fold-search is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
@@ -3668,11 +3916,11 @@ Caesar rotates Japanese letters by 47 places in any case."
 
 (defun gnus-summary-rmail-digest ()
   "Run RMAIL on current digest article.
-gnus-select-digest-hook will be called with no arguments, if that
-value is non-nil. It is possible to modify the article so that Rmail
+`gnus-select-digest-hook' will be called with no arguments, if that
+value is non-nil.  It is possible to modify the article so that Rmail
 can work with it.
-gnus-rmail-digest-hook will be called with no arguments, if that value
-is non-nil. The hook is intended to customize Rmail mode."
+`gnus-rmail-digest-hook' will be called with no arguments, if that value
+is non-nil.  The hook is intended to customize Rmail mode."
   (interactive)
   (gnus-summary-select-article)
   (require 'rmail)
@@ -3710,13 +3958,13 @@ is non-nil. The hook is intended to customize Rmail mode."
                         (message "(No changes need to be saved)")
                         'no-need-to-write-this-buffer))))
          ;; Default file name saving digest messages.
-         (setq rmail-last-rmail-file
+         (setq rmail-default-rmail-file
                (funcall gnus-rmail-save-name
                         gnus-newsgroup-name
                         gnus-current-headers
                         gnus-newsgroup-last-rmail
                         ))
-         (setq rmail-last-file
+         (setq rmail-default-file
                (funcall gnus-mail-save-name
                         gnus-newsgroup-name
                         gnus-current-headers
@@ -3824,8 +4072,14 @@ is initialized from the SAVEDIR environment variable."
                             ") ")
                     (file-name-directory default-name)
                     default-name)))
+         (setq filename
+               (expand-file-name filename
+                                 (and default-name
+                                      (file-name-directory default-name))))
          (gnus-make-directory (file-name-directory filename))
-         (rmail-output filename)
+         (if (and (file-readable-p filename) (rmail-file-p filename))
+             (gnus-output-to-rmail filename)
+           (rmail-output filename 1 t t))
          ;; Remember the directory name to save articles.
          (setq gnus-newsgroup-last-mail filename)
          )))
@@ -3921,6 +4175,7 @@ Optional argument FOLDER specifies folder name."
 If prefix argument ALL is non-nil, all articles are marked as read."
   (interactive "P")
   (if (or quietly
+         (not gnus-interactive-catchup) ;Without confirmation?
          (y-or-n-p
           (if all
               "Do you really want to mark everything as read? "
@@ -3937,6 +4192,16 @@ If prefix argument ALL is non-nil, all articles are marked as read."
          ))
     ))
 
+(defun gnus-summary-catchup-to-here ()
+  "Mark all articles before the current one in this newsgroup as read."
+  (interactive)
+  (beginning-of-line)
+  (let ((current (gnus-summary-article-number)))
+       (beginning-of-buffer)
+       (while (not (= (gnus-summary-article-number) current))
+         (gnus-summary-mark-as-read)
+         (gnus-summary-next-subject 1))))
+
 (defun gnus-summary-catchup-all (&optional quietly)
   "Mark all articles in this newsgroup as read."
   (interactive)
@@ -3947,6 +4212,7 @@ If prefix argument ALL is non-nil, all articles are marked as read."
 If prefix argument ALL is non-nil, all articles are marked as read."
   (interactive "P")
   (if (or quietly
+         (not gnus-interactive-catchup) ;Without confirmation?
          (y-or-n-p
           (if all
               "Do you really want to mark everything as read? "
@@ -3991,7 +4257,7 @@ If prefix argument ALL is non-nil, all articles are marked as read."
 
 (defun gnus-summary-exit (&optional temporary)
   "Exit reading current newsgroup, and then return to group selection mode.
-gnus-exit-group-hook is called with no arguments if that value is non-nil."
+`gnus-exit-group-hook' is called with no arguments if that value is non-nil."
   (interactive)
   (let ((updated nil)
        (gnus-newsgroup-headers gnus-newsgroup-headers)
@@ -4135,7 +4401,8 @@ Various hooks for customization:
 (defun gnus-article-prepare (article &optional all-headers)
   "Prepare ARTICLE in Article mode buffer.
 ARTICLE can be either a article number or Message-ID.
-If optional argument ALL-HEADERS is non-nil, all headers are inserted."
+If optional argument ALL-HEADERS is non-nil,
+include the article's whole original header."
   ;; Make sure a connection to NNTP server is alive.
   (if (not (gnus-server-opened))
       (progn
@@ -4253,7 +4520,7 @@ If optional argument ALL-HEADERS is non-nil, all headers are inserted."
 
 (defun gnus-article-set-mode-line ()
   "Set Article mode line string.
-If you don't like it, define your own gnus-article-set-mode-line."
+If you don't like it, define your own `gnus-article-set-mode-line'."
   (let ((maxlen 15)                    ;Maximum subject length
        (subject
         (if gnus-current-headers
@@ -4291,7 +4558,7 @@ If you don't like it, define your own gnus-article-set-mode-line."
 
 (defun gnus-article-next-page (lines)
   "Show next page of current article.
-If end of article, return non-nil. Otherwise return nil.
+If end of article, return non-nil.  Otherwise return nil.
 Argument LINES specifies lines to be scrolled up."
   (interactive "P")
   (move-to-window-line -1)
@@ -4362,18 +4629,18 @@ Set mark at end of digested message."
     (message "End of message")
     ))
 
-(defun gnus-article-prev-digest (nth)
-  "Move to head of NTH previous digested message."
+(defun gnus-article-prev-digest (n)
+  "Move to head of Nth previous digested message."
   ;; Stop page breaking in digest mode.
   (widen)
   (beginning-of-line)
-  ;; Skip NTH - 1 digest.
+  ;; Skip N - 1 digest.
   ;; Suggested by Khalid Sattar <admin@cs.exeter.ac.uk>.
   ;; Digest separator is customizable.
   ;; Suggested by Skip Montanaro <montanaro@sprite.crd.ge.com>.
-  (while (and (> nth 1)
+  (while (and (> n 1)
              (re-search-backward gnus-digest-separator nil 'move))
-    (setq nth (1- nth)))
+    (setq n (1- n)))
   (if (re-search-backward gnus-digest-separator nil t)
       (let ((begin (point)))
        ;; Search for end of this message.
@@ -4458,27 +4725,27 @@ In addition to Emacs-Lisp Mode, the following commands are available:
 \\[gnus-kill-file-exit]        Save file and exit editing KILL file.
 \\[gnus-info-find-node]        Read Info about KILL file.
 
-  A KILL file contains lisp expressions to be applied to a selected
-newsgroup. The purpose is to mark articles as read on the basis of
-some set of regexps. A global KILL file is applied to every newsgroup,
-and a local KILL file is applied to a specified newsgroup. Since a
+  A KILL file contains Lisp expressions to be applied to a selected
+newsgroup.  The purpose is to mark articles as read on the basis of
+some set of regexps.  A global KILL file is applied to every newsgroup,
+and a local KILL file is applied to a specified newsgroup.  Since a
 global KILL file is applied to every newsgroup, for better performance
 use a local one.
 
-  A KILL file can contain any kind of Emacs lisp expressions expected
-to be evaluated in the Summary buffer. Writing lisp programs for this
+  A KILL file can contain any kind of Emacs Lisp expressions expected
+to be evaluated in the Summary buffer.  Writing Lisp programs for this
 purpose is not so easy because the internal working of GNUS must be
-well-known. For this reason, GNUS provides a general function which
+well-known.  For this reason, GNUS provides a general function which
 does this easily for non-Lisp programmers.
 
   The `gnus-kill' function executes commands available in Summary Mode
-by their key sequences. `gnus-kill' should be called with FIELD,
-REGEXP and optional COMMAND and ALL. FIELD is a string representing
-the header field or an empty string. If FIELD is an empty string, the
-entire article body is searched for. REGEXP is a string which is
-compared with FIELD value. COMMAND is a string representing a valid
-key sequence in Summary Mode or Lisp expression. COMMAND is default to
-'(gnus-summary-mark-as-read nil \"X\"). Make sure that COMMAND is
+by their key sequences.  `gnus-kill' should be called with FIELD,
+REGEXP and optional COMMAND and ALL.  FIELD is a string representing
+the header field or an empty string.  If FIELD is an empty string, the
+entire article body is searched for.  REGEXP is a string which is
+compared with FIELD value.  COMMAND is a string representing a valid
+key sequence in Summary mode or Lisp expression.  COMMAND defaults to
+\(gnus-summary-mark-as-read nil \"X\").  Make sure that COMMAND is
 executed in the Summary buffer.  If the second optional argument ALL
 is non-nil, the COMMAND is applied to articles which are already
 marked as read or unread.  Articles which are marked are skipped over
@@ -4494,8 +4761,8 @@ the following expression:
 
        (gnus-kill \"Subject\" \"AI\" \"d\")
 
-In this example it is assumed that the command
-`gnus-summary-mark-as-read-forward' is assigned to `d' in Summary Mode.
+\(Here we assume the command `gnus-summary-mark-as-read-forward' is
+assigned to `d' in Summary Mode.)
 
   It is possible to delete unnecessary headers which are marked with
 `X' in a KILL file as follows:
@@ -4508,8 +4775,8 @@ with `D' are deleted in a KILL file, it is impossible to read articles
 which are marked as read in the previous GNUS sessions.  Marks other
 than `D' should be used for articles which should really be deleted.
 
-Entry to this mode calls emacs-lisp-mode-hook and
-gnus-kill-file-mode-hook with no arguments, if that value is non-nil."
+Entry to this mode calls `emacs-lisp-mode-hook' and
+`gnus-kill-file-mode-hook' with no arguments, if that value is non-nil."
   (interactive)
   (kill-all-local-variables)
   (use-local-map gnus-kill-file-mode-map)
@@ -4774,17 +5041,17 @@ If NEWSGROUP is nil, return the global KILL file instead."
             (string-equal newsgroup ""))
         ;; The global KILL file is placed at top of the directory.
         (expand-file-name gnus-kill-file-name
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        (gnus-use-long-file-name
         ;; Append ".KILL" to capitalized newsgroup name.
         (expand-file-name (concat (gnus-capitalize-newsgroup newsgroup)
                                   "." gnus-kill-file-name)
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        (t
         ;; Place "KILL" under the hierarchical directory.
         (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
                                   "/" gnus-kill-file-name)
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        ))
 
 (defun gnus-newsgroup-kill-file (newsgroup)
@@ -4794,16 +5061,16 @@ If NEWSGROUP is nil, return the global KILL file instead."
             (string-equal newsgroup ""))
         ;; The global KILL file is placed at top of the directory.
         (expand-file-name gnus-kill-file-name
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        (gnus-use-long-file-name
         ;; Append ".KILL" to newsgroup name.
         (expand-file-name (concat newsgroup "." gnus-kill-file-name)
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        (t
         ;; Place "KILL" under the hierarchical directory.
         (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
                                   "/" gnus-kill-file-name)
-                          (or gnus-article-save-directory "~/News")))
+                          (or gnus-kill-files-directory "~/News")))
        ))
 
 ;; For subscribing new newsgroup
@@ -4902,11 +5169,12 @@ If optional argument NEXT is non-nil, it is inserted before NEXT."
        ))
 
 (defun gnus-capitalize-newsgroup (newsgroup)
-  "Capitalize NEWSGROUP name with treating '.' and '-' as part of words."
+  "Capitalize NEWSGROUP name with treating `.' and `-' as part of words."
   ;; Suggested by "Jonathan I. Kamens" <jik@pit-manager.MIT.EDU>.
-  (let ((current-syntax-table (copy-syntax-table (syntax-table))))
+  (let ((current-syntax-table (syntax-table)))
     (unwind-protect
        (progn
+         (set-syntax-table (copy-syntax-table current-syntax-table))
          (modify-syntax-entry ?- "w")
          (modify-syntax-entry ?. "w")
          (capitalize newsgroup))
@@ -4987,7 +5255,7 @@ Optional argument REVERSE means reverse order."
 
 (defun gnus-string-lessp (a b)
   "Return T if first arg string is less than second in lexicographic order.
-If case-fold-search is non-nil, case of letters is ignored."
+If `case-fold-search' is non-nil, case of letters is ignored."
   (if case-fold-search
       (string-lessp (downcase a) (downcase b))
     (string-lessp a b)))
@@ -4998,16 +5266,15 @@ If case-fold-search is non-nil, case of letters is ignored."
                (gnus-sortable-date date2)))
 
 (defun gnus-sortable-date (date)
-  "Make sortable string by string-lessp from DATE.
+  "Convert DATE into a string that can be sorted with `string-lessp'.
 Timezone package is used."
-  (let* ((date   (timezone-parse-date date)) ;[Y M D T]
-        (year   (string-to-int (aref date 0)))
-        (month  (string-to-int (aref date 1)))
-        (day    (string-to-int (aref date 2)))
-        (time   (aref date 3)))        ;HH:MM:SS
-    ;; Timezone package is used.  But, we don't have to care about
-    ;; the timezone since article's timezones are always GMT.
-    (timezone-make-sortable-date year month day time)
+  (let* ((date   (timezone-fix-time date nil nil)) ;[Y M D H M S]
+        (year   (aref date 0))
+        (month  (aref date 1))
+        (day    (aref date 2)))
+    (timezone-make-sortable-date year month day 
+                                (timezone-make-time-string
+                                 (aref date 3) (aref date 4) (aref date 5)))
     ))
 
 ;;(defun gnus-sortable-date (date)
@@ -5050,7 +5317,7 @@ Timezone package is used."
                        (progn (search-forward "\n\n" nil 'move) (point)))
       (mail-fetch-field field))))
 
-(fset 'gnus-expunge 'gnus-summary-delete-marked-with)
+(defalias 'gnus-expunge 'gnus-summary-delete-marked-with)
 
 (defun gnus-kill (field regexp &optional command all)
   "If FIELD of an article matches REGEXP, execute COMMAND.
@@ -5058,12 +5325,12 @@ Optional 1st argument COMMAND is default to
        (gnus-summary-mark-as-read nil \"X\").
 If optional 2nd argument ALL is non-nil, articles marked are also applied to.
 If FIELD is an empty string (or nil), entire article body is searched for.
-COMMAND must be a lisp expression or a string representing a key sequence."
+COMMAND must be a Lisp expression or a string representing a key sequence."
   ;; We don't want to change current point nor window configuration.
   (save-excursion
     (save-window-excursion
       ;; Selected window must be Summary buffer to execute keyboard
-      ;; macros correctly. See command_loop_1.
+      ;; macros correctly.  See command_loop_1.
       (switch-to-buffer gnus-summary-buffer 'norecord)
       (goto-char (point-min))          ;From the beginning.
       (if (null command)
@@ -5075,8 +5342,8 @@ COMMAND must be a lisp expression or a string representing a key sequence."
   "If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
 If FIELD is an empty string (or nil), entire article body is searched for.
 If optional 1st argument BACKWARD is non-nil, do backward instead.
-If optional 2nd argument IGNORE-MARKED is non-nil, articles which are
-marked as read or unread are ignored."
+If optional 2nd argument IGNORE-MARKED is non-nil, ignore articles
+marked as read or unread."
   (let ((function nil)
        (header nil)
        (article nil))
@@ -5157,8 +5424,7 @@ ROT47 will be performed for Japanese text in any case."
                   (list (prefix-numeric-value current-prefix-arg))
                 (list nil)))
   (cond ((not (numberp n)) (setq n 13))
-       ((< n 0) (setq n (- 26 (% (- n) 26))))
-       (t (setq n (% n 26))))          ;canonicalize N
+       (t (setq n (mod n 26))))        ;canonicalize N
   (if (not (zerop n))          ; no action needed for a rot of 0
       (progn
        (if (or (not (boundp 'caesar-translate-table))
@@ -5186,7 +5452,7 @@ ROT47 will be performed for Japanese text in any case."
                          (if (<= v t1) (if (< v t2) v (+ v 47))
                            (if (<= v t3) (- v 47) v))))
                  (setq i (1+ i))))
-             (message "Building caesar-translate-table... done")))
+             (message "Building caesar-translate-table...done")))
        (let ((from (region-beginning))
              (to (region-end))
              (i 0) str len)
@@ -5244,7 +5510,7 @@ ROT47 will be performed for Japanese text in any case."
   (require 'rmail)
   ;; Most of these codes are borrowed from rmailout.el.
   (setq file-name (expand-file-name file-name))
-  (setq rmail-last-rmail-file file-name)
+  (setq rmail-default-rmail-file file-name)
   (let ((artbuf (current-buffer))
        (tmpbuf (get-buffer-create " *GNUS-output*")))
     (save-excursion
@@ -5349,22 +5615,26 @@ ROT47 will be performed for Japanese text in any case."
   "Open network stream to remote NNTP server.
 If optional argument CONFIRM is non-nil, ask you host that NNTP server
 is running even if it is defined.
-Run gnus-open-server-hook just before opening news server."
+Run `gnus-open-server-hook' just before opening news server."
   (if (gnus-server-opened)
       ;; Stream is already opened.
       nil
     ;; Open NNTP server.
     (if (or confirm
            (null gnus-nntp-server))
-       (if (and (boundp 'gnus-secondary-servers) gnus-secondary-servers)
-           ;; Read server name with completion.
-           (setq gnus-nntp-server
-                 (completing-read "NNTP server: "
-                                  (cons (list gnus-nntp-server)
-                                        gnus-secondary-servers)
-                                  nil nil gnus-nntp-server))
-         (setq gnus-nntp-server
-               (read-string "NNTP server: " gnus-nntp-server))))
+       ;; If someone has set the service to nil, then this should always
+       ;; be the local host.
+       (if gnus-nntp-service
+           (if (and (boundp 'gnus-secondary-servers) gnus-secondary-servers)
+               ;; Read server name with completion.
+               (setq gnus-nntp-server
+                     (completing-read "NNTP server: "
+                                      (cons (list gnus-nntp-server)
+                                            gnus-secondary-servers)
+                                      nil nil gnus-nntp-server))
+             (setq gnus-nntp-server
+                   (read-string "NNTP server: " gnus-nntp-server)))
+         (setq gnus-nntp-server "")))
     ;; If no server name is given, local host is assumed.
     (if (or (string-equal gnus-nntp-server "")
            (string-equal gnus-nntp-server "::")) ;RMS preference.
@@ -5391,12 +5661,12 @@ Run gnus-open-server-hook just before opening news server."
          ((gnus-open-server gnus-nntp-server gnus-nntp-service)
           (message ""))
          (t
-          (error
+          (error "%s"
            (gnus-nntp-message
             (format "Cannot open NNTP server on %s" gnus-nntp-server)))))
     ))
 
-;; Dummy functions used only once. Should return nil.
+;; Dummy functions used only once.  Should return nil.
 (defun gnus-server-opened () nil)
 (defun gnus-close-server () nil)
 
@@ -5412,7 +5682,7 @@ If no message is available and optional MESSAGE is given, return it."
 (defun gnus-define-access-method (method &optional access-methods)
   "Define access functions for the access METHOD.
 Methods definition is taken from optional argument ACCESS-METHODS or
-the variable gnus-access-methods."
+the variable `gnus-access-methods'."
   (let ((bindings
         (cdr (assoc method (or access-methods gnus-access-methods)))))
     (if (null bindings)
@@ -5533,8 +5803,8 @@ are selected."
 
 (defun gnus-get-header-by-number (number)
   "Return a header specified by a NUMBER.
-If the variable gnus-newsgroup-headers is updated, the hashed table
-gnus-newsgroup-headers-hashtb-by-number must be set to nil to indicate
+If you update the variable `gnus-newsgroup-headers', you must set the
+hash table `gnus-newsgroup-headers-hashtb-by-number' to nil to indicate
 rehash is necessary."
   (or gnus-newsgroup-headers-hashtb-by-number
       (gnus-make-headers-hashtable-by-number))
@@ -5543,8 +5813,8 @@ rehash is necessary."
 
 (defun gnus-get-header-by-id (id)
   "Return a header specified by an ID.
-If the variable gnus-newsgroup-headers is updated, the hashed table
-gnus-newsgroup-headers-hashtb-by-id must be set to nil to indicate
+If you update the variable `gnus-newsgroup-headers', you must set the
+hash table `gnus-newsgroup-headers-hashtb-by-id' to nil to indicate
 rehash is necessary."
   (or gnus-newsgroup-headers-hashtb-by-id
       (gnus-make-headers-hashtable-by-id))
@@ -5552,7 +5822,7 @@ rehash is necessary."
        (gnus-gethash id gnus-newsgroup-headers-hashtb-by-id)))
 
 (defun gnus-make-headers-hashtable-by-number ()
-  "Make hashtable for the variable gnus-newsgroup-headers by number."
+  "Make hashtable for the variable `gnus-newsgroup-headers' by number."
   (let ((header nil)
        (headers gnus-newsgroup-headers))
     (setq gnus-newsgroup-headers-hashtb-by-number
@@ -5565,7 +5835,7 @@ rehash is necessary."
       )))
 
 (defun gnus-make-headers-hashtable-by-id ()
-  "Make hashtable for the variable gnus-newsgroup-headers by id."
+  "Make hashtable for the variable `gnus-newsgroup-headers' by id."
   (let ((header nil)
        (headers gnus-newsgroup-headers))
     (setq gnus-newsgroup-headers-hashtb-by-id
@@ -5578,7 +5848,7 @@ rehash is necessary."
       )))
 
 (defun gnus-clear-hashtables-for-newsgroup-headers ()
-  "Clear hash tables created for the variable gnus-newsgroup-headers."
+  "Clear hash tables created for the variable `gnus-newsgroup-headers'."
   (setq gnus-newsgroup-headers-hashtb-by-id nil)
   (setq gnus-newsgroup-headers-hashtb-by-number nil))
 
@@ -5689,7 +5959,7 @@ that it was marked as read once."
   "Configure GNUS windows according to the next ACTION.
 The ACTION is either a symbol, such as `summary', or a
 configuration list such as `(1 1 2)'.  If ACTION is not a list,
-configuration list is got from the variable gnus-window-configuration."
+configuration list is got from the variable `gnus-window-configuration'."
   (let* ((windows
          (if (listp action)
              action (car (cdr (assq action gnus-window-configuration)))))
@@ -5700,7 +5970,9 @@ configuration list is got from the variable gnus-window-configuration."
         (height nil)
         (grpheight 0)
         (subheight 0)
-        (artheight 0))
+        (artheight 0)
+        ;; Make split-window-vertically leave focus in upper window.
+        (split-window-keep-point t))
     (if (or (null windows)             ;No configuration is specified.
            (and (eq (null grpwin)
                     (zerop (nth 0 windows)))
@@ -5720,7 +5992,7 @@ configuration list is got from the variable gnus-window-configuration."
             (setq height (+ (if grpwin (window-height grpwin) 0)
                             (if subwin (window-height subwin) 0)
                             (if artwin (window-height artwin) 0)))))
-      ;; The Newsgroup buffer exits always. So, use it to extend the
+      ;; The Newsgroup buffer exits always.  So, use it to extend the
       ;; Group window so as to get enough window space.
       (switch-to-buffer gnus-group-buffer 'norecord)
       (and (get-buffer gnus-summary-buffer)
@@ -5817,7 +6089,7 @@ configuration list is got from the variable gnus-window-configuration."
 
 (defun gnus-overload-functions (&optional overloads)
   "Overload functions specified by optional argument OVERLOADS.
-If nothing is specified, use the variable gnus-overload-functions."
+If nothing is specified, use the variable `gnus-overload-functions'."
   (let ((defs nil)
        (overloads (or overloads gnus-overload-functions)))
     (while overloads
@@ -6033,6 +6305,15 @@ If optional argument RAWFILE is non-nil, force to read raw startup file."
          ))
     (gnus-expire-marked-articles)
     (gnus-get-unread-articles)
+    
+    ;; newsgroups description
+    (if gnus-newsgroups-display
+       (if (not gnus-newsgroups-alist)
+           ;; Get newsgroups file only once.
+           (gnus-newsgroups-retrieve-description)))
+       
+    (setq gnus-newsgroups-hashtb (gnus-make-hashtable-from-alist gnus-newsgroups-alist))
+    
     ;; Check new newsgroups and subscribe them.
     (if init
        (let ((new-newsgroups (gnus-find-new-newsgroups)))
@@ -6052,7 +6333,7 @@ If optional argument RAWFILE is non-nil, force to read raw startup file."
 
 (defun gnus-find-new-newsgroups ()
   "Looking for new newsgroups and return names.
-`-n' option of options line in .newsrc file is recognized."
+`-n' option of options line in `.newsrc' file is recognized."
   (let ((group nil)
        (new-newsgroups nil))
     (mapatoms
@@ -6076,7 +6357,7 @@ If optional argument RAWFILE is non-nil, force to read raw startup file."
     ))
 
 (defun gnus-kill-newsgroup (group)
-  "Kill GROUP from gnus-newsrc-assoc, .newsrc and gnus-unread-hashtb."
+  "Kill GROUP from `gnus-newsrc-assoc', `.newsrc' and `gnus-unread-hashtb'."
   (let ((info (gnus-gethash group gnus-newsrc-hashtb)))
     (if (null info)
        nil
@@ -6146,8 +6427,8 @@ If optional argument NEXT is nil, appended to the last."
     ))
 
 (defun gnus-check-killed-newsgroups ()
-  "Check consistency between gnus-newsrc-assoc and gnus-killed-assoc.
-gnus-killed-hashtb is also updated."
+  "Update `gnus-killed-assoc' based on `gnus-newsrc-assoc'.
+Update `gnus-killed-hashtb' also."
   (let ((group nil)
        (new-killed nil)
        (old-killed gnus-killed-assoc))
@@ -6223,7 +6504,7 @@ If optional argument CONFIRM is non-nil, confirm deletion of newsgroups."
     (setq gnus-marked-assoc new-marked)
     (setq gnus-marked-hashtb
          (gnus-make-hashtable-from-alist gnus-marked-assoc))
-    (message "Checking bogus newsgroups... done")
+    (message "Checking bogus newsgroups...done")
     ))
 
 (defun gnus-get-unread-articles ()
@@ -6258,7 +6539,7 @@ If optional argument CONFIRM is non-nil, confirm deletion of newsgroups."
        )
       (setq read (cdr read))
       )
-    (message "Checking new news... done")
+    (message "Checking new news...done")
     ))
 
 (defun gnus-expire-marked-articles ()
@@ -6427,12 +6708,12 @@ Arguments are GROUP, HEADERS, UNREADS, and optional SUBSCRIBED-ONLY."
       (save-excursion
        (set-buffer nntp-server-buffer)
        (gnus-active-to-gnus-format)
-       (message "Reading active file... done"))
+       (message "Reading active file...done"))
     (error "Cannot read active file from NNTP server.")))
 
 (defun gnus-active-to-gnus-format ()
   "Convert active file format to internal format.
-Lines matching gnus-ignored-newsgroups are ignored."
+Lines matching `gnus-ignored-newsgroups' are ignored."
   ;; Delete unnecessary lines.
   (goto-char (point-min))
   ;;(delete-matching-lines "^to\\..*$")
@@ -6507,7 +6788,7 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
             (message "Reading %s..." newsrc-file)
             (gnus-newsrc-to-gnus-format)
             (gnus-check-killed-newsgroups)
-            (message "Reading %s... Done" newsrc-file)))
+            (message "Reading %s...done" newsrc-file)))
       )))
 
 (defun gnus-make-newsrc-file (file)
@@ -6519,7 +6800,7 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
     ))
 
 (defun gnus-newsrc-to-gnus-format ()
-  "Parse current buffer as .newsrc file."
+  "Parse current buffer as `.newsrc' file."
   (let ((newsgroup nil)
        (subscribe nil)
        (ranges nil)
@@ -6561,11 +6842,17 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
     ;; Before supporting continuation lines, " newsgroup ! 1-5" was
     ;; okay, but now it is invalid.  It should be "newsgroup! 1-5".
     (goto-char (point-min))
-    ;; Due to overflows in regex.c, change the following regexp:
+    ;; We used this regexp, but it caused overflows.
     ;; "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(.*\\)$"
-    ;; Suggested by composer@bucsf.bu.edu (Jeff Kellem).
-    (while (re-search-forward
-           "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(\\(...\\)*.*\\)$" nil t)
+    ;; Suggested by composer@bucsf.bu.edu (Jeff Kellem)
+    ;; but no longer viable because of extensive backtracking in Emacs 19:
+    ;; "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(\\(...\\)*.*\\)$"
+    ;; but, the following causes trouble on some case:
+    ;; "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(\\|[^ \t\n].*\\)$"
+    ;; So now we don't try to match the tail of the line at all.
+    ;; It's just as easy to extract it later.
+    (while (re-search-forward "^\\([^:! \t\n]+\\)\\([:!]\\)"
+                             nil t)
       (setq newsgroup (buffer-substring (match-beginning 1) (match-end 1)))
       ;; Check duplications of newsgroups.
       ;; Note: Checking the duplications takes very long time.
@@ -6574,7 +6861,9 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
        (setq subscribe
              (string-equal
               ":" (buffer-substring (match-beginning 2) (match-end 2))))
-       (setq ranges (buffer-substring (match-beginning 3) (match-end 3)))
+       (skip-chars-forward " \t")
+       (setq ranges (buffer-substring (point) (save-excursion
+                                                (end-of-line) (point))))
        (setq read-list nil)
        (while (string-match "^[, \t]*\\([0-9-]+\\)" ranges)
          (setq subrange (substring ranges (match-beginning 1) (match-end 1)))
@@ -6616,7 +6905,7 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
     ;; Parse each newsgroup description such as "comp.all".  Commas
     ;; and white spaces can be a newsgroup separator.
     (while
-       (string-match "^[ \t\n,]*\\(!?\\)\\([^--- \t\n,][^ \t\n,]*\\)" options)
+       (string-match "^[ \t\n,]*\\(!?\\)\\([^- \t\n,][^ \t\n,]*\\)" options)
       (setq yes-or-no
            (substring options (match-beginning 1) (match-end 1)))
       (setq newsgroup
@@ -6664,7 +6953,7 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
     ))
 
 (defun gnus-save-newsrc-file ()
-  "Save to .newsrc FILE."
+  "Save current status in the `.newsrc' file."
   ;; Note: We cannot save .newsrc file if all newsgroups are removed
   ;; from the variable gnus-newsrc-assoc.
   (and (or gnus-newsrc-assoc gnus-killed-assoc)
@@ -6693,12 +6982,12 @@ If optional argument RAWFILE is non-nil, the raw startup file is read."
                 (require-final-newline t)) ;Don't ask even if requested.
             (write-file (concat gnus-current-startup-file ".el")))
           (kill-buffer (current-buffer))
-          (message "Saving %s... Done" gnus-current-startup-file)
+          (message "Saving %s...done" gnus-current-startup-file)
           ))
     ))
 
 (defun gnus-update-newsrc-buffer (group &optional delete next)
-  "Incrementally update .newsrc buffer about GROUP.
+  "Incrementally update `.newsrc' buffer about GROUP.
 If optional 1st argument DELETE is non-nil, delete the group.
 If optional 2nd argument NEXT is non-nil, inserted before it."
   (save-excursion
@@ -6754,7 +7043,7 @@ If optional 2nd argument NEXT is non-nil, inserted before it."
       )))
 
 (defun gnus-gnus-to-quick-newsrc-format ()
-  "Insert GNUS variables such as gnus-newsrc-assoc in lisp format."
+  "Insert GNUS variables such as `gnus-newsrc-assoc' in Lisp format."
   (insert ";; GNUS internal format of .newsrc.\n")
   (insert ";; Touch .newsrc instead if you think to remove this file.\n")
   (let ((variable nil)
@@ -6839,7 +7128,7 @@ If optional 2nd argument NEXT is non-nil, inserted before it."
   (let ((count 0))
     (while range
       (if (/= (cdr (car range)) 0)
-         ;; If end1 is 0, it must be skipped. Usually no articles in
+         ;; If end1 is 0, it must be skipped.  Usually no articles in
          ;;  this group.
          (setq count (+ count 1 (- (cdr (car range)) (car (car range))))))
       (setq range (cdr range))
@@ -6887,7 +7176,7 @@ Range of OBJ is expressed as `((beg1 . end1) (beg2 . end2) ...)."
       (save-excursion
        (set-buffer nntp-server-buffer)
        (gnus-distributions-to-gnus-format)
-       (message "Reading distributions file... done"))
+       (message "Reading distributions file...done"))
     ;; It's not a fatal error.
     ;;(error "Cannot read distributions file from NNTP server.")
     )
@@ -6914,26 +7203,41 @@ Range of OBJ is expressed as `((beg1 . end1) (beg2 . end2) ...)."
                gnus-distribution-list)))
   (setq gnus-distribution-list
        (nreverse gnus-distribution-list)))
+\f
+(defun gnus-newsgroups-retrieve-description ()
+  "Retrieve newsgroups description and build gnus-newsgroups-alist"
+  (message "Reading newsgroups file...")
+  (if (gnus-request-list-newsgroups)
+      (save-excursion
+       (setq gnus-newsgroups-alist nil)
+       (set-buffer nntp-server-buffer)
+       (goto-char (point-min))
+       (while (re-search-forward gnus-newsgroups-regex nil t)
+         (setq gnus-newsgroups-alist
+               (cons (cons (buffer-substring (match-beginning 1) (match-end 1))
+                           (buffer-substring (match-beginning 2) (match-end 2)))
+                     gnus-newsgroups-alist)))
+       (message "Reading newsgroups file...done"))
+    (message "Cannot read newsgroups file")))
+
+(defun gnus-newsgroups-update-description ()
+  "Update the newsgroups description"
+  (interactive)
+  (gnus-newsgroups-retrieve-description)
+  (setq gnus-newsgroups-hashtb (gnus-make-hashtable-from-alist gnus-newsgroups-alist)))
 
-;; Some older version of GNU Emacs does not support function
-;; `file-newer-than-file-p'.
-
-(or (fboundp 'file-newer-than-file-p)
-    (defun file-newer-than-file-p (file1 file2)
-      "Return t if file FILE1 is newer than file FILE2.
-If FILE1 does not exist, the answer is nil;
-otherwise, if FILE2 does not exist, the answer is t."
-      (let ((mod1 (nth 5 (file-attributes file1)))
-           (mod2 (nth 5 (file-attributes file2))))
-       (cond ((not (file-exists-p file1)) nil)
-             ((not (file-exists-p file2)) t)
-             ((and mod2 mod1)
-              (or (< (car mod2) (car mod1))
-                  (and (= (car mod2) (car mod1))
-                       (<= (nth 1 mod2) (nth 1 mod1)))))
-             ))))
-
+(defun gnus-newsgroups-display-toggle ()
+  "Toggle displaying newsgroup descriptions in *Newsgroup* buffer."
+  (interactive)
+  (setq gnus-newsgroups-display (not gnus-newsgroups-display))
+  (if gnus-newsgroups-showall
+        (gnus-group-list-groups t)
+    (gnus-group-list-groups nil)))
 \f
+(provide 'gnus)
+
 ;;Local variables:
 ;;eval: (put 'gnus-eval-in-buffer-window 'lisp-indent-hook 1)
 ;;end:
+
+;;; gnus.el ends here