(gnus-version-number): Bump.
[gnus] / lisp / gnus.el
index f5ffcfb..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>
@@ -33,6 +33,7 @@
 (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)
@@ -45,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
@@ -281,7 +286,7 @@ is restarted, and sometimes reloaded."
   :link '(custom-manual "(gnus)Exiting Gnus")
   :group 'gnus)
 
-(defconst gnus-version-number "0.08"
+(defconst gnus-version-number "0.17"
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Oort Gnus v%s" gnus-version-number)
@@ -671,16 +676,16 @@ be set in `.emacs' instead."
      ()))
   "Face used for normal interest ancient articles.")
 
-(defface gnus-summary-high-uncached-face
+(defface gnus-summary-high-undownloaded-face
    '((((class color)
        (background light))
-      (:bold t :foreground "cyan4" :bold nil))
+      (:bold t :foreground "cyan4"))
      (((class color) (background dark))
-      (:bold t :foreground "LightGray" :bold nil))
+      (:bold t :foreground "LightGray"))
      (t (:inverse-video t :bold t)))
   "Face used for high interest uncached articles.")
 
-(defface gnus-summary-low-uncached-face
+(defface gnus-summary-low-undownloaded-face
    '((((class color)
        (background light))
       (:italic t :foreground "cyan4" :bold nil))
@@ -689,7 +694,7 @@ be set in `.emacs' instead."
      (t (:inverse-video t :italic t)))
   "Face used for low interest uncached articles.")
 
-(defface gnus-summary-normal-uncached-face
+(defface gnus-summary-normal-undownloaded-face
    '((((class color)
        (background light))
       (:foreground "cyan4" :bold nil))
@@ -766,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
@@ -960,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.
@@ -1037,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)
 
@@ -1303,7 +1315,7 @@ If the default site is too slow, try one of these:
     ("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."
+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"))))
 
@@ -1335,7 +1347,7 @@ 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 '(choice (const :tag "No limit" nil)
                 integer))
@@ -1477,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)
 
@@ -1575,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
@@ -1740,136 +1752,204 @@ posting an article."
 
 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
+`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>
-(defvar gnus-group-spam-classification-spam t
-  "Spam group classification (requires spam.el).
+(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).
+  (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
+  (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"
  :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)
-                          (other :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)
-                          (other :tag "Unclassified" nil)))
- :parameter-document
- "The spam classification (spam, ham, or neither) of this group.
+                          (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.
+  (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-bogofilter "bogofilter"
-  "The Bogofilter summary exit spam processor.
+  (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-blacklist "blacklist"
-  "The Blacklist summary exit spam processor.
+  (defvar gnus-group-spam-exit-processor-bogofilter "bogofilter"
+    "The Bogofilter summary exit spam processor.
 Only applicable to spam groups.")
 
-(defvar gnus-group-ham-exit-processor-whitelist "whitelist"
-  "The whitelist summary exit ham processor.
+  (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-BBDB "bbdb"
-  "The BBDB summary exit ham processor.
+  (defvar gnus-group-ham-exit-processor-bogofilter "bogofilter-ham"
+    "The Bogofilter summary 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-bogofilter)
-                           (variable-item gnus-group-spam-exit-processor-blacklist)
-                           (variable-item gnus-group-ham-exit-processor-whitelist)
-                           (variable-item gnus-group-ham-exit-processor-BBDB))))
- :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
+  (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-bogofilter)
-                              (variable-item gnus-group-spam-exit-processor-blacklist)
-                              (variable-item gnus-group-ham-exit-processor-whitelist)
-                              (variable-item gnus-group-ham-exit-processor-BBDB))))
- :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")
-                         (other :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
+   :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
+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")
-                                 (other :tag "Expire" nil))))
- :parameter-document
- "Where spam-processed articles will go at summary exit.")
+   :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."
@@ -1995,8 +2075,9 @@ face."
   "Whether Gnus is plugged or not.")
 
 (defcustom gnus-agent-cache t
-  "Whether Gnus use agent cache.
-You also need to enable `gnus-agent'."
+  "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)
@@ -2004,7 +2085,7 @@ You also need to enable `gnus-agent'."
 (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)
@@ -2026,7 +2107,7 @@ Putting (gnus-agentize) in ~/.gnus is obsolete by (setq gnus-agent t)."
 
 (defcustom gnus-other-frame-parameters nil
   "Frame parameters used by `gnus-other-frame' to create a Gnus frame.
-This should be an alist for FSF Emacs, or a plist for XEmacs."
+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"
@@ -2041,6 +2122,7 @@ This should be an alist for FSF Emacs, or a plist for XEmacs."
 
 (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*")
@@ -2163,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-agent-covered-methods gnus-format-specs)
   "Gnus variables saved in the quick startup file.")
 
 (defvar gnus-newsrc-alist nil
@@ -2261,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
@@ -2366,7 +2449,6 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
       gnus-article-decode-HZ
       gnus-article-wash-html
       gnus-article-unsplit-urls
-      gnus-article-hide-pgp
       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
@@ -2451,7 +2533,7 @@ with some simple extensions.
 %V   Total thread score (number).
 %P   The line number (number).
 %O   Download mark (character).
-%C   If present, indicates desired cursor position
+%*   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,
@@ -3048,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."