diff lisp/=gnus.el @ 257:e5ba2ba35226

Initial revision
author Jim Blandy <jimb@redhat.com>
date Thu, 09 May 1991 21:50:45 +0000
parents
children 4cd7543be581
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/=gnus.el	Thu May 09 21:50:45 1991 +0000
@@ -0,0 +1,6081 @@
+;;; GNUS: an NNTP-based News Reader for GNU Emacs
+;; Copyright (C) 1987, 1988, 1989 Fujitsu Laboratories LTD.
+;; Copyright (C) 1987, 1988, 1989, 1990 Masanobu UMEDA
+;; $Header: gnus.el,v 3.13 90/03/23 13:24:27 umerin Locked $
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY.  No author or distributor
+;; accepts responsibility to anyone for the consequences of using it
+;; or for whether it serves any particular purpose or works at all,
+;; unless he says so in writing.  Refer to the GNU Emacs General Public
+;; License for full details.
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; GNU Emacs, but only under the conditions described in the
+;; GNU Emacs General Public License.   A copy of this license is
+;; supposed to have been given to you along with GNU Emacs so you
+;; can know your rights and responsibilities.  It should be in a
+;; file named COPYING.  Among other things, the copyright notice
+;; and this notice must be preserved on all copies.
+
+;; 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
+
+;; 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.
+
+(provide 'gnus)
+(require 'nntp)
+(require 'mail-utils)
+
+(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.")
+
+(defvar gnus-signature-file "~/.signature"
+  "*Your .signature file. Use `.signature-DISTRIBUTION' instead if exists.")
+
+(defvar gnus-use-cross-reference t
+  "Specifies what to do with cross references (Xref: field).
+If nil, ignore cross references.  If t, mark articles as read in subscribed
+newsgroups.  Otherwise, mark articles as 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 execpt for
+`poster'.  Otherewise, if not nil nor t, always use its value.")
+
+(defvar gnus-large-newsgroup 50
+  "*The number of articles which indicates a large newsgroup.
+If the number of articles in a newsgroup is greater than the value,
+confirmation is required for selecting the newsgroup.")
+
+(defvar gnus-author-copy (getenv "AUTHORCOPY")
+  "*Filename for saving a copy of an article posted using FCC: field.
+Initialized from the AUTHORCOPY environment variable.
+
+Articles are saved using a function specified by the the variable
+`gnus-author-copy-saver' (`rmail-output' is the 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
+possible to save an article in an MH folder as follows:
+
+    (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.")
+
+(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 nil, the directory form of a newsgroup is
+used instead.")
+
+(defvar gnus-article-save-directory (getenv "SAVEDIR")
+  "*The directory in which to save articles; defaults to ~/News.
+Initialized from the SAVEDIR environment variable.")
+
+(defvar gnus-default-article-saver (function gnus-Subject-save-in-rmail)
+  "A function used to save articles in your favorite format.
+The function must be interactively callable (in other words, it must
+be an Emacs command).
+
+GNUS provides the following functions:
+	gnus-Subject-save-in-rmail (in Rmail format)
+	gnus-Subject-save-in-mail (in Unix mail format)
+	gnus-Subject-save-in-folder (in an MH folder)
+	gnus-Subject-save-in-file (in article format).")
+
+(defvar gnus-rmail-save-name (function gnus-plain-save-name)
+  "A function generating a file name to save articles in Rmail format.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
+
+(defvar gnus-mail-save-name (function gnus-plain-save-name)
+  "A function generating a file name to save articles in Unix mail format.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
+
+(defvar gnus-folder-save-name (function gnus-folder-save-name)
+  "A function generating a file name to save articles in MH folder.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FOLDER.")
+
+(defvar gnus-file-save-name (function gnus-numeric-save-name)
+  "A function generating a file name to save articles in article format.
+The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
+
+(defvar gnus-kill-file-name "KILL"
+  "File name of a KILL file.")
+
+(defvar gnus-default-distribution "local"
+  "*Use this value as distribution if no distribution is specified.")
+
+(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 confirmation
+may be required.")
+
+(defvar gnus-interactive-post t
+  "*Newsgroup, subject, and distribution will be asked for if non-nil.")
+
+(defvar gnus-user-login-name nil
+  "*The login name of the user.
+Uses USER and LOGNAME environment variables if undefined.")
+
+(defvar gnus-user-full-name nil
+  "*The full name of the user.
+Uses from the NAME environment variable if undefined.")
+
+(defvar gnus-show-threads t
+  "*Show conversation threads in Subject Mode if non-nil.")
+
+(defvar gnus-thread-hide-subject t
+  "*Non-nil means hide subjects for thread subtrees.")
+
+(defvar gnus-thread-hide-subtree nil
+  "*Non-nil means hide thread subtrees initially.
+If non-nil, you have to run the command `gnus-Subject-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.")
+
+(defvar gnus-thread-ignore-subject nil
+  "*Don't take care of subject differences, but only references if non-nil.
+If it is non-nil, some commands work with subjects do not work properly.")
+
+(defvar gnus-thread-indent-level 4
+  "Indentation of thread subtrees.")
+
+(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:\\|^In-Reply-To:"
+  "Regexp matching headers not to display in messages.")
+
+(defvar gnus-show-all-headers nil
+  "*Show all headers of an article if non-nil.")
+
+(defvar gnus-save-all-headers nil
+  "*Save all headers of an article if non-nil.")
+
+(defvar gnus-optional-headers (function gnus-optional-lines-and-from)
+  "A function generating a optional string displayed in GNUS Subject
+mode buffer.  The function is called with an article HEADER. The
+result must be a string excluding `[' and `]'.")
+
+(defvar gnus-auto-extend-newsgroup t
+  "*Extend visible articles to forward and backward if non-nil.")
+
+(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'.")
+
+(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
+Subject mode and go back to Group mode.  If the value is neither nil
+nor t, GNUS will select the following unread newsgroup. Especially, if
+the value is the symbol `quietly', the next unread newsgroup will be
+selected without any confirmations.")
+
+(defvar gnus-auto-select-same nil
+  "*Select the next article with the same subject automagically if non-nil.")
+
+(defvar gnus-auto-center-subject t
+  "*Always center the current subject in GNUS Subject mode window if non-nil.")
+
+(defvar gnus-break-pages t
+  "*Break an article into pages if non-nil.
+Page delimiter is specified by the variable `gnus-page-delimiter'.")
+
+(defvar gnus-page-delimiter "^\^L"
+  "*Regexp describing line-beginnings that separate pages of news article.")
+
+(defvar gnus-digest-show-summary t
+  "*Show a summary of undigestified messages if non-nil.")
+
+(defvar gnus-digest-separator "^Subject:[ \t]"
+  "*Regexp that separates messages in a digest article.")
+
+(defvar gnus-use-full-window t
+  "*Non-nil means to take up the entire screen of Emacs.")
+
+(defvar gnus-window-configuration
+  '((SelectNewsgroup (0 1 0))
+    (ExitNewsgroup   (1 0 0))
+    (SelectArticle   (0 3 10))
+    (ExpandSubject   (0 1 0)))
+  "Specify window configurations for each action.
+The format of the variable is a list of (ACTION (G S A)), where
+G, S, and A are the relative height of Group, Subject, and Article
+windows, respectively.  ACTION is `SelectNewsgroup', `ExitNewsgroup',
+`SelectArticle', or `ExpandSubject'.")
+
+(defvar gnus-mail-reply-method
+  (function gnus-mail-reply-using-mail)
+  "A function to compose reply mail.
+The function `gnus-mail-reply-using-mail' uses usual the 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-other-window-method
+  (function gnus-mail-other-window-using-mail)
+  "A 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
+mail program.  You can use yet another program by customizing this variable.")
+
+(defvar gnus-subscribe-newsgroup-method
+  (function
+   (lambda (newsgroup)
+     (gnus-subscribe-newsgroup newsgroup
+			       (car (car gnus-newsrc-assoc)))))
+  "A function called with a newsgroup name when it is created.")
+
+(defvar gnus-Group-mode-hook nil
+  "A hook for GNUS Group Mode.")
+
+(defvar gnus-Subject-mode-hook nil
+  "A hook for GNUS Subject Mode.")
+
+(defvar gnus-Article-mode-hook nil
+  "A hook for GNUS Article Mode.")
+
+(defvar gnus-Kill-file-mode-hook nil
+  "A hook for GNUS KILL File Mode.")
+
+(defvar gnus-Open-server-hook nil
+  "A hook called just before opening connection to news server.")
+
+(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 is possible to change the behavior of GNUS according to the
+selected NNTP server.")
+
+(defvar gnus-Group-prepare-hook nil
+  "A hook called after newsgroup list is created in the Newsgroup buffer.
+If you want to modify the Newsgroup buffer, you can use this hook.")
+
+(defvar gnus-Subject-prepare-hook nil
+  "A hook called after subject list is created in the Subject buffer.
+If you want to modify the Subject buffer, you can use this hook.")
+
+(defvar gnus-Article-prepare-hook nil
+  "A hook called after an article is prepared in the Article buffer.
+If you want to run a special decoding program like nkf, use this hook.")
+
+(defvar gnus-Select-group-hook nil
+  "A hook called when a newsgroup is selected.
+If you want to sort Subject buffer by date and then by subject, you
+can use the following hook:
+
+(setq gnus-Select-group-hook
+      '(lambda ()
+	 ;; First of all, sort by date.
+	 (gnus-sort-headers
+	  '(lambda (a b)
+	     (gnus-date-lessp (gnus-header-date a)
+			      (gnus-header-date b))))
+	 ;; Then sort by subject string ignoring `Re:'.
+	 ;; If case-fold-search is non-nil, case of letters is ignored.
+	 (gnus-sort-headers
+	  '(lambda (a b)
+	     (gnus-string-lessp
+	      (gnus-simplify-subject (gnus-header-subject a) 're)
+	      (gnus-simplify-subject (gnus-header-subject b) 're)
+	      )))))
+
+If you'd like to simplify subjects like the `gnus-Subject-next-same-subject'
+command does, you can use the following hook:
+
+(setq gnus-Select-group-hook
+      '(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 the GNUS Subject buffer as follows:
+
+(setq gnus-Select-group-hook
+      '(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-Subject-show-thread)))
+  "Hook called when an article is selected.
+The default hook automatically shows conversation thread subtrees
+of the selected article as follows:
+
+(setq gnus-Select-article-hook
+      '(lambda ()
+	 (gnus-Subject-show-thread)))
+
+If you'd like to run RMAIL on a digest article automagically, you can
+use the following hook:
+
+(setq gnus-Select-article-hook
+      '(lambda ()
+	 (gnus-Subject-show-thread)
+	 (cond ((string-equal \"comp.sys.sun\" gnus-newsgroup-name)
+		(gnus-Subject-rmail-digest))
+	       ((and (string-equal \"comp.text\" gnus-newsgroup-name)
+		     (string-match \"^TeXhax Digest\"
+				   (gnus-header-subject gnus-current-headers)))
+		(gnus-Subject-rmail-digest)
+		))))")
+
+(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"))))))
+  "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):
+
+(setq gnus-Select-digest-hook
+      '(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)
+  "A hook called when a newsgroup is selected and subject 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.
+
+Since a general KILL file is too heavy to use for only a few
+newsgroups, we recommend you 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
+      '(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-Subject-mark-as-read gnus-current-article))
+     (gnus-Subject-set-current-mark "+")))
+  "A hook called when an article is selected for the first time.
+The hook is intended to mark an article as read when it is selected.
+If you'd like to mark as unread (-) instead, use the following hook:
+
+(setq gnus-Mark-article-hook
+      '(lambda ()
+	 (gnus-Subject-mark-as-unread gnus-current-article)
+	 (gnus-Subject-set-current-mark \"+\")))")
+
+(defvar gnus-Inews-article-hook nil
+  "A hook called before posting an article.
+If you'd like to run a special encoding program, use this hook.")
+
+(defvar gnus-Exit-group-hook nil
+  "A hook called when exiting (not quitting) Subject mode.
+If your machine is so slow that exiting from Subject mode takes a
+long time, set the variable `gnus-newsgroup-headers' to nil.  This
+inhibits marking articles as read using cross-reference information.")
+
+(defvar gnus-Suspend-gnus-hook nil
+  "A hook called when suspending (not exiting) GNUS.")
+
+(defvar gnus-Exit-gnus-hook nil
+  "A hook called when exiting (not suspending) GNUS.")
+
+(defvar gnus-Save-newsrc-hook nil
+  "A hook called when saving the newsrc file.
+This hook is called before saving .newsrc file.")
+
+(defvar gnus-your-domain nil
+  "*Your domain name without your host name like: \"stars.flab.Fujitsu.CO.JP\"
+The environment variable DOMAINNAME is used instead if defined.  If
+the function `system-name' returns the full internet name, there is no
+need to define this variable.")
+
+(defvar gnus-your-organization nil
+  "*Your organization like: \"Fujitsu Laboratories Ltd., Kawasaki, Japan.\"
+The `ORGANIZATION' environment variable is used instead if defined.")
+
+(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.")
+
+(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)")
+
+;; Internal variables.
+
+(defconst gnus-version "GNUS 3.13"
+  "Version numbers of this version of GNUS.")
+
+(defvar gnus-Info-nodes
+  '((gnus-Group-mode . "(gnus)Newsgroup Commands")
+    (gnus-Subject-mode . "(gnus)Subject Commands")
+    (gnus-Article-mode . "(gnus)Article Commands")
+    (gnus-Kill-file-mode . "(gnus)KILL File")
+    (gnus-Browse-killed-mode . "(gnus)Maintenance"))
+  "Assoc list of major modes and related Info nodes.")
+
+(defvar gnus-access-methods
+  '((nntp
+     (gnus-retrieve-headers .	nntp-retrieve-headers)
+     (gnus-open-server .	nntp-open-server)
+     (gnus-close-server .	nntp-close-server)
+     (gnus-server-opened .	nntp-server-opened)
+     (gnus-status-message .	nntp-status-message)
+     (gnus-request-article .	nntp-request-article)
+     (gnus-request-group .	nntp-request-group)
+     (gnus-request-list .	nntp-request-list)
+     (gnus-request-post .	nntp-request-post))
+    (nnspool
+     (gnus-retrieve-headers .	nnspool-retrieve-headers)
+     (gnus-open-server .	nnspool-open-server)
+     (gnus-close-server .	nnspool-close-server)
+     (gnus-server-opened .	nnspool-server-opened)
+     (gnus-status-message .	nnspool-status-message)
+     (gnus-request-article .	nnspool-request-article)
+     (gnus-request-group .	nnspool-request-group)
+     (gnus-request-list .	nnspool-request-list)
+     (gnus-request-post .	nnspool-request-post))
+    (mhspool
+     (gnus-retrieve-headers .	mhspool-retrieve-headers)
+     (gnus-open-server .	mhspool-open-server)
+     (gnus-close-server .	mhspool-close-server)
+     (gnus-server-opened .	mhspool-server-opened)
+     (gnus-status-message .	mhspool-status-message)
+     (gnus-request-article .	mhspool-request-article)
+     (gnus-request-group .	mhspool-request-group)
+     (gnus-request-list .	mhspool-request-list)
+     (gnus-request-post .	mhspool-request-post)))
+  "Access method for NNTP, nnspool, and mhspool.")
+
+(defvar gnus-Group-buffer "*Newsgroup*")
+(defvar gnus-Subject-buffer "*Subject*")
+(defvar gnus-Article-buffer "*Article*")
+(defvar gnus-Digest-buffer "GNUS Digest")
+(defvar gnus-Digest-summary-buffer "GNUS Digest-summary")
+
+(defvar gnus-buffer-list
+  (list gnus-Group-buffer gnus-Subject-buffer gnus-Article-buffer
+	gnus-Digest-buffer gnus-Digest-summary-buffer)
+  "GNUS buffer names which should be killed when exiting.")
+
+(defvar gnus-variable-list
+  '(gnus-newsrc-options
+    gnus-newsrc-options-n-yes gnus-newsrc-options-n-no
+    gnus-newsrc-assoc gnus-killed-assoc gnus-marked-assoc)
+  "GNUS variables saved in the quick startup file.")
+
+(defvar gnus-overload-functions
+  '((news-inews gnus-inews-news "rnewspost")
+    (caesar-region gnus-caesar-region "rnews"))
+  "Functions overloaded by gnus.
+It is a list of `(original overload &optional file)'.")
+
+(defvar gnus-newsrc-options nil
+  "Options line in the .newsrc file.")
+
+(defvar gnus-newsrc-options-n-yes nil
+  "Regexp representing subscribed newsgroups.")
+
+(defvar gnus-newsrc-options-n-no nil
+  "Regexp representing unsubscribed newsgroups.")
+
+(defvar gnus-newsrc-assoc nil
+  "Assoc list of read articles.")
+
+(defvar gnus-killed-assoc nil
+  "Assoc list of newsgroups removed from `gnus-newsrc-assoc'.")
+
+(defvar gnus-marked-assoc nil
+  "Assoc list of articles marked as unread.")
+
+(defvar gnus-unread-hashtb nil
+  "Hashtable of unread articles.")
+
+(defvar gnus-active-hashtb nil
+  "Hashtable of active articles.")
+
+(defvar gnus-octive-hashtb nil
+  "Hashtable of OLD active articles.")
+
+(defvar gnus-current-startup-file nil
+  "Startup file for the current host.")
+
+(defvar gnus-last-search-regexp nil
+  "Default regexp for article search command.")
+
+(defvar gnus-last-shell-command nil
+  "Default shell command on article.")
+
+(defvar gnus-have-all-newsgroups nil)
+
+(defvar gnus-newsgroup-name nil)
+(defvar gnus-newsgroup-begin nil)
+(defvar gnus-newsgroup-end nil)
+(defvar gnus-newsgroup-last-rmail nil)
+(defvar gnus-newsgroup-last-mail nil)
+(defvar gnus-newsgroup-last-folder nil)
+(defvar gnus-newsgroup-last-file nil)
+
+(defvar gnus-newsgroup-unreads nil
+  "List of unread articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-unselected nil
+  "List of unselected unread articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-marked nil
+  "List of marked articles in the current newsgroup (a subset of unread art).")
+
+(defvar gnus-newsgroup-headers nil
+  "List of article headers in the current newsgroup.")
+
+(defvar gnus-current-article nil)
+(defvar gnus-current-headers nil)
+(defvar gnus-current-history nil)
+(defvar gnus-have-all-headers nil)
+(defvar gnus-last-article nil)
+(defvar gnus-current-kill-article nil)
+
+;; Save window configuration.
+(defvar gnus-winconf-kill-file nil)
+
+(defvar gnus-Group-mode-map nil)
+(defvar gnus-Subject-mode-map nil)
+(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"))
+
+;; Define GNUS Subsystems.
+(autoload 'gnus-Group-post-news "gnuspost"
+	  "Post an article." t)
+(autoload 'gnus-Subject-post-news "gnuspost"
+	  "Post an article." t)
+(autoload 'gnus-Subject-post-reply "gnuspost"
+	  "Post a reply article." t)
+(autoload 'gnus-Subject-post-reply-with-original "gnuspost"
+	  "Post a reply article with original article." t)
+(autoload 'gnus-Subject-cancel-article "gnuspost"
+	  "Cancel an article you posted." t)
+
+(autoload 'gnus-Subject-mail-reply "gnusmail"
+	  "Reply mail to news author." t)
+(autoload 'gnus-Subject-mail-reply-with-original "gnusmail"
+	  "Reply mail to news author with original article." t)
+(autoload 'gnus-Subject-mail-other-window "gnusmail"
+	  "Compose mail in other window." t)
+
+(autoload 'gnus-Group-kill-group "gnusmisc"
+	  "Kill newsgroup on current line." t)
+(autoload 'gnus-Group-yank-group "gnusmisc"
+	  "Yank the last killed newsgroup on current line." t)
+(autoload 'gnus-Browse-killed-groups "gnusmisc"
+	  "Browse the killed newsgroups." t)
+
+(autoload 'rmail-output "rmailout"
+	  "Append this message to Unix mail file named FILE-NAME." t)
+(autoload 'mail-position-on-field "sendmail")
+(autoload 'mh-find-path "mh-e")
+(autoload 'mh-prompt-for-folder "mh-e")
+
+(put 'gnus-Group-mode 'mode-class 'special)
+(put 'gnus-Subject-mode 'mode-class 'special)
+(put 'gnus-Article-mode 'mode-class 'special)
+
+
+;;(put 'gnus-eval-in-buffer-window 'lisp-indent-function 1)
+
+(defmacro gnus-eval-in-buffer-window (buffer &rest forms)
+  "Pop to BUFFER, evaluate FORMS, and then returns to original window."
+  (` (let ((GNUSStartBufferWindow (selected-window)))
+       (unwind-protect
+	   (progn
+	     (pop-to-buffer (, buffer))
+	     (,@ forms))
+	 (select-window GNUSStartBufferWindow)))))
+
+(defmacro gnus-make-hashtable ()
+  '(make-abbrev-table))
+
+(defmacro gnus-gethash (string hashtable)
+  "Get hash value of STRING in HASHTABLE."
+  ;;(` (symbol-value (abbrev-symbol (, string) (, hashtable))))
+  (` (abbrev-expansion (, string) (, hashtable))))
+
+(defmacro gnus-sethash (string value hashtable)
+  "Set hash value. Arguments are STRING, VALUE, and HASHTABLE."
+  ;; We cannot use define-abbrev since it only accepts string as value.
+  (` (set (intern (, string) (, hashtable)) (, value))))
+
+;; 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.
+
+(defmacro nntp-header-number (header)
+  "Return article number in HEADER."
+  (` (aref (, header) 0)))
+
+(defmacro nntp-set-header-number (header number)
+  "Set article number of HEADER to NUMBER."
+  (` (aset (, header) 0 (, number))))
+
+(defmacro nntp-header-subject (header)
+  "Return subject string in HEADER."
+  (` (aref (, header) 1)))
+
+(defmacro nntp-set-header-subject (header subject)
+  "Set article subject of HEADER to SUBJECT."
+  (` (aset (, header) 1 (, subject))))
+
+(defmacro nntp-header-from (header)
+  "Return author string in HEADER."
+  (` (aref (, header) 2)))
+
+(defmacro nntp-set-header-from (header from)
+  "Set article author of HEADER to FROM."
+  (` (aset (, header) 2 (, from))))
+
+(defmacro nntp-header-xref (header)
+  "Return xref string in HEADER."
+  (` (aref (, header) 3)))
+
+(defmacro nntp-set-header-xref (header xref)
+  "Set article xref of HEADER to xref."
+  (` (aset (, header) 3 (, xref))))
+
+(defmacro nntp-header-lines (header)
+  "Return lines in HEADER."
+  (` (aref (, header) 4)))
+
+(defmacro nntp-set-header-lines (header lines)
+  "Set article lines of HEADER to LINES."
+  (` (aset (, header) 4 (, lines))))
+
+(defmacro nntp-header-date (header)
+  "Return date in HEADER."
+  (` (aref (, header) 5)))
+
+(defmacro nntp-set-header-date (header date)
+  "Set article date of HEADER to DATE."
+  (` (aset (, header) 5 (, date))))
+
+(defmacro nntp-header-id (header)
+  "Return Id in HEADER."
+  (` (aref (, header) 6)))
+
+(defmacro nntp-set-header-id (header id)
+  "Set article Id of HEADER to ID."
+  (` (aset (, header) 6 (, id))))
+
+(defmacro nntp-header-references (header)
+  "Return references in HEADER."
+  (` (aref (, header) 7)))
+
+(defmacro nntp-set-header-references (header ref)
+  "Set article references of HEADER to REF."
+  (` (aset (, header) 7 (, ref))))
+
+
+;;;
+;;; GNUS Group Mode
+;;;
+
+(if gnus-Group-mode-map
+    nil
+  (setq gnus-Group-mode-map (make-keymap))
+  (suppress-keymap gnus-Group-mode-map)
+  (define-key gnus-Group-mode-map " " 'gnus-Group-read-group)
+  (define-key gnus-Group-mode-map "=" 'gnus-Group-select-group)
+  (define-key gnus-Group-mode-map "j" 'gnus-Group-jump-to-group)
+  (define-key gnus-Group-mode-map "n" 'gnus-Group-next-unread-group)
+  (define-key gnus-Group-mode-map "p" 'gnus-Group-prev-unread-group)
+  (define-key gnus-Group-mode-map "\177" 'gnus-Group-prev-unread-group)
+  (define-key gnus-Group-mode-map "N" 'gnus-Group-next-group)
+  (define-key gnus-Group-mode-map "P" 'gnus-Group-prev-group)
+  (define-key gnus-Group-mode-map "\C-n" 'gnus-Group-next-group)
+  (define-key gnus-Group-mode-map "\C-p" '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)
+  (define-key gnus-Group-mode-map ">" 'end-of-buffer)
+  (define-key gnus-Group-mode-map "u" 'gnus-Group-unsubscribe-current-group)
+  (define-key gnus-Group-mode-map "U" 'gnus-Group-unsubscribe-group)
+  (define-key gnus-Group-mode-map "c" 'gnus-Group-catch-up)
+  (define-key gnus-Group-mode-map "C" 'gnus-Group-catch-up-all)
+  (define-key gnus-Group-mode-map "l" 'gnus-Group-list-groups)
+  (define-key gnus-Group-mode-map "L" 'gnus-Group-list-all-groups)
+  (define-key gnus-Group-mode-map "g" 'gnus-Group-get-new-news)
+  (define-key gnus-Group-mode-map "R" 'gnus-Group-restart)
+  (define-key gnus-Group-mode-map "b" 'gnus-Group-check-bogus-groups)
+  (define-key gnus-Group-mode-map "r" 'gnus-Group-restrict-groups)
+  (define-key gnus-Group-mode-map "a" 'gnus-Group-post-news)
+  (define-key gnus-Group-mode-map "\ek" 'gnus-Group-edit-local-kill)
+  (define-key gnus-Group-mode-map "\eK" 'gnus-Group-edit-global-kill)
+  (define-key gnus-Group-mode-map "\C-k" 'gnus-Group-kill-group)
+  (define-key gnus-Group-mode-map "\C-y" 'gnus-Group-yank-group)
+  (define-key gnus-Group-mode-map "\C-c\C-y" 'gnus-Browse-killed-groups)
+  (define-key gnus-Group-mode-map "V" 'gnus-version)
+  (define-key gnus-Group-mode-map "x" 'gnus-Group-force-update)
+  (define-key gnus-Group-mode-map "s" 'gnus-Group-force-update)
+  (define-key gnus-Group-mode-map "z" 'gnus-Group-suspend)
+  (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))
+
+(defun gnus-Group-mode ()
+  "Major mode for reading network news.
+All normal editing commands are turned off.
+Instead, these commands are available:
+\\{gnus-Group-mode-map}
+
+  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
+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
+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.
+
+  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
+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
+line is `options -n !talk talk.rumors', newsgroups under the `talk'
+hierarchy except for `talk.rumors' are ignored while checking new
+newsgroups.
+
+  If there is a file named `~/.signature-DISTRIBUTION', it is used as
+signature file instead of standard one when posting a news in
+DISTRIBUTION.
+
+  If an Info file generated from `gnus.texinfo' is installed, you can
+read an appropriate Info node of the Info file according to the
+current major mode of GNUS by \\[gnus-Info-find-node].
+
+  The variable `gnus-version', `nntp-version', `nnspool-version', and
+`mhspool-version' have the version numbers of this version of gnus.el,
+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
+    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.
+
+ gnus-nntp-service
+    Specifies a NNTP service name. It is usually \"nntp\" or 119.  Nil
+    forces GNUS to use a local news spool if the variable
+    `gnus-nntp-server' is set to the local host name.
+
+ gnus-startup-file
+    Specifies a startup file (.newsrc). If there is a file named
+    `.newsrc-SERVER', it's used instead when talking to SERVER. I
+    recommend you to use the server specific file, if you'd like to
+    talk to many servers.  Especially if you'd like to read your
+    private directory, the name of the file must be
+    `.newsrc-:DIRECTORY'.
+
+ gnus-signature-file
+    Specifies a signature file (.signature). If there is a file named
+    `.signature-DISTRIBUTION', it's used instead when posting an
+    article in DISTRIBUTION. Set the variable to nil to prevent
+    appending the file automatically. If you use an NNTP inews which
+    comes with the NNTP package, you may have to set the variable to
+    nil.
+
+ gnus-use-cross-reference
+    Specifies what to do with cross references (Xref: field).  If it
+    is nil, cross references are ignored.  If it is t, articles in
+    subscribed newsgroups are only marked as read.  Otherwise, if it
+    is not nil nor t, articles in all newsgroups are marked as read.
+
+ gnus-use-followup-to
+    Specifies what to do with followup-to: field.  If it is nil, its
+    value is ignored.  If it is non-nil, its value is used as followup
+    newsgroups.  Especially, if it is t and field value is `poster',
+    your confirmation is required.
+
+ gnus-author-copy
+    Specifies a file name to save a copy of article you posted using
+    FCC: field.  If the first character of the value is `|', the
+    contents of the article is piped out to a program specified by the
+    rest of the value.  The variable is initialized from the
+    AUTHORCOPY environment variable.
+
+ gnus-author-copy-saver
+    Specifies a function to save an author copy.  The function is
+    called with a file name.  The default function `rmail-output'
+    saves in Unix mail format.
+
+ gnus-kill-file-name
+    Use specified file name as a KILL file (default to `KILL').
+
+ gnus-novice-user
+    Non-nil means that you are a novice to USENET.  If non-nil,
+    verbose messages may be displayed or your confirmations may be
+    required.
+
+ gnus-interactive-post
+    Non-nil means that newsgroup, subject and distribution are asked
+    for interactively when posting a new article.
+
+ gnus-use-full-window
+    Non-nil means to take up the entire screen of Emacs.
+
+ gnus-window-configuration
+    Specifies the configuration of Group, Subject, and Article
+    windows.  It is a list of (ACTION (G S A)), where G, S, and A are
+    the relative height of Group, Subject, and Article windows,
+    respectively.  ACTION is `SelectNewsgroup', `ExitNewsgroup',
+    `SelectArticle', or `ExpandSubject'.
+
+ gnus-subscribe-newsgroup-method
+    Specifies a function called with a newsgroup name when new
+    newsgroup is found.  The default definition adds new newsgroup at
+    the beginning of other newsgroups.
+
+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
+    this hook.
+
+ gnus-Startup-hook
+    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.
+
+ gnus-Group-prepare-hook
+    Called with no arguments after a newsgroup list is created in the
+    Newsgroup buffer, if that value is non-nil.
+
+ gnus-Save-newsrc-hook
+    Called with no arguments when saving newsrc file if that value is
+    non-nil.
+
+ gnus-Inews-article-hook
+    Called with no arguments when posting an article if that value is
+    non-nil. This hook is called just before posting an article, while
+    `news-inews-hook' is called before preparing article headers. If
+    you'd like to convert kanji code of the article, this hook is recommended.
+
+ gnus-Suspend-gnus-hook
+    Called with no arguments when suspending (not exiting) GNUS, if
+    that value is non-nil.
+
+ gnus-Exit-gnus-hook
+    Called with no arguments when exiting (not suspending) GNUS, if
+    that value is non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  ;; Gee.  Why don't you upgrade?
+  (cond ((boundp 'mode-line-modified)
+	 (setq mode-line-modified "--- "))
+	((listp (default-value 'mode-line-format))
+	 (setq mode-line-format
+	       (cons "--- " (cdr (default-value 'mode-line-format)))))
+	(t
+	 (setq mode-line-format
+	       "--- GNUS: List of Newsgroups  %[(%m)%]----%3p-%-")))
+  (setq major-mode 'gnus-Group-mode)
+  (setq mode-name "Newsgroup")
+  (setq mode-line-buffer-identification	"GNUS: List of Newsgroups")
+  (setq mode-line-process nil)
+  (use-local-map gnus-Group-mode-map)
+  (buffer-flush-undo (current-buffer))
+  (setq buffer-read-only t)		;Disable modification
+  (run-hooks 'gnus-Group-mode-hook))
+
+;;;###autoload
+(defun gnus (&optional confirm)
+  "Read network news.
+If optional argument CONFIRM is non-nil, ask NNTP server."
+  (interactive "P")
+  (unwind-protect
+      (progn
+	(switch-to-buffer (get-buffer-create gnus-Group-buffer))
+	(gnus-Group-mode)
+	(gnus-start-news-server confirm))
+    (if (not (gnus-server-opened))
+	(gnus-Group-quit)
+      ;; NNTP server is successfully open. 
+      (setq mode-line-process (format " {%s}" gnus-nntp-server))
+      (let ((buffer-read-only nil))
+	(erase-buffer)
+	(gnus-Group-startup-message)
+	(sit-for 0))
+      (run-hooks 'gnus-Startup-hook)
+      (gnus-setup-news-info)
+      (if gnus-novice-user
+	  (gnus-Group-describe-briefly)) ;Show brief help message.
+      (gnus-Group-list-groups nil)
+      )))
+
+(defun gnus-Group-startup-message ()
+  "Insert startup message in current buffer."
+  ;; Insert the message.
+  (insert "
+                   GNUS Version 3.13
+
+         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.
+
+Comments, suggestions, and bug fixes are welcome.
+
+Masanobu UMEDA
+umerin@tc.Nagasaki.GO.JP")
+  ;; And then hack it.
+  ;; 57 is the longest line.
+  (indent-rigidly (point-min) (point-max) (/ (max (- (window-width) 57) 0) 2))
+  (goto-char (point-min))
+  ;; +4 is fuzzy factor.
+  (insert-char ?\n (/ (max (- (window-height) 18) 0) 2)))
+
+(defun gnus-Group-list-groups (show-all)
+  "List newsgroups in the Newsgroup buffer.
+If argument SHOW-ALL is non-nil, unsubscribed groups are also listed."
+  (interactive "P")
+  (let ((last-group			;Current newsgroup.
+	 (gnus-Group-group-name))
+	(next-group			;Next possible newsgroup.
+	 (progn
+	   (gnus-Group-search-forward nil nil)
+	   (gnus-Group-group-name)))
+	(prev-group			;Previous possible newsgroup.
+	 (progn
+	   (gnus-Group-search-forward t nil)
+	   (gnus-Group-group-name))))
+    (gnus-Group-prepare show-all)
+    (if (zerop (buffer-size))
+	(message "No news is good news")
+      ;; Go to last newsgroup if possible.  If cannot, try next and
+      ;; previous.  If all fail, go to first unread newsgroup.
+      (goto-char (point-min))
+      (or (and last-group
+	       (re-search-forward
+		(concat "^.+: " (regexp-quote last-group) "$") nil t))
+	  (and next-group
+	       (re-search-forward
+		(concat "^.+: " (regexp-quote next-group) "$") nil t))
+	  (and prev-group
+	       (re-search-forward
+		(concat "^.+: " (regexp-quote prev-group) "$") nil t))
+	  (re-search-forward "^[ \t]+[1-9][0-9]*:" nil t))
+      ;; Adjust cursor point.
+      (beginning-of-line)
+      (search-forward ":" nil t)
+      )))
+
+(defun gnus-Group-prepare (&optional all)
+  "Prepare list of newsgroups in current buffer.
+If optional argument ALL is non-nil, unsubscribed groups are also listed."
+  (let ((buffer-read-only nil)
+	(newsrc gnus-newsrc-assoc)
+	(group-info nil)
+	(group-name nil)
+	(unread-count 0)
+	;; This specifies the format of Group buffer.
+	(cntl "%s%s%5d: %s\n"))
+    (erase-buffer)
+    ;; List newsgroups.
+    (while newsrc
+      (setq group-info (car newsrc))
+      (setq group-name (car group-info))
+      (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
+		   ;; Subscribed or not.
+		   (if (nth 1 group-info) " " "U")
+		   ;; Has new news?
+		   (if (and (> unread-count 0)
+			    (>= 0
+				(- unread-count
+				   (length
+				    (cdr (assoc group-name
+						gnus-marked-assoc))))))
+		       "*" " ")
+		   ;; Number of unread articles.
+		   unread-count
+		   ;; Newsgroup name.
+		   group-name))
+	)
+      (setq newsrc (cdr newsrc))
+      )
+    (setq gnus-have-all-newsgroups all)
+    (goto-char (point-min))
+    (run-hooks 'gnus-Group-prepare-hook)
+    ))
+
+(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."
+  (let* ((group-name (car info))
+	 (unread-count
+	  (or (nth 1 (gnus-gethash group-name gnus-unread-hashtb))
+	      ;; Not in hash table, so compute it now.
+	      (gnus-number-of-articles
+	       (gnus-difference-of-range
+		(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
+	    ;; Subscribed or not.
+	    (if (nth 1 info) " " "U")
+	    ;; Has new news?
+	    (if (and (> unread-count 0)
+		     (>= 0
+			 (- unread-count
+			    (length
+			     (cdr (assoc group-name gnus-marked-assoc))))))
+		"*" " ")
+	    ;; Number of unread articles.
+	    unread-count
+	    ;; Newsgroup name.
+	    group-name
+	    )))
+
+(defun gnus-Group-update-group (group &optional visible-only)
+  "Update newsgroup info of GROUP.
+If optional argument VISIBLE-ONLY is non-nil, non displayed group is ignored."
+  (let ((buffer-read-only nil)
+	(visible nil))
+    ;; Buffer may be narrowed.
+    (save-restriction
+      (widen)
+      ;; Search point to modify.
+      (goto-char (point-min))
+      (if (re-search-forward (concat "^.+: " (regexp-quote group) "$") nil t)
+	  ;; GROUP is listed in current buffer. So, delete old line.
+	  (progn
+	    (setq visible t)
+	    (beginning-of-line)
+	    (delete-region (point) (progn (forward-line 1) (point)))
+	    ))
+      (if (or visible (not visible-only))
+	  (progn
+	    (insert (gnus-Group-prepare-line (assoc group gnus-newsrc-assoc)))
+	    (forward-line -1)		;Move point on that line.
+	    ))
+      )))
+
+;; GNUS Group mode command
+
+(defun gnus-Group-group-name ()
+  "Get newsgroup name around point."
+  (save-excursion
+    (beginning-of-line)
+    (if (looking-at ".[* \t]*[0-9]+:[ \t]+\\([^ \t\n]+\\)$")
+	(buffer-substring (match-beginning 1) (match-end 1))
+      )))
+
+(defun gnus-Group-read-group (all &optional no-article)
+  "Read news in this newsgroup.
+If argument ALL is non-nil, already read articles become readable.
+If optional argument NO-ARTICLE is non-nil, no article body is displayed."
+  (interactive "P")
+  (let ((group (gnus-Group-group-name))) ;Newsgroup name to read.
+    (if group
+	(gnus-Subject-read-group
+	 group
+	 (or all
+	     ;;(not (nth 1 (assoc group gnus-newsrc-assoc)))	;Unsubscribed
+	     (zerop
+	      (nth 1 (gnus-gethash group gnus-unread-hashtb))))	;No unread
+	 no-article
+	 ))
+    ))
+
+(defun gnus-Group-select-group (all)
+  "Select this newsgroup.
+No article is selected automatically.
+If argument ALL is non-nil, already read articles become readable."
+  (interactive "P")
+  (gnus-Group-read-group all t))
+
+(defun gnus-Group-jump-to-group (group)
+  "Jump to newsgroup GROUP."
+  (interactive
+   (list (completing-read "Newsgroup: " gnus-newsrc-assoc nil 'require-match)))
+  (goto-char (point-min))
+  (or (re-search-forward (concat "^.+: " (regexp-quote group) "$") nil t)
+      (if (assoc group gnus-newsrc-assoc)
+	  ;; Add GROUP entry, then seach again.
+	  (gnus-Group-update-group group)))
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t))
+
+(defun gnus-Group-search-forward (backward any-group)
+  "Search for newsgroup forward.
+If first argument BACKWARD is non-nil, search backward instead.
+If second argument ANY-GROUP is non-nil, unsubscribed or empty
+group may be selected."
+  (let ((func (if backward 're-search-backward 're-search-forward))
+	(regexp 
+	 (format "^%s[ \t]*\\(%s\\):"
+		 (if any-group ".." " [ \t]")
+		 (if any-group "[0-9]+" "[1-9][0-9]*")))
+	(found nil))
+    (if backward
+	(beginning-of-line)
+      (end-of-line))
+    (setq found (funcall func regexp nil t))
+    ;; Adjust cursor point.
+    (beginning-of-line)
+    (search-forward ":" nil t)
+    ;; Return T if found.
+    found
+    ))
+
+(defun gnus-Group-next-group (n)
+  "Go to next N'th newsgroup."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Group-search-forward nil t))
+    (setq n (1- n)))
+  (or (gnus-Group-search-forward nil t)
+      (message "No more newsgroups")))
+
+(defun gnus-Group-next-unread-group (n)
+  "Go to next N'th unread newsgroup."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Group-search-forward nil nil))
+    (setq n (1- n)))
+  (or (gnus-Group-search-forward nil nil)
+      (message "No more unread newsgroups")))
+
+(defun gnus-Group-prev-group (n)
+  "Go to previous N'th newsgroup."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Group-search-forward t t))
+    (setq n (1- n)))
+  (or (gnus-Group-search-forward t t)
+      (message "No more newsgroups")))
+
+(defun gnus-Group-prev-unread-group (n)
+  "Go to previous N'th unread newsgroup."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Group-search-forward t nil))	      
+    (setq n (1- n)))
+  (or (gnus-Group-search-forward t nil)
+      (message "No more unread newsgroups")))
+
+(defun gnus-Group-catch-up (all &optional quietly)
+  "Mark all articles not marked as unread in current newsgroup as read.
+If prefix argument ALL is non-nil, all articles are marked as read.
+Cross references (Xref: field) of articles are ignored."
+  (interactive "P")
+  (let* ((group (gnus-Group-group-name))
+         (marked (if (not all)
+		     (cdr (assoc group gnus-marked-assoc)))))
+    (and group
+	 (or quietly
+	     (y-or-n-p
+	      (if all
+		  "Do you really want to mark everything as read? "
+		"Delete all articles not marked as read? ")))
+	 (progn
+	   (message "")			;Erase "Yes or No" question.
+	   ;; Any marked articles will be preserved.
+	   (gnus-update-unread-articles group marked marked)
+	   (gnus-Group-update-group group)
+	   (gnus-Group-next-group 1)))
+    ))
+
+(defun gnus-Group-catch-up-all (&optional quietly)
+  "Mark all articles in current newsgroup as read.
+Cross references (Xref: field) of articles are ignored."
+  (interactive)
+  (gnus-Group-catch-up t quietly))
+
+(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))
+
+(defun gnus-Group-unsubscribe-group (group)
+  "Toggle subscribe from/to unsubscribe GROUP.
+New newsgroup is added to .newsrc automatically."
+  (interactive
+   (list (completing-read "Newsgroup: "
+			  gnus-active-hashtb nil 'require-match)))
+  (let ((newsrc (assoc group gnus-newsrc-assoc)))
+    (cond ((not (null newsrc))
+	   ;; Toggle subscription flag.
+	   (setcar (nthcdr 1 newsrc) (not (nth 1 newsrc)))
+	   (gnus-update-newsrc-buffer group)
+	   (gnus-Group-update-group group)
+	   ;; Adjust cursor point.
+	   (beginning-of-line)
+	   (search-forward ":" nil t))
+	  ((and (stringp group)
+		(gnus-gethash group gnus-active-hashtb))
+	   ;; Add new newsgroup.
+	   (gnus-add-newsgroup group)
+	   (gnus-Group-update-group group)
+	   ;; Adjust cursor point.
+	   (beginning-of-line)
+	   (search-forward ":" nil t))
+	  (t (error "No such newsgroup: %s" group)))
+    ))
+
+(defun gnus-Group-list-all-groups ()
+  "List all of newsgroups in the Newsgroup buffer."
+  (interactive)
+  (gnus-Group-list-groups t))
+
+(defun gnus-Group-get-new-news ()
+  "Get newly arrived articles.  In fact, read the active file again."
+  (interactive)
+  (gnus-setup-news-info)
+  (gnus-Group-list-groups gnus-have-all-newsgroups))
+
+(defun gnus-Group-restart ()
+  "Force GNUS to read the raw startup file."
+  (interactive)
+  (gnus-save-newsrc-file)
+  (gnus-setup-news-info t)		;Force to read the raw startup file.
+  (gnus-Group-list-groups gnus-have-all-newsgroups))
+
+(defun gnus-Group-check-bogus-groups ()
+  "Check bogus newsgroups."
+  (interactive)
+  (gnus-check-bogus-newsgroups t)	;Require confirmation.
+  (gnus-Group-list-groups gnus-have-all-newsgroups))
+
+(defun gnus-Group-restrict-groups (start end)
+  "Restrict visible newsgroups to the current region (START and END).
+Type \\[widen] to remove restriction."
+  (interactive "r")
+  (save-excursion
+    (narrow-to-region (progn
+			(goto-char start)
+			(beginning-of-line)
+			(point))
+		      (progn
+			(goto-char end)
+			(forward-line 1)
+			(point))))
+  (message (substitute-command-keys "Type \\[widen] to remove restriction")))
+
+(defun gnus-Group-edit-global-kill ()
+  "Edit a global KILL file."
+  (interactive)
+  (setq gnus-current-kill-article nil)	;No articles selected.
+  (gnus-Kill-file-edit-file nil) 	;Nil stands for global KILL file.
+  (message
+   (substitute-command-keys
+    "Editing a global KILL file (Type \\[gnus-Kill-file-exit] to exit)")))
+
+(defun gnus-Group-edit-local-kill ()
+  "Edit a local KILL file."
+  (interactive)
+  (setq gnus-current-kill-article nil)	;No articles selected.
+  (gnus-Kill-file-edit-file (gnus-Group-group-name))
+  (message
+   (substitute-command-keys
+    "Editing a local KILL file (Type \\[gnus-Kill-file-exit] to exit)")))
+
+(defun gnus-Group-force-update ()
+  "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."
+  (interactive)
+  (run-hooks 'gnus-Suspend-gnus-hook)
+  ;; Kill GNUS buffers except for Group Mode buffer.
+  (let ((buffers gnus-buffer-list))
+    (while buffers
+      (and (not (eq (car buffers) gnus-Group-buffer))
+	   (get-buffer (car buffers))
+	   (kill-buffer (car buffers)))
+      (setq buffers (cdr buffers))
+      ))
+  (bury-buffer))
+
+(defun gnus-Group-exit ()
+  "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.
+	  (not (gnus-server-opened))	;NNTP connection closed.
+	  (y-or-n-p "Are you sure you want to quit reading news? "))
+      (progn
+	(message "")			;Erase "Yes or No" question.
+	(run-hooks 'gnus-Exit-gnus-hook)
+	(gnus-save-newsrc-file)
+	(gnus-clear-system)
+	(gnus-close-server))
+    ))
+
+(defun gnus-Group-quit ()
+  "Quit reading news without updating .newsrc.
+The hook `gnus-Exit-gnus-hook' is called before actually quitting."
+  (interactive)
+  (if (or (zerop (buffer-size))
+	  (not (gnus-server-opened))
+	  (yes-or-no-p
+	   (format "Quit reading news without saving %s? "
+		   (file-name-nondirectory gnus-current-startup-file))))
+      (progn
+	(message "")			;Erase "Yes or No" question.
+	(run-hooks 'gnus-Exit-gnus-hook)
+	(gnus-clear-system)
+	(gnus-close-server))
+    ))
+
+(defun gnus-Group-describe-briefly ()
+  "Describe Group mode commands briefly."
+  (interactive)
+  (message
+   (concat
+    (substitute-command-keys "\\[gnus-Group-read-group]:Select  ")
+    (substitute-command-keys "\\[gnus-Group-next-unread-group]:Forward  ")
+    (substitute-command-keys "\\[gnus-Group-prev-unread-group]:Backward  ")
+    (substitute-command-keys "\\[gnus-Group-exit]:Exit  ")
+    (substitute-command-keys "\\[gnus-Info-find-node]:Run Info  ")
+    (substitute-command-keys "\\[gnus-Group-describe-briefly]:This help")
+    )))
+
+
+;;;
+;;; GNUS Subject Mode
+;;;
+
+(if gnus-Subject-mode-map
+    nil
+  (setq gnus-Subject-mode-map (make-keymap))
+  (suppress-keymap gnus-Subject-mode-map)
+  (define-key gnus-Subject-mode-map " " 'gnus-Subject-next-page)
+  (define-key gnus-Subject-mode-map "\177" 'gnus-Subject-prev-page)
+  (define-key gnus-Subject-mode-map "\r" 'gnus-Subject-scroll-up)
+  (define-key gnus-Subject-mode-map "n" 'gnus-Subject-next-unread-article)
+  (define-key gnus-Subject-mode-map "p" 'gnus-Subject-prev-unread-article)
+  (define-key gnus-Subject-mode-map "N" 'gnus-Subject-next-article)
+  (define-key gnus-Subject-mode-map "P" 'gnus-Subject-prev-article)
+  (define-key gnus-Subject-mode-map "\e\C-n" 'gnus-Subject-next-same-subject)
+  (define-key gnus-Subject-mode-map "\e\C-p" 'gnus-Subject-prev-same-subject)
+  ;;(define-key gnus-Subject-mode-map "\e\C-n" 'gnus-Subject-next-unread-same-subject)
+  ;;(define-key gnus-Subject-mode-map "\e\C-p" 'gnus-Subject-prev-unread-same-subject)
+  (define-key gnus-Subject-mode-map "\C-c\C-n" 'gnus-Subject-next-digest)
+  (define-key gnus-Subject-mode-map "\C-c\C-p" 'gnus-Subject-prev-digest)
+  (define-key gnus-Subject-mode-map "\C-n" 'gnus-Subject-next-subject)
+  (define-key gnus-Subject-mode-map "\C-p" 'gnus-Subject-prev-subject)
+  (define-key gnus-Subject-mode-map "\en" 'gnus-Subject-next-unread-subject)
+  (define-key gnus-Subject-mode-map "\ep" 'gnus-Subject-prev-unread-subject)
+  ;;(define-key gnus-Subject-mode-map "\C-cn" 'gnus-Subject-next-group)
+  ;;(define-key gnus-Subject-mode-map "\C-cp" 'gnus-Subject-prev-group)
+  (define-key gnus-Subject-mode-map "." 'gnus-Subject-first-unread-article)
+  (define-key gnus-Subject-mode-map "/" 'isearch-forward)
+  (define-key gnus-Subject-mode-map "s" 'gnus-Subject-isearch-article)
+  (define-key gnus-Subject-mode-map "\es" 'gnus-Subject-search-article-forward)
+  (define-key gnus-Subject-mode-map "\eS" 'gnus-Subject-search-article-backward)
+  (define-key gnus-Subject-mode-map "<" 'gnus-Subject-beginning-of-article)
+  (define-key gnus-Subject-mode-map ">" 'gnus-Subject-end-of-article)
+  (define-key gnus-Subject-mode-map "j" 'gnus-Subject-goto-subject)
+  (define-key gnus-Subject-mode-map "J" 'gnus-Subject-goto-article)
+  (define-key gnus-Subject-mode-map "l" 'gnus-Subject-goto-last-article)
+  (define-key gnus-Subject-mode-map "^" 'gnus-Subject-refer-parent-article)
+  (define-key gnus-Subject-mode-map "\er" 'gnus-Subject-refer-article)
+  (define-key gnus-Subject-mode-map "u" 'gnus-Subject-mark-as-unread-forward)
+  (define-key gnus-Subject-mode-map "U" 'gnus-Subject-mark-as-unread-backward)
+  (define-key gnus-Subject-mode-map "d" 'gnus-Subject-mark-as-read-forward)
+  (define-key gnus-Subject-mode-map "D" 'gnus-Subject-mark-as-read-backward)
+  (define-key gnus-Subject-mode-map "\eu" 'gnus-Subject-clear-mark-forward)
+  (define-key gnus-Subject-mode-map "\eU" 'gnus-Subject-clear-mark-backward)
+  (define-key gnus-Subject-mode-map "k" 'gnus-Subject-kill-same-subject-and-select)
+  (define-key gnus-Subject-mode-map "\C-k" 'gnus-Subject-kill-same-subject)
+  (define-key gnus-Subject-mode-map "\e\C-t" 'gnus-Subject-toggle-threads)
+  (define-key gnus-Subject-mode-map "\e\C-s" 'gnus-Subject-show-thread)
+  (define-key gnus-Subject-mode-map "\e\C-h" 'gnus-Subject-hide-thread)
+  (define-key gnus-Subject-mode-map "\e\C-f" 'gnus-Subject-next-thread)
+  (define-key gnus-Subject-mode-map "\e\C-b" 'gnus-Subject-prev-thread)
+  (define-key gnus-Subject-mode-map "\e\C-u" 'gnus-Subject-up-thread)
+  (define-key gnus-Subject-mode-map "\e\C-d" 'gnus-Subject-down-thread)
+  (define-key gnus-Subject-mode-map "\e\C-k" 'gnus-Subject-kill-thread)
+  (define-key gnus-Subject-mode-map "&" 'gnus-Subject-execute-command)
+  ;;(define-key gnus-Subject-mode-map "c" 'gnus-Subject-catch-up)
+  ;;(define-key gnus-Subject-mode-map "c" 'gnus-Subject-catch-up-all)
+  (define-key gnus-Subject-mode-map "c" 'gnus-Subject-catch-up-and-exit)
+  ;;(define-key gnus-Subject-mode-map "c" 'gnus-Subject-catch-up-all-and-exit)
+  (define-key gnus-Subject-mode-map "\C-t" 'gnus-Subject-toggle-truncation)
+  (define-key gnus-Subject-mode-map "x" 'gnus-Subject-delete-marked-as-read)
+  (define-key gnus-Subject-mode-map "X" 'gnus-Subject-delete-marked-with)
+  (define-key gnus-Subject-mode-map "\C-c\C-sn" 'gnus-Subject-sort-by-number)
+  (define-key gnus-Subject-mode-map "\C-c\C-sa" 'gnus-Subject-sort-by-author)
+  (define-key gnus-Subject-mode-map "\C-c\C-ss" 'gnus-Subject-sort-by-subject)
+  (define-key gnus-Subject-mode-map "\C-c\C-sd" 'gnus-Subject-sort-by-date)
+  (define-key gnus-Subject-mode-map "\C-c\C-s\C-n" 'gnus-Subject-sort-by-number)
+  (define-key gnus-Subject-mode-map "\C-c\C-s\C-a" 'gnus-Subject-sort-by-author)
+  (define-key gnus-Subject-mode-map "\C-c\C-s\C-s" 'gnus-Subject-sort-by-subject)
+  (define-key gnus-Subject-mode-map "\C-c\C-s\C-d" 'gnus-Subject-sort-by-date)
+  (define-key gnus-Subject-mode-map "=" 'gnus-Subject-expand-window)
+  (define-key gnus-Subject-mode-map "G" 'gnus-Subject-reselect-current-group)
+  (define-key gnus-Subject-mode-map "w" 'gnus-Subject-stop-page-breaking)
+  (define-key gnus-Subject-mode-map "\C-c\C-r" 'gnus-Subject-caesar-message)
+  (define-key gnus-Subject-mode-map "g" 'gnus-Subject-show-article)
+  (define-key gnus-Subject-mode-map "t" 'gnus-Subject-toggle-header)
+  (define-key gnus-Subject-mode-map "v" 'gnus-Subject-show-all-headers)
+  (define-key gnus-Subject-mode-map "\C-d" 'gnus-Subject-rmail-digest)
+  (define-key gnus-Subject-mode-map "a" 'gnus-Subject-post-news)
+  (define-key gnus-Subject-mode-map "f" 'gnus-Subject-post-reply)
+  (define-key gnus-Subject-mode-map "F" 'gnus-Subject-post-reply-with-original)
+  (define-key gnus-Subject-mode-map "C" 'gnus-Subject-cancel-article)
+  (define-key gnus-Subject-mode-map "r" 'gnus-Subject-mail-reply)
+  (define-key gnus-Subject-mode-map "R" 'gnus-Subject-mail-reply-with-original)
+  (define-key gnus-Subject-mode-map "m" 'gnus-Subject-mail-other-window)
+  (define-key gnus-Subject-mode-map "o" 'gnus-Subject-save-article)
+  (define-key gnus-Subject-mode-map "\C-o" 'gnus-Subject-save-in-mail)
+  (define-key gnus-Subject-mode-map "|" 'gnus-Subject-pipe-output)
+  (define-key gnus-Subject-mode-map "\ek" 'gnus-Subject-edit-local-kill)
+  (define-key gnus-Subject-mode-map "\eK" 'gnus-Subject-edit-global-kill)
+  (define-key gnus-Subject-mode-map "V" 'gnus-version)
+  (define-key gnus-Subject-mode-map "q" 'gnus-Subject-exit)
+  (define-key gnus-Subject-mode-map "Q" 'gnus-Subject-quit)
+  (define-key gnus-Subject-mode-map "?" 'gnus-Subject-describe-briefly)
+  (define-key gnus-Subject-mode-map "\C-c\C-i" 'gnus-Info-find-node))
+
+(defun gnus-Subject-mode ()
+  "Major mode for reading articles in this newsgroup.
+All normal editing commands are turned off.
+Instead, these commands are available:
+\\{gnus-Subject-mode-map}
+
+User customizable variables:
+ gnus-large-newsgroup
+    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
+    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
+    newsgroup is used instead.
+
+ gnus-default-article-saver
+    Specifies your favorite article saver which is interactively
+    funcallable.  Following functions are available:
+
+	gnus-Subject-save-in-rmail (in Rmail format)
+	gnus-Subject-save-in-mail (in Unix mail format)
+	gnus-Subject-save-in-folder (in MH folder)
+	gnus-Subject-save-in-file (in article format).
+
+ gnus-rmail-save-name
+ gnus-mail-save-name
+ gnus-folder-save-name
+ gnus-file-save-name
+    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'.
+
+ gnus-article-save-directory
+    Specifies a directory name to save articles to using the commands
+    `gnus-Subject-save-in-rmail', `gnus-Subject-save-in-mail' and
+    `gnus-Subject-save-in-file'.  The variable is initialized from the
+    SAVEDIR environment variable.
+
+ gnus-show-all-headers
+    Non-nil means that all headers of an article are shown.
+
+ gnus-save-all-headers
+    Non-nil means that all headers of an article are saved in a file.
+
+ gnus-show-threads
+    Non-nil means that conversation threads are shown in tree structure.
+
+ gnus-thread-hide-subject
+    Non-nil means that subjects for thread subtrees are hidden.
+
+ gnus-thread-hide-subtree
+    Non-nil means that thread subtrees are hidden initially.
+
+ gnus-thread-hide-killed
+    Non-nil means that killed thread subtrees are hidden automatically.
+
+ gnus-thread-ignore-subject
+    Non-nil means that subject differences are ignored in constructing
+    thread trees.
+
+ gnus-thread-indent-level
+    Indentation of thread subtrees.
+
+ gnus-optional-headers
+    Specifies a function which generates an optional string displayed
+    in the Subject 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
+    author.
+
+ gnus-auto-extend-newsgroup
+    Non-nil means visible articles are extended to forward and
+    backward automatically if possible.
+
+ 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).
+    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-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
+    empty (no unread articles), GNUS will exit Subject mode and go
+    back to Group mode. If the value is neither nil nor t, GNUS won't
+    exit Subject 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.
+
+ gnus-auto-select-same
+    Non-nil means an article with the same subject as the current
+    article is selected automagically like `rn -S'.
+
+ gnus-auto-center-subject
+    Non-nil means the point of Subject Mode window is always kept
+    centered.
+
+ gnus-break-pages
+    Non-nil means an article is broken into pages at page delimiters.
+    This may not work with some versions of GNU Emacs earlier than
+    version 18.50.
+
+ gnus-page-delimiter
+    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-Subject-rmail-digest' command.
+
+ gnus-digest-separator
+    Specifies a regexp separating messages in a digest article.
+
+ gnus-mail-reply-method
+ gnus-mail-other-window-method
+    Specifies a function to begin composing mail message using
+    commands gnus-Subject-mail-reply and
+    gnus-Subject-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.
+
+Various hooks for customization:
+ gnus-Subject-mode-hook
+    Entry to this mode calls the value with no arguments, if that
+    value is non-nil.
+
+ 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
+    documentation of this variable for more information.
+
+ gnus-Subject-prepare-hook
+    Called with no arguments after a subject list is created in the
+    Subject 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 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
+    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
+    mode.
+
+ gnus-Apply-kill-hook
+    Called with no arguments when a newsgroup is selected and the
+    Subject 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)
+    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
+    from Subject mode takes very long time, inhibit marking articles
+    as read using cross-references by setting the variable
+    `gnus-newsgroup-headers' to nil in this hook."
+  (interactive)
+  (kill-all-local-variables)
+  ;; Gee.  Why don't you upgrade?
+  (cond ((boundp 'mode-line-modified)
+	 (setq mode-line-modified "--- "))
+	((listp (default-value 'mode-line-format))
+	 (setq mode-line-format
+	       (cons "--- " (cdr (default-value 'mode-line-format))))))
+  (make-local-variable 'global-mode-string)
+  (setq global-mode-string nil)
+  (setq major-mode 'gnus-Subject-mode)
+  (setq mode-name "Subject")
+  ;;(setq mode-line-process '(" " gnus-newsgroup-name))
+  (make-local-variable 'minor-mode-alist)
+  (or (assq 'gnus-show-threads minor-mode-alist)
+      (setq minor-mode-alist
+	    (cons (list 'gnus-show-threads " Thread") minor-mode-alist)))
+  (gnus-Subject-set-mode-line)
+  (use-local-map gnus-Subject-mode-map)
+  (buffer-flush-undo (current-buffer))
+  (setq buffer-read-only t)		;Disable modification
+  (setq truncate-lines t)		;Stop line folding
+  (setq selective-display t)
+  (setq selective-display-ellipses t)	;Display `...'
+  ;;(setq case-fold-search t)
+  (run-hooks 'gnus-Subject-mode-hook))
+
+(defun gnus-Subject-setup-buffer ()
+  "Initialize subject display buffer."
+  (if (get-buffer gnus-Subject-buffer)
+      (set-buffer gnus-Subject-buffer)
+    (set-buffer (get-buffer-create gnus-Subject-buffer))
+    (gnus-Subject-mode)
+    ))
+
+(defun gnus-Subject-read-group (group &optional show-all no-article)
+  "Start reading news in newsgroup GROUP.
+If optional first argument SHOW-ALL is non-nil, already read articles are
+also listed.
+If optional second argument NO-ARTICLE is non-nil, no article is selected
+initially."
+  (message "Retrieving newsgroup: %s..." group)
+  (if (gnus-select-newsgroup group show-all)
+      (progn
+	;; Don't switch-to-buffer to prevent displaying old contents
+	;;  of the buffer until new subjects list is created.
+	;; Suggested by Juha Heinanen <jh@tut.fi>
+	(gnus-Subject-setup-buffer)
+	;; You can change the order of subjects in this hook.
+	(run-hooks 'gnus-Select-group-hook)
+	(gnus-Subject-prepare)
+	;; Function `gnus-apply-kill-file' must be called in this hook.
+	(run-hooks 'gnus-Apply-kill-hook)
+	(if (zerop (buffer-size))
+	    ;; This newsgroup is empty.
+	    (progn
+	      (gnus-Subject-catch-up-and-exit nil t) ;Without confirmations.
+	      (message "No unread news"))
+	  ;; Hide conversation thread subtrees.  We cannot do this in
+	  ;; gnus-Subject-prepare-hook since kill processing may not
+	  ;; work with hidden articles.
+	  (and gnus-show-threads
+	       gnus-thread-hide-subtree
+	       (gnus-Subject-hide-all-threads))
+	  ;; Show first unread article if requested.
+	  (goto-char (point-min))
+	  (if (and (not no-article)
+		   gnus-auto-select-first
+		   (gnus-Subject-first-unread-article))
+	      ;; Window is configured automatically.
+	      ;; Current buffer may be changed as a result of hook
+	      ;; evaluation, especially by gnus-Subject-rmail-digest
+	      ;; command, so we should adjust cursor point carefully.
+	      (if (eq (current-buffer) (get-buffer gnus-Subject-buffer))
+		  (progn
+		    ;; Adjust cursor point.
+		    (beginning-of-line)
+		    (search-forward ":" nil t)))
+	    (gnus-configure-windows 'SelectNewsgroup)
+	    (pop-to-buffer gnus-Subject-buffer)
+	    (gnus-Subject-set-mode-line)
+	    ;; I sometime get confused with the old Article buffer.
+	    (if (get-buffer gnus-Article-buffer)
+		(if (get-buffer-window gnus-Article-buffer)
+		    (save-excursion
+		      (set-buffer gnus-Article-buffer)
+		      (let ((buffer-read-only nil))
+			(erase-buffer)))
+		  (kill-buffer gnus-Article-buffer)))
+	    ;; Adjust cursor point.
+	    (beginning-of-line)
+	    (search-forward ":" nil t))
+	  ))
+    ;; Cannot select newsgroup GROUP.
+    (if (gnus-gethash group gnus-active-hashtb)
+	(progn
+	  ;; If NNTP is used, nntp_access file may not be installed
+	  ;; properly.  Otherwise, may be active file problem.
+	  (ding)
+	  (message "Cannot select %s.  May be security or active file problem." group)
+	  (sit-for 0))
+      ;; Check bogus newsgroups.
+      ;; We must be in Group Mode buffer.
+      (gnus-Group-check-bogus-groups))
+    ))
+
+(defun gnus-Subject-prepare ()
+  "Prepare subject list of current newsgroup in Subject mode buffer."
+  (let ((buffer-read-only nil))
+    ;; Note: The next codes are not actually used because the user who
+    ;; want it can define them in gnus-Select-group-hook.
+    ;; Print verbose messages if too many articles are selected.
+    ;;    (and (numberp gnus-large-newsgroup)
+    ;;       (> (length gnus-newsgroup-headers) gnus-large-newsgroup)
+    ;;       (message "Preparing headers..."))
+    (erase-buffer)
+    (gnus-Subject-prepare-threads
+     (if gnus-show-threads
+	 (gnus-make-threads gnus-newsgroup-headers)
+       gnus-newsgroup-headers) 0)
+    ;; Erase header retrieval message.
+    (message "")
+    ;; Call hooks for modifying Subject mode buffer.
+    ;; Suggested by sven@tde.LTH.Se (Sven Mattisson).
+    (goto-char (point-min))
+    (run-hooks 'gnus-Subject-prepare-hook)
+    ))
+
+;; Basic ideas by Paul Dworkin <paul@media-lab.media.mit.edu>
+
+(defun gnus-Subject-prepare-threads (threads level)
+  "Prepare Subject buffer from THREADS and indentation LEVEL.
+THREADS is a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...]).'"
+  (let ((thread nil)
+	(header nil)
+	(number nil)
+	;; `M Indent NUM: [OPT] SUBJECT'
+	(cntl (format "%%s %%s%%%dd: [%%s] %%s\n"
+		      (length (prin1-to-string gnus-newsgroup-end)))))
+    (while threads
+      (setq thread (car threads))
+      (setq threads (cdr threads))
+      ;; If thread is a cons, hierarchical threads is given.
+      ;; Otherwise, thread itself is header.
+      (if (consp thread)
+	  (setq header (car thread))
+	(setq header thread))
+      ;; Print valid header only.
+      (if (vectorp header)		;Depends on nntp.el.
+	  (progn
+	    (setq number (nntp-header-number header))
+	    (insert
+	     (format cntl
+		     ;; Read or not.
+		     (cond ((memq number gnus-newsgroup-marked)  "-")
+			   ((memq number gnus-newsgroup-unreads) " ")
+			   (t "D"))
+		     ;; Thread level.
+		     (make-string (* level gnus-thread-indent-level) ? )
+		     ;; Article number.
+		     number
+		     ;; Optional headers.
+		     (or (and gnus-optional-headers
+			      (funcall gnus-optional-headers header)) "")
+		     ;; Its subject string.
+		     (concat (if (or (zerop level)
+				     (not gnus-thread-hide-subject))
+				 nil
+			       (make-string (window-width) ? ))
+			     (nntp-header-subject header))
+		     ))
+	    ))
+      ;; Print subthreads.
+      (and (consp thread)
+	   (cdr thread)
+	   (gnus-Subject-prepare-threads (cdr thread) (1+ level)))
+      )))
+
+(defun gnus-Subject-set-mode-line ()
+  "Set Subject mode line string."
+  ;; The value must be a string to escape %-constructs.
+  (let ((subject
+	 (if gnus-current-headers
+	     (nntp-header-subject gnus-current-headers) gnus-newsgroup-name)))
+    (setq mode-line-buffer-identification
+	  (concat "GNUS: "
+		  subject
+		  ;; Enough spaces to pad subject to 17 positions.
+		  (make-string (max 0 (- 17 (length subject))) ? ))))
+  (set-buffer-modified-p t))
+
+;; GNUS Subject mode command.
+
+(defun gnus-Subject-search-group (&optional backward)
+  "Search for next unread newsgroup.
+If optional argument BACKWARD is non-nil, search backward instead."
+  (save-excursion
+    (set-buffer gnus-Group-buffer)
+    (save-excursion
+      ;; We don't want to alter current point of Group mode buffer.
+      (if (gnus-Group-search-forward backward nil)
+	  (gnus-Group-group-name))
+      )))
+
+(defun gnus-Subject-search-subject (backward unread subject)
+  "Search for article forward.
+If first argument BACKWARD is non-nil, search backward.
+If second argument UNREAD is non-nil, only unread article is selected.
+If third argument SUBJECT is non-nil, the article which has
+the same subject will be searched for."
+  (let ((func (if backward 're-search-backward 're-search-forward))
+	(article nil)
+	;; We have to take care of hidden lines.
+	(regexp 
+	 (format "^%s[ \t]+\\([0-9]+\\):.\\[[^]\r\n]*\\][ \t]+%s"
+		 ;;(if unread " " ".")
+		 (cond ((eq unread t) " ") (unread "[ ---]") (t "."))
+		 (if subject
+		     (concat "\\([Rr][Ee]:[ \t]+\\)*"
+			     (regexp-quote (gnus-simplify-subject subject))
+			     ;; Ignore words in parentheses.
+			     "\\([ \t]*([^\r\n]*)\\)*[ \t]*\\(\r\\|$\\)")
+		   "")
+		 )))
+    (if backward
+	(beginning-of-line)
+      (end-of-line))
+    (if (funcall func regexp nil t)
+	(setq article
+	      (string-to-int
+	       (buffer-substring (match-beginning 1) (match-end 1)))))
+    ;; Adjust cursor point.
+    (beginning-of-line)
+    (search-forward ":" nil t)
+    ;; This is the result.
+    article
+    ))
+
+(defun gnus-Subject-search-forward (&optional unread subject)
+  "Search for article forward.
+If first optional argument UNREAD is non-nil, only unread article is selected.
+If second optional argument SUBJECT is non-nil, the article which has
+the same subject will be searched for."
+  (gnus-Subject-search-subject nil unread subject))
+
+(defun gnus-Subject-search-backward (&optional unread subject)
+  "Search for article backward.
+If first optional argument UNREAD is non-nil, only unread article is selected.
+If second optional argument SUBJECT is non-nil, the article which has
+the same subject will be searched for."
+  (gnus-Subject-search-subject t unread subject))
+
+(defun gnus-Subject-article-number ()
+  "Article number around point. If nothing, return current number."
+  (save-excursion
+    (beginning-of-line)
+    (if (looking-at ".[ \t]+\\([0-9]+\\):")
+	(string-to-int
+	 (buffer-substring (match-beginning 1) (match-end 1)))
+      ;; If search fail, return current article number.
+      gnus-current-article
+      )))
+
+(defun gnus-Subject-subject-string ()
+  "Return current subject string or nil if nothing."
+  (save-excursion
+    ;; It is possible to implement this function using
+    ;;  `gnus-Subject-article-number' and `gnus-newsgroup-headers'.
+    (beginning-of-line)
+    ;; We have to take care of hidden lines.
+    (if (looking-at ".[ \t]+[0-9]+:.\\[[^]\r\n]*\\][ \t]+\\([^\r\n]*\\)[\r\n]")
+	(buffer-substring (match-beginning 1) (match-end 1)))
+    ))
+
+(defun gnus-Subject-goto-subject (article)
+  "Move point to ARTICLE's subject."
+  (interactive
+   (list
+    (string-to-int
+     (completing-read "Article number: "
+		      (mapcar
+		       (function
+			(lambda (headers)
+			  (list
+			   (int-to-string (nntp-header-number headers)))))
+		       gnus-newsgroup-headers)
+		      nil 'require-match))))
+  (let ((current (point)))
+    (goto-char (point-min))
+    (or (and article (re-search-forward (format "^.[ \t]+%d:" article) nil t))
+	(progn (goto-char current) nil))
+    ))
+
+(defun gnus-Subject-recenter ()
+  "Center point in Subject mode window."
+  ;; Scroll window so as to cursor comes center of Subject mode window
+  ;;  only when article is displayed.
+  ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
+  ;; Recenter only when requested.
+  ;; Suggested by popovich@park.cs.columbia.edu
+  (and gnus-auto-center-subject
+       (get-buffer-window gnus-Article-buffer)
+       (< (/ (- (window-height) 1) 2)
+	  (count-lines (point) (point-max)))
+       (recenter (/ (- (window-height) 2) 2))))
+
+;; Walking around Group mode buffer.
+
+(defun gnus-Subject-jump-to-group (newsgroup)
+  "Move point to NEWSGROUP in Group mode buffer."
+  ;; Keep update point of Group mode buffer if visible.
+  (if (eq (current-buffer)
+	  (get-buffer gnus-Group-buffer))
+      (save-window-excursion
+	;; Take care of tree window mode.
+	(if (get-buffer-window gnus-Group-buffer)
+	    (pop-to-buffer gnus-Group-buffer))
+	(gnus-Group-jump-to-group newsgroup))
+    (save-excursion
+      ;; Take care of tree window mode.
+      (if (get-buffer-window gnus-Group-buffer)
+	  (pop-to-buffer gnus-Group-buffer)
+	(set-buffer gnus-Group-buffer))
+      (gnus-Group-jump-to-group newsgroup))))
+
+(defun gnus-Subject-next-group (no-article)
+  "Exit current newsgroup and then select next unread newsgroup.
+If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
+  (interactive "P")
+  ;; Make sure Group mode buffer point is on current newsgroup.
+  (gnus-Subject-jump-to-group gnus-newsgroup-name)
+  (let ((group (gnus-Subject-search-group)))
+    (if (null group)
+	(progn
+	  (message "Exiting %s..." gnus-newsgroup-name)  
+	  (gnus-Subject-exit)
+	  (message ""))
+      (message "Selecting %s..." group)
+      (gnus-Subject-exit t)		;Exit Subject mode temporary.
+      ;; We are now in Group mode buffer.
+      ;; Make sure Group mode buffer point is on GROUP.
+      (gnus-Subject-jump-to-group group)
+      (gnus-Subject-read-group group nil no-article)
+      (or (eq (current-buffer)
+	      (get-buffer gnus-Subject-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.)
+	  (and (eq (current-buffer)
+		   (get-buffer gnus-Group-buffer))
+	       (gnus-Group-group-name)
+	       (gnus-Subject-read-group
+		(gnus-Group-group-name) nil no-article))
+	  )
+      )))
+
+(defun gnus-Subject-prev-group (no-article)
+  "Exit current newsgroup and then select previous unread newsgroup.
+If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
+  (interactive "P")
+  ;; Make sure Group mode buffer point is on current newsgroup.
+  (gnus-Subject-jump-to-group gnus-newsgroup-name)
+  (let ((group (gnus-Subject-search-group t)))
+    (if (null group)
+	(progn
+	  (message "Exiting %s..." gnus-newsgroup-name)  
+	  (gnus-Subject-exit)
+	  (message ""))
+      (message "Selecting %s..." group)
+      (gnus-Subject-exit t)		;Exit Subject mode temporary.
+      ;; We are now in Group mode buffer.
+      ;; We have to adjust point of Group mode buffer because current
+      ;; point is moved to next unread newsgroup by exiting.
+      (gnus-Subject-jump-to-group group)
+      (gnus-Subject-read-group group nil no-article)
+      (or (eq (current-buffer)
+	      (get-buffer gnus-Subject-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.)
+	  (and (eq (current-buffer)
+		   (get-buffer gnus-Group-buffer))
+	       (gnus-Subject-search-group t)
+	       (gnus-Subject-read-group
+		(gnus-Subject-search-group t) nil no-article))
+	  )
+      )))
+
+;; Walking around subject lines.
+
+(defun gnus-Subject-next-subject (n &optional unread)
+  "Go to next N'th subject line.
+If optional argument UNREAD is non-nil, only unread article is selected."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Subject-search-forward unread))
+    (setq n (1- n)))
+  (cond ((gnus-Subject-search-forward unread)
+	 (gnus-Subject-recenter))
+	(unread
+	 (message "No more unread articles"))
+	(t
+	 (message "No more articles"))
+	))
+
+(defun gnus-Subject-next-unread-subject (n)
+  "Go to next N'th unread subject line."
+  (interactive "p")
+  (gnus-Subject-next-subject n t))
+
+(defun gnus-Subject-prev-subject (n &optional unread)
+  "Go to previous N'th subject line.
+If optional argument UNREAD is non-nil, only unread article is selected."
+  (interactive "p")
+  (while (and (> n 1)
+	      (gnus-Subject-search-backward unread))
+    (setq n (1- n)))
+  (cond ((gnus-Subject-search-backward unread)
+	 (gnus-Subject-recenter))
+	(unread
+	 (message "No more unread articles"))
+	(t
+	 (message "No more articles"))
+	))
+
+(defun gnus-Subject-prev-unread-subject (n)
+  "Go to previous N'th unread subject line."
+  (interactive "p")
+  (gnus-Subject-prev-subject n t))
+
+;; Walking around subject lines with displaying articles.
+
+(defun gnus-Subject-expand-window ()
+  "Expand Subject window to show headers full window."
+  (interactive)
+  (gnus-configure-windows 'ExpandSubject)
+  (pop-to-buffer gnus-Subject-buffer))
+
+(defun gnus-Subject-display-article (article &optional all-header)
+  "Display ARTICLE in Article buffer."
+  (if (null article)
+      nil
+    (gnus-configure-windows 'SelectArticle)
+    (pop-to-buffer gnus-Subject-buffer)
+    (gnus-Article-prepare article all-header)
+    (gnus-Subject-recenter)
+    (gnus-Subject-set-mode-line)
+    (run-hooks 'gnus-Select-article-hook)
+    ;; Successfully display article.
+    t
+    ))
+
+(defun gnus-Subject-select-article (&optional all-headers force)
+  "Select the current article.
+Optional argument ALL-HEADERS is non-nil, show all headers."
+  (let ((article (gnus-Subject-article-number)))
+    (if (or (null gnus-current-article)
+	    (/= article gnus-current-article)
+	    (and force (not (eq all-headers gnus-have-all-headers))))
+	;; The selected subject is different from that of the current article.
+	(gnus-Subject-display-article article all-headers)
+      (gnus-configure-windows 'SelectArticle)
+      (pop-to-buffer gnus-Subject-buffer))
+    ))
+
+(defun gnus-Subject-set-current-mark (&optional current-mark)
+  "Put `+' at the current article.
+Optional argument specifies CURRENT-MARK instead of `+'."
+  (save-excursion
+    (set-buffer gnus-Subject-buffer)
+    (let ((buffer-read-only nil))
+      (goto-char (point-min))
+      ;; First of all clear mark at last article.
+      (if (re-search-forward "^.[ \t]+[0-9]+:[^ \t]" nil t)
+	  (progn
+	    (delete-char -1)
+	    (insert " ")
+	    (goto-char (point-min))))
+      (if (re-search-forward (format "^.[ \t]+%d:" gnus-current-article) nil t)
+	  (progn
+	    (delete-char 1)
+	    (insert (or current-mark "+"))))
+      )))
+
+(defun gnus-Subject-next-article (unread &optional subject)
+  "Select article after current one.
+If argument UNREAD is non-nil, only unread article is selected."
+  (interactive "P")
+  (let ((header nil))
+    (cond ((gnus-Subject-display-article
+	    (gnus-Subject-search-forward unread subject)))
+	  ((and subject
+		gnus-auto-select-same
+		(gnus-set-difference gnus-newsgroup-unreads
+				     gnus-newsgroup-marked)
+		(memq this-command
+		      '(gnus-Subject-next-unread-article
+			gnus-Subject-next-page
+			gnus-Subject-kill-same-subject-and-select
+			;;gnus-Subject-next-article
+			;;gnus-Subject-next-same-subject
+			;;gnus-Subject-next-unread-same-subject
+			)))
+	   ;; Wrap article pointer if there are unread articles.
+	   ;; Hook function, such as gnus-Subject-rmail-digest, may
+	   ;; change current buffer, so need check.
+	   (let ((buffer (current-buffer))
+		 (last-point (point)))
+	     ;; No more articles with same subject, so jump to the first
+	     ;; unread article.
+	     (gnus-Subject-first-unread-article)
+	     ;;(and (eq buffer (current-buffer))
+	     ;;	(= (point) last-point)
+	     ;;	;; Ignore given SUBJECT, and try again.
+	     ;;	(gnus-Subject-next-article unread nil))
+	     (and (eq buffer (current-buffer))
+		  (< (point) last-point)
+		  (message "Wrapped"))
+	     ))
+	  ((and (not unread)
+		gnus-auto-extend-newsgroup
+		(setq header (gnus-more-header-forward)))
+	   ;; Extend to next article if possible.
+	   ;; Basic ideas by himacdonald@watdragon.waterloo.edu
+	   (gnus-extend-newsgroup header nil)
+	   ;; Threads feature must be turned off.
+	   (let ((buffer-read-only nil))
+	     (goto-char (point-max))
+	     (gnus-Subject-prepare-threads (list header) 0))
+	   (gnus-Subject-goto-article gnus-newsgroup-end))
+	  (t
+	   ;; Select next newsgroup automatically if requested.
+	   (let ((cmd (string-to-char (this-command-keys)))
+		 (group (gnus-Subject-search-group))
+		 (auto-select
+		  (and gnus-auto-select-next
+		       ;;(null (gnus-set-difference gnus-newsgroup-unreads
+		       ;;				gnus-newsgroup-marked))
+		       (memq this-command
+			     '(gnus-Subject-next-unread-article
+			       gnus-Subject-next-article
+			       gnus-Subject-next-page
+			       gnus-Subject-next-same-subject
+			       gnus-Subject-next-unread-same-subject
+			       gnus-Subject-kill-same-subject
+			       gnus-Subject-kill-same-subject-and-select
+			       ))
+		       ;; Ignore characters typed ahead.
+		       (not (input-pending-p))
+		       )))
+	     (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 to %s [%d])"
+				      (key-description (char-to-string 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
+				    ))
+			""))
+	     ;; Select next unread newsgroup automagically.
+	     (cond ((and auto-select
+			 (eq gnus-auto-select-next 'quietly))
+		    ;; Select quietly.
+		    (gnus-Subject-next-group nil))
+		   (auto-select
+		    ;; Confirm auto selection.
+		    (let ((char (read-char)))
+		      (if (= char cmd)
+			  (gnus-Subject-next-group nil)
+			(setq unread-command-char char))))
+		   )
+	     ))
+	  )))
+
+(defun gnus-Subject-next-unread-article ()
+  "Select unread article after current one."
+  (interactive)
+  (gnus-Subject-next-article t (and gnus-auto-select-same
+				    (gnus-Subject-subject-string))))
+
+(defun gnus-Subject-prev-article (unread &optional subject)
+  "Select article before current one.
+If argument UNREAD is non-nil, only unread article is selected."
+  (interactive "P")
+  (let ((header nil))
+    (cond ((gnus-Subject-display-article
+	    (gnus-Subject-search-backward unread subject)))
+	  ((and subject
+		gnus-auto-select-same
+		(gnus-set-difference gnus-newsgroup-unreads
+				     gnus-newsgroup-marked)
+		(memq this-command
+		      '(gnus-Subject-prev-unread-article
+			;;gnus-Subject-prev-page
+			;;gnus-Subject-prev-article
+			;;gnus-Subject-prev-same-subject
+			;;gnus-Subject-prev-unread-same-subject
+			)))
+	   ;; Ignore given SUBJECT, and try again.
+	   (gnus-Subject-prev-article unread nil))
+	  (unread
+	   (message "No more unread articles"))
+	  ((and gnus-auto-extend-newsgroup
+		(setq header (gnus-more-header-backward)))
+	   ;; Extend to previous article if possible.
+	   ;; Basic ideas by himacdonald@watdragon.waterloo.edu
+	   (gnus-extend-newsgroup header t)
+	   (let ((buffer-read-only nil))
+	     (goto-char (point-min))
+	     (gnus-Subject-prepare-threads (list header) 0))
+	   (gnus-Subject-goto-article gnus-newsgroup-begin))
+	  (t
+	   (message "No more articles"))
+	  )))
+
+(defun gnus-Subject-prev-unread-article ()
+  "Select unred article before current one."
+  (interactive)
+  (gnus-Subject-prev-article t (and gnus-auto-select-same
+				    (gnus-Subject-subject-string))))
+
+(defun gnus-Subject-next-page (lines)
+  "Show next page of selected article.
+If end of artile, select next article.
+Argument LINES specifies lines to be scrolled up."
+  (interactive "P")
+  (let ((article (gnus-Subject-article-number))
+	(endp nil))
+    (if (or (null gnus-current-article)
+	    (/= article gnus-current-article))
+	;; Selected subject is different from current article's.
+	(gnus-Subject-display-article article)
+      (gnus-configure-windows 'SelectArticle)
+      (pop-to-buffer gnus-Subject-buffer)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	(setq endp (gnus-Article-next-page lines)))
+      (cond ((and endp lines)
+	     (message "End of message"))
+	    ((and endp (null lines))
+	     (gnus-Subject-next-unread-article)))
+      )))
+
+(defun gnus-Subject-prev-page (lines)
+  "Show previous page of selected article.
+Argument LINES specifies lines to be scrolled down."
+  (interactive "P")
+  (let ((article (gnus-Subject-article-number)))
+    (if (or (null gnus-current-article)
+	    (/= article gnus-current-article))
+	;; Selected subject is different from current article's.
+	(gnus-Subject-display-article article)
+      (gnus-configure-windows 'SelectArticle)
+      (pop-to-buffer gnus-Subject-buffer)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	(gnus-Article-prev-page lines))
+      )))
+
+(defun gnus-Subject-scroll-up (lines)
+  "Scroll up (or down) one line current article.
+Argument LINES specifies lines to be scrolled up (or down if negative)."
+  (interactive "p")
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (cond ((> lines 0)
+	   (if (gnus-Article-next-page lines)
+	       (message "End of message")))
+	  ((< lines 0)
+	   (gnus-Article-prev-page (- 0 lines))))
+    ))
+
+(defun gnus-Subject-next-same-subject ()
+  "Select next article which has the same subject as current one."
+  (interactive)
+  (gnus-Subject-next-article nil (gnus-Subject-subject-string)))
+
+(defun gnus-Subject-prev-same-subject ()
+  "Select previous article which has the same subject as current one."
+  (interactive)
+  (gnus-Subject-prev-article nil (gnus-Subject-subject-string)))
+
+(defun gnus-Subject-next-unread-same-subject ()
+  "Select next unread article which has the same subject as current one."
+  (interactive)
+  (gnus-Subject-next-article t (gnus-Subject-subject-string)))
+
+(defun gnus-Subject-prev-unread-same-subject ()
+  "Select previous unread article which has the same subject as current one."
+  (interactive)
+  (gnus-Subject-prev-article t (gnus-Subject-subject-string)))
+
+(defun gnus-Subject-refer-parent-article (child)
+  "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."
+  (interactive "P")
+  (gnus-Subject-select-article t t)	;Request all headers.
+  (let ((referenced-id nil))		;Message-id of parent or child article.
+    (if child
+	;; Go back to child article using history.
+	(gnus-Subject-refer-article nil)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	;; Look for parent Message-ID.
+	;; We cannot use gnus-current-headers to get references
+	;; because we may be looking at parent or refered article.
+	(let ((references (gnus-fetch-field "References")))
+	  ;; Get the last message-id in the references.
+	  (and references
+	       (string-match "\\(<[^<>]+>\\)[^>]*\\'" references)
+	       (setq referenced-id
+		     (substring references
+				(match-beginning 1) (match-end 1))))
+	  ))
+      (if (stringp referenced-id)
+	  (gnus-Subject-refer-article referenced-id)
+	(error "No more parents"))
+      )))
+
+(defun gnus-Subject-refer-article (message-id)
+  "Refer article specified by MESSAGE-ID.
+If MESSAGE-ID is nil or an empty string, it is popped from an
+internally maintained articles history.
+NOTE: This command may not work with nnspool.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
+  ;; by Message-ID.
+  (gnus-Subject-select-article t t)	;Request all headers.
+  (if (and (stringp message-id)
+	   (> (length message-id) 0))
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	;; Construct the correct Message-ID if necessary.
+	;; Suggested by tale@pawl.rpi.edu.
+	(or (string-match "^<" message-id)
+	    (setq message-id (concat "<" message-id)))
+	(or (string-match ">$" message-id)
+	    (setq message-id (concat message-id ">")))
+	;; Push current message-id on history.
+	;; We cannot use gnus-current-headers to get current
+	;; message-id because we may be looking at parent or refered
+	;; article.
+	(let ((current (gnus-fetch-field "Message-ID")))
+	  (or (equal current message-id) ;Nothing to do.
+	      (equal current (car gnus-current-history))
+	      (setq gnus-current-history
+		    (cons current gnus-current-history)))
+	  ))
+    ;; Pop message-id from history.
+    (setq message-id (car gnus-current-history))
+    (setq gnus-current-history (cdr gnus-current-history)))
+  (if (stringp message-id)
+      ;; Retrieve article by message-id.  This may not work with nnspool.
+      (gnus-Article-prepare message-id t)
+    (error "No such references"))
+  )
+
+(defun gnus-Subject-next-digest (nth)
+  "Move to head of NTH next digested message."
+  (interactive "p")
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (gnus-Article-next-digest (or nth 1))
+    ))
+
+(defun gnus-Subject-prev-digest (nth)
+  "Move to head of NTH previous digested message."
+  (interactive "p")
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (gnus-Article-prev-digest (or nth 1))
+    ))
+
+(defun gnus-Subject-first-unread-article ()
+  "Select first unread article.  Return non-nil if successfully selected."
+  (interactive)
+  (let ((begin (point)))
+    (goto-char (point-min))
+    (if (re-search-forward "^ [ \t]+[0-9]+:" nil t)
+	(gnus-Subject-display-article (gnus-Subject-article-number))
+      ;; If there is no unread articles, stay there.
+      (goto-char begin)
+      ;;(gnus-Subject-display-article (gnus-Subject-article-number))
+      (message "No more unread articles")
+      nil
+      )
+    ))
+
+(defun gnus-Subject-isearch-article ()
+  "Do incremental search forward on current article."
+  (interactive)
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (call-interactively 'isearch-forward)
+    ))
+
+(defun gnus-Subject-search-article-forward (regexp)
+  "Search for an article containing REGEXP forward.
+`gnus-Select-article-hook' is not called during the search."
+  (interactive
+   (list (read-string
+	  (concat "Search forward (regexp): "
+		  (if gnus-last-search-regexp
+		      (concat "(default " gnus-last-search-regexp ") "))))))
+  (if (string-equal regexp "")
+      (setq regexp (or gnus-last-search-regexp ""))
+    (setq gnus-last-search-regexp regexp))
+  (if (gnus-Subject-search-article regexp nil)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	(recenter 0)
+	;;(sit-for 1)
+	)
+    (error "Search failed: \"%s\"" regexp)
+    ))
+
+(defun gnus-Subject-search-article-backward (regexp)
+  "Search for an article containing REGEXP backward.
+`gnus-Select-article-hook' is not called during the search."
+  (interactive
+   (list (read-string
+	  (concat "Search backward (regexp): "
+		  (if gnus-last-search-regexp
+		      (concat "(default " gnus-last-search-regexp ") "))))))
+  (if (string-equal regexp "")
+      (setq regexp (or gnus-last-search-regexp ""))
+    (setq gnus-last-search-regexp regexp))
+  (if (gnus-Subject-search-article regexp t)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	(recenter 0)
+	;;(sit-for 1)
+	)
+    (error "Search failed: \"%s\"" regexp)
+    ))
+
+(defun gnus-Subject-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."
+  (let ((gnus-Select-article-hook nil)	;Disable hook.
+	(gnus-Mark-article-hook nil)	;Inhibit marking as read.
+	(re-search
+	 (if backward
+	     (function re-search-backward) (function re-search-forward)))
+	(found nil)
+	(last nil))
+    ;; Hidden thread subtrees must be searched for ,too.
+    (gnus-Subject-show-all-threads)
+    ;; First of all, search current article.
+    ;; We don't want to read article again from NNTP server nor reset
+    ;; current point.
+    (gnus-Subject-select-article)
+    (message "Searching article: %d..." gnus-current-article)
+    (setq last gnus-current-article)
+    (gnus-eval-in-buffer-window gnus-Article-buffer
+      (save-restriction
+	(widen)
+	;; Begin search from current point.
+	(setq found (funcall re-search regexp nil t))))
+    ;; Then search next articles.
+    (while (and (not found)
+		(gnus-Subject-display-article 
+		 (gnus-Subject-search-subject backward nil nil)))
+      (message "Searching article: %d..." gnus-current-article)
+      (gnus-eval-in-buffer-window gnus-Article-buffer
+	(save-restriction
+	  (widen)
+	  (goto-char (if backward (point-max) (point-min)))
+	  (setq found (funcall re-search regexp nil t)))
+	))
+    (message "")
+    ;; Adjust article pointer.
+    (or (eq last gnus-current-article)
+	(setq gnus-last-article last))
+    ;; Return T if found such article.
+    found
+    ))
+
+(defun gnus-Subject-execute-command (field regexp command &optional backward)
+  "If FIELD of article header matches REGEXP, execute COMMAND string.
+If FIELD is an empty string (or nil), entire article body is searched for.
+If optional (prefix) argument BACKWARD is non-nil, do backward instead."
+  (interactive
+   (list (let ((completion-ignore-case t))
+	   (completing-read "Field name: "
+			    '(("Number")("Subject")("From")
+			      ("Lines")("Date")("Id")
+			      ("Xref")("References"))
+			    nil 'require-match))
+	 (read-string "Regexp: ")
+	 (read-key-sequence "Command: ")
+	 current-prefix-arg))
+  ;; Hidden thread subtrees must be searched for ,too.
+  (gnus-Subject-show-all-threads)
+  ;; We don't want to change current point nor window configuration.
+  (save-excursion
+    (save-window-excursion
+      (message "Executing %s..." (key-description command))
+      ;; We'd like to execute COMMAND interactively so as to give arguments.
+      (gnus-execute field regexp
+		    (` (lambda ()
+			 (call-interactively '(, (key-binding command)))))
+		    backward)
+      (message "Executing %s... done" (key-description command)))))
+
+(defun gnus-Subject-beginning-of-article ()
+  "Go to beginning of article body"
+  (interactive)
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (widen)
+    (beginning-of-buffer)
+    (if gnus-break-pages
+	(gnus-narrow-to-page))
+    ))
+
+(defun gnus-Subject-end-of-article ()
+  "Go to end of article body"
+  (interactive)
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (widen)
+    (end-of-buffer)
+    (if gnus-break-pages
+	(gnus-narrow-to-page))
+    ))
+
+(defun gnus-Subject-goto-article (article &optional all-headers)
+  "Read ARTICLE if exists.
+Optional argument ALL-HEADERS means all headers are shown."
+  (interactive
+   (list
+    (string-to-int
+     (completing-read "Article number: "
+		      (mapcar
+		       (function
+			(lambda (headers)
+			  (list
+			   (int-to-string (nntp-header-number headers)))))
+		       gnus-newsgroup-headers)
+		      nil 'require-match))))
+  (if (gnus-Subject-goto-subject article)
+      (gnus-Subject-display-article article all-headers)))
+
+(defun gnus-Subject-goto-last-article ()
+  "Go to last subject line."
+  (interactive)
+  (if gnus-last-article
+      (gnus-Subject-goto-article gnus-last-article)))
+
+(defun gnus-Subject-show-article ()
+  "Force to show current article."
+  (interactive)
+  ;; The following is a trick to force to read the current article again.
+  (setq gnus-have-all-headers (not gnus-have-all-headers))
+  (gnus-Subject-select-article (not gnus-have-all-headers) t))
+
+(defun gnus-Subject-toggle-header (arg)
+  "Show original header if pruned header currently shown, or vice versa.
+With arg, show original header iff arg is positive."
+  (interactive "P")
+  ;; Variable gnus-show-all-headers must be NIL to toggle really.
+  (let ((gnus-show-all-headers nil)
+	(all-headers
+	 (if (null arg) (not gnus-have-all-headers)
+	   (> (prefix-numeric-value arg) 0))))
+    (gnus-Subject-select-article all-headers t)))
+
+(defun gnus-Subject-show-all-headers ()
+  "Show original article header."
+  (interactive)
+  (gnus-Subject-select-article t t))
+
+(defun gnus-Subject-stop-page-breaking ()
+  "Stop page breaking by linefeed temporary (Widen article buffer)."
+  (interactive)
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (widen)))
+
+(defun gnus-Subject-kill-same-subject-and-select (unmark)
+  "Mark articles which has the same subject as read, and then select next.
+If argument UNMARK is positive, remove any kinds of marks.
+If argument UNMARK is negative, mark articles as unread instead."
+  (interactive "P")
+  (if unmark
+      (setq unmark (prefix-numeric-value unmark)))
+  (let ((count
+	 (gnus-Subject-mark-same-subject
+	  (gnus-Subject-subject-string) unmark)))
+    ;; Select next unread article. If auto-select-same mode, should
+    ;; select the first unread article.
+    (gnus-Subject-next-article t (and gnus-auto-select-same
+				      (gnus-Subject-subject-string)))
+    (message "%d articles are marked as %s"
+	     count (if unmark "unread" "read"))
+    ))
+
+(defun gnus-Subject-kill-same-subject (unmark)
+  "Mark articles which has the same subject as read. 
+If argument UNMARK is positive, remove any kinds of marks.
+If argument UNMARK is negative, mark articles as unread instead."
+  (interactive "P")
+  (if unmark
+      (setq unmark (prefix-numeric-value unmark)))
+  (let ((count
+	 (gnus-Subject-mark-same-subject
+	  (gnus-Subject-subject-string) unmark)))
+    ;; If marked as read, go to next unread subject.
+    (if (null unmark)
+	;; Go to next unread subject.
+	(gnus-Subject-next-subject 1 t))
+    (message "%d articles are marked as %s"
+	     count (if unmark "unread" "read"))
+    ))
+
+(defun gnus-Subject-mark-same-subject (subject &optional unmark)
+  "Mark articles with same SUBJECT as read, and return marked number.
+If optional argument UNMARK is positive, remove any kinds of marks.
+If optional argument UNMARK is negative, mark articles as unread instead."
+  (let ((count 1))
+    (save-excursion
+      (cond ((null unmark)
+	     (gnus-Subject-mark-as-read nil "K"))
+	    ((> unmark 0)
+	     (gnus-Subject-mark-as-unread nil t))
+	    (t
+	     (gnus-Subject-mark-as-unread)))
+      (while (and subject
+		  (gnus-Subject-search-forward nil subject))
+	(cond ((null unmark)
+	       (gnus-Subject-mark-as-read nil "K"))
+	      ((> unmark 0)
+	       (gnus-Subject-mark-as-unread nil t))
+	      (t
+	       (gnus-Subject-mark-as-unread)))
+	(setq count (1+ count))
+	))
+    ;; Hide killed thread subtrees.  Does not work properly always.
+    ;;(and (null unmark)
+    ;;     gnus-thread-hide-killed
+    ;;	   (gnus-Subject-hide-thread))
+    ;; Return number of articles marked as read.
+    count
+    ))
+
+(defun gnus-Subject-mark-as-unread-forward (count)
+  "Mark current article as unread, and then go forward.
+Argument COUNT specifies number of articles marked as unread."
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-unread nil nil)
+    (gnus-Subject-next-subject 1 nil)
+    (setq count (1- count))))
+
+(defun gnus-Subject-mark-as-unread-backward (count)
+  "Mark current article as unread, and then go backward.
+Argument COUNT specifies number of articles marked as unread."
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-unread nil nil)
+    (gnus-Subject-prev-subject 1 nil)
+    (setq count (1- count))))
+
+(defun gnus-Subject-mark-as-unread (&optional article clear-mark)
+  "Mark current article as unread.
+Optional first argument ARTICLE specifies article number to be
+marked as unread.  Optional second argument CLEAR-MARK removes
+any kind of mark."
+  (save-excursion
+    (set-buffer gnus-Subject-buffer)
+    ;; First of all, show hidden thread subtrees.
+    (gnus-Subject-show-thread)
+    (let* ((buffer-read-only nil)
+	   (current (gnus-Subject-article-number))
+	   (article (or article current)))
+      (gnus-mark-article-as-unread article clear-mark)
+      (if (or (eq article current)
+	      (gnus-Subject-goto-subject article))
+	  (progn
+	    (beginning-of-line)
+	    (delete-char 1)
+	    (insert (if clear-mark " " "-"))))
+      )))
+
+(defun gnus-Subject-mark-as-read-forward (count)
+  "Mark current article as read, and then go forward.
+Argument COUNT specifies number of articles marked as read"
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-read)
+    (gnus-Subject-next-subject 1 'unread-only)
+    (setq count (1- count))))
+
+(defun gnus-Subject-mark-as-read-backward (count)
+  "Mark current article as read, and then go backward.
+Argument COUNT specifies number of articles marked as read"
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-read)
+    (gnus-Subject-prev-subject 1 'unread-only)
+    (setq count (1- count))))
+
+(defun gnus-Subject-mark-as-read (&optional article mark)
+  "Mark current article as read.
+Optional first argument ARTICLE specifies article number to be marked as read.
+Optional second argument MARK specifies a string inserted at beginning of line.
+Any kind of string (length 1) except for a space and `-' is ok."
+  (save-excursion
+    (set-buffer gnus-Subject-buffer)
+    ;; First of all, show hidden thread subtrees.
+    (gnus-Subject-show-thread)
+    (let* ((buffer-read-only nil)
+	   (mark (or mark "D"))		;Default mark is `D'.
+	   (current (gnus-Subject-article-number))
+	   (article (or article current)))
+      (gnus-mark-article-as-read article)
+      (if (or (eq article current)
+	      (gnus-Subject-goto-subject article))
+	  (progn
+	    (beginning-of-line)
+	    (delete-char 1)
+	    (insert mark)))
+      )))
+
+(defun gnus-Subject-clear-mark-forward (count)
+  "Remove current article's mark, and go forward.
+Argument COUNT specifies number of articles unmarked"
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-unread nil t)
+    (gnus-Subject-next-subject 1 nil)
+    (setq count (1- count))))
+
+(defun gnus-Subject-clear-mark-backward (count)
+  "Remove current article's mark, and go backward.
+Argument COUNT specifies number of articles unmarked"
+  (interactive "p")
+  (while (> count 0)
+    (gnus-Subject-mark-as-unread nil t)
+    (gnus-Subject-prev-subject 1 nil)
+    (setq count (1- count))))
+
+(defun gnus-Subject-delete-marked-as-read ()
+  "Delete lines which are marked as read."
+  (interactive)
+  (if gnus-newsgroup-unreads
+      (let ((buffer-read-only nil))
+	(save-excursion
+	  (goto-char (point-min))
+	  (delete-non-matching-lines "^[ ---]"))
+	;; Adjust point.
+	(if (eobp)
+	    (gnus-Subject-prev-subject 1)
+	  (beginning-of-line)
+	  (search-forward ":" nil t)))
+    ;; It is not so good idea to make the buffer empty.
+    (message "All articles are marked as read")
+    ))
+
+(defun gnus-Subject-delete-marked-with (marks)
+  "Delete lines which are marked with MARKS (e.g. \"DK\")."
+  (interactive "sMarks: ")
+  (let ((buffer-read-only nil))
+    (save-excursion
+      (goto-char (point-min))
+      (delete-matching-lines (concat "^[" marks "]")))
+    ;; Adjust point.
+    (or (zerop (buffer-size))
+	(if (eobp)
+	    (gnus-Subject-prev-subject 1)
+	  (beginning-of-line)
+	  (search-forward ":" nil t)))
+    ))
+
+;; Thread-based commands.
+
+(defun gnus-Subject-toggle-threads (arg)
+  "Toggle showing conversation threads.
+With arg, turn showing conversation threads on iff arg is positive."
+  (interactive "P")
+  (let ((current (gnus-Subject-article-number)))
+    (setq gnus-show-threads
+	  (if (null arg) (not gnus-show-threads)
+	    (> (prefix-numeric-value arg) 0)))
+    (gnus-Subject-prepare)
+    (gnus-Subject-goto-subject current)
+    ))
+
+(defun gnus-Subject-show-all-threads ()
+  "Show all thread subtrees."
+  (interactive)
+  (if gnus-show-threads
+      (save-excursion
+	(let ((buffer-read-only nil))
+	  (subst-char-in-region (point-min) (point-max) ?\^M ?\n t)
+	  ))))
+
+(defun gnus-Subject-show-thread ()
+  "Show thread subtrees."
+  (interactive)
+  (if gnus-show-threads
+      (save-excursion
+	(let ((buffer-read-only nil))
+	  (subst-char-in-region (progn
+				  (beginning-of-line) (point))
+				(progn
+				  (end-of-line) (point))
+				?\^M ?\n t)
+	  ))))
+
+(defun gnus-Subject-hide-all-threads ()
+  "Hide all thread subtrees."
+  (interactive)
+  (if gnus-show-threads
+      (save-excursion
+	;; Adjust cursor point.
+	(goto-char (point-min))
+	(search-forward ":" nil t)
+	(let ((level (current-column)))
+	  (gnus-Subject-hide-thread)
+	  (while (gnus-Subject-search-forward)
+	    (and (>= level (current-column))
+		 (gnus-Subject-hide-thread)))
+	  ))))
+
+(defun gnus-Subject-hide-thread ()
+  "Hide thread subtrees."
+  (interactive)
+  (if gnus-show-threads
+      (save-excursion
+	;; Adjust cursor point.
+	(beginning-of-line)
+	(search-forward ":" nil t)
+	(let ((buffer-read-only nil)
+	      (init (point))
+	      (last (point))
+	      (level (current-column)))
+	  (while (and (gnus-Subject-search-forward)
+		      (< level (current-column)))
+	    ;; Interested in lower levels.
+	    (if (< level (current-column))
+		(progn
+		  (setq last (point))
+		  ))
+	    )
+	  (subst-char-in-region init last ?\n ?\^M t)
+	  ))))
+
+(defun gnus-Subject-next-thread (n)
+  "Go to the same level next thread.
+Argument N specifies the number of threads."
+  (interactive "p")
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t)
+  (let ((init (point))
+	(last (point))
+	(level (current-column)))
+    (while (and (> n 0)
+		(gnus-Subject-search-forward)
+		(<= level (current-column)))
+      ;; We have to skip lower levels.
+      (if (= level (current-column))
+	  (progn
+	    (setq last (point))
+	    (setq n (1- n))
+	    ))
+      )
+    ;; Return non-nil if successfully move to the next.
+    (prog1 (not (= init last))
+      (goto-char last))
+    ))
+
+(defun gnus-Subject-prev-thread (n)
+  "Go to the same level previous thread.
+Argument N specifies the number of threads."
+  (interactive "p")
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t)
+  (let ((init (point))
+	(last (point))
+	(level (current-column)))
+    (while (and (> n 0)
+		(gnus-Subject-search-backward)
+		(<= level (current-column)))
+      ;; We have to skip lower levels.
+      (if (= level (current-column))
+	  (progn
+	    (setq last (point))
+	    (setq n (1- n))
+	    ))
+      )
+    ;; Return non-nil if successfully move to the previous.
+    (prog1 (not (= init last))
+      (goto-char last))
+    ))
+
+(defun gnus-Subject-down-thread (d)
+  "Go downward current thread.
+Argument D specifies the depth goes down."
+  (interactive "p")
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t)
+  (let ((last (point))
+	(level (current-column)))
+    (while (and (> d 0)
+		(gnus-Subject-search-forward)
+		(<= level (current-column))) ;<= can be <.  Which do you like?
+      ;; We have to skip the same levels.
+      (if (< level (current-column))
+	  (progn
+	    (setq last (point))
+	    (setq level (current-column))
+	    (setq d (1- d))
+	    ))
+      )
+    (goto-char last)
+    ))
+
+(defun gnus-Subject-up-thread (d)
+  "Go upward current thread.
+Argument D specifies the depth goes up."
+  (interactive "p")
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t)
+  (let ((last (point))
+	(level (current-column)))
+    (while (and (> d 0)
+		(gnus-Subject-search-backward))
+      ;; We have to skip the same levels.
+      (if (> level (current-column))
+	  (progn
+	    (setq last (point))
+	    (setq level (current-column))
+	    (setq d (1- d))
+	    ))
+      )
+    (goto-char last)
+    ))
+
+(defun gnus-Subject-kill-thread (unmark)
+  "Mark articles under current thread as read.
+If argument UNMARK is positive, remove any kinds of marks.
+If argument UNMARK is negative, mark articles as unread instead."
+  (interactive "P")
+  (if unmark
+      (setq unmark (prefix-numeric-value unmark)))
+  ;; Adjust cursor point.
+  (beginning-of-line)
+  (search-forward ":" nil t)
+  (save-excursion
+    (let ((level (current-column)))
+      ;; Mark current article.
+      (cond ((null unmark)
+	     (gnus-Subject-mark-as-read nil "K"))
+	    ((> unmark 0)
+	     (gnus-Subject-mark-as-unread nil t))
+	    (t
+	     (gnus-Subject-mark-as-unread))
+	    )
+      ;; Mark following articles.
+      (while (and (gnus-Subject-search-forward)
+		  (< level (current-column)))
+	(cond ((null unmark)
+	       (gnus-Subject-mark-as-read nil "K"))
+	      ((> unmark 0)
+	       (gnus-Subject-mark-as-unread nil t))
+	      (t
+	       (gnus-Subject-mark-as-unread))
+	      ))
+      ))
+  ;; Hide killed subtrees.
+  (and (null unmark)
+       gnus-thread-hide-killed
+       (gnus-Subject-hide-thread))
+  ;; If marked as read, go to next unread subject.
+  (if (null unmark)
+      ;; Go to next unread subject.
+      (gnus-Subject-next-subject 1 t))
+  )
+
+(defun gnus-Subject-toggle-truncation (arg)
+  "Toggle truncation of subject lines.
+With ARG, turn line truncation on iff ARG is positive."
+  (interactive "P")
+  (setq truncate-lines
+	(if (null arg) (not truncate-lines)
+	  (> (prefix-numeric-value arg) 0)))
+  (redraw-display))
+
+(defun gnus-Subject-sort-by-number (reverse)
+  "Sort subject display buffer by article number.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-Subject-sort-subjects
+   (function
+    (lambda (a b)
+      (< (nntp-header-number a) (nntp-header-number b))))
+   reverse
+   ))
+
+(defun gnus-Subject-sort-by-author (reverse)
+  "Sort subject display buffer by author name alphabetically.
+If case-fold-search is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-Subject-sort-subjects
+   (function
+    (lambda (a b)
+      (gnus-string-lessp (nntp-header-from a) (nntp-header-from b))))
+   reverse
+   ))
+
+(defun gnus-Subject-sort-by-subject (reverse)
+  "Sort subject display buffer by subject alphabetically. `Re:'s are ignored.
+If case-fold-search is non-nil, case of letters is ignored.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-Subject-sort-subjects
+   (function
+    (lambda (a b)
+      (gnus-string-lessp
+       (gnus-simplify-subject (nntp-header-subject a) 're-only)
+       (gnus-simplify-subject (nntp-header-subject b) 're-only))))
+   reverse
+   ))
+
+(defun gnus-Subject-sort-by-date (reverse)
+  "Sort subject display buffer by posted date.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-Subject-sort-subjects
+   (function
+    (lambda (a b)
+      (gnus-date-lessp (nntp-header-date a) (nntp-header-date b))))
+   reverse
+   ))
+
+(defun gnus-Subject-sort-subjects (predicate &optional reverse)
+  "Sort subject display buffer by PREDICATE.
+Optional argument REVERSE means reverse order."
+  (let ((current (gnus-Subject-article-number)))
+    (gnus-sort-headers predicate reverse)
+    (gnus-Subject-prepare)
+    (gnus-Subject-goto-subject current)
+    ))
+
+(defun gnus-Subject-reselect-current-group (show-all)
+  "Once exit and then reselect the current newsgroup.
+Prefix argument SHOW-ALL means to select all articles."
+  (interactive "P")
+  (let ((current-subject (gnus-Subject-article-number)))
+    (gnus-Subject-exit t)
+    ;; We have to adjust the point of Group mode buffer because the
+    ;; current point was moved to the next unread newsgroup by
+    ;; exiting.
+    (gnus-Subject-jump-to-group gnus-newsgroup-name)
+    (gnus-Group-read-group show-all t)
+    (gnus-Subject-goto-subject current-subject)
+    ))
+
+(defun gnus-Subject-caesar-message (rotnum)
+  "Caesar rotates all letters of current message by 13/47 places.
+With prefix arg, specifies the number of places to rotate each letter forward.
+Caesar rotates Japanese letters by 47 places in any case."
+  (interactive "P")
+  (gnus-Subject-select-article)
+  (gnus-overload-functions)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-restriction
+      (widen)
+      ;; We don't want to jump to the beginning of the message.
+      ;; `save-excursion' does not do its job.
+      (move-to-window-line 0)
+      (let ((last (point)))
+	(news-caesar-buffer-body rotnum)
+	(goto-char last)
+	(recenter 0)
+	))
+    ))
+
+(defun gnus-Subject-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
+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."
+  (interactive)
+  (gnus-Subject-select-article)
+  (require 'rmail)
+  (let ((artbuf gnus-Article-buffer)
+	(digbuf (get-buffer-create gnus-Digest-buffer))
+	(mail-header-separator ""))
+    (set-buffer digbuf)
+    (buffer-flush-undo (current-buffer))
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (insert-buffer-substring artbuf)
+    (run-hooks 'gnus-Select-digest-hook)
+    (gnus-convert-article-to-rmail)
+    (goto-char (point-min))
+    ;; Rmail initializations.
+    (rmail-insert-rmail-file-header)
+    (rmail-mode)
+    (rmail-set-message-counters)
+    (rmail-show-message)
+    (condition-case ()
+	(progn
+	  (undigestify-rmail-message)
+	  (rmail-expunge)		;Delete original message.
+	  ;; File name is meaningless but `save-buffer' requires it.
+	  (setq buffer-file-name "GNUS Digest")
+	  (setq mode-line-buffer-identification
+		(concat "Digest: "
+			(nntp-header-subject gnus-current-headers)))
+	  ;; There is no need to write this buffer to a file.
+	  (make-local-variable 'write-file-hooks)
+	  (setq write-file-hooks
+		(list (function
+		       (lambda ()
+			 (set-buffer-modified-p nil)
+			 (message "(No changes need to be saved)")
+			 'no-need-to-write-this-buffer))))
+	  ;; Default file name saving digest messages.
+	  (setq rmail-last-rmail-file
+		(funcall gnus-rmail-save-name
+			 gnus-newsgroup-name
+			 gnus-current-headers
+			 gnus-newsgroup-last-rmail
+			 ))
+	  (setq rmail-last-file
+		(funcall gnus-mail-save-name
+			 gnus-newsgroup-name
+			 gnus-current-headers
+			 gnus-newsgroup-last-mail
+			 ))
+	  ;; Prevent generating new buffer named ***<N> each time.
+	  (setq rmail-summary-buffer
+		(get-buffer-create gnus-Digest-summary-buffer))
+	  (run-hooks 'gnus-Rmail-digest-hook)
+	  ;; Take all windows safely.
+	  (gnus-configure-windows '(1 0 0))
+	  (pop-to-buffer gnus-Group-buffer)
+	  ;; Use Subject and Article windows for Digest summary and
+	  ;; Digest buffers.
+	  (if gnus-digest-show-summary
+	      (let ((gnus-Subject-buffer gnus-Digest-summary-buffer)
+		    (gnus-Article-buffer gnus-Digest-buffer))
+		(gnus-configure-windows 'SelectArticle)
+		(pop-to-buffer gnus-Digest-buffer)
+		(rmail-summary)
+		(pop-to-buffer gnus-Digest-summary-buffer)
+		(message (substitute-command-keys
+			  "Type \\[rmail-summary-quit] to return to GNUS")))
+	    (let ((gnus-Subject-buffer gnus-Digest-buffer))
+	      (gnus-configure-windows 'ExpandSubject)
+	      (pop-to-buffer gnus-Digest-buffer)
+	      (message (substitute-command-keys
+			"Type \\[rmail-quit] to return to GNUS")))
+	    )
+	  ;; Move the buffers to the end of buffer list.
+	  (bury-buffer gnus-Article-buffer)
+	  (bury-buffer gnus-Group-buffer)
+	  (bury-buffer gnus-Digest-summary-buffer)
+	  (bury-buffer gnus-Digest-buffer))
+      (error (set-buffer-modified-p nil)
+	     (kill-buffer digbuf)
+	     ;; This command should not signal an error because the
+	     ;; command is called from hooks.
+	     (ding) (message "Article is not a digest")))
+    ))
+
+(defun gnus-Subject-save-article ()
+  "Save this article using default saver function.
+Variable `gnus-default-article-saver' specifies the saver function."
+  (interactive)
+  (gnus-Subject-select-article
+   (not (null gnus-save-all-headers)) gnus-save-all-headers)
+  (if gnus-default-article-saver
+      (call-interactively gnus-default-article-saver)
+    (error "No default saver is defined.")))
+
+(defun gnus-Subject-save-in-rmail (&optional filename)
+  "Append this article to Rmail file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory' which
+is initialized from the SAVEDIR environment variable."
+  (interactive)
+  (gnus-Subject-select-article
+   (not (null gnus-save-all-headers)) gnus-save-all-headers)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-excursion
+      (save-restriction
+	(widen)
+	(let ((default-name
+		(funcall gnus-rmail-save-name
+			 gnus-newsgroup-name
+			 gnus-current-headers
+			 gnus-newsgroup-last-rmail
+			 )))
+	  (or filename
+	      (setq filename
+		    (read-file-name
+		     (concat "Save article in Rmail file: (default "
+			     (file-name-nondirectory default-name)
+			     ") ")
+		     (file-name-directory default-name)
+		     default-name)))
+	  (gnus-make-directory (file-name-directory filename))
+	  (gnus-output-to-rmail filename)
+	  ;; Remember the directory name to save articles.
+	  (setq gnus-newsgroup-last-rmail filename)
+	  )))
+    ))
+
+(defun gnus-Subject-save-in-mail (&optional filename)
+  "Append this article to Unix mail file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory' which
+is initialized from the SAVEDIR environment variable."
+  (interactive)
+  (gnus-Subject-select-article
+   (not (null gnus-save-all-headers)) gnus-save-all-headers)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-excursion
+      (save-restriction
+	(widen)
+	(let ((default-name
+		(funcall gnus-mail-save-name
+			 gnus-newsgroup-name
+			 gnus-current-headers
+			 gnus-newsgroup-last-mail
+			 )))
+	  (or filename
+	      (setq filename
+		    (read-file-name
+		     (concat "Save article in Unix mail file: (default "
+			     (file-name-nondirectory default-name)
+			     ") ")
+		     (file-name-directory default-name)
+		     default-name)))
+	  (gnus-make-directory (file-name-directory filename))
+	  (rmail-output filename)
+	  ;; Remember the directory name to save articles.
+	  (setq gnus-newsgroup-last-mail filename)
+	  )))
+    ))
+
+(defun gnus-Subject-save-in-file (&optional filename)
+  "Append this article to file.
+Optional argument FILENAME specifies file name.
+Directory to save to is default to `gnus-article-save-directory' which
+is initialized from the SAVEDIR environment variable."
+  (interactive)
+  (gnus-Subject-select-article
+   (not (null gnus-save-all-headers)) gnus-save-all-headers)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-excursion
+      (save-restriction
+	(widen)
+	(let ((default-name
+		(funcall gnus-file-save-name
+			 gnus-newsgroup-name
+			 gnus-current-headers
+			 gnus-newsgroup-last-file
+			 )))
+	  (or filename
+	      (setq filename
+		    (read-file-name
+		     (concat "Save article in file: (default "
+			     (file-name-nondirectory default-name)
+			     ") ")
+		     (file-name-directory default-name)
+		     default-name)))
+	  (gnus-make-directory (file-name-directory filename))
+	  (gnus-output-to-file filename)
+	  ;; Remember the directory name to save articles.
+	  (setq gnus-newsgroup-last-file filename)
+	  )))
+    ))
+
+(defun gnus-Subject-save-in-folder (&optional folder)
+  "Save this article to MH folder (using `rcvstore' in MH library).
+Optional argument FOLDER specifies folder name."
+  (interactive)
+  (gnus-Subject-select-article
+   (not (null gnus-save-all-headers)) gnus-save-all-headers)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-restriction
+      (widen)
+      ;; Thanks to yuki@flab.Fujitsu.JUNET and ohm@kaba.junet.
+      (mh-find-path)
+      (let ((folder
+	     (or folder
+		 (mh-prompt-for-folder "Save article in"
+				       (funcall gnus-folder-save-name
+						gnus-newsgroup-name
+						gnus-current-headers
+						gnus-newsgroup-last-folder
+						)
+				       t
+				       )))
+	    (errbuf (get-buffer-create " *GNUS rcvstore*")))
+	(unwind-protect
+	    (call-process-region (point-min) (point-max)
+				 (expand-file-name "rcvstore" mh-lib)
+				 nil errbuf nil folder)
+	  (set-buffer errbuf)
+	  (if (zerop (buffer-size))
+	      (message "Article saved in folder: %s" folder)
+	    (message "%s" (buffer-string)))
+	  (kill-buffer errbuf)
+	  (setq gnus-newsgroup-last-folder folder))
+	))
+    ))
+
+(defun gnus-Subject-pipe-output ()
+  "Pipe this article to subprocess."
+  (interactive)
+  ;; Ignore `gnus-save-all-headers' since this is not save command.
+  (gnus-Subject-select-article)
+  (gnus-eval-in-buffer-window gnus-Article-buffer
+    (save-restriction
+      (widen)
+      (let ((command (read-string "Shell command on article: "
+				  gnus-last-shell-command)))
+	(if (string-equal command "")
+	    (setq command gnus-last-shell-command))
+	(shell-command-on-region (point-min) (point-max) command nil)
+	(setq gnus-last-shell-command command)
+	))
+    ))
+
+(defun gnus-Subject-catch-up (all &optional quietly)
+  "Mark all articles not marked as unread in this newsgroup as read.
+If prefix argument ALL is non-nil, all articles are marked as read."
+  (interactive "P")
+  (if (or quietly
+	  (y-or-n-p
+	   (if all
+	       "Do you really want to mark everything as read? "
+	     "Delete all articles not marked as unread? ")))
+      (let ((unmarked
+	     (gnus-set-difference gnus-newsgroup-unreads
+				  (if (not all) gnus-newsgroup-marked))))
+        (message "")			;Erase "Yes or No" question.
+	(while unmarked
+          (gnus-Subject-mark-as-read (car unmarked) "C")
+	  (setq unmarked (cdr unmarked))
+	  ))
+    ))
+
+(defun gnus-Subject-catch-up-all (&optional quietly)
+  "Mark all articles in this newsgroup as read."
+  (interactive)
+  (gnus-Subject-catch-up t quietly))
+
+(defun gnus-Subject-catch-up-and-exit (all &optional quietly)
+  "Mark all articles not marked as unread in this newsgroup as read, then exit.
+If prefix argument ALL is non-nil, all articles are marked as read."
+  (interactive "P")
+  (if (or quietly
+	  (y-or-n-p
+	   (if all
+	       "Do you really want to mark everything as read? "
+	     "Delete all articles not marked as unread? ")))
+      (let ((unmarked
+             (gnus-set-difference gnus-newsgroup-unreads
+                                  (if (not all) gnus-newsgroup-marked))))
+        (message "")			;Erase "Yes or No" question.
+	(while unmarked
+          (gnus-mark-article-as-read (car unmarked))
+	  (setq unmarked (cdr unmarked)))
+	;; Select next newsgroup or exit.
+	(cond ((eq gnus-auto-select-next 'quietly)
+	       ;; Select next newsgroup quietly.
+	       (gnus-Subject-next-group nil))
+	      (t
+	       (gnus-Subject-exit)))
+	)))
+
+(defun gnus-Subject-catch-up-all-and-exit (&optional quietly)
+  "Mark all articles in this newsgroup as read, and then exit."
+  (interactive)
+  (gnus-Subject-catch-up-and-exit t quietly))
+
+(defun gnus-Subject-edit-global-kill ()
+  "Edit a global KILL file."
+  (interactive)
+  (setq gnus-current-kill-article (gnus-Subject-article-number))
+  (gnus-Kill-file-edit-file nil)	;Nil stands for global KILL file.
+  (message
+   (substitute-command-keys
+    "Editing a global KILL file (Type \\[gnus-Kill-file-exit] to exit)")))
+
+(defun gnus-Subject-edit-local-kill ()
+  "Edit a local KILL file applied to the current newsgroup."
+  (interactive)
+  (setq gnus-current-kill-article (gnus-Subject-article-number))
+  (gnus-Kill-file-edit-file gnus-newsgroup-name)
+  (message
+   (substitute-command-keys
+    "Editing a local KILL file (Type \\[gnus-Kill-file-exit] to exit)")))
+
+(defun gnus-Subject-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."
+  (interactive)
+  (let ((updated nil)
+	(gnus-newsgroup-headers gnus-newsgroup-headers)
+	(gnus-newsgroup-unreads gnus-newsgroup-unreads)
+	(gnus-newsgroup-unselected gnus-newsgroup-unselected)
+	(gnus-newsgroup-marked gnus-newsgroup-marked))
+    ;; Important internal variables are save, so we can reenter
+    ;; Subject Mode buffer even if hook changes them.
+    (run-hooks 'gnus-Exit-group-hook)
+    (gnus-update-unread-articles gnus-newsgroup-name
+				 (append gnus-newsgroup-unselected
+					 gnus-newsgroup-unreads)
+				 gnus-newsgroup-marked)
+    ;; T means ignore unsubscribed newsgroups.
+    (if gnus-use-cross-reference
+	(setq updated
+	      (gnus-mark-as-read-by-xref gnus-newsgroup-name
+					 gnus-newsgroup-headers
+					 gnus-newsgroup-unreads
+					 (eq gnus-use-cross-reference t)
+					 )))
+    ;; Do not switch windows but change the buffer to work.
+    (set-buffer gnus-Group-buffer)
+    ;; Update cross referenced group info.
+    (while updated
+      (gnus-Group-update-group (car updated) t) ;Ignore invisible group.
+      (setq updated (cdr updated)))
+    (gnus-Group-update-group gnus-newsgroup-name))
+  ;; Make sure where I was, and go to next newsgroup.
+  (gnus-Group-jump-to-group gnus-newsgroup-name)
+  (gnus-Group-next-unread-group 1)
+  (if temporary
+      ;; If exiting temporary, caller should adjust Group mode
+      ;; buffer point by itself.
+      nil				;Nothing to do.
+    ;; Return to Group mode buffer.
+    (if (get-buffer gnus-Subject-buffer)
+	(bury-buffer gnus-Subject-buffer))
+    (if (get-buffer gnus-Article-buffer)
+	(bury-buffer gnus-Article-buffer))
+    (gnus-configure-windows 'ExitNewsgroup)
+    (pop-to-buffer gnus-Group-buffer)))
+
+(defun gnus-Subject-quit ()
+  "Quit reading current newsgroup without updating read article info."
+  (interactive)
+  (if (y-or-n-p "Do you really wanna quit reading this group? ")
+      (progn
+	(message "")			;Erase "Yes or No" question.
+	;; Return to Group selection mode.
+	(if (get-buffer gnus-Subject-buffer)
+	    (bury-buffer gnus-Subject-buffer))
+	(if (get-buffer gnus-Article-buffer)
+	    (bury-buffer gnus-Article-buffer))
+	(gnus-configure-windows 'ExitNewsgroup)
+	(pop-to-buffer gnus-Group-buffer)
+	(gnus-Group-jump-to-group gnus-newsgroup-name) ;Make sure where I was.
+	(gnus-Group-next-group 1)	;(gnus-Group-next-unread-group 1)
+	)))
+
+(defun gnus-Subject-describe-briefly ()
+  "Describe Subject mode commands briefly."
+  (interactive)
+  (message
+   (concat
+    (substitute-command-keys "\\[gnus-Subject-next-page]:Select  ")
+    (substitute-command-keys "\\[gnus-Subject-next-unread-article]:Forward  ")
+    (substitute-command-keys "\\[gnus-Subject-prev-unread-article]:Backward  ")
+    (substitute-command-keys "\\[gnus-Subject-exit]:Exit  ")
+    (substitute-command-keys "\\[gnus-Info-find-node]:Run Info  ")
+    (substitute-command-keys "\\[gnus-Subject-describe-briefly]:This help")
+    )))
+
+
+;;;
+;;; GNUS Article Mode
+;;;
+
+(if gnus-Article-mode-map
+    nil
+  (setq gnus-Article-mode-map (make-keymap))
+  (suppress-keymap gnus-Article-mode-map)
+  (define-key gnus-Article-mode-map " " 'gnus-Article-next-page)
+  (define-key gnus-Article-mode-map "\177" 'gnus-Article-prev-page)
+  (define-key gnus-Article-mode-map "r" 'gnus-Article-refer-article)
+  (define-key gnus-Article-mode-map "o" 'gnus-Article-pop-article)
+  (define-key gnus-Article-mode-map "h" 'gnus-Article-show-subjects)
+  (define-key gnus-Article-mode-map "s" 'gnus-Article-show-subjects)
+  (define-key gnus-Article-mode-map "?" 'gnus-Article-describe-briefly)
+  (define-key gnus-Article-mode-map "\C-c\C-i" 'gnus-Info-find-node))
+
+(defun gnus-Article-mode ()
+  "Major mode for browsing through an article.
+All normal editing commands are turned off.
+Instead, these commands are available:
+\\{gnus-Article-mode-map}
+
+Various hooks for customization:
+ gnus-Article-mode-hook
+    Entry to this mode calls the value with no arguments, if that
+    value is non-nil.
+
+ gnus-Article-prepare-hook
+    Called with no arguments after an article is prepared for reading,
+    if that value is non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  ;; Gee.  Why don't you upgrade?
+  (cond ((boundp 'mode-line-modified)
+	 (setq mode-line-modified "--- "))
+	((listp (default-value 'mode-line-format))
+	 (setq mode-line-format
+	       (cons "--- " (cdr (default-value 'mode-line-format))))))
+  (make-local-variable 'global-mode-string)
+  (setq global-mode-string nil)
+  (setq major-mode 'gnus-Article-mode)
+  (setq mode-name "Article")
+  (gnus-Article-set-mode-line)
+  (use-local-map gnus-Article-mode-map)
+  (make-local-variable 'page-delimiter)
+  (setq page-delimiter gnus-page-delimiter)
+  (make-local-variable 'mail-header-separator)
+  (setq mail-header-separator "")	;For caesar function.
+  (buffer-flush-undo (current-buffer))
+  (setq buffer-read-only t)		;Disable modification
+  (run-hooks 'gnus-Article-mode-hook))
+
+(defun gnus-Article-setup-buffer ()
+  "Initialize Article mode buffer."
+  (or (get-buffer gnus-Article-buffer)
+      (save-excursion
+	(set-buffer (get-buffer-create gnus-Article-buffer))
+	(gnus-Article-mode))
+      ))
+
+(defun gnus-Article-prepare (article &optional all-headers)
+  "Prepare ARTICLE in Article mode buffer.
+If optional argument ALL-HEADERS is non-nil, all headers are inserted."
+  (save-excursion
+    (set-buffer gnus-Article-buffer)
+    (let ((buffer-read-only nil))
+      (erase-buffer)
+      (if (gnus-request-article article)
+	  (progn
+	    ;; Prepare article buffer
+	    (insert-buffer-substring nntp-server-buffer)
+	    (setq gnus-have-all-headers (or all-headers gnus-show-all-headers))
+	    (if (and (numberp article)
+		     (not (eq article gnus-current-article)))
+		;; Seems me that a new article is selected.
+		(progn
+		  ;; gnus-current-article must be an article number.
+		  (setq gnus-last-article gnus-current-article)
+		  (setq gnus-current-article article)
+		  (setq gnus-current-headers
+			(gnus-find-header-by-number gnus-newsgroup-headers
+						    gnus-current-article))
+		  ;; Clear articles history only when articles are
+		  ;; retrieved by article numbers.
+		  (setq gnus-current-history nil)
+		  (run-hooks 'gnus-Mark-article-hook)
+		  ))
+	    ;; Hooks for modifying contents of the article. This hook
+	    ;; must be called before being narrowed.
+	    (run-hooks 'gnus-Article-prepare-hook)
+	    ;; Delete unnecessary headers.
+	    (or gnus-have-all-headers
+		(gnus-Article-delete-headers))
+	    ;; Do page break.
+	    (goto-char (point-min))
+	    (if gnus-break-pages
+		(gnus-narrow-to-page))
+	    ;; Next function must be called after setting
+	    ;;  `gnus-current-article' variable and narrowed to page.
+	    (gnus-Article-set-mode-line)
+	    )
+	(if (numberp article)
+	    (gnus-Subject-mark-as-read article))
+	(ding) (message "No such article (may be canceled)"))
+      )))
+
+(defun gnus-Article-show-all-headers ()
+  "Show all article headers in Article mode buffer."
+  (or gnus-have-all-headers
+      (gnus-Article-prepare gnus-current-article t)))
+
+;;(defun gnus-Article-set-mode-line ()
+;;  "Set Article mode line string."
+;;  (setq mode-line-buffer-identification
+;;	(list 17
+;;	      (format "GNUS: %s {%d-%d} %d"
+;;		      gnus-newsgroup-name
+;;		      gnus-newsgroup-begin
+;;		      gnus-newsgroup-end
+;;		      gnus-current-article
+;;                    )))
+;;  (set-buffer-modified-p t))
+
+(defun gnus-Article-set-mode-line ()
+  "Set Article mode line string."
+  (let ((unmarked
+	 (- (length gnus-newsgroup-unreads)
+	    (length (gnus-intersection
+		     gnus-newsgroup-unreads gnus-newsgroup-marked))))
+	(unselected
+	 (- (length gnus-newsgroup-unselected)
+	    (length (gnus-intersection
+		     gnus-newsgroup-unselected gnus-newsgroup-marked)))))
+    (setq mode-line-buffer-identification
+	  (list 17
+		(format "GNUS: %s{%d} %s"
+			gnus-newsgroup-name
+			gnus-current-article
+			;; This is proposed by tale@pawl.rpi.edu.
+			(cond ((and (zerop unmarked)
+				    (zerop unselected))
+			       "      ")
+			      ((zerop unselected)
+			       (format "%d more" unmarked))
+			      (t
+			       (format "%d(+%d) more" unmarked unselected)))
+			))))
+  (set-buffer-modified-p t))
+
+(defun gnus-Article-delete-headers ()
+  "Delete unnecessary headers."
+  (save-excursion
+    (save-restriction
+      (goto-char (point-min))
+      (narrow-to-region (point-min)
+			(progn (search-forward "\n\n" nil 'move) (point)))
+      (goto-char (point-min))
+      (and (stringp gnus-ignored-headers)
+	   (while (re-search-forward gnus-ignored-headers nil t)
+	     (beginning-of-line)
+	     (delete-region (point)
+			    (progn (re-search-forward "\n[^ \t]")
+				   (forward-char -1)
+				   (point)))))
+      )))
+
+;; Working on article's buffer
+
+(defun gnus-Article-next-page (lines)
+  "Show next page of current article.
+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)
+  ;; Fixed by enami@ptgd.sony.co.jp (enami tsugutomo)
+  (if (save-excursion
+	(end-of-line)
+	(and (pos-visible-in-window-p)	;Not continuation line.
+	     (eobp)))
+      ;; Nothing in this page.
+      (if (or (not gnus-break-pages)
+	      (save-excursion
+		(save-restriction
+		  (widen) (forward-line 1) (eobp)))) ;Real end-of-buffer?
+	  t				;Nothing more.
+	(gnus-narrow-to-page 1)		;Go to next page.
+	nil
+	)
+    ;; More in this page.
+    (condition-case ()
+	(scroll-up lines)
+      (end-of-buffer
+       ;; Long lines may cause an end-of-buffer error.
+       (goto-char (point-max))))
+    nil
+    ))
+
+(defun gnus-Article-prev-page (lines)
+  "Show previous page of current article.
+Argument LINES specifies lines to be scrolled down."
+  (interactive "P")
+  (move-to-window-line 0)
+  (if (and gnus-break-pages
+	   (bobp)
+	   (not (save-restriction (widen) (bobp)))) ;Real beginning-of-buffer?
+      (progn
+	(gnus-narrow-to-page -1) ;Go to previous page.
+	(goto-char (point-max))
+	(recenter -1))
+    (scroll-down lines)))
+
+(defun gnus-Article-next-digest (nth)
+  "Move to head of NTH next digested message.
+Set mark at end of digested message."
+  ;; Stop page breaking in digest mode.
+  (widen)
+  (end-of-line)
+  ;; Skip NTH - 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)
+	      (re-search-forward gnus-digest-separator nil 'move))
+    (setq nth (1- nth)))
+  (if (re-search-forward gnus-digest-separator nil t)
+      (let ((begin (point)))
+	;; Search for end of this message.
+	(end-of-line)
+	(if (re-search-forward gnus-digest-separator nil t)
+	    (progn
+	      (search-backward "\n\n")	;This may be incorrect.
+	      (forward-line 1))
+	  (goto-char (point-max)))
+	(push-mark)			;Set mark at end of digested message.
+	(goto-char begin)
+	(beginning-of-line)
+	;; Show From: and Subject: fields.
+	(recenter 1))
+    (message "End of message")
+    ))
+
+(defun gnus-Article-prev-digest (nth)
+  "Move to head of NTH previous digested message."
+  ;; Stop page breaking in digest mode.
+  (widen)
+  (beginning-of-line)
+  ;; Skip NTH - 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)
+	      (re-search-backward gnus-digest-separator nil 'move))
+    (setq nth (1- nth)))
+  (if (re-search-backward gnus-digest-separator nil t)
+      (let ((begin (point)))
+	;; Search for end of this message.
+	(end-of-line)
+	(if (re-search-forward gnus-digest-separator nil t)
+	    (progn
+	      (search-backward "\n\n")	;This may be incorrect.
+	      (forward-line 1))
+	  (goto-char (point-max)))
+	(push-mark)			;Set mark at end of digested message.
+	(goto-char begin)
+	;; Show From: and Subject: fields.
+	(recenter 1))
+    (goto-char (point-min))
+    (message "Top of message")
+    ))
+
+(defun gnus-Article-refer-article ()
+  "Read article specified by message-id around point."
+  (interactive)
+  (save-window-excursion
+    (save-excursion
+      (re-search-forward ">" nil t)	;Move point to end of "<....>".
+      (if (re-search-backward "\\(<[^<> \t\n]+>\\)" nil t)
+	  (let ((message-id
+		 (buffer-substring (match-beginning 1) (match-end 1))))
+	    (set-buffer gnus-Subject-buffer)
+	    (gnus-Subject-refer-article message-id))
+	(error "No references around point"))
+      )))
+
+(defun gnus-Article-pop-article ()
+  "Pop up article history."
+  (interactive)
+  (save-window-excursion
+    (set-buffer gnus-Subject-buffer)
+    (gnus-Subject-refer-article nil)))
+
+(defun gnus-Article-show-subjects ()
+  "Reconfigure windows to show headers."
+  (interactive)
+  (gnus-configure-windows 'SelectArticle)
+  (pop-to-buffer gnus-Subject-buffer)
+  (gnus-Subject-goto-subject gnus-current-article))
+
+(defun gnus-Article-describe-briefly ()
+  "Describe Article mode commands briefly."
+  (interactive)
+  (message
+   (concat
+    (substitute-command-keys "\\[gnus-Article-next-page]:Next page  ")
+    (substitute-command-keys "\\[gnus-Article-prev-page]:Prev page  ")
+    (substitute-command-keys "\\[gnus-Article-show-subjects]:Show headers  ")
+    (substitute-command-keys "\\[gnus-Info-find-node]:Run Info  ")
+    (substitute-command-keys "\\[gnus-Article-describe-briefly]:This help")
+    )))
+
+
+;;;
+;;; GNUS KILL-File Mode
+;;;
+
+(if gnus-Kill-file-mode-map
+    nil
+  (setq gnus-Kill-file-mode-map (copy-keymap emacs-lisp-mode-map))
+  (define-key gnus-Kill-file-mode-map "\C-c\C-k\C-s" 'gnus-Kill-file-kill-by-subject)
+  (define-key gnus-Kill-file-mode-map "\C-c\C-k\C-a" 'gnus-Kill-file-kill-by-author)
+  (define-key gnus-Kill-file-mode-map "\C-c\C-a" 'gnus-Kill-file-apply-buffer)
+  (define-key gnus-Kill-file-mode-map "\C-c\C-e" 'gnus-Kill-file-apply-last-sexp)
+  (define-key gnus-Kill-file-mode-map "\C-c\C-c" 'gnus-Kill-file-exit)
+  (define-key gnus-Kill-file-mode-map "\C-c\C-i" 'gnus-Info-find-node))
+
+(defun gnus-Kill-file-mode ()
+  "Major mode for editing KILL file.
+
+In addition to Emacs-Lisp Mode, the following commands are available:
+
+\\[gnus-Kill-file-kill-by-subject]	Insert KILL command for current subject.
+\\[gnus-Kill-file-kill-by-author]	Insert KILL command for current author.
+\\[gnus-Kill-file-apply-buffer]	Apply current buffer to selected newsgroup.
+\\[gnus-Kill-file-apply-last-sexp]	Apply sexp before point to selected newsgroup.
+\\[gnus-Kill-file-exit]	Save file and exit editing KILL file.
+\\[gnus-Info-find-node]	Read Info about KILL file.
+
+  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 Subject buffer. Writing lisp programs for this
+purpose is not so easy because the internal working of GNUS must be
+well-known. For this reason, GNUS provides a general function which
+does this easily for non-Lisp programmers.
+
+  The `gnus-kill' function executes commands available in Subject 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 Subject Mode or Lisp expression. COMMAND is default to
+'(gnus-Subject-mark-as-read nil \"X\"). Make sure that COMMAND is
+executed in the Subject buffer.  If the second optional argument ALL
+is non-nil, the COMMAND is applied to articles which are already
+marked as read or unread.  Articles which are marked are skipped over
+by default.
+
+  For example, if you want to mark articles of which subjects contain
+the string `AI' as read, a possible KILL file may look like:
+
+	(gnus-kill \"Subject\" \"AI\")
+
+  If you want to mark articles with `D' instead of `X', you can use
+the following expression:
+
+	(gnus-kill \"Subject\" \"AI\" \"d\")
+
+In this example it is assumed that the command
+`gnus-Subject-mark-as-read-forward' is assigned to `d' in Subject Mode.
+
+  It is possible to delete unnecessary headers which are marked with
+`X' in a KILL file as follows:
+
+	(gnus-expunge \"X\")
+
+  If the Subject buffer is empty after applying KILL files, GNUS will
+exit the selected newsgroup normally.  If headers which are marked
+with `D' are deleted in a KILL file, it is impossible to read articles
+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."
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map gnus-Kill-file-mode-map)
+  (set-syntax-table emacs-lisp-mode-syntax-table)
+  (setq major-mode 'gnus-Kill-file-mode)
+  (setq mode-name "KILL-File")
+  (lisp-mode-variables nil)
+  (run-hooks 'emacs-lisp-mode-hook 'gnus-Kill-file-mode-hook))
+
+(defun gnus-Kill-file-edit-file (newsgroup)
+  "Begin editing a KILL file of NEWSGROUP.
+If NEWSGROUP is nil, the global KILL file is selected."
+  (interactive "sNewsgroup: ")
+  (let ((file (gnus-newsgroup-kill-file newsgroup)))
+    (gnus-make-directory (file-name-directory file))
+    ;; Save current window configuration if this is first invocation.
+    (or (and (get-file-buffer file)
+	     (get-buffer-window (get-file-buffer file)))
+	(setq gnus-winconf-kill-file (current-window-configuration)))
+    ;; Hack windows.
+    (let ((buffer (find-file-noselect file)))
+      (cond ((get-buffer-window buffer)
+	     (pop-to-buffer buffer))
+	    ((eq major-mode 'gnus-Group-mode)
+	     (gnus-configure-windows '(1 0 0)) ;Take all windows.
+	     (pop-to-buffer gnus-Group-buffer)
+	     (let ((gnus-Subject-buffer buffer))
+	       (gnus-configure-windows '(1 1 0)) ;Split into two.
+	       (pop-to-buffer buffer)))
+	    ((eq major-mode 'gnus-Subject-mode)
+	     (gnus-configure-windows 'SelectArticle)
+	     (pop-to-buffer gnus-Article-buffer)
+	     (bury-buffer gnus-Article-buffer)
+	     (switch-to-buffer buffer))
+	    (t				;No good rules.
+	     (find-file-other-window file))
+	    ))
+    (gnus-Kill-file-mode)
+    ))
+
+(defun gnus-Kill-file-kill-by-subject ()
+  "Insert KILL command for current subject."
+  (interactive)
+  (insert
+   (format "(gnus-kill \"Subject\" %s)\n"
+	   (prin1-to-string
+	    (if gnus-current-kill-article
+		(regexp-quote
+		 (nntp-header-subject
+		  (gnus-find-header-by-number gnus-newsgroup-headers
+					      gnus-current-kill-article)))
+	      "")))))
+
+(defun gnus-Kill-file-kill-by-author ()
+  "Insert KILL command for current author."
+  (interactive)
+  (insert
+   (format "(gnus-kill \"From\" %s)\n"
+	   (prin1-to-string
+	    (if gnus-current-kill-article
+		(regexp-quote
+		 (nntp-header-from
+		  (gnus-find-header-by-number gnus-newsgroup-headers
+					      gnus-current-kill-article)))
+	      "")))))
+
+(defun gnus-Kill-file-apply-buffer ()
+  "Apply current buffer to current newsgroup."
+  (interactive)
+  (if (and gnus-current-kill-article
+	   (get-buffer gnus-Subject-buffer))
+      ;; Assume newsgroup is selected.
+      (let ((string (concat "(progn \n" (buffer-string) "\n)" )))
+	(save-excursion
+	  (save-window-excursion
+	    (pop-to-buffer gnus-Subject-buffer)
+	    (eval (car (read-from-string string))))))
+    (ding) (message "No newsgroup is selected.")))
+
+(defun gnus-Kill-file-apply-last-sexp ()
+  "Apply sexp before point in current buffer to current newsgroup."
+  (interactive)
+  (if (and gnus-current-kill-article
+	   (get-buffer gnus-Subject-buffer))
+      ;; Assume newsgroup is selected.
+      (let ((string
+	     (buffer-substring
+	      (save-excursion (forward-sexp -1) (point)) (point))))
+	(save-excursion
+	  (save-window-excursion
+	    (pop-to-buffer gnus-Subject-buffer)
+	    (eval (car (read-from-string string))))))
+    (ding) (message "No newsgroup is selected.")))
+
+(defun gnus-Kill-file-exit ()
+  "Save a KILL file, then return to the previous buffer."
+  (interactive)
+  (save-buffer)
+  (let ((killbuf (current-buffer)))
+    ;; We don't want to return to Article buffer.
+    (and (get-buffer gnus-Article-buffer)
+	 (bury-buffer (get-buffer gnus-Article-buffer)))
+    ;; Delete the KILL file windows.
+    (delete-windows-on killbuf)
+    ;; Restore last window configuration if available.
+    (and gnus-winconf-kill-file
+	 (set-window-configuration gnus-winconf-kill-file))
+    (setq gnus-winconf-kill-file nil)
+    ;; Kill the KILL file buffer.  Suggested by tale@pawl.rpi.edu.
+    (kill-buffer killbuf)))
+
+
+;;;
+;;; Utility functions
+;;;
+
+;; Basic ideas by emv@math.lsa.umich.edu (Edward Vielmetti)
+
+(defun gnus-batch-kill ()
+  "Run batched KILL.
+Usage: emacs -batch -l gnus -f gnus-batch-kill NEWSGROUP ..."
+  (if (not noninteractive)
+      (error "gnus-batch-kill is to be used only with -batch"))
+  (let* ((group nil)
+	 (subscribed nil)
+	 (newsrc nil)
+	 (yes-and-no
+	  (gnus-parse-n-options
+	   (apply (function concat)
+		  (mapcar (function (lambda (g) (concat g " ")))
+			  command-line-args-left))))
+	 (yes (car yes-and-no))
+	 (no  (cdr yes-and-no))
+	 ;; Disable verbose message.
+	 (gnus-novice-user nil)
+	 (gnus-large-newsgroup nil)
+	 (nntp-large-newsgroup nil))
+    ;; Eat all arguments.
+    (setq command-line-args-left nil)
+    ;; Startup GNUS.
+    (gnus)
+    ;; Apply kills to specified newsgroups in command line arguments.
+    (setq newsrc (copy-sequence gnus-newsrc-assoc))
+    (while newsrc
+      (setq group (car (car newsrc)))
+      (setq subscribed (nth 1 (car newsrc)))
+      (setq newsrc (cdr newsrc))
+      (if (and subscribed
+	       (not (zerop (nth 1 (gnus-gethash group gnus-unread-hashtb))))
+	       (if yes
+		   (string-match yes group) t)
+	       (or (null no)
+		   (not (string-match no group))))
+	  (progn
+	    (gnus-Subject-read-group group nil t)
+	    (if (eq (current-buffer) (get-buffer gnus-Subject-buffer))
+		(gnus-Subject-exit t))
+	    ))
+      )
+    ;; Finally, exit Emacs.
+    (set-buffer gnus-Group-buffer)
+    (gnus-Group-exit)
+    ))
+
+(defun gnus-Numeric-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is nil, it is ~/News/News.group/num.
+Otherwise, it is like ~/News/news/group/num."
+  (let ((default
+	  (expand-file-name
+	   (concat (if gnus-use-long-file-name
+		       (capitalize newsgroup)
+		     (gnus-newsgroup-directory-form newsgroup))
+		   "/" (int-to-string (nntp-header-number headers)))
+	   (or gnus-article-save-directory "~/News"))))
+    (if (and last-file
+	     (string-equal (file-name-directory default)
+			   (file-name-directory last-file))
+	     (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
+	default
+      (or last-file default))))
+
+(defun gnus-numeric-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is nil, it is ~/News/news.group/num.
+Otherwise, it is like ~/News/news/group/num."
+  (let ((default
+	  (expand-file-name
+	   (concat (if gnus-use-long-file-name
+		       newsgroup
+		     (gnus-newsgroup-directory-form newsgroup))
+		   "/" (int-to-string (nntp-header-number headers)))
+	   (or gnus-article-save-directory "~/News"))))
+    (if (and last-file
+	     (string-equal (file-name-directory default)
+			   (file-name-directory last-file))
+	     (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
+	default
+      (or last-file default))))
+
+(defun gnus-Plain-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is nil, it is ~/News/News.group.
+Otherwise, it is like ~/News/news/group/news."
+  (or last-file
+      (expand-file-name
+       (if gnus-use-long-file-name
+	   (capitalize newsgroup)
+	 (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
+       (or gnus-article-save-directory "~/News"))))
+
+(defun gnus-plain-save-name (newsgroup headers &optional last-file)
+  "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
+If variable `gnus-use-long-file-name' is nil, it is ~/News/news.group.
+Otherwise, it is like ~/News/news/group/news."
+  (or last-file
+      (expand-file-name
+       (if gnus-use-long-file-name
+	   newsgroup
+	 (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
+       (or gnus-article-save-directory "~/News"))))
+
+(defun gnus-Folder-save-name (newsgroup headers &optional last-folder)
+  "Generate folder name from NEWSGROUP, HEADERS, and optional LAST-FOLDER.
+If variable `gnus-use-long-file-name' is nil, it is +News.group.
+Otherwise, it is like +news/group."
+  (or last-folder
+      (concat "+"
+	      (if gnus-use-long-file-name
+		  (capitalize newsgroup)
+		(gnus-newsgroup-directory-form newsgroup)))))
+
+(defun gnus-folder-save-name (newsgroup headers &optional last-folder)
+  "Generate folder name from NEWSGROUP, HEADERS, and optional LAST-FOLDER.
+If variable `gnus-use-long-file-name' is nil, it is +news.group.
+Otherwise, it is like +news/group."
+  (or last-folder
+      (concat "+"
+	      (if gnus-use-long-file-name
+		  newsgroup
+		(gnus-newsgroup-directory-form newsgroup)))))
+
+(defun gnus-apply-kill-file ()
+  "Apply KILL file to the current newsgroup."
+  ;; Apply the global KILL file.
+  (load (gnus-newsgroup-kill-file nil) t nil t)
+  ;; And then apply the local KILL file.
+  (load (gnus-newsgroup-kill-file gnus-newsgroup-name) t nil t))
+
+(defun gnus-Newsgroup-kill-file (newsgroup)
+  "Return the name of a KILL file of NEWSGROUP.
+If NEWSGROUP is nil, return the global KILL file instead."
+  (cond ((or (null newsgroup)
+	     (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")))
+	(gnus-use-long-file-name
+	 ;; Append ".KILL" to capitalized newsgroup name.
+	 (expand-file-name (concat (capitalize newsgroup)
+				   "." gnus-kill-file-name)
+			   (or gnus-article-save-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")))
+	))
+
+(defun gnus-newsgroup-kill-file (newsgroup)
+  "Return the name of a KILL file of NEWSGROUP.
+If NEWSGROUP is nil, return the global KILL file instead."
+  (cond ((or (null newsgroup)
+	     (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")))
+	(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")))
+	(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")))
+	))
+
+(defun gnus-newsgroup-directory-form (newsgroup)
+  "Make hierarchical directory name from NEWSGROUP name."
+  (let ((newsgroup (substring newsgroup 0)) ;Copy string.
+	(len (length newsgroup))
+	(idx 0))
+    ;; Replace all occurence of `.' with `/'.
+    (while (< idx len)
+      (if (= (aref newsgroup idx) ?.)
+	  (aset newsgroup idx ?/))
+      (setq idx (1+ idx)))
+    newsgroup
+    ))
+
+(defun gnus-make-directory (directory)
+  "Make DIRECTORY recursively."
+  (let ((directory (expand-file-name directory default-directory)))
+    (or (file-exists-p directory)
+	(gnus-make-directory-1 "" directory))
+    ))
+
+(defun gnus-make-directory-1 (head tail)
+  (cond ((string-match "^/\\([^/]+\\)" tail)
+	 (setq head
+	       (concat (file-name-as-directory head)
+		       (substring tail (match-beginning 1) (match-end 1))))
+	 (or (file-exists-p head)
+	     (call-process "mkdir" nil nil nil head))
+	 (gnus-make-directory-1 head (substring tail (match-end 1))))
+	((string-equal tail "") t)
+	))
+
+(defun gnus-simplify-subject (subject &optional re-only)
+  "Remove `Re:' and words in parentheses.
+If optional argument RE-ONLY is non-nil, strip `Re:' only."
+  (let ((case-fold-search t))		;Ignore case.
+    ;; Remove `Re:' and `Re^N:'.
+    (if (string-match "\\`\\(re\\(\\^[0-9]+\\)?:[ \t]+\\)+" subject)
+	(setq subject (substring subject (match-end 0))))
+    ;; Remove words in parentheses from end.
+    (or re-only
+	(while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
+	  (setq subject (substring subject 0 (match-beginning 0)))))
+    ;; Return subject string.
+    subject
+    ))
+
+(defun gnus-optional-lines-and-from (header)
+  "Return a string like `NNN:AUTHOR' from HEADER."
+  (let ((name-length (length "umerin@photon")))
+    (substring (format "%3d:%s"
+		       ;; Lines of the article.
+		       ;; Suggested by dana@bellcore.com.
+		       (nntp-header-lines header)
+		       ;; Its author.
+		       (concat (mail-strip-quoted-names
+				(nntp-header-from header))
+			       (make-string name-length ? )))
+	       ;; 4 stands for length of `NNN:'.
+	       0 (+ 4 name-length))))
+
+(defun gnus-optional-lines (header)
+  "Return a string like `NNN' from HEADER."
+  (format "%4d" (nntp-header-lines header)))
+
+(defun gnus-sort-headers (predicate &optional reverse)
+  "Sort current group headers by PREDICATE safely.
+*Safely* means C-g quitting is disabled during sorting.
+Optional argument REVERSE means reverse order."
+  (let ((inhibit-quit t))
+    (setq gnus-newsgroup-headers
+	  (if reverse
+	      (nreverse (sort (nreverse gnus-newsgroup-headers) predicate))
+	    (sort gnus-newsgroup-headers predicate)))
+    ))
+
+(defun gnus-string-lessp (a b)
+  "Return T if first arg string is less than second in lexicographic order.
+If case-fold-search is non-nil, case of letters is ignored."
+  (if case-fold-search
+      (string-lessp (downcase a) (downcase b)) (string-lessp a b)))
+
+(defun gnus-date-lessp (date1 date2)
+  "Return T if DATE1 is earlyer than DATE2."
+  (string-lessp (gnus-comparable-date date1)
+		(gnus-comparable-date date2)))
+
+(defun gnus-comparable-date (date)
+  "Make comparable string by string-lessp from DATE."
+  (let ((month '(("JAN" . " 1")("FEB" . " 2")("MAR" . " 3")
+		 ("APR" . " 4")("MAY" . " 5")("JUN" . " 6")
+		 ("JUL" . " 7")("AUG" . " 8")("SEP" . " 9")
+		 ("OCT" . "10")("NOV" . "11")("DEC" . "12")))
+	(date (or date "")))
+    ;; Can understand the following styles:
+    ;; (1) 14 Apr 89 03:20:12 GMT
+    ;; (2) Fri, 17 Mar 89 4:01:33 GMT
+    (if (string-match
+	 "\\([0-9]+\\) \\([^ ,]+\\) \\([0-9]+\\) \\([0-9:]+\\)" date)
+	(concat
+	 ;; Year
+	 (substring date (match-beginning 3) (match-end 3))
+	 ;; Month
+	 (cdr
+	  (assoc
+	   (upcase (substring date (match-beginning 2) (match-end 2))) month))
+	 ;; Day
+	 (format "%2d" (string-to-int
+			(substring date
+				   (match-beginning 1) (match-end 1))))
+	 ;; Time
+	 (substring date (match-beginning 4) (match-end 4)))
+      ;; Cannot understand DATE string.
+      date
+      )
+    ))
+
+(defun gnus-fetch-field (field)
+  "Return the value of the header FIELD of current article."
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (narrow-to-region (point-min)
+			(progn (search-forward "\n\n" nil 'move) (point)))
+      (mail-fetch-field field))))
+
+(fset 'gnus-expunge 'gnus-Subject-delete-marked-with)
+
+(defun gnus-kill (field regexp &optional command all)
+  "If FIELD of an article matches REGEXP, execute COMMAND.
+Optional third argument COMMAND is default to
+	(gnus-Subject-mark-as-read nil \"X\").
+If optional fourth 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."
+  ;; We don't want to change current point nor window configuration.
+  (save-excursion
+    (save-window-excursion
+      ;; Selected window must be Subject mode buffer to execute
+      ;; keyboard macros correctly. See command_loop_1.
+      (switch-to-buffer gnus-Subject-buffer 'norecord)
+      (goto-char (point-min))		;From the beginning.
+      (if (null command)
+	  (setq command '(gnus-Subject-mark-as-read nil "X")))
+      (gnus-execute field regexp command nil (not all))
+      )))
+
+(defun gnus-execute (field regexp form &optional backward ignore-marked)
+  "If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
+If FIELD is an empty string (or nil), entire article body is searched for.
+If optional fifth argument BACKWARD is non-nil, do backward instead.
+If optional sixth argument IGNORE-MARKED is non-nil, articles which are
+marked as read or unread are ignored."
+  (let ((function nil)
+	(header nil)
+	(article nil))
+    (if (string-equal field "")
+	(setq field nil))
+    (if (null field)
+	nil
+      (or (stringp field)
+	  (setq field (symbol-name field)))
+      ;; Get access function of header filed.
+      (setq function (intern-soft (concat "gnus-header-" (downcase field))))
+      (if (and function (fboundp function))
+	  (setq function (symbol-function function))
+	(error "Unknown header field: \"%s\"" field)))
+    ;; Make FORM funcallable.
+    (if (and (listp form) (not (eq (car form) 'lambda)))
+	(setq form (list 'lambda nil form)))
+    ;; Starting from the current article.
+    (or (and ignore-marked
+	     ;; Articles marked as read and unread should be ignored.
+	     (setq article (gnus-Subject-article-number))
+	     (or (not (memq article gnus-newsgroup-unreads)) ;Marked as read.
+		 (memq article gnus-newsgroup-marked) ;Marked as unread.
+		 ))
+	(gnus-execute-1 function regexp form))
+    (while (gnus-Subject-search-subject backward ignore-marked nil)
+      (gnus-execute-1 function regexp form))
+    ))
+
+(defun gnus-execute-1 (function regexp form)
+  (save-excursion
+    ;; The point of Subject mode buffer must be saved during execution.
+    (let ((article (gnus-Subject-article-number)))
+      (if (null article)
+	  nil				;Nothing to do.
+	(if function
+	    ;; Compare with header field.
+	    (let ((header (gnus-find-header-by-number
+			   gnus-newsgroup-headers article))
+		  (value nil))
+	      (and header
+		   (progn
+		     (setq value (funcall function header))
+		     ;; Number (Lines:) or symbol must be converted to string.
+		     (or (stringp value)
+			 (setq value (prin1-to-string value)))
+		     (string-match regexp value))
+		   (if (stringp form)	;Keyboard macro.
+		       (execute-kbd-macro form)
+		     (funcall form))))
+	  ;; Search article body.
+	  (let ((gnus-current-article nil) ;Save article pointer.
+		(gnus-last-article nil)
+		(gnus-break-pages nil)	;No need to break pages.
+		(gnus-Mark-article-hook nil)) ;Inhibit marking as read.
+	    (message "Searching for article: %d..." article)
+	    (gnus-Article-setup-buffer)
+	    (gnus-Article-prepare article t)
+	    (if (save-excursion
+		  (set-buffer gnus-Article-buffer)
+		  (goto-char (point-min))
+		  (re-search-forward regexp nil t))
+		(if (stringp form)	;Keyboard macro.
+		    (execute-kbd-macro form)
+		  (funcall form))))
+	  ))
+      )))
+
+;;; caesar-region written by phr@prep.ai.mit.edu  Nov 86
+;;; modified by tower@prep Nov 86
+;;; Modified by umerin@flab.flab.Fujitsu.JUNET for ROT47.
+
+(defun gnus-caesar-region (&optional n)
+  "Caesar rotation of region by N, default 13, for decrypting netnews.
+ROT47 will be performed for Japanese text in any case."
+  (interactive (if current-prefix-arg	; Was there a prefix arg?
+		   (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
+  (if (not (zerop n))		; no action needed for a rot of 0
+      (progn
+	(if (or (not (boundp 'caesar-translate-table))
+		(/= (aref caesar-translate-table ?a) (+ ?a n)))
+	    (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper)
+	      (message "Building caesar-translate-table...")
+	      (setq caesar-translate-table (make-vector 256 0))
+	      (while (< i 256)
+		(aset caesar-translate-table i i)
+		(setq i (1+ i)))
+	      (setq lower (concat lower lower) upper (upcase lower) i 0)
+	      (while (< i 26)
+		(aset caesar-translate-table (+ ?a i) (aref lower (+ i n)))
+		(aset caesar-translate-table (+ ?A i) (aref upper (+ i n)))
+		(setq i (1+ i)))
+	      ;; ROT47 for Japanese text.
+	      ;; Thanks to ichikawa@flab.fujitsu.junet.
+	      (setq i 161)
+	      (let ((t1 (logior ?O 128))
+		    (t2 (logior ?! 128))
+		    (t3 (logior ?~ 128)))
+		(while (< i 256)
+		  (aset caesar-translate-table i
+			(let ((v (aref caesar-translate-table i)))
+			  (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")))
+	(let ((from (region-beginning))
+	      (to (region-end))
+	      (i 0) str len)
+	  (setq str (buffer-substring from to))
+	  (setq len (length str))
+	  (while (< i len)
+	    (aset str i (aref caesar-translate-table (aref str i)))
+	    (setq i (1+ i)))
+	  (goto-char from)
+	  (delete-region from to)
+	  (insert str)))))
+
+;; Functions accessing headers.
+;; Functions are more convenient than macros in some case.
+
+(defun gnus-header-number (header)
+  "Return article number in HEADER."
+  (nntp-header-number header))
+
+(defun gnus-header-subject (header)
+  "Return subject string in HEADER."
+  (nntp-header-subject header))
+
+(defun gnus-header-from (header)
+  "Return author string in HEADER."
+  (nntp-header-from header))
+
+(defun gnus-header-xref (header)
+  "Return xref string in HEADER."
+  (nntp-header-xref header))
+
+(defun gnus-header-lines (header)
+  "Return lines in HEADER."
+  (nntp-header-lines header))
+
+(defun gnus-header-date (header)
+  "Return date in HEADER."
+  (nntp-header-date header))
+
+(defun gnus-header-id (header)
+  "Return Id in HEADER."
+  (nntp-header-id header))
+
+(defun gnus-header-references (header)
+  "Return references in HEADER."
+  (nntp-header-references header))
+
+
+;;;
+;;; Article savers.
+;;;
+
+(defun gnus-output-to-rmail (file-name)
+  "Append the current article to an Rmail file named FILE-NAME."
+  (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)
+  (let ((artbuf (current-buffer))
+	(tmpbuf (get-buffer-create " *GNUS-output*")))
+    (save-excursion
+      (or (get-file-buffer file-name)
+	  (file-exists-p file-name)
+	  (if (yes-or-no-p
+	       (concat "\"" file-name "\" does not exist, create it? "))
+	      (let ((file-buffer (create-file-buffer file-name)))
+		(save-excursion
+		  (set-buffer file-buffer)
+		  (rmail-insert-rmail-file-header)
+		  (let ((require-final-newline nil))
+		    (write-region (point-min) (point-max) file-name t 1)))
+		(kill-buffer file-buffer))
+	    (error "Output file does not exist")))
+      (set-buffer tmpbuf)
+      (buffer-flush-undo (current-buffer))
+      (erase-buffer)
+      (insert-buffer-substring artbuf)
+      (gnus-convert-article-to-rmail)
+      ;; Decide whether to append to a file or to an Emacs buffer.
+      (let ((outbuf (get-file-buffer file-name)))
+	(if (not outbuf)
+	    (append-to-file (point-min) (point-max) file-name)
+	  ;; File has been visited, in buffer OUTBUF.
+	  (set-buffer outbuf)
+	  (let ((buffer-read-only nil)
+		(msg (and (boundp 'rmail-current-message)
+			  rmail-current-message)))
+	    ;; If MSG is non-nil, buffer is in RMAIL mode.
+	    (if msg
+		(progn (widen)
+		       (narrow-to-region (point-max) (point-max))))
+	    (insert-buffer-substring tmpbuf)
+	    (if msg
+		(progn
+		  (goto-char (point-min))
+		  (widen)
+		  (search-backward "\^_")
+		  (narrow-to-region (point) (point-max))
+		  (goto-char (1+ (point-min)))
+		  (rmail-count-new-messages t)
+		  (rmail-show-message msg))))))
+      )
+    (kill-buffer tmpbuf)
+    ))
+
+(defun gnus-output-to-file (file-name)
+  "Append the current article to a file named FILE-NAME."
+  (setq file-name (expand-file-name file-name))
+  (let ((artbuf (current-buffer))
+	(tmpbuf (get-buffer-create " *GNUS-output*")))
+    (save-excursion
+      (set-buffer tmpbuf)
+      (buffer-flush-undo (current-buffer))
+      (erase-buffer)
+      (insert-buffer-substring artbuf)
+      ;; Append newline at end of the buffer as separator, and then
+      ;; save it to file.
+      (goto-char (point-max))
+      (insert "\n")
+      (append-to-file (point-min) (point-max) file-name))
+    (kill-buffer tmpbuf)
+    ))
+
+(defun gnus-convert-article-to-rmail ()
+  "Convert article in current buffer to Rmail message format."
+  (let ((buffer-read-only nil))
+    ;; Convert article directly into Babyl format.
+    ;; Suggested by Rob Austein <sra@lcs.mit.edu>
+    (goto-char (point-min))
+    (insert "\^L\n0, unseen,,\n*** EOOH ***\n")
+    (while (search-forward "\n\^_" nil t) ;single char
+      (replace-match "\n^_"))		;2 chars: "^" and "_"
+    (goto-char (point-max))
+    (insert "\^_")))
+
+;;(defun gnus-convert-article-to-rmail ()
+;;  "Convert article in current buffer to Rmail message format."
+;;  (let ((buffer-read-only nil))
+;;    ;; Insert special header of Unix mail.
+;;    (goto-char (point-min))
+;;    (insert "From "
+;;	    (or (mail-strip-quoted-names (mail-fetch-field "from"))
+;;		"unknown")
+;;	    " " (current-time-string) "\n")
+;;    ;; Stop quoting `From' since this seems unnecessary in most cases.
+;;    ;; ``Quote'' "\nFrom " as "\n>From "
+;;    ;;(while (search-forward "\nFrom " nil t)
+;;    ;;  (forward-char -5)
+;;    ;;  (insert ?>))
+;;    ;; Convert article to babyl format.
+;;    (rmail-convert-to-babyl-format)
+;;    ))
+
+
+;;;
+;;; Internal functions.
+;;;
+
+(defun gnus-start-news-server (&optional confirm)
+  "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."
+  (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 no server name is given, local host is assumed.
+    (if (string-equal gnus-nntp-server "")
+	(setq gnus-nntp-server (system-name)))
+    (cond ((string-match ":" gnus-nntp-server)
+	   ;; :DIRECTORY
+	   (require 'mhspool)
+	   (gnus-define-access-method 'mhspool)
+	   (message "Looking up private directory..."))
+	  ((and (null gnus-nntp-service)
+	        (string-equal gnus-nntp-server (system-name)))
+	   (require 'nnspool)
+	   (gnus-define-access-method 'nnspool)
+	   (message "Looking up local news spool..."))
+	  (t
+	   (gnus-define-access-method 'nntp)
+	   (message "Connecting to NNTP server on %s..." gnus-nntp-server)))
+    (run-hooks 'gnus-Open-server-hook)
+    (cond ((gnus-open-server gnus-nntp-server gnus-nntp-service))
+	  ((and (stringp (gnus-status-message))
+		(> (length (gnus-status-message)) 0))
+	   ;; Show valuable message if available.
+	   (error (gnus-status-message)))
+	  (t (error "Cannot open NNTP server on %s" gnus-nntp-server)))
+    ))
+
+;; Dummy functions used only once. Should return nil.
+(defun gnus-server-opened () nil)
+(defun gnus-close-server () nil)
+
+(defun gnus-define-access-method (method &optional access-methods)
+  "Define access functions for the access METHOD.
+Methods defintion is taken from optional argument ACCESS-METHODS or
+the variable gnus-access-methods."
+  (let ((bindings
+	 (cdr (assoc method (or access-methods gnus-access-methods)))))
+    (if (null bindings)
+	(error "Unknown access method: %s" method)
+      ;; Should not use symbol-function here since overload does not work.
+      (while bindings
+	(fset (car (car bindings)) (cdr (car bindings)))
+	(setq bindings (cdr bindings)))
+      )))
+
+(defun gnus-select-newsgroup (group &optional show-all)
+  "Select newsgroup GROUP.
+If optional argument SHOW-ALL is non-nil, all of articles in the group
+are selected."
+  (if (gnus-request-group group)
+      (let ((articles nil))
+	(setq gnus-newsgroup-name group)
+	(setq gnus-newsgroup-unreads
+	      (gnus-uncompress-sequence
+	       (nthcdr 2 (gnus-gethash group gnus-unread-hashtb))))
+	(cond (show-all
+	       ;; Select all active articles.
+	       (setq articles
+		     (gnus-uncompress-sequence
+		      (nthcdr 2 (gnus-gethash group gnus-active-hashtb)))))
+	      (t
+	       ;; Select unread articles only.
+	       (setq articles gnus-newsgroup-unreads)))
+	;; Require confirmation if selecting large newsgroup.
+	(setq gnus-newsgroup-unselected nil)
+	(if (not (numberp gnus-large-newsgroup))
+	    nil
+	  (let ((selected nil)
+		(number (length articles)))
+	    (if (> number gnus-large-newsgroup)
+		(progn
+		  (condition-case ()
+		      (let ((input
+			     (read-string
+			      (format
+			       "How many articles from %s (default %d): "
+			       gnus-newsgroup-name number))))
+			(setq selected
+			      (if (string-equal input "")
+				  number (string-to-int input))))
+		    (quit
+		     (setq selected 0)))
+		  (cond ((and (> selected 0)
+			      (< selected number))
+			 ;; Select last N articles.
+			 (setq articles (nthcdr (- number selected) articles)))
+			((and (< selected 0)
+			      (< (- 0 selected) number))
+			 ;; Select first N articles.
+			 (setq selected (- 0 selected))
+			 (setq articles (copy-sequence articles))
+			 (setcdr (nthcdr (1- selected) articles) nil))
+			((zerop selected)
+			 (setq articles nil))
+			;; Otherwise select all.
+			)
+		  ;; Get unselected unread articles.
+		  (setq gnus-newsgroup-unselected
+			(gnus-set-difference gnus-newsgroup-unreads articles))
+		  ))
+	    ))
+	;; Get headers list.
+	(setq gnus-newsgroup-headers (gnus-retrieve-headers articles))
+	;; UNREADS may contain expired articles, so we have to remove
+	;;  them from the list.
+	(setq gnus-newsgroup-unreads
+	      (gnus-intersection gnus-newsgroup-unreads
+				 (mapcar
+				  (function
+				   (lambda (header)
+				     (nntp-header-number header)))
+				  gnus-newsgroup-headers)))
+	;; Marked article must be a subset of unread articles.
+	(setq gnus-newsgroup-marked
+	      (gnus-intersection (append gnus-newsgroup-unselected
+					 gnus-newsgroup-unreads)
+				 (cdr (assoc group gnus-marked-assoc))))
+	;; First and last article in this newsgroup.
+	(setq gnus-newsgroup-begin
+	      (if gnus-newsgroup-headers
+		  (nntp-header-number (car gnus-newsgroup-headers))
+		0
+		))
+	(setq gnus-newsgroup-end
+	      (if gnus-newsgroup-headers
+		  (nntp-header-number
+		   (gnus-last-element gnus-newsgroup-headers))
+		0
+		))
+	;; File name that an article was saved last.
+	(setq gnus-newsgroup-last-rmail nil)
+	(setq gnus-newsgroup-last-mail nil)
+	(setq gnus-newsgroup-last-folder nil)
+	(setq gnus-newsgroup-last-file nil)
+	;; Reset article pointer etc.
+	(setq gnus-current-article nil)
+	(setq gnus-current-headers nil)
+	(setq gnus-current-history nil)
+	(setq gnus-have-all-headers nil)
+	(setq gnus-last-article nil)
+	;; GROUP is successfully selected.
+	t
+	)
+    ))
+
+(defun gnus-more-header-backward ()
+  "Find new header backward."
+  (let ((first
+	 (car (nth 2 (gnus-gethash gnus-newsgroup-name gnus-active-hashtb))))
+	(artnum gnus-newsgroup-begin)
+	(header nil))
+    (while (and (not header)
+		(> artnum first))
+      (setq artnum (1- artnum))
+      (setq header (car (gnus-retrieve-headers (list artnum)))))
+    header
+    ))
+
+(defun gnus-more-header-forward ()
+  "Find new header forward."
+  (let ((last
+	 (cdr (nth 2 (gnus-gethash gnus-newsgroup-name gnus-active-hashtb))))
+	(artnum gnus-newsgroup-end)
+	(header nil))
+    (while (and (not header)
+		(< artnum last))
+      (setq artnum (1+ artnum))
+      (setq header (car (gnus-retrieve-headers (list artnum)))))
+    header
+    ))
+
+(defun gnus-extend-newsgroup (header &optional backward)
+  "Extend newsgroup selection with HEADER.
+Optional argument BACKWARD means extend toward backward."
+  (if header
+      (let ((artnum (nntp-header-number header)))
+	(setq gnus-newsgroup-headers
+	      (if backward
+		  (cons header gnus-newsgroup-headers)
+		(append gnus-newsgroup-headers (list header))))
+	;; We have to update unreads and unselected, but don't have to
+	;; care about gnus-newsgroup-marked.
+	(if (memq artnum gnus-newsgroup-unselected)
+	    (setq gnus-newsgroup-unreads
+		  (cons artnum gnus-newsgroup-unreads)))
+	(setq gnus-newsgroup-unselected
+	      (delq artnum gnus-newsgroup-unselected))
+	(setq gnus-newsgroup-begin (min gnus-newsgroup-begin artnum))
+	(setq gnus-newsgroup-end (max gnus-newsgroup-end artnum))
+	)))
+
+(defun gnus-mark-article-as-read (article)
+  "Remember that ARTICLE is marked as read."
+  ;; Remove from unread and marked list.
+  (setq gnus-newsgroup-unreads
+	(delq article gnus-newsgroup-unreads))
+  (setq gnus-newsgroup-marked
+	(delq article gnus-newsgroup-marked)))
+
+(defun gnus-mark-article-as-unread (article &optional clear-mark)
+  "Remember that ARTICLE is marked as unread.
+Optional argument CLEAR-MARK means ARTICLE should not be remembered
+that it was marked as read once."
+  ;; Add to unread list.
+  (or (memq article gnus-newsgroup-unreads)
+      (setq gnus-newsgroup-unreads
+	    (cons article gnus-newsgroup-unreads)))
+  ;; If CLEAR-MARK is non-nil, the article must be removed from marked
+  ;; list.  Otherwise, it must be added to the list.
+  (if clear-mark
+      (setq gnus-newsgroup-marked
+	    (delq article gnus-newsgroup-marked))
+    (or (memq article gnus-newsgroup-marked)
+	(setq gnus-newsgroup-marked
+	      (cons article gnus-newsgroup-marked)))))
+
+(defun gnus-clear-system ()
+  "Clear all variables and buffer."
+  ;; Clear GNUS variables.
+  (let ((variables gnus-variable-list))
+    (while variables
+      (set (car variables) nil)
+      (setq variables (cdr variables))))
+  ;; Clear other internal variables.
+  (setq gnus-active-hashtb nil)
+  (setq gnus-unread-hashtb nil)
+  ;; Kill the startup file.
+  (and gnus-current-startup-file
+       (get-file-buffer gnus-current-startup-file)
+       (kill-buffer (get-file-buffer gnus-current-startup-file)))
+  (setq gnus-current-startup-file nil)
+  ;; Kill GNUS buffers.
+  (let ((buffers gnus-buffer-list))
+    (while buffers
+      (if (get-buffer (car buffers))
+	  (kill-buffer (car buffers)))
+      (setq buffers (cdr buffers))
+      )))
+
+(defun gnus-configure-windows (action)
+  "Configure GNUS windows according to the next ACTION.
+The ACTION is either a symbol, such as `SelectNewsgroup', 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."
+  (let* ((windows
+	  (if (listp action)
+	      action (car (cdr (assq action gnus-window-configuration)))))
+	 (grpwin (get-buffer-window gnus-Group-buffer))
+	 (subwin (get-buffer-window gnus-Subject-buffer))
+	 (artwin (get-buffer-window gnus-Article-buffer))
+	 (winsum nil)
+	 (height nil)
+	 (grpheight 0)
+	 (subheight 0)
+	 (artheight 0))
+    (if (or (null windows)		;No configuration is specified.
+	    (and (eq (null grpwin)
+		     (zerop (nth 0 windows)))
+		 (eq (null subwin)
+		     (zerop (nth 1 windows)))
+		 (eq (null artwin)
+		     (zerop (nth 2 windows)))))
+	;; No need to change window configuration.
+	nil
+      (select-window (or grpwin subwin artwin (selected-window)))
+      ;; First of all, compute the height of each window.
+      (cond (gnus-use-full-window
+	     ;; Take up the entire screen.
+	     (delete-other-windows)
+	     (setq height (window-height (selected-window))))
+	    (t
+	     (setq height (+ (if grpwin (window-height grpwin) 0)
+			     (if subwin (window-height subwin) 0)
+			     (if artwin (window-height artwin) 0)))))
+      ;; The Newsgroup buffer exits always. So, use it to extend the
+      ;; Group window so as to get enough window space.
+      (switch-to-buffer gnus-Group-buffer 'norecord)
+      (and (get-buffer gnus-Subject-buffer)
+	   (delete-windows-on gnus-Subject-buffer))
+      (and (get-buffer gnus-Article-buffer)
+	   (delete-windows-on gnus-Article-buffer))
+      ;; Compute expected window height.
+      (setq winsum (apply (function +) windows))
+      (if (not (zerop (nth 0 windows)))
+	  (setq grpheight (max window-min-height
+			       (/ (* height (nth 0 windows)) winsum))))
+      (if (not (zerop (nth 1 windows)))
+	  (setq subheight (max window-min-height
+			       (/ (* height (nth 1 windows)) winsum))))
+      (if (not (zerop (nth 2 windows)))
+	  (setq artheight (max window-min-height
+			       (/ (* height (nth 2 windows)) winsum))))
+      (setq height (+ grpheight subheight artheight))
+      (enlarge-window (max 0 (- height (window-height (selected-window)))))
+      ;; Then split the window.
+      (and (not (zerop artheight))
+	   (or (not (zerop grpheight))
+	       (not (zerop subheight)))
+	   (split-window-vertically (+ grpheight subheight)))
+      (and (not (zerop grpheight))
+	   (not (zerop subheight))
+	   (split-window-vertically grpheight))
+      ;; Then select buffers in each window.
+      (and (not (zerop grpheight))
+	   (progn
+	     (switch-to-buffer gnus-Group-buffer 'norecord)
+	     (other-window 1)))
+      (and (not (zerop subheight))
+	   (progn
+	     (switch-to-buffer gnus-Subject-buffer 'norecord)
+	     (other-window 1)))
+      (and (not (zerop artheight))
+	   (progn
+	     ;; If Article buffer does not exist, it will be created
+	     ;; and initialized.
+	     (gnus-Article-setup-buffer)
+	     (switch-to-buffer gnus-Article-buffer 'norecord)))
+      )
+    ))
+
+(defun gnus-find-header-by-number (headers number)
+  "Return a header which is a element of HEADERS and has NUMBER."
+  (let ((found nil))
+    (while (and headers (not found))
+      ;; We cannot use `=' to accept non-numeric NUMBER.
+      (if (eq number (nntp-header-number (car headers)))
+	  (setq found (car headers)))
+      (setq headers (cdr headers)))
+    found
+    ))
+
+(defun gnus-find-header-by-id (headers id)
+  "Return a header which is a element of HEADERS and has Message-ID."
+  (let ((found nil))
+    (while (and headers (not found))
+      (if (string-equal id (nntp-header-id (car headers)))
+	  (setq found (car headers)))
+      (setq headers (cdr headers)))
+    found
+    ))
+
+(defun gnus-version ()
+  "Version numbers of this version of GNUS."
+  (interactive)
+  (cond ((and (boundp 'mhspool-version) (boundp 'nnspool-version))
+	 (message "%s; %s; %s; %s"
+		  gnus-version nntp-version nnspool-version mhspool-version))
+	((boundp 'mhspool-version)
+	 (message "%s; %s; %s"
+		  gnus-version nntp-version mhspool-version))
+	((boundp 'nnspool-version)
+	 (message "%s; %s; %s"
+		  gnus-version nntp-version nnspool-version))
+	(t
+	 (message "%s; %s" gnus-version nntp-version))))
+
+(defun gnus-Info-find-node ()
+  "Find Info documentation of GNUS."
+  (interactive)
+  (require 'info)
+  ;; Enlarge info window if needed.
+  (cond ((eq major-mode 'gnus-Group-mode)
+	 (gnus-configure-windows '(1 0 0)) ;Take all windows.
+	 (pop-to-buffer gnus-Group-buffer))
+	((eq major-mode 'gnus-Subject-mode)
+	 (gnus-configure-windows '(0 1 0)) ;Take all windows.
+	 (pop-to-buffer gnus-Subject-buffer)))
+  (Info-goto-node (cdr (assq major-mode gnus-Info-nodes))))
+
+(defun gnus-overload-functions (&optional overloads)
+  "Overload functions specified by optional argument OVERLOADS.
+If nothing is specified, use the variable gnus-overload-functions."
+  (let ((defs nil)
+	(overloads (or overloads gnus-overload-functions)))
+    (while overloads
+      (setq defs (car overloads))
+      (setq overloads (cdr overloads))
+      ;; Load file before overloading function if necessary.  Make
+      ;; sure we cannot use `requre' always.
+      (and (not (fboundp (car defs)))
+	   (car (cdr (cdr defs)))
+	   (load (car (cdr (cdr defs))) nil 'nomessage))
+      (fset (car defs) (car (cdr defs)))
+      )))
+
+(defun gnus-make-threads (newsgroup-headers)
+  "Make conversation threads tree from NEWSGROUP-HEADERS."
+  (let ((headers newsgroup-headers)
+	(h nil)
+	(d nil)
+	(roots nil)
+	(dependencies nil))
+    ;; Make message dependency alist.
+    (while headers
+      (setq h (car headers))
+      (setq headers (cdr headers))
+      ;; Ignore invalid headers.
+      (if (vectorp h)			;Depends on nntp.el.
+	  (progn
+	    ;; Ignore broken references, e.g "<123@a.b.c".
+	    (setq d (and (nntp-header-references h)
+			 (string-match "\\(<[^<>]+>\\)[^>]*$"
+				       (nntp-header-references h))
+			 (gnus-find-header-by-id
+			  newsgroup-headers
+			  (substring (nntp-header-references h)
+				     (match-beginning 1) (match-end 1)))))
+	    ;; Check subject equality.
+	    (or gnus-thread-ignore-subject
+		(null d)
+		(string-equal (gnus-simplify-subject
+			       (nntp-header-subject h) 're)
+			      (gnus-simplify-subject
+			       (nntp-header-subject d) 're))
+		;; H should be a thread root.
+		(setq d nil))
+	    ;; H depends on D.
+	    (setq dependencies
+		  (cons (cons h d) dependencies))
+	    ;; H is a thread root.
+	    (if (null d)
+		(setq roots (cons h roots)))
+	    ))
+      )
+    ;; Make complete threads from the roots.
+    ;; Note: dependencies are in reverse order, but
+    ;; gnus-make-threads-1 processes it in reverse order again.  So,
+    ;; we don't have to worry about it.
+    (mapcar
+     (function
+      (lambda (root)
+	(gnus-make-threads-1 root dependencies))) (nreverse roots))
+    ))
+
+(defun gnus-make-threads-1 (parent dependencies)
+  (let ((children nil)
+	(d nil)
+	(depends dependencies))
+    ;; Find children.
+    (while depends
+      (setq d (car depends))
+      (setq depends (cdr depends))
+      (and (cdr d)
+	   (eq (nntp-header-id parent) (nntp-header-id (cdr d)))
+	   (setq children (cons (car d) children))))
+    ;; Go down.
+    (cons parent
+	  (mapcar
+	   (function
+	    (lambda (child)
+	      (gnus-make-threads-1 child dependencies))) children))
+    ))
+
+(defun gnus-narrow-to-page (&optional arg)
+  "Make text outside current page invisible except for page delimiter.
+A numeric arg specifies to move forward or backward by that many pages,
+thus showing a page other than the one point was originally in."
+  (interactive "P")
+  (setq arg (if arg (prefix-numeric-value arg) 0))
+  (save-excursion
+    (forward-page -1)			;Beginning of current page.
+    (widen)
+    (if (> arg 0)
+	(forward-page arg)
+      (if (< arg 0)
+	  (forward-page (1- arg))))
+    ;; Find the end of the page.
+    (forward-page)
+    ;; If we stopped due to end of buffer, stay there.
+    ;; If we stopped after a page delimiter, put end of restriction
+    ;; at the beginning of that line.
+    ;; These are commented out.
+    ;;    (if (save-excursion (beginning-of-line)
+    ;;			(looking-at page-delimiter))
+    ;;	(beginning-of-line))
+    (narrow-to-region (point)
+		      (progn
+			;; Find the top of the page.
+			(forward-page -1)
+			;; If we found beginning of buffer, stay there.
+			;; If extra text follows page delimiter on same line,
+			;; include it.
+			;; Otherwise, show text starting with following line.
+			(if (and (eolp) (not (bobp)))
+			    (forward-line 1))
+			(point)))
+    ))
+
+(defun gnus-last-element (list)
+  "Return last element of LIST."
+  (let ((last nil))
+    (while list
+      (if (null (cdr list))
+	  (setq last (car list)))
+      (setq list (cdr list)))
+    last
+    ))
+
+(defun gnus-set-difference (list1 list2)
+  "Return a list of elements of LIST1 that do not appear in LIST2."
+  (let ((list1 (copy-sequence list1)))
+    (while list2
+      (setq list1 (delq (car list2) list1))
+      (setq list2 (cdr list2)))
+    list1
+    ))
+
+(defun gnus-intersection (list1 list2)
+  "Return a list of elements that appear in both LIST1 and LIST2."
+  (let ((result nil))
+    (while list2
+      (if (memq (car list2) list1)
+	  (setq result (cons (car list2) result)))
+      (setq list2 (cdr list2)))
+    result
+    ))
+
+
+;;;
+;;; Get information about active articles, already read articles, and
+;;;  still unread articles.
+;;;
+
+;; GNUS internal format of gnus-newsrc-assoc and gnus-killed-assoc:
+;; (("general" t (1 . 1))
+;;  ("misc"    t (1 . 10) (12 . 15))
+;;  ("test"  nil (1 . 99)) ...)
+;; GNUS internal format of gnus-marked-assoc:
+;; (("general" 1 2 3)
+;;  ("misc" 2) ...)
+;; GNUS internal format of gnus-active-hashtb:
+;; (("general" t (1 . 1))
+;;  ("misc"    t (1 . 10))
+;;  ("test"  nil (1 . 99)) ...)
+;; GNUS internal format of gnus-unread-hashtb:
+;; (("general" 1 (1 . 1))
+;;  ("misc"   14 (1 . 10) (12 . 15))
+;;  ("test"   99 (1 . 99)) ...)
+
+(defun gnus-setup-news-info (&optional rawfile)
+  "Setup news information.
+If optional argument RAWFILE is non-nil, force to read raw startup file."
+  (let ((init (not (and gnus-newsrc-assoc
+			gnus-active-hashtb
+			gnus-unread-hashtb
+			(not rawfile)
+			))))
+    ;; We have to clear some variables to re-initialize news info.
+    (if init
+	(setq gnus-newsrc-assoc nil
+	      gnus-active-hashtb nil
+	      gnus-unread-hashtb nil))
+    (if init
+	(gnus-read-newsrc-file rawfile))
+    (gnus-read-active-file)
+    (gnus-expire-marked-articles)
+    (gnus-get-unread-articles)
+    ;; Check new newsgroups and subscribe them.
+    (if init
+	(let ((new-newsgroups (gnus-find-new-newsgroups)))
+	  (while new-newsgroups
+	    (funcall gnus-subscribe-newsgroup-method (car new-newsgroups))
+	    (setq new-newsgroups (cdr new-newsgroups))
+	    )))
+    ))
+
+(defun gnus-subscribe-newsgroup (newsgroup &optional next)
+  "Subscribe new NEWSGROUP.
+If optional argument NEXT is non-nil, it is inserted before NEXT."
+  (gnus-insert-newsgroup (list newsgroup t) next)
+  (message "Newsgroup %s is subscribed" newsgroup))
+
+(defun gnus-add-newsgroup (newsgroup)
+  "Subscribe new NEWSGROUP safely and put it at top."
+  (and (null (assoc newsgroup gnus-newsrc-assoc)) ;Really new?
+       (gnus-gethash newsgroup gnus-active-hashtb) ;Really exist?
+       (gnus-insert-newsgroup (or (assoc newsgroup gnus-killed-assoc)
+				  (list newsgroup t))
+			      (car (car gnus-newsrc-assoc)))))
+
+(defun gnus-find-new-newsgroups ()
+  "Looking for new newsgroups and return names.
+`-n' option of options line in .newsrc file is recognized."
+  (let ((group nil)
+	(new-newsgroups nil))
+    (mapatoms
+     (function
+      (lambda (sym)
+	(setq group (symbol-name sym))
+	;; Taking account of `-n' option.
+	(and (or (null gnus-newsrc-options-n-no)
+		 (not (string-match gnus-newsrc-options-n-no group))
+		 (and gnus-newsrc-options-n-yes
+		      (string-match gnus-newsrc-options-n-yes group)))
+	     (null (assoc group gnus-killed-assoc)) ;Ignore killed.
+	     (null (assoc group gnus-newsrc-assoc)) ;Really new.
+	     ;; Find new newsgroup.
+	     (setq new-newsgroups
+		   (cons group new-newsgroups)))
+	))
+     gnus-active-hashtb)
+    ;; Return new newsgroups.
+    new-newsgroups
+    ))
+
+(defun gnus-kill-newsgroup (group)
+  "Kill GROUP from gnus-newsrc-assoc, .newsrc and gnus-unread-hashtb."
+  (let ((info (assoc group gnus-newsrc-assoc)))
+    (if (null info)
+	nil
+      ;; Delete from gnus-newsrc-assoc
+      (setq gnus-newsrc-assoc (delq info gnus-newsrc-assoc))
+      ;; Add to gnus-killed-assoc.
+      (setq gnus-killed-assoc
+	    (cons info
+		  (delq (assoc group gnus-killed-assoc) gnus-killed-assoc)))
+      ;; Clear unread hashtable.
+      ;; Thanks cwitty@csli.Stanford.EDU (Carl Witty).
+      (gnus-sethash group nil gnus-unread-hashtb)
+      ;; Then delete from .newsrc
+      (gnus-update-newsrc-buffer group 'delete)
+      ;; Return the deleted newsrc entry.
+      info
+      )))
+
+(defun gnus-insert-newsgroup (info &optional next)
+  "Insert newsrc INFO entry before NEXT.
+If optional argument NEXT is nil, appended to the last."
+  (if (null info)
+      (error "Invalid argument: %s" info))
+  (let* ((group (car info))		;Newsgroup name.
+	 (range
+	  (gnus-difference-of-range
+	   (nth 2 (gnus-gethash group gnus-active-hashtb)) (nthcdr 2 info))))
+    ;; Check duplication.
+    (if (assoc group gnus-newsrc-assoc)
+	(error "Duplicated: %s" group))
+    ;; Insert to gnus-newsrc-assoc.
+    (if (string-equal next (car (car gnus-newsrc-assoc)))
+	(setq gnus-newsrc-assoc
+	      (cons info gnus-newsrc-assoc))
+      (let ((found nil)
+	    (rest gnus-newsrc-assoc)
+	    (tail (cons nil gnus-newsrc-assoc)))
+	;; Seach insertion point.
+	(while (and (not found) rest)
+	  (if (string-equal next (car (car rest)))
+	      (setq found t)
+	    (setq rest (cdr rest))
+	    (setq tail (cdr tail))
+	    ))
+	;; Find it.
+	(setcdr tail nil)
+	(setq gnus-newsrc-assoc
+	      (append gnus-newsrc-assoc (cons info rest)))
+	))
+    ;; Delete from gnus-killed-assoc.
+    (setq gnus-killed-assoc
+	  (delq (assoc group gnus-killed-assoc) gnus-killed-assoc))
+    ;; Then insert to .newsrc.
+    (gnus-update-newsrc-buffer group nil next)
+    ;; Add to gnus-unread-hashtb.
+    (gnus-sethash group
+		  (cons group		;Newsgroup name.
+			(cons (gnus-number-of-articles range) range))
+		  gnus-unread-hashtb)
+    ))
+
+(defun gnus-check-killed-newsgroups ()
+  "Check consistency between gnus-newsrc-assoc and gnus-killed-assoc."
+  (let ((group nil)
+	(new-killed nil)
+	(old-killed gnus-killed-assoc))
+    (while old-killed
+      (setq group (car (car old-killed)))
+      (and (or (null gnus-newsrc-options-n-no)
+	       (not (string-match gnus-newsrc-options-n-no group))
+	       (and gnus-newsrc-options-n-yes
+		    (string-match gnus-newsrc-options-n-yes group)))
+	   (null (assoc group gnus-newsrc-assoc)) ;No duplication.
+	   ;; Subscribed in options line and not in gnus-newsrc-assoc.
+	   (setq new-killed
+		 (cons (car old-killed) new-killed)))
+      (setq old-killed (cdr old-killed))
+      )
+    (setq gnus-killed-assoc (nreverse new-killed))
+    ))
+
+(defun gnus-check-bogus-newsgroups (&optional confirm)
+  "Delete bogus newsgroups.
+If optional argument CONFIRM is non-nil, confirm deletion of newsgroups."
+  (let ((group nil)			;Newsgroup name temporary used.
+	(old-newsrc gnus-newsrc-assoc)
+	(new-newsrc nil)
+	(bogus nil)			;List of bogus newsgroups.
+	(old-killed gnus-killed-assoc)
+	(new-killed nil)
+	(old-marked gnus-marked-assoc)
+	(new-marked nil))
+    (message "Checking bogus newsgroups...")
+    ;; Update gnus-newsrc-assoc.
+    (while old-newsrc
+      (setq group (car (car old-newsrc)))
+      (if (or (gnus-gethash group gnus-active-hashtb)
+	      (and confirm
+		   (not (y-or-n-p
+			 (format "Delete bogus newsgroup: %s " group)))))
+	  ;; Active newsgroup.
+	  (setq new-newsrc (cons (car old-newsrc) new-newsrc))
+	;; Found a bogus newsgroup.
+	(setq bogus (cons group bogus)))
+      (setq old-newsrc (cdr old-newsrc))
+      )
+    (setq gnus-newsrc-assoc (nreverse new-newsrc))
+    ;; Update gnus-killed-assoc.
+    ;; The killed newsgroups are deleted without any confirmations.
+    (while old-killed
+      (setq group (car (car old-killed)))
+      (and (gnus-gethash group gnus-active-hashtb)
+	   (null (assoc group gnus-newsrc-assoc))
+	   ;; Active and really killed newsgroup.
+	   (setq new-killed (cons (car old-killed) new-killed)))
+      (setq old-killed (cdr old-killed))
+      )
+    (setq gnus-killed-assoc (nreverse new-killed))
+    ;; Remove BOGUS from .newsrc file.
+    (while bogus
+      (gnus-update-newsrc-buffer (car bogus) 'delete)
+      (setq bogus (cdr bogus)))
+    ;; Update gnus-marked-assoc.
+    (while old-marked
+      (setq group (car (car old-marked)))
+      (if (and (cdr (car old-marked))	;Non-empty?
+	       (assoc group gnus-newsrc-assoc))	;Not bogus?
+	  (setq new-marked (cons (car old-marked) new-marked)))
+      (setq old-marked (cdr old-marked)))
+    (setq gnus-marked-assoc new-marked)
+    (message "Checking bogus newsgroups... done")
+    ))
+
+(defun gnus-get-unread-articles ()
+  "Compute diffs between active and read articles."
+  (let ((read gnus-newsrc-assoc)
+	(group-info nil)
+	(group-name nil)
+	(active nil)
+	(range nil))
+    (message "Checking new news...")
+    (or gnus-unread-hashtb
+	(setq gnus-unread-hashtb (gnus-make-hashtable)))
+    (while read
+      (setq group-info (car read))	;About one newsgroup
+      (setq group-name (car group-info))
+      (setq active (nth 2 (gnus-gethash group-name gnus-active-hashtb)))
+      (if (and gnus-octive-hashtb
+	       ;; Is nothing changed?
+	       (equal active
+		      (nth 2 (gnus-gethash group-name gnus-octive-hashtb)))
+	       ;; Is this newsgroup in the unread hash table?
+	       (gnus-gethash group-name gnus-unread-hashtb)
+	       )
+	  nil				;Nothing to do.
+	(setq range (gnus-difference-of-range active (nthcdr 2 group-info)))
+	(gnus-sethash group-name
+		      (cons group-name	;Group name
+			    (cons (gnus-number-of-articles range)
+				  range)) ;Range of unread articles
+		      gnus-unread-hashtb)
+	)
+      (setq read (cdr read))
+      )
+    (message "Checking new news... done")
+    ))
+
+(defun gnus-expire-marked-articles ()
+  "Check expired article which is marked as unread."
+  (let ((marked-assoc gnus-marked-assoc)
+	(updated-assoc nil)
+	(marked nil)			;Current marked info.
+	(articles nil)			;List of marked articles.
+	(updated nil)			;List of real marked.
+	(begin nil))
+    (while marked-assoc
+      (setq marked (car marked-assoc))
+      (setq articles (cdr marked))
+      (setq updated nil)
+      (setq begin
+	    (car (nth 2 (gnus-gethash (car marked) gnus-active-hashtb))))
+      (while (and begin articles)
+	(if (>= (car articles) begin)
+	    ;; This article is still active.
+	    (setq updated (cons (car articles) updated)))
+	(setq articles (cdr articles)))
+      (if updated
+	  (setq updated-assoc
+		(cons (cons (car marked) updated) updated-assoc)))
+      (setq marked-assoc (cdr marked-assoc)))
+    (setq gnus-marked-assoc updated-assoc)
+    ))
+
+(defun gnus-mark-as-read-by-xref
+  (group headers unreads &optional subscribed-only)
+  "Mark articles as read using cross references and return updated newsgroups.
+Arguments are GROUP, HEADERS, UNREADS, and optional SUBSCRIBED-ONLY."
+  (let ((xref-list nil)
+	(header nil)
+	(xrefs nil)			;One Xref: field info.
+	(xref nil)			;(NEWSGROUP . ARTICLE)
+	(gname nil)			;Newsgroup name
+	(article nil))			;Article number
+    (while headers
+      (setq header (car headers))
+      (if (memq (nntp-header-number header) unreads)
+	  ;; This article is not yet marked as read.
+	  nil
+	(setq xrefs (gnus-parse-xref-field (nntp-header-xref header)))
+	;; For each cross reference info. in one Xref: field.
+	(while xrefs
+	  (setq xref (car xrefs))
+	  (setq gname (car xref))	;Newsgroup name
+	  (setq article (cdr xref))	;Article number
+	  (or (string-equal group gname) ;Ignore current newsgroup.
+	      ;; Ignore unsubscribed newsgroup if requested.
+	      (and subscribed-only
+		   (not (nth 1 (assoc gname gnus-newsrc-assoc))))
+	      ;; Ignore article marked as unread.
+	      (memq article (cdr (assoc gname gnus-marked-assoc)))
+	      (let ((group-xref (assoc gname xref-list)))
+		(if group-xref
+		    (if (memq article (cdr group-xref))
+			nil		;Alread marked.
+		      (setcdr group-xref (cons article (cdr group-xref))))
+		  ;; Create new assoc entry for GROUP.
+		  (setq xref-list (cons (list gname article) xref-list)))
+		))
+	  (setq xrefs (cdr xrefs))
+	  ))
+      (setq headers (cdr headers)))
+    ;; Mark cross referenced articles as read.
+    (gnus-mark-xrefed-as-read xref-list)
+    ;;(message "%s %s" (prin1-to-string unreads) (prin1-to-string xref-list))
+    ;; Return list of updated group name.
+    (mapcar (function car) xref-list)
+    ))
+
+(defun gnus-parse-xref-field (xref-value)
+  "Parse Xref: field value, and return list of `(group . article-id)'."
+  (let ((xref-list nil)
+	(xref-value (or xref-value "")))
+    ;; Remove server host name.
+    (if (string-match "^[ \t]*[^ \t,]+[ \t,]+\\(.*\\)$" xref-value)
+	(setq xref-value (substring xref-value (match-beginning 1)))
+      (setq xref-value nil))
+    ;; Process each xref info.
+    (while xref-value
+      (if (string-match
+	   "^[ \t,]*\\([^ \t,]+\\):\\([0-9]+\\)[^0-9]*" xref-value)
+	  (progn
+	    (setq xref-list
+		  (cons
+		   (cons
+		    ;; Group name
+		    (substring xref-value (match-beginning 1) (match-end 1))
+		    ;; Article-ID
+		    (string-to-int
+		     (substring xref-value (match-beginning 2) (match-end 2))))
+		   xref-list))
+	    (setq xref-value (substring xref-value (match-end 2))))
+	(setq xref-value nil)))
+    ;; Return alist.
+    xref-list
+    ))
+
+(defun gnus-mark-xrefed-as-read (xrefs)
+  "Update unread article information using XREFS alist."
+  (let ((group nil)
+	(idlist nil)
+	(unread nil))
+    (while xrefs
+      (setq group (car (car xrefs)))
+      (setq idlist (cdr (car xrefs)))
+      (setq unread (gnus-uncompress-sequence
+		    (nthcdr 2 (gnus-gethash group gnus-unread-hashtb))))
+      (while idlist
+	(setq unread (delq (car idlist) unread))
+	(setq idlist (cdr idlist)))
+      (gnus-update-unread-articles group unread 'ignore)
+      (setq xrefs (cdr xrefs))
+      )))
+
+(defun gnus-update-unread-articles (group unread-list marked-list)
+  "Update unread articles of GROUP using UNREAD-LIST and MARKED-LIST."
+  (let ((active (nth 2 (gnus-gethash group gnus-active-hashtb)))
+	(unread (gnus-gethash group gnus-unread-hashtb)))
+    (if (or (null active) (null unread))
+	;; Ignore unknown newsgroup.
+	nil
+      ;; Update gnus-unread-hashtb.
+      (if unread-list
+	  (setcdr (cdr unread)
+		  (gnus-compress-sequence unread-list))
+	;; All of the articles are read.
+	(setcdr (cdr unread) '((0 . 0))))
+      ;; Number of unread articles.
+      (setcar (cdr unread)
+	      (gnus-number-of-articles (nthcdr 2 unread)))
+      ;; Update gnus-newsrc-assoc.
+      (if (> (car active) 0)
+	  ;; Articles from 1 to N are not active.
+	  (setq active (cons 1 (cdr active))))
+      (setcdr (cdr (assoc group gnus-newsrc-assoc))
+	      (gnus-difference-of-range active (nthcdr 2 unread)))
+      ;; Update .newsrc buffer.
+      (gnus-update-newsrc-buffer group)
+      ;; Update gnus-marked-assoc.
+      (if (listp marked-list)		;Includes NIL.
+	  (let ((marked (assoc group gnus-marked-assoc)))
+	    (cond (marked
+		   (setcdr marked marked-list))
+		  (marked-list		;Non-NIL.
+		   (setq gnus-marked-assoc
+			 (cons (cons group marked-list)
+			       gnus-marked-assoc)))
+		  )))
+      )))
+
+(defun gnus-read-active-file ()
+  "Get active file from NNTP server."
+  (message "Reading active file...")
+  (if (gnus-request-list)		;Get active file from server
+      (save-excursion
+	(set-buffer nntp-server-buffer)
+	;; Save OLD active info.
+	(setq gnus-octive-hashtb gnus-active-hashtb)
+	(setq gnus-active-hashtb (gnus-make-hashtable))
+	(gnus-active-to-gnus-format)
+	(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."
+  ;; Delete unnecessary lines.
+  (goto-char (point-min))
+  (delete-matching-lines "^to\\..*$")
+  ;; Store active file in hashtable.
+  (goto-char (point-min))
+  (while
+      (re-search-forward
+       "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([ymn]\\).*$"
+       nil t)
+    (gnus-sethash
+     (buffer-substring (match-beginning 1) (match-end 1))
+     (list (buffer-substring (match-beginning 1) (match-end 1))
+	   (string-equal
+	    "y" (buffer-substring (match-beginning 4) (match-end 4)))
+	   (cons (string-to-int
+		  (buffer-substring (match-beginning 3) (match-end 3)))
+		 (string-to-int
+		  (buffer-substring (match-beginning 2) (match-end 2)))))
+     gnus-active-hashtb)))
+
+(defun gnus-read-newsrc-file (&optional rawfile)
+  "Read startup FILE.
+If optional argument RAWFILE is non-nil, the raw startup file is read."
+  (setq gnus-current-startup-file
+	(let* ((file (expand-file-name gnus-startup-file nil))
+	       (real-file (concat file "-" gnus-nntp-server)))
+	  (if (file-exists-p real-file)
+	      real-file file)))
+  ;; Reset variables which may be included in the quick startup file.
+  (let ((variables gnus-variable-list))
+    (while variables
+      (set (car variables) nil)
+      (setq variables (cdr variables))))
+  (let* ((newsrc-file gnus-current-startup-file)
+	 (quick-file (concat newsrc-file ".el"))
+	 (quick-loaded nil)
+	 (newsrc-mod (nth 5 (file-attributes newsrc-file)))
+	 (quick-mod (nth 5 (file-attributes quick-file))))
+    (save-excursion
+      ;; Prepare .newsrc buffer.
+      (set-buffer (find-file-noselect newsrc-file))
+      ;; It is not so good idea turning off undo.
+      ;;(buffer-flush-undo (current-buffer))
+      ;; Load quick .newsrc to restore gnus-marked-assoc and
+      ;; gnus-killed-assoc even if gnus-newsrc-assoc is out of date.
+      (condition-case nil
+	  (setq quick-loaded (load quick-file t t t))
+	(error nil))
+      (cond ((and (not rawfile)		;Not forced to read the raw file.
+		  (or (and (fboundp 'file-newer-than-file-p)
+			   (file-newer-than-file-p quick-file newsrc-file))
+		      (and newsrc-mod quick-mod
+			   ;; .newsrc.el is newer than .newsrc.
+			   ;; Some older version does not support function
+			   ;; `file-newer-than-file-p'.
+			   (or (< (car newsrc-mod) (car quick-mod))
+			       (and (= (car newsrc-mod) (car quick-mod))
+				    (<= (nth 1 newsrc-mod) (nth 1 quick-mod))))
+			   ))
+		  quick-loaded
+		  gnus-newsrc-assoc	;Really loaded?
+		  )
+	     ;; We don't have to read the raw startup file.
+	     )
+	    (t
+	     ;; Since .newsrc file is newer than quick file, read it.
+	     (message "Reading %s..." newsrc-file)
+	     (gnus-newsrc-to-gnus-format)
+	     (gnus-check-killed-newsgroups)
+	     (message "Reading %s... Done" newsrc-file)))
+      )))
+
+(defun gnus-make-newsrc-file (file)
+  "Make server dependent file name by catenating FILE and server host name."
+  (let* ((file (expand-file-name file nil))
+	 (real-file (concat file "-" gnus-nntp-server)))
+    (if (file-exists-p real-file)
+	real-file file)
+    ))
+
+(defun gnus-newsrc-to-gnus-format ()
+  "Parse current buffer as .newsrc file."
+  (let ((newsgroup nil)
+	(subscribe nil)
+	(ranges nil)
+	(subrange nil)
+	(read-list nil))
+    ;; We have to re-initialize these variable (except for
+    ;; gnus-marked-assoc and gnus-killed-assoc) because quick startup
+    ;; file may contain bogus values.
+    (setq gnus-newsrc-options nil)
+    (setq gnus-newsrc-options-n-yes nil)
+    (setq gnus-newsrc-options-n-no nil)
+    (setq gnus-newsrc-assoc nil)
+    ;; Save options line to variable.
+    ;; Lines beginning with white spaces are treated as continuation
+    ;; line.  Refer man page of newsrc(5).
+    (goto-char (point-min))
+    (if (re-search-forward
+	 "^[ \t]*options[ \t]*\\(.*\\(\n[ \t]+.*\\)*\\)[ \t]*$" nil t)
+	(progn
+	  ;; Save entire options line.
+	  (setq gnus-newsrc-options
+		(buffer-substring (match-beginning 1) (match-end 1)))
+	  ;; Compile "-n" option.
+	  (if (string-match "\\(^\\|[ \t\n]\\)-n" gnus-newsrc-options)
+	      (let ((yes-and-no
+		     (gnus-parse-n-options
+		      (substring gnus-newsrc-options (match-end 0)))))
+		(setq gnus-newsrc-options-n-yes (car yes-and-no))
+		(setq gnus-newsrc-options-n-no  (cdr yes-and-no))
+		))
+	  ))
+    ;; Parse body of .newsrc file
+    ;; Options line continuation lines must be also considered here.
+    ;; 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:
+    ;; "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(.*\\)$"
+    ;; Suggested by composer@bucsf.bu.edu (Jeff Kellem).
+    (while (re-search-forward
+	    "^\\([^:! \t\n]+\\)\\([:!]\\)[ \t]*\\(\\(...\\)*.*\\)$" nil t)
+      (setq newsgroup (buffer-substring (match-beginning 1) (match-end 1)))
+      ;; Check duplications of newsgroups.
+      ;; Note: Checking the duplications takes very long time.
+      (if (assoc newsgroup gnus-newsrc-assoc)
+	  (message "Ignore duplicated newsgroup: %s" newsgroup)
+	(setq subscribe
+	      (string-equal
+	       ":" (buffer-substring (match-beginning 2) (match-end 2))))
+	(setq ranges (buffer-substring (match-beginning 3) (match-end 3)))
+	(setq read-list nil)
+	(while (string-match "^[, \t]*\\([0-9-]+\\)" ranges)
+	  (setq subrange (substring ranges (match-beginning 1) (match-end 1)))
+	  (setq ranges (substring ranges (match-end 1)))
+	  (cond ((string-match "^\\([0-9]+\\)-\\([0-9]+\\)$" subrange)
+		 (setq read-list
+		       (cons
+			(cons (string-to-int
+			       (substring subrange
+					  (match-beginning 1) (match-end 1)))
+			      (string-to-int
+			       (substring subrange
+					  (match-beginning 2) (match-end 2))))
+			read-list)))
+		((string-match "^[0-9]+$" subrange)
+		 (setq read-list
+		       (cons (cons (string-to-int subrange)
+				   (string-to-int subrange))
+			     read-list)))
+		(t
+		 (ding) (message "Ignoring bogus lines of %s" newsgroup)
+		 (sit-for 0))
+		))
+	(setq gnus-newsrc-assoc
+	      (cons (cons newsgroup (cons subscribe (nreverse read-list)))
+		    gnus-newsrc-assoc))
+	))
+    (setq gnus-newsrc-assoc
+	  (nreverse gnus-newsrc-assoc))
+    ))
+
+(defun gnus-parse-n-options (options)
+  "Parse -n NEWSGROUPS options and return a cons of YES and NO regexps."
+  (let ((yes nil)
+	(no nil)
+	(yes-or-no nil)			;`!' or not.
+	(newsgroup nil))
+    ;; 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)
+      (setq yes-or-no
+	    (substring options (match-beginning 1) (match-end 1)))
+      (setq newsgroup
+	    (regexp-quote
+	     (substring options
+			(match-beginning 2) (match-end 2))))
+      (setq options (substring options (match-end 2)))
+      ;; Rewrite "all" to ".+" not ".*".  ".+" requires at least one
+      ;; character.
+      (while (string-match "\\(^\\|\\\\[.]\\)all\\(\\\\[.]\\|$\\)" newsgroup)
+	(setq newsgroup
+	      (concat (substring newsgroup 0 (match-end 1))
+		      ".+"
+		      (substring newsgroup (match-beginning 2)))))
+      (cond ((string-equal yes-or-no "!")
+	     (setq no (cons newsgroup no)))
+	    ((string-equal newsgroup ".+")) ;Ignore `all'.
+	    (t
+	     (setq yes (cons newsgroup yes)))
+	    ))
+    ;; Make a cons of regexps from parsing result.
+    (cons (if yes
+	      (concat "^\\("
+		      (apply (function concat)
+			     (mapcar
+			      (function
+			       (lambda (newsgroup)
+				 (concat newsgroup "\\|")))
+			      (cdr yes)))
+		      (car yes) "\\)"))
+	  (if no
+	      (concat "^\\("
+		      (apply (function concat)
+			     (mapcar
+			      (function
+			       (lambda (newsgroup)
+				 (concat newsgroup "\\|")))
+			      (cdr no)))
+		      (car no) "\\)")))
+    ))
+
+(defun gnus-save-newsrc-file ()
+  "Save to .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)
+       gnus-current-startup-file
+       (save-excursion
+	 ;; A buffer containing .newsrc file may be deleted.
+	 (set-buffer (find-file-noselect gnus-current-startup-file))
+	 (if (not (buffer-modified-p))
+	     (message "(No changes need to be saved)")
+	   (message "Saving %s..." gnus-current-startup-file)
+	   (let ((make-backup-files t)
+		 (version-control nil)
+		 (require-final-newline t)) ;Don't ask even if requested.
+	     ;; Make backup file of master newsrc.
+	     ;; You can stop or change version control of backup file.
+	     ;; Suggested by jason@violet.berkeley.edu.
+	     (run-hooks 'gnus-Save-newsrc-hook)
+	     (save-buffer))
+	   ;; Quickly loadable .newsrc.
+	   (set-buffer (get-buffer-create " *GNUS-newsrc*"))
+	   (buffer-flush-undo (current-buffer))
+	   (erase-buffer)
+	   (gnus-gnus-to-quick-newsrc-format)
+	   (let ((make-backup-files nil)
+		 (version-control nil)
+		 (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)
+	   ))
+    ))
+
+(defun gnus-update-newsrc-buffer (group &optional delete next)
+  "Incrementally update .newsrc buffer about GROUP.
+If optional second argument DELETE is non-nil, delete the group.
+If optional third argument NEXT is non-nil, inserted before it."
+  (save-excursion
+    ;; Taking account of the killed startup file.
+    ;; Suggested by tale@pawl.rpi.edu.
+    (set-buffer (or (get-file-buffer gnus-current-startup-file)
+		    (find-file-noselect gnus-current-startup-file)))
+    ;; Options line continuation lines must be also considered here.
+    ;; Before supporting continuation lines, " newsgroup ! 1-5" was
+    ;; okay, but now it is invalid.  It should be "newsgroup! 1-5".
+    (let ((deleted nil)
+	  (buffer-read-only nil))	;May be not modifiable.
+      ;; Delete ALL entries which match for GROUP.
+      (goto-char (point-min))
+      (while (re-search-forward
+	      (concat "^" (regexp-quote group) "[:!]") nil t)
+	(beginning-of-line)
+	(delete-region (point) (progn (forward-line 1) (point)))
+	(setq deleted t)		;Old entry is deleted.
+	)
+      (if delete
+	  nil
+	;; Insert group entry.
+	(let ((newsrc (assoc group gnus-newsrc-assoc)))
+	  (if (null newsrc)
+	      nil
+	    ;; Find insertion point.
+	    (cond (deleted nil)		;Insert here.
+		  ((and (stringp next)
+			(progn
+			  (goto-char (point-min))
+			  (re-search-forward
+			   (concat "^" (regexp-quote next) "[:!]") nil t)))
+		   (beginning-of-line))
+		  (t
+		   (goto-char (point-max))
+		   (or (bolp)
+		       (insert "\n"))))
+	    ;; Insert after options line.
+	    (if (looking-at "^[ \t]*options\\([ \t]\\|$\\)")
+		(progn
+		  (forward-line 1)
+		  ;; Skip continuation lines.
+		  (while (and (not (eobp))
+			      (looking-at "^[ \t]+"))
+		    (forward-line 1))))
+	    (insert group		;Group name
+		    (if (nth 1 newsrc) ": " "! ")) ;Subscribed?
+	    (gnus-ranges-to-newsrc-format (nthcdr 2 newsrc)) ;Read articles
+	    (insert "\n")
+	    )))
+      )))
+
+(defun gnus-gnus-to-quick-newsrc-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)
+	(variables gnus-variable-list)
+	;; Temporary rebind to make changes invisible.
+	(gnus-killed-assoc gnus-killed-assoc))
+    ;; Remove duplicated or unsubscribed newsgroups in gnus-killed-assoc.
+    (gnus-check-killed-newsgroups)
+    ;; Then, insert lisp expressions.
+    (while variables
+      (setq variable (car variables))
+      (and (boundp variable)
+	   (symbol-value variable)
+	   (insert "(setq " (symbol-name variable) " '"
+		   (prin1-to-string (symbol-value variable))
+		   ")\n"))
+      (setq variables (cdr variables)))
+    ))
+
+(defun gnus-ranges-to-newsrc-format (ranges)
+  "Insert ranges of read articles."
+  (let ((range nil))			;Range is a pair of BEGIN and END.
+    (while ranges
+      (setq range (car ranges))
+      (setq ranges (cdr ranges))
+      (cond ((= (car range) (cdr range))
+	     (if (= (car range) 0)
+		 (setq ranges nil)	;No unread articles.
+	       (insert (int-to-string (car range)))
+	       (if ranges (insert ","))
+	       ))
+	    (t
+	     (insert (int-to-string (car range))
+		     "-"
+		     (int-to-string (cdr range)))
+	     (if ranges (insert ","))
+	     ))
+      )))
+
+(defun gnus-compress-sequence (numbers)
+  "Convert list of sorted numbers to ranges."
+  (let* ((numbers (sort (copy-sequence numbers) (function <)))
+	 (first (car numbers))
+	 (last (car numbers))
+	 (result nil))
+    (while numbers
+      (cond ((= last (car numbers)) nil) ;Omit duplicated number
+	    ((= (1+ last) (car numbers)) ;Still in sequence
+	     (setq last (car numbers)))
+	    (t				;End of one sequence
+	     (setq result (cons (cons first last) result))
+	     (setq first (car numbers))
+	     (setq last  (car numbers)))
+	    )
+      (setq numbers (cdr numbers))
+      )
+    (nreverse (cons (cons first last) result))
+    ))
+
+(defun gnus-uncompress-sequence (ranges)
+  "Expand compressed format of sequence."
+  (let ((first nil)
+	(last  nil)
+	(result nil))
+    (while ranges
+      (setq first (car (car ranges)))
+      (setq last  (cdr (car ranges)))
+      (while (< first last)
+	(setq result (cons first result))
+	(setq first (1+ first)))
+      (setq result (cons first result))
+      (setq ranges (cdr ranges))
+      )
+    (nreverse result)
+    ))
+
+(defun gnus-number-of-articles (range)
+  "Compute number of articles from RANGE `((beg1 . end1) (beg2 . end2) ...)'."
+  (let ((count 0))
+    (while range
+      (if (/= (cdr (car range)) 0)
+	  ;; 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))
+      )
+    count				;Result
+    ))
+
+(defun gnus-difference-of-range (src obj)
+  "Compute (SRC - OBJ) on range.
+Range of SRC is expressed as `(beg . end)'.
+Range of OBJ is expressed as `((beg1 . end1) (beg2 . end2) ...)."
+  (let ((beg (car src))
+	(end (cdr src))
+	(range nil))			;This is result.
+    ;; Src may be nil.
+    (while (and src obj)
+      (let ((beg1 (car (car obj)))
+	    (end1 (cdr (car obj))))
+	(cond ((> beg end)
+	       (setq obj nil))		;Terminate loop
+	      ((< beg beg1)
+	       (setq range (cons (cons beg (min (1- beg1) end)) range))
+	       (setq beg (1+ end1)))
+	      ((>= beg beg1)
+	       (setq beg (max beg (1+ end1))))
+	      )
+	(setq obj (cdr obj))		;Next OBJ
+	))
+    ;; Src may be nil.
+    (if (and src (<= beg end))
+	(setq range (cons (cons beg end) range)))
+    ;; Result
+    (if range
+	(nreverse range)
+      (list (cons 0 0)))
+    ))
+
+
+;;Local variables:
+;;eval: (put 'gnus-eval-in-buffer-window 'lisp-indent-function 1)
+;;end: