(gnus-version-number): Bump.
[gnus] / lisp / gnus.el
index 125e1e1..03f7af9 100644 (file)
@@ -1,7 +1,7 @@
 ;;; gnus.el --- a newsreader for GNU Emacs
 
 ;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996, 1997,
-;; 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
+;; 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
 (eval-when-compile (require 'cl))
 (require 'wid-edit)
 (require 'mm-util)
+(require 'nnheader)
+
+;; Make sure it was the right mm-util.
+(unless (fboundp 'mm-guess-mime-charset)
+  (error "Wrong `mm-util' found in `load-path'.  Make sure the Gnus one is found first."))
 
 (defgroup gnus nil
   "The coffee-brewing, all singing, all dancing, kitchen sink newsreader."
@@ -41,8 +46,7 @@
 
 (defgroup gnus-format nil
   "Dealing with formatting issues."
-  :group 'news
-  :group 'mail)
+  :group 'gnus)
 
 (defgroup gnus-charset nil
   "Group character set issues."
 
 (defgroup gnus-cache nil
   "Cache interface."
+  :link '(custom-manual "(gnus)Article Caching")
+  :group 'gnus)
+
+(defgroup gnus-registry nil
+  "Article Registry."
   :group 'gnus)
 
 (defgroup gnus-start nil
 
 ;; Other
 (defgroup gnus-visual nil
-  "Options controling the visual fluff."
+  "Options controlling the visual fluff."
   :group 'gnus
   :group 'faces)
 
   :group 'gnus)
 
 (defgroup gnus-meta nil
-  "Meta variables controling major portions of Gnus.
+  "Meta variables controlling major portions of Gnus.
 In general, modifying these variables does not take affect until Gnus
 is restarted, and sometimes reloaded."
   :group 'gnus)
@@ -277,7 +286,7 @@ is restarted, and sometimes reloaded."
   :link '(custom-manual "(gnus)Exiting Gnus")
   :group 'gnus)
 
-(defconst gnus-version-number "0.05"
+(defconst gnus-version-number "0.17"
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Oort Gnus v%s" gnus-version-number)
@@ -667,6 +676,33 @@ be set in `.emacs' instead."
      ()))
   "Face used for normal interest ancient articles.")
 
+(defface gnus-summary-high-undownloaded-face
+   '((((class color)
+       (background light))
+      (:bold t :foreground "cyan4"))
+     (((class color) (background dark))
+      (:bold t :foreground "LightGray"))
+     (t (:inverse-video t :bold t)))
+  "Face used for high interest uncached articles.")
+
+(defface gnus-summary-low-undownloaded-face
+   '((((class color)
+       (background light))
+      (:italic t :foreground "cyan4" :bold nil))
+     (((class color) (background dark))
+      (:italic t :foreground "LightGray" :bold nil))
+     (t (:inverse-video t :italic t)))
+  "Face used for low interest uncached articles.")
+
+(defface gnus-summary-normal-undownloaded-face
+   '((((class color)
+       (background light))
+      (:foreground "cyan4" :bold nil))
+     (((class color) (background dark))
+      (:foreground "LightGray" :bold nil))
+     (t (:inverse-video t)))
+  "Face used for normal interest uncached articles.")
+
 (defface gnus-summary-high-unread-face
   '((t
      (:bold t)))
@@ -735,6 +771,13 @@ be set in `.emacs' instead."
   "Add the current buffer to the list of Gnus buffers."
   (push (current-buffer) gnus-buffers))
 
+(defmacro gnus-kill-buffer (buffer)
+  "Kill BUFFER and remove from the list of Gnus buffers."
+  `(let ((buf ,buffer))
+     (when (gnus-buffer-exists-p buf)
+       (setq gnus-buffers (delete (get-buffer buf) gnus-buffers))
+       (kill-buffer buf))))
+
 (defun gnus-buffers ()
   "Return a list of live Gnus buffers."
   (while (and gnus-buffers
@@ -831,20 +874,22 @@ be set in `.emacs' instead."
    ((and
      (fboundp 'find-image)
      (display-graphic-p)
-     (let ((image (find-image
-                  `((:type xpm :file "gnus.xpm"
-                           :color-symbols
-                           (("thing" . ,(car gnus-logo-colors))
-                            ("shadow" . ,(cadr gnus-logo-colors))
-                            ("background" . ,(face-background 'default))))
-                    (:type pbm :file "gnus.pbm"
-                           ;; Account for the pbm's blackground.
-                           :background ,(face-foreground 'gnus-splash-face)
-                           :foreground ,(face-background 'default))
-                    (:type xbm :file "gnus.xbm"
-                           ;; Account for the xbm's blackground.
-                           :background ,(face-foreground 'gnus-splash-face)
-                           :foreground ,(face-background 'default))))))
+     (let* ((data-directory (nnheader-find-etc-directory "gnus"))
+           (image (find-image
+                   `((:type xpm :file "gnus.xpm"
+                            :color-symbols
+                            (("thing" . ,(car gnus-logo-colors))
+                             ("shadow" . ,(cadr gnus-logo-colors))
+                             ("oort" . "#eeeeee")
+                             ("background" . ,(face-background 'default))))
+                     (:type pbm :file "gnus.pbm"
+                            ;; Account for the pbm's blackground.
+                            :background ,(face-foreground 'gnus-splash-face)
+                            :foreground ,(face-background 'default))
+                     (:type xbm :file "gnus.xbm"
+                            ;; Account for the xbm's blackground.
+                            :background ,(face-foreground 'gnus-splash-face)
+                            :foreground ,(face-background 'default))))))
        (when image
         (let ((size (image-size image)))
           (insert-char ?\n (max 0 (round (- (window-height)
@@ -927,7 +972,7 @@ For example:
 (defmacro gnus-define-group-parameter (param &rest rest)
   "Define a group parameter PARAM.
 REST is a plist of following:
-:type               One of `bool', `list' or `nil'.
+:type               One of `bool', `list' or nil.
 :function           The name of the function.
 :function-document  The documentation of the function.
 :parameter-type     The type for customizing the parameter.
@@ -1004,7 +1049,7 @@ REST is a plist of following:
 
 (defcustom gnus-home-directory "~/"
   "Directory variable that specifies the \"home\" directory.
-All other Gnus path variables are initialized from this variable."
+All other Gnus file and directory variables are initialized from this variable."
   :group 'gnus-files
   :type 'directory)
 
@@ -1085,8 +1130,8 @@ used to 899, you would say something along these lines:
 This variable should be a list, where the first element is how the
 news is to be fetched, the second is the address.
 
-For instance, if you want to get your news via NNTP from
-\"flab.flab.edu\", you could say:
+For instance, if you want to get your news via \"flab.flab.edu\" using
+NNTP, you could say:
 
 \(setq gnus-select-method '(nntp \"flab.flab.edu\"))
 
@@ -1154,7 +1199,7 @@ variable instead."
 This is a list where each element is a complete select method (see
 `gnus-select-method').
 
-If, for instance, you want to read your mail with the nnml backend,
+If, for instance, you want to read your mail with the nnml back end,
 you could set this variable:
 
 \(setq gnus-secondary-select-methods '((nnml \"\")))"
@@ -1195,15 +1240,15 @@ It can also be a list of select methods, as well as the special symbol
 list, Gnus will try all the methods in the list until it finds a match."
   :group 'gnus-server
   :type '(choice (const :tag "default" nil)
-                (const :tag "DejaNews" (nnweb "refer" (nnweb-type dejanews)))
+                (const :tag "Google" (nnweb "refer" (nnweb-type google)))
                 gnus-select-method
                 (repeat :menu-tag "Try multiple"
                         :tag "Multiple"
-                        :value (current (nnweb "refer" (nnweb-type dejanews)))
+                        :value (current (nnweb "refer" (nnweb-type google)))
                         (choice :tag "Method"
                                 (const current)
-                                (const :tag "DejaNews"
-                                       (nnweb "refer" (nnweb-type dejanews)))
+                                (const :tag "Google"
+                                       (nnweb "refer" (nnweb-type google)))
                                 gnus-select-method))))
 
 (defcustom gnus-group-faq-directory
@@ -1246,6 +1291,41 @@ If the default site is too slow, try one of these:
   :type '(choice directory
                 (repeat directory)))
 
+(defcustom gnus-group-charter-alist
+  '(("no" . (concat "http://no.news-admin.org/charter/" name ".txt"))
+    ("de" . (concat "http://purl.net/charta/" name ".html"))
+    ("dk" . (concat "http://www.usenet.dk/grupper.pl?get=" name))
+    ("england" . (concat "http://england.news-admin.org/charters/" name))
+    ("fr" . (concat "http://www.usenet-fr.net/fur/chartes/" name ".html"))
+    ("europa" . (concat "http://www.europa.usenet.eu.org/chartas/charta-en-" 
+                       (gnus-replace-in-string name "europa\\." "") ".html"))
+    ("nl" . (concat "http://www.xs4all.nl/~sister/usenet/charters/" name))
+    ("aus" . (concat "http://aus.news-admin.org/groupinfo.php/" name))
+    ("pl" . (concat "http://www.usenet.pl/opisy/" name))
+    ("ch" . (concat "http://www.use-net.ch/Usenet/charter.html#" name))
+    ("at" . (concat "http://www.usenet.at/chartas/" name "/charta"))
+    ("uk" . (concat "http://www.usenet.org.uk/" name ".html"))
+    ("wales" . (concat "http://www.wales-usenet.org/english/groups/" name ".html"))
+    ("dfw" . (concat "http://www.cirr.com/dfw/charters/" name ".html"))
+    ("se" . (concat "http://www.usenet-se.net/Reglementen/" 
+                   (gnus-replace-in-string name "\\." "_") ".html"))
+    ("milw" . (concat "http://usenet.mil.wi.us/" 
+                     (gnus-replace-in-string name "milw\\." "") "-charter"))
+    ("ca" . (concat "http://www.sbay.org/ca/charter-" name ".html"))
+    ("netins" . (concat "http://www.netins.net/usenet/charter/" 
+                       (gnus-replace-in-string name "\\." "-") "-charter.html")))
+  "*An alist of (HIERARCHY . FORM) pairs used to construct the URL of a charter.
+When FORM is evaluated `name' is bound to the name of the group."
+  :group 'gnus-group-various
+  :type '(repeat (cons (string :tag "Hierarchy") (sexp :tag "Form"))))
+
+(defcustom gnus-group-fetch-control-use-browse-url nil
+  "*Non-nil means that control messages are displayed using `browse-url'.
+Otherwise they are fetched with ange-ftp and displayed in an ephemeral
+group."
+  :group 'gnus-group-various
+  :type 'boolean)
+
 (defcustom gnus-use-cross-reference t
   "*Non-nil means that cross referenced articles will be marked as read.
 If nil, ignore cross references.  If t, mark articles as read in
@@ -1267,9 +1347,10 @@ newsgroups."
   "*The number of articles which indicates a large newsgroup.
 If the number of articles in a newsgroup is greater than this value,
 confirmation is required for selecting the newsgroup.
-If it is `nil', no confirmation is required."
+If it is nil, no confirmation is required."
   :group 'gnus-group-select
-  :type 'integer)
+  :type '(choice (const :tag "No limit" nil)
+                integer))
 
 (defcustom gnus-use-long-file-name (not (memq system-type '(usg-unix-v xenix)))
   "*Non-nil means that the default name of a file to save articles in is the group name.
@@ -1334,7 +1415,7 @@ cache to the full extent of the law."
   :group 'gnus-meta
   :type 'boolean)
 
-(defcustom gnus-keep-backlog nil
+(defcustom gnus-keep-backlog 20
   "*If non-nil, Gnus will keep read articles for later re-retrieval.
 If it is a number N, then Gnus will only keep the last N articles
 read.  If it is neither nil nor a number, Gnus will keep all read
@@ -1408,7 +1489,7 @@ slower."
   :type 'boolean)
 
 (defcustom gnus-shell-command-separator ";"
-  "String used to separate to shell commands."
+  "String used to separate shell commands."
   :group 'gnus-files
   :type 'string)
 
@@ -1429,6 +1510,7 @@ slower."
     ("nnfolder" mail respool address)
     ("nngateway" post-mail address prompt-address physical-address)
     ("nnweb" none)
+    ("nngoogle" post)
     ("nnslashdot" post)
     ("nnultimate" none)
     ("nnrss" none)
@@ -1437,7 +1519,8 @@ slower."
     ("nnlistserv" none)
     ("nnagent" post-mail)
     ("nnimap" post-mail address prompt-address physical-address)
-    ("nnmaildir" mail respool address))
+    ("nnmaildir" mail respool address)
+    ("nnnil" none))
   "*An alist of valid select methods.
 The first element of each list lists should be a string with the name
 of the select method.  The other elements may be the category of
@@ -1504,7 +1587,7 @@ to be desirable; see the manual for further details."
 
 ;; There should be special validation for this.
 (define-widget 'gnus-email-address 'string
-  "An email address")
+  "An email address.")
 
 (gnus-define-group-parameter
  to-address
@@ -1549,6 +1632,21 @@ present in a news group, you'll get mail group semantics when doing
 The gnus-group-split mail splitting mechanism will behave as if this
 address was listed in gnus-group-split Addresses (see below).")
 
+(gnus-define-group-parameter
+ subscribed
+ :type bool
+ :function-document
+ "Return GROUP's subscription status."
+ :variable-document
+ "*Groups which are automatically considered subscribed."
+ :parameter-type '(const :tag "Subscribed" t)
+ :parameter-document "\
+Gnus assumed that you are subscribed to the To/List address.
+
+When constructing a list of subscribed groups using
+`gnus-find-subscribed-addresses', Gnus includes the To address given
+above, or the list address (if the To address has not been set).")
+
 (gnus-define-group-parameter
  auto-expire
  :type bool
@@ -1609,8 +1707,7 @@ Use with caution.")
    ("\\(^\\|:\\)han\\>" euc-kr)
    ("\\(^\\|:\\)alt.chinese.text.big5\\>" chinese-big5)
    ("\\(^\\|:\\)soc.culture.vietnamese\\>" vietnamese-viqr)
-   ("\\(^\\|:\\)\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1)
-   (".*" iso-8859-1))
+   ("\\(^\\|:\\)\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1))
  :variable-document
  "Alist of regexps (to match group names) and default charsets to be used when reading."
  :variable-group gnus-charset
@@ -1641,6 +1738,219 @@ posting an article."
  :parameter-document
  "Posting method for this group.")
 
+(gnus-define-group-parameter
+ large-newsgroup-initial
+ :type integer
+ :function-document
+ "Return GROUP's initial input of the number of articles."
+ :variable-document
+ "*Alist of group regexps and its initial input of the number of articles."
+ :parameter-type '(choice :tag "Initial Input for Large Newsgroup"
+                         (const :tag "All" nil)
+                         (integer))
+ :parameter-document "\
+
+This number will be prompted as the initial value of the number of
+articles to list when the group is a large newsgroup (see
+`gnus-large-newsgroup').  If it is nil, the default value is the
+total number of articles in the group.")
+
+;; group parameters for spam processing added by Ted Zlatanov <tzz@lifelogs.com>
+(defcustom gnus-install-group-spam-parameters t
+  "*Disable the group parameters for spam detection.  
+Enable if `G c' in XEmacs is giving you trouble, and make sure to submit a bug report."
+  :type 'boolean
+  :group 'gnus-start)
+
+(when gnus-install-group-spam-parameters
+  (defvar gnus-group-spam-classification-spam t
+    "Spam group classification (requires spam.el).
+This group contains spam messages.  On summary entry, unread messages
+will be marked as spam.  On summary exit, the specified spam
+processors will be invoked on spam-marked messages, then those
+messages will be expired, so the spam processor will only see a
+spam-marked message once.")
+
+  (defvar gnus-group-spam-classification-ham 'ask
+    "The ham value for the spam group parameter (requires spam.el).
+On summary exit, the specified ham processors will be invoked on
+ham-marked messages.  Exercise caution, since the ham processor will
+see the same message more than once because there is no ham message
+registry.")
+
+  (gnus-define-group-parameter
+   spam-contents
+   :type list
+   :function-document
+   "The spam type (spam, ham, or neither) of the group."
+   :variable gnus-spam-newsgroup-contents
+   :variable-default nil
+   :variable-document
+   "*Groups in which to automatically mark new articles as spam on
+summary entry.  If non-nil, this should be a list of group name
+regexps that should match all groups in which to do automatic spam
+tagging, associated with a classification (spam, ham, or neither).
+This only makes sense for mail groups."
+   :variable-group spam
+   :variable-type '(repeat 
+                   (list :tag "Group contents spam/ham classification"
+                         (regexp :tag "Group")
+                         (choice
+                          (variable-item gnus-group-spam-classification-spam)
+                          (variable-item gnus-group-spam-classification-ham)
+                          (const :tag "Unclassified" nil))))
+
+   :parameter-type '(list :tag "Group contents spam/ham classification"
+                         (choice :tag "Group contents classification for spam sorting"
+                                 (variable-item gnus-group-spam-classification-spam)
+                                 (variable-item gnus-group-spam-classification-ham)
+                                 (const :tag "Unclassified" nil)))
+   :parameter-document
+   "The spam classification (spam, ham, or neither) of this group.
+When a spam group is entered, all unread articles are marked as spam.")
+
+  (defvar gnus-group-spam-exit-processor-ifile "ifile"
+    "The ifile summary exit spam processor.
+Only applicable to spam groups.")
+
+  (defvar gnus-group-spam-exit-processor-stat "stat"
+    "The spam-stat summary exit spam processor.
+Only applicable to spam groups.")
+
+  (defvar gnus-group-spam-exit-processor-bogofilter "bogofilter"
+    "The Bogofilter summary exit spam processor.
+Only applicable to spam groups.")
+
+  (defvar gnus-group-spam-exit-processor-blacklist "blacklist"
+    "The Blacklist summary exit spam processor.
+Only applicable to spam groups.")
+
+  (defvar gnus-group-ham-exit-processor-ifile "ifile-ham"
+    "The ifile summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-bogofilter "bogofilter-ham"
+    "The Bogofilter summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-stat "stat-ham"
+    "The spam-stat summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-whitelist "whitelist"
+    "The whitelist summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-BBDB "bbdb"
+    "The BBDB summary exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (defvar gnus-group-ham-exit-processor-copy "copy"
+    "The ham copy exit ham processor.
+Only applicable to non-spam (unclassified and ham) groups.")
+
+  (gnus-define-group-parameter
+   spam-process
+   :type list
+   :parameter-type '(choice :tag "Spam Summary Exit Processor"
+                           :value nil
+                           (list :tag "Spam Summary Exit Processor Choices"
+                                 (set 
+                                  (variable-item gnus-group-spam-exit-processor-ifile)
+                                  (variable-item gnus-group-spam-exit-processor-stat)
+                                  (variable-item gnus-group-spam-exit-processor-bogofilter)
+                                  (variable-item gnus-group-spam-exit-processor-blacklist)
+                                  (variable-item gnus-group-ham-exit-processor-bogofilter)
+                                  (variable-item gnus-group-ham-exit-processor-ifile)
+                                  (variable-item gnus-group-ham-exit-processor-stat)
+                                  (variable-item gnus-group-ham-exit-processor-whitelist)
+                                  (variable-item gnus-group-ham-exit-processor-BBDB)
+                                  (variable-item gnus-group-ham-exit-processor-copy))))
+   :function-document
+   "Which spam or ham processors will be applied to the GROUP articles at summary exit."
+   :variable gnus-spam-process-newsgroups
+   :variable-default nil
+   :variable-document
+   "*Groups in which to automatically process spam or ham articles with
+a backend on summary exit.  If non-nil, this should be a list of group
+name regexps that should match all groups in which to do automatic
+spam processing, associated with the appropriate processor.  This only makes sense
+for mail groups."
+   :variable-group spam
+   :variable-type '(repeat :tag "Spam/Ham Processors" 
+                          (list :tag "Spam Summary Exit Processor Choices"
+                                (regexp :tag "Group Regexp") 
+                                (set :tag "Spam/Ham Summary Exit Processor"
+                                     (variable-item gnus-group-spam-exit-processor-ifile)
+                                     (variable-item gnus-group-spam-exit-processor-stat)
+                                     (variable-item gnus-group-spam-exit-processor-bogofilter)
+                                     (variable-item gnus-group-spam-exit-processor-blacklist)
+                                     (variable-item gnus-group-ham-exit-processor-bogofilter)
+                                     (variable-item gnus-group-ham-exit-processor-ifile)
+                                     (variable-item gnus-group-ham-exit-processor-stat)
+                                     (variable-item gnus-group-ham-exit-processor-whitelist)
+                                     (variable-item gnus-group-ham-exit-processor-BBDB)
+                                     (variable-item gnus-group-ham-exit-processor-copy))))
+   :parameter-document
+   "Which spam processors will be applied to the spam or ham GROUP articles at summary exit.")
+
+  (gnus-define-group-parameter
+   spam-process-destination
+   :parameter-type '(choice :tag "Destination for spam-processed articles at summary exit"
+                           (string :tag "Move to a group")
+                           (const :tag "Expire" nil))
+   :function-document
+   "Where spam-processed articles will go at summary exit."
+   :variable gnus-spam-process-destinations
+   :variable-default nil
+   :variable-document
+   "*Groups in which to explicitly send spam-processed articles to
+another group, or expire them (the default).  If non-nil, this should
+be a list of group name regexps that should match all groups in which
+to do spam-processed article moving, associated with the destination
+group or nil for explicit expiration.  This only makes sense for
+mail groups."
+   :variable-group spam
+   :variable-type '(repeat 
+                   :tag "Spam-processed articles destination" 
+                   (list
+                    (regexp :tag "Group Regexp") 
+                    (choice 
+                     :tag "Destination for spam-processed articles at summary exit"
+                     (string :tag "Move to a group")
+                     (const :tag "Expire" nil))))
+   :parameter-document
+   "Where spam-processed articles will go at summary exit.")
+
+  (gnus-define-group-parameter
+   ham-process-destination
+   :parameter-type '(choice 
+                    :tag "Destination for ham articles at summary exit from a spam group"
+                    (string :tag "Move to a group")
+                    (const :tag "Do nothing" nil))
+   :function-document
+   "Where ham articles will go at summary exit from a spam group."
+   :variable gnus-ham-process-destinations
+   :variable-default nil
+   :variable-document
+   "*Groups in which to explicitly send ham articles to
+another group, or do nothing (the default).  If non-nil, this should
+be a list of group name regexps that should match all groups in which
+to do ham article moving, associated with the destination
+group or nil for explicit ignoring.  This only makes sense for
+mail groups, and only works in spam groups."
+   :variable-group spam
+   :variable-type '(repeat 
+                   :tag "Ham articles destination" 
+                   (list
+                    (regexp :tag "Group Regexp") 
+                    (choice 
+                     :tag "Destination for ham articles at summary exit from spam group"
+                     (string :tag "Move to a group")
+                     (const :tag "Expire" nil))))
+   :parameter-document
+   "Where ham articles will go at summary exit from a spam group."))
+
 (defcustom gnus-group-uncollapsed-levels 1
   "Number of group name elements to leave alone when making a short group name."
   :group 'gnus-group-visual
@@ -1764,30 +2074,61 @@ face."
 (defvar gnus-plugged t
   "Whether Gnus is plugged or not.")
 
-(defvar gnus-agent-cache t
-  "Whether Gnus use agent cache.")
+(defcustom gnus-agent-cache t
+  "Controls use of the agent cache while plugged.  When set, Gnus will prefer
+using the locally stored content rather than re-fetching it from the server.
+You also need to enable `gnus-agent' for this to have any affect."
+  :version "21.3"
+  :group 'gnus-agent
+  :type 'boolean)
 
-(defcustom gnus-default-charset 'iso-8859-1
+(defcustom gnus-default-charset (mm-guess-mime-charset)
   "Default charset assumed to be used when viewing non-ASCII characters.
 This variable is overridden on a group-to-group basis by the
-gnus-group-charset-alist variable and is only used on groups not
+`gnus-group-charset-alist' variable and is only used on groups not
 covered by that variable."
   :type 'symbol
   :group 'gnus-charset)
 
+(defcustom gnus-agent t
+  "Whether we want to use the Gnus agent or not.
+Putting (gnus-agentize) in ~/.gnus is obsolete by (setq gnus-agent t)."
+  :version "21.3"
+  :group 'gnus-agent
+  :type 'boolean)
+
+(defcustom gnus-other-frame-function 'gnus
+  "Function called by the command `gnus-other-frame'."
+  :group 'gnus-start
+  :type '(choice (function-item gnus)
+                (function-item gnus-no-server)
+                (function-item gnus-slave)
+                (function-item gnus-slave-no-server)))
+
+(defcustom gnus-other-frame-parameters nil
+  "Frame parameters used by `gnus-other-frame' to create a Gnus frame.
+This should be an alist for Emacs, or a plist for XEmacs."
+  :group 'gnus-start
+  :type (if (featurep 'xemacs)
+           '(repeat (list :inline t :format "%v"
+                          (symbol :tag "Property")
+                          (sexp :tag "Value")))
+         '(repeat (cons :format "%v"
+                        (symbol :tag "Parameter")
+                        (sexp :tag "Value")))))
+
 \f
 ;;; Internal variables
 
 (defvar gnus-agent-gcc-header "X-Gnus-Agent-Gcc")
 (defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
+(defvar gnus-agent-target-move-group-header "X-Gnus-Agent-Move-To")
 (defvar gnus-draft-meta-information-header "X-Draft-From")
 (defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
 (defvar gnus-original-article-buffer " *Original Article*")
 (defvar gnus-newsgroup-name nil)
 (defvar gnus-ephemeral-servers nil)
-
-(defvar gnus-agent nil
-  "Whether we want to use the Gnus agent or not.")
+(defvar gnus-server-method-cache nil)
 
 (defvar gnus-agent-fetching nil
   "Whether Gnus agent is in fetching mode.")
@@ -1795,7 +2136,7 @@ covered by that variable."
 (defvar gnus-agent-covered-methods nil)
 
 (defvar gnus-command-method nil
-  "Dynamically bound variable that says what the current backend is.")
+  "Dynamically bound variable that says what the current back end is.")
 
 (defvar gnus-current-select-method nil
   "The current method for selecting a newsgroup.")
@@ -1856,12 +2197,13 @@ covered by that variable."
 ;; `download' is a agent flag private to each gnus installation
 ;; `unsend' are for nndraft groups only
 ;; `score' is not a proper mark
+;; `bookmark': don't propagated it, or fix the bug in update-mark.
 (defconst gnus-article-unpropagated-mark-lists
-  '(seen cache download unsend score)
-  "Marks that shouldn't be propagated to backends.
-Typical marks are those that make no sense in a standalone backend,
+  '(seen cache download unsend score bookmark)
+  "Marks that shouldn't be propagated to back ends.
+Typical marks are those that make no sense in a standalone back end,
 such as a mark that says whether an article is stored in the cache
-(which doesn't make sense in a standalone backend).")
+\(which doesn't make sense in a standalone back end).")
 
 (defvar gnus-headers-retrieved-by nil)
 (defvar gnus-article-reply nil)
@@ -1903,7 +2245,7 @@ such as a mark that says whether an article is stored in the cache
                        gnus-newsrc-alist gnus-server-alist
                        gnus-killed-list gnus-zombie-list
                        gnus-topic-topology gnus-topic-alist
-                       gnus-format-specs)
+                       gnus-agent-covered-methods gnus-format-specs)
   "Gnus variables saved in the quick startup file.")
 
 (defvar gnus-newsrc-alist nil
@@ -1947,6 +2289,9 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
 (defvar gnus-invalid-group-regexp "[: `'\"/]\\|^$"
   "Regexp matching invalid groups.")
 
+(defvar gnus-other-frame-object nil
+  "A frame object which will be created by `gnus-other-frame'.")
+
 ;;; End of variables.
 
 ;; Define some autoload functions Gnus might use.
@@ -1998,7 +2343,8 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
      ("gnus-demon" :interactive t
       gnus-demon-init gnus-demon-cancel)
      ("gnus-fun" gnus-convert-gray-x-face-to-xpm gnus-display-x-face-in-from
-      gnus-convert-image-to-gray-x-face)
+      gnus-convert-image-to-gray-x-face gnus-convert-face-to-png
+      gnus-face-from-file)
      ("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
       gnus-tree-open gnus-tree-close gnus-carpal-setup-buffer)
      ("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
@@ -2102,11 +2448,11 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
       gnus-article-de-base64-unreadable
       gnus-article-decode-HZ
       gnus-article-wash-html
-      gnus-article-hide-pgp
+      gnus-article-unsplit-urls
       gnus-article-hide-pem gnus-article-hide-signature
       gnus-article-strip-leading-blank-lines gnus-article-date-local
       gnus-article-date-original gnus-article-date-lapsed
-      gnus-article-show-all-headers
+;;      gnus-article-show-all-headers
       gnus-article-edit-mode gnus-article-edit-article
       gnus-article-edit-done gnus-article-decode-encoded-words
       gnus-start-date-timer gnus-stop-date-timer
@@ -2138,7 +2484,8 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
      ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-queue)
      ("gnus-mlspl" gnus-group-split gnus-group-split-fancy)
      ("gnus-mlspl" :interactive t gnus-group-split-setup
-      gnus-group-split-update))))
+      gnus-group-split-update)
+     ("gnus-delay" gnus-delay-initialize))))
 
 ;;; gnus-sum.el thingies
 
@@ -2164,6 +2511,8 @@ with some simple extensions.
 %M   Message-id of the article (string)
 %r   References of the article (string)
 %c   Number of characters in the article (integer)
+%k   Pretty-printed version of the above (string)
+     For example, \"1.2k\" or \"0.4M\".
 %L   Number of lines in the article (integer)
 %I   Indentation based on thread level (a string of spaces)
 %B   A complex trn-style thread tree (string)
@@ -2184,6 +2533,8 @@ with some simple extensions.
 %V   Total thread score (number).
 %P   The line number (number).
 %O   Download mark (character).
+%*   If present, indicates desired cursor position
+     (instead of after first colon).
 %u   User defined specifier.  The next character in the format string should
      be a letter.  Gnus will call the function gnus-user-format-function-X,
      where X is the letter following %u.  The function will be passed the
@@ -2203,8 +2554,8 @@ possible.
 
 This restriction may disappear in later versions of Gnus.
 
-General format specifiers can also be used.  
-See (gnus)Formatting Variables."
+General format specifiers can also be used.
+See Info node `(gnus)Formatting Variables'."
   :link '(custom-manual "(gnus)Formatting Variables")
   :type 'string
   :group 'gnus-summary-format)
@@ -2340,7 +2691,7 @@ Return nil if not defined."
 (defmacro gnus-get-info (group)
   `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
 
-;;; Load the compatability functions.
+;;; Load the compatibility functions.
 
 (require 'gnus-ems)
 
@@ -2375,12 +2726,14 @@ with a `subscribed' parameter."
   (let (group address addresses)
     (dolist (entry (cdr gnus-newsrc-alist))
       (setq group (car entry))
-      (when (gnus-group-find-parameter group 'subscribed)
-       (setq address (or (gnus-group-fast-parameter group 'to-address)
-                         (gnus-group-fast-parameter group 'to-list)))
+      (when (gnus-parameter-subscribed group)
+       (setq address (mail-strip-quoted-names
+                      (or (gnus-group-fast-parameter group 'to-address)
+                          (gnus-group-fast-parameter group 'to-list))))
        (when address
-         (push address addresses))))
-    (list (mapconcat 'regexp-quote addresses "\\|"))))
+         (add-to-list 'addresses address))))
+    (when addresses
+      (list (mapconcat 'regexp-quote addresses "\\|")))))
 
 (defmacro gnus-string-or (&rest strings)
   "Return the first element of STRINGS that is a non-blank string.
@@ -2662,6 +3015,36 @@ that that variable is buffer-local to the summary buffers."
                                   (nth 1 method))))
       method)))
 
+(defsubst gnus-server-to-method (server)
+  "Map virtual server names to select methods."
+  (or (and server (listp server) server)
+      (cdr (assoc server gnus-server-method-cache))
+      (let ((result
+            (or
+             ;; Perhaps this is the native server?
+             (and (equal server "native") gnus-select-method)
+             ;; It should be in the server alist.
+             (cdr (assoc server gnus-server-alist))
+             ;; It could be in the predefined server alist.
+             (cdr (assoc server gnus-predefined-server-alist))
+             ;; If not, we look through all the opened server
+             ;; to see whether we can find it there.
+             (let ((opened gnus-opened-servers))
+               (while (and opened
+                           (not (equal server (format "%s:%s" (caaar opened)
+                                                      (cadaar opened)))))
+                 (pop opened))
+               (caar opened))
+             ;; It could be a named method, search all servers
+             (let ((servers gnus-secondary-select-methods))
+               (while (and servers
+                           (not (equal server (format "%s:%s" (caar servers)
+                                                      (cadar servers)))))
+                 (pop servers))
+               (car servers)))))
+       (push (cons server result) gnus-server-method-cache)
+       result)))
+
 (defsubst gnus-server-get-method (group method)
   ;; Input either a server name, and extended server name, or a
   ;; select method, and return a select method.
@@ -2679,33 +3062,6 @@ that that variable is buffer-local to the summary buffers."
        (t
         (gnus-server-add-address method))))
 
-(defun gnus-server-to-method (server)
-  "Map virtual server names to select methods."
-  (or
-   ;; Is this a method, perhaps?
-   (and server (listp server) server)
-   ;; Perhaps this is the native server?
-   (and (equal server "native") gnus-select-method)
-   ;; It should be in the server alist.
-   (cdr (assoc server gnus-server-alist))
-   ;; It could be in the predefined server alist.
-   (cdr (assoc server gnus-predefined-server-alist))
-   ;; If not, we look through all the opened server
-   ;; to see whether we can find it there.
-   (let ((opened gnus-opened-servers))
-     (while (and opened
-                (not (equal server (format "%s:%s" (caaar opened)
-                                           (cadaar opened)))))
-       (pop opened))
-     (caar opened))
-   ;; It could be a named method, search all servers
-   (let ((servers gnus-secondary-select-methods))
-     (while (and servers
-                (not (equal server (format "%s:%s" (caar servers)
-                                           (cadar servers)))))
-       (pop servers))
-     (car servers))))
-
 (defmacro gnus-method-equal (ss1 ss2)
   "Say whether two servers are equal."
   `(let ((s1 ,ss1)
@@ -2774,21 +3130,40 @@ that that variable is buffer-local to the summary buffers."
 (defsubst gnus-method-to-full-server-name (method)
   (format "%s+%s" (car method) (nth 1 method)))
 
-(defun gnus-group-prefixed-name (group method)
-  "Return the whole name from GROUP and METHOD."
+(defun gnus-group-prefixed-name (group method &optional full)
+  "Return the whole name from GROUP and METHOD.  Call with full set to
+get the fully qualified group name (even if the server is native)."
   (and (stringp method) (setq method (gnus-server-to-method method)))
   (if (or (not method)
-         (gnus-server-equal method "native")
+         (and (not full) (gnus-server-equal method "native"))
          (string-match ":" group))
       group
     (concat (gnus-method-to-server-name method) ":" group)))
 
+(defun gnus-group-guess-prefixed-name (group)
+  "Guess the whole name from GROUP and METHOD."
+  (gnus-group-prefixed-name group (gnus-find-method-for-group
+                              group)))
+
+(defun gnus-group-full-name (group method)
+  "Return the full name from GROUP and METHOD, even if the method is
+native."
+  (gnus-group-prefixed-name group method t))
+
+(defun gnus-group-guess-full-name (group)
+  "Guess the full name from GROUP, even if the method is native."
+  (gnus-group-full-name group (gnus-find-method-for-group group)))
+
 (defun gnus-group-real-prefix (group)
   "Return the prefix of the current group name."
   (if (string-match "^[^:]+:" group)
       (substring group 0 (match-end 0))
     ""))
 
+(defun gnus-summary-buffer-name (group)
+  "Return the summary buffer name of GROUP."
+  (concat "*Summary " (gnus-group-decoded-name group) "*"))
+
 (defun gnus-group-method (group)
   "Return the server or method used for selecting GROUP.
 You should probably use `gnus-find-method-for-group' instead."
@@ -2900,9 +3275,13 @@ You should probably use `gnus-find-method-for-group' instead."
 You should call this in the `gnus-group-buffer' buffer.
 The function `gnus-group-find-parameter' will do that for you."
   ;; The speed trick:  No cons'ing and quit early.
-  (or (let ((params (funcall gnus-group-get-parameter-function group)))
-       ;; Start easy, check the "real" group parameters.
-       (gnus-group-parameter-value params symbol allow-list))
+  (let* ((params (funcall gnus-group-get-parameter-function group))
+        ;; Start easy, check the "real" group parameters.
+        (simple-results
+         (gnus-group-parameter-value params symbol allow-list t)))
+    (if simple-results
+       ;; Found results; return them.
+       (car simple-results)
       ;; We didn't found it there, try `gnus-parameters'.
       (let ((result nil)
            (head nil)
@@ -2918,13 +3297,13 @@ The function `gnus-group-find-parameter' will do that for you."
                                                     symbol allow-list))
            (when result
              ;; Expand if necessary.
-             (if (and (stringp result) (string-match "\\\\" result))
+             (if (and (stringp result) (string-match "\\\\[0-9&]" result))
                  (setq result (gnus-expand-group-parameter (car head)
                                                            result group)))
              ;; Exit the loop early.
              (setq tail nil))))
        ;; Done.
-       result)))
+       result))))
 
 (defun gnus-group-find-parameter (group &optional symbol allow-list)
   "Return the group parameters for GROUP.
@@ -2936,12 +3315,10 @@ If you call this function inside a loop, consider using the faster
     (set-buffer gnus-group-buffer)
     (if symbol
        (gnus-group-fast-parameter group symbol allow-list)
-      (let ((parameters
-            (nconc
-             (copy-sequence
-              (funcall gnus-group-get-parameter-function group))
-             (gnus-parameters-get-parameter group))))
-       parameters))))
+      (nconc
+       (copy-sequence
+       (funcall gnus-group-get-parameter-function group))
+       (gnus-parameters-get-parameter group)))))
 
 (defun gnus-group-get-parameter (group &optional symbol allow-list)
   "Return the group parameters for GROUP.
@@ -2953,7 +3330,8 @@ also examines the topic parameters."
        (gnus-group-parameter-value params symbol allow-list)
       params)))
 
-(defun gnus-group-parameter-value (params symbol &optional allow-list)
+(defun gnus-group-parameter-value (params symbol &optional
+                                         allow-list present-p)
   "Return the value of SYMBOL in group PARAMS."
   ;; We only wish to return group parameters (dotted lists) and
   ;; not local variables, which may have the same names.
@@ -2967,7 +3345,8 @@ also examines the topic parameters."
                       (eq (car elem) symbol)
                       (or allow-list
                           (atom (cdr elem))))
-             (throw 'found (cdr elem))))))))
+             (throw 'found (if present-p (list (cdr elem))
+                             (cdr elem)))))))))
 
 (defun gnus-group-add-parameter (group param)
   "Add parameter PARAM to GROUP."
@@ -3179,7 +3558,7 @@ If NEWSGROUP is nil, return the global kill file name instead."
         (address (nth 1 server)))
     (if (and address
             (not (zerop (length address))))
-       (format "%s via %s" address (car server))
+       (format "%s using %s" address (car server))
       (format "%s" (car server)))))
 
 (defun gnus-find-method-for-group (group &optional info)
@@ -3287,18 +3666,19 @@ Allow completion over sensible values."
 
 ;;;###autoload
 (defun gnus-slave-no-server (&optional arg)
-  "Read network news as a slave, without connecting to local server."
+  "Read network news as a slave, without connecting to the local server."
   (interactive "P")
   (gnus-no-server arg t))
 
 ;;;###autoload
 (defun gnus-no-server (&optional arg slave)
   "Read network news.
-If ARG is a positive number, Gnus will use that as the
-startup level. If ARG is nil, Gnus will be started at level 2.
-If ARG is non-nil and not a positive number, Gnus will
-prompt the user for the name of an NNTP server to use.
-As opposed to `gnus', this command will not connect to the local server."
+If ARG is a positive number, Gnus will use that as the startup
+level. If ARG is nil, Gnus will be started at level 2.  If ARG is
+non-nil and not a positive number, Gnus will prompt the user for the
+name of an NNTP server to use.
+As opposed to `gnus', this command will not connect to the local
+server."
   (interactive "P")
   (gnus-no-server-1 arg slave))
 
@@ -3309,15 +3689,51 @@ As opposed to `gnus', this command will not connect to the local server."
   (gnus arg nil 'slave))
 
 ;;;###autoload
-(defun gnus-other-frame (&optional arg)
-  "Pop up a frame to read news."
+(defun gnus-other-frame (&optional arg display)
+  "Pop up a frame to read news.
+This will call one of the Gnus commands which is specified by the user
+option `gnus-other-frame-function' (default `gnus') with the argument
+ARG if Gnus is not running, otherwise just pop up a Gnus frame.  The
+optional second argument DISPLAY should be a standard display string
+such as \"unix:0\" to specify where to pop up a frame.  If DISPLAY is
+omitted or the function `make-frame-on-display' is not available, the
+current display is used."
   (interactive "P")
-  (let ((window (get-buffer-window gnus-group-buffer)))
-    (cond (window
-          (select-frame (window-frame window)))
-         (t
-          (select-frame (make-frame)))))
-  (gnus arg))
+  (if (fboundp 'make-frame-on-display)
+      (unless display
+       (setq display (gnus-frame-or-window-display-name (selected-frame))))
+    (setq display nil))
+  (let ((alive (gnus-alive-p)))
+    (unless (and alive
+                (catch 'found
+                  (walk-windows
+                   (lambda (window)
+                     (when (and (or (not display)
+                                    (equal display
+                                           (gnus-frame-or-window-display-name
+                                            window)))
+                                (with-current-buffer (window-buffer window)
+                                  (string-match "\\`gnus-"
+                                                (symbol-name major-mode))))
+                       (gnus-select-frame-set-input-focus
+                        (setq gnus-other-frame-object (window-frame window)))
+                       (select-window window)
+                       (throw 'found t)))
+                   'ignore t)))
+      (gnus-select-frame-set-input-focus
+       (setq gnus-other-frame-object
+            (if display
+                (make-frame-on-display display gnus-other-frame-parameters)
+              (make-frame gnus-other-frame-parameters))))
+      (if alive
+         (switch-to-buffer gnus-group-buffer)
+       (funcall gnus-other-frame-function arg)
+       (add-hook 'gnus-exit-gnus-hook
+                 (lambda nil
+                   (when (and (frame-live-p gnus-other-frame-object)
+                              (cdr (frame-list)))
+                     (delete-frame gnus-other-frame-object))
+                   (setq gnus-other-frame-object nil)))))))
 
 ;;(setq thing ?                                ; this is a comment
 ;;      more 'yes)