Use .invalid.
[gnus] / lisp / spam.el
index 152a9f3..a9d0ac4 100644 (file)
@@ -1,8 +1,10 @@
 ;;; spam.el --- Identifying spam
-;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+
+;; Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: network
+;; Maintainer: Ted Zlatanov <tzz@lifelogs.com>
+;; Keywords: network, spam, mail, bogofilter, BBDB, dspam, dig, whitelist, blacklist, gmane, hashcash, spamassassin, bsfilter, ifile, stat, crm114, spamoracle
 
 ;; This file is part of GNU Emacs.
 
@@ -18,8 +20,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 
 ;;; Several TODO items are marked as such
 
-;; TODO: spam scores, detection of spam in newsgroups, cross-server splitting,
-;; remote processing, training through files
+;; TODO: cross-server splitting, remote processing, training through files
 
 ;;; Code:
 
+;;{{{ compilation directives and autoloads/requires
+
 (eval-when-compile (require 'cl))
+(eval-when-compile (require 'spam-report))
+(eval-when-compile (require 'hashcash))
 
 (require 'gnus-sum)
 
@@ -56,6 +61,8 @@
 ;; autoload spam-report
 (eval-and-compile
   (autoload 'spam-report-gmane "spam-report")
+  (autoload 'spam-report-gmane-spam "spam-report")
+  (autoload 'spam-report-gmane-ham "spam-report")
   (autoload 'spam-report-resend "spam-report"))
 
 ;; autoload gnus-registry
 (eval-and-compile
   (autoload 'query-dns "dns"))
 
-;;; Main parameters.
+;;}}}
+
+;;{{{ Main parameters.
+(defvar spam-backends nil
+  "List of spam.el backends with all the pertinent data.
+Populated by spam-install-backend-super.")
 
 (defgroup spam nil
-  "Spam configuration.")
+  "Spam configuration."
+  :version "22.1"
+  :group 'mail
+  :group 'news)
+
+(defcustom spam-summary-exit-behavior 'default
+  "Exit behavior at the time of summary exit.
+Note that setting the spam-use-move or spam-use-copy backends on
+a group through group/topic parameters overrides this mechanism."
+  :type '(choice (const 'default :tag 
+                       "Move spam out of all groups.  Move ham out of spam groups.")
+                (const 'move-all :tag 
+                       "Move spam out of all groups.  Move ham out of all groups.")
+                (const 'move-none :tag 
+                       "Never move spam or ham out of any groups."))
+  :group 'spam)
 
 (defcustom spam-directory (nnheader-concat gnus-directory "spam/")
   "Directory for spam whitelists and blacklists."
   :type 'directory
   :group 'spam)
 
-(defcustom spam-move-spam-nonspam-groups-only t
-  "Whether spam should be moved in non-spam groups only.
-When t, only ham and unclassified groups will have their spam moved
-to the spam-process-destination.  When nil, spam will also be moved from
-spam groups."
-  :type 'boolean
-  :group 'spam)
-
 (defcustom spam-mark-new-messages-in-spam-group-as-spam t
   "Whether new messages in a spam group should get the spam-mark."
   :type 'boolean
-  :group 'spam)
-
-(defcustom spam-process-ham-in-nonham-groups nil
-  "Whether ham should be processed in non-ham groups."
-  :type 'boolean
+  ;; :version "22.1" ;; Gnus 5.10.8 / No Gnus 0.3
   :group 'spam)
 
 (defcustom spam-log-to-registry nil
@@ -114,11 +129,6 @@ Do not set this if you use `spam-split' in a fancy split
   :type 'boolean
   :group 'spam)
 
-(defcustom spam-process-ham-in-spam-groups nil
-  "Whether ham should be processed in spam groups."
-  :type 'boolean
-  :group 'spam)
-
 (defcustom spam-mark-only-unseen-as-spam t
   "Whether only unseen articles should be marked as spam in spam groups.
 When nil, all unread articles in a spam group are marked as
@@ -345,11 +355,25 @@ Only meaningful if you enable `spam-use-blackholes'."
 (defcustom spam-blackhole-good-server-regex nil
   "String matching IP addresses that should not be checked in the blackholes.
 Only meaningful if you enable `spam-use-blackholes'."
-  :type '(radio (const nil)
-               (regexp :format "%t: %v\n" :size 0))
+  :type '(radio (const nil) regexp)
+  :group 'spam)
+
+(defface spam
+  '((((class color) (type tty) (background dark))
+     (:foreground "gray80" :background "gray50"))
+    (((class color) (type tty) (background light))
+     (:foreground "gray50" :background "gray80"))
+    (((class color) (background dark))
+     (:foreground "ivory2"))
+    (((class color) (background light))
+     (:foreground "ivory4"))
+    (t :inverse-video t))
+  "Face for spam-marked articles."
   :group 'spam)
+;; backward-compatibility alias
+(put 'spam-face 'face-alias 'spam)
 
-(defcustom spam-face 'gnus-splash-face
+(defcustom spam-face 'spam
   "Face for spam-marked articles."
   :type 'face
   :group 'spam)
@@ -378,6 +402,14 @@ Only meaningful if you enable `spam-use-regex-body'."
   :type '(repeat (regexp :tag "Regular expression to match ham body"))
   :group 'spam)
 
+(defcustom spam-summary-score-preferred-header nil
+  "Preferred header to use for spam-summary-score."
+  :type '(choice :tag "Header name"
+         (symbol :tag "SpamAssassin etc" X-Spam-Status)
+         (symbol :tag "Bogofilter"       X-Bogosity)
+         (const  :tag "No preference, take best guess." nil))
+  :group 'spam)
+
 (defgroup spam-ifile nil
   "Spam ifile configuration."
   :group 'spam)
@@ -423,6 +455,8 @@ your main source of newsgroup names."
                 (const :tag "Bogofilter is not installed"))
   :group 'spam-bogofilter)
 
+(defvar spam-bogofilter-valid 'unknown "Is the bogofilter version valid?")
+
 (defcustom spam-bogofilter-header "X-Bogosity"
   "The header that Bogofilter inserts in messages."
   :type 'string
@@ -652,11 +686,8 @@ order for SpamAssassin to recognize the new registered spam."
                     :test 'equal)
   "Cache of spam detection entries.")
 
-(defvar spam-old-ham-articles nil
-  "List of old ham articles, generated when a group is entered.")
-
-(defvar spam-old-spam-articles nil
-  "List of old spam articles, generated when a group is entered.")
+(defvar spam-old-articles nil
+  "List of old ham and spam articles, generated when a group is entered.")
 
 (defvar spam-split-disabled nil
   "If non-nil, `spam-split' is disabled, and always returns nil.")
@@ -666,7 +697,17 @@ order for SpamAssassin to recognize the new registered spam."
 `spam-split' will set this to nil or a spam-use-XYZ check if it
 finds ham or spam.")
 
-;; convenience functions
+;; internal variables for backends
+;; TODO: find a way to create these on the fly in spam-install-backend-super
+(defvar spam-use-copy nil)
+(defvar spam-use-move nil)
+(defvar spam-use-gmane nil)
+(defvar spam-use-resend nil)
+
+;;}}}
+
+;;{{{ convenience functions
+
 (defun spam-clear-cache (symbol)
   "Clear the spam-caches entry for a check."
   (remhash symbol spam-caches))
@@ -675,6 +716,20 @@ finds ham or spam.")
   "Logical A xor B."
   (and (or a b) (not (and a b))))
 
+(defun spam-set-difference (list1 list2)
+  "Return a set difference of LIST1 and LIST2.  
+When either list is nil, the other is returned."
+  (if (and list1 list2)
+      ;; we have two non-nil lists
+      (progn
+       (dolist (item (append list1 list2))
+         (when (and (memq item list1) (memq item list2))
+           (setq list1 (delq item list1))
+           (setq list2 (delq item list2))))
+       (append list1 list2))
+    ;; if either of the lists was nil, return the other one
+    (if list1 list1 list2)))
+
 (defun spam-group-ham-mark-p (group mark &optional spam)
   "Checks if MARK is considered a ham mark in GROUP."
   (when (stringp group)
@@ -704,7 +759,7 @@ finds ham or spam.")
 
 (defun spam-group-spam-contents-p (group)
   "Is GROUP a spam group?"
-  (if (stringp group)
+  (if (and (stringp group) (< 0 (length group)))
       (or (member group spam-junk-mailgroups)
          (memq 'gnus-group-spam-classification-spam
                (gnus-parameter-spam-contents group)))
@@ -717,75 +772,381 @@ finds ham or spam.")
            (gnus-parameter-spam-contents group))
     nil))
 
-(defvar spam-list-of-processors
-  ;; note the nil processors are not defined in gnus.el
-  '((nil spam spam-use-gmane)
-    (nil spam spam-use-resend)
-    (gnus-group-spam-exit-processor-bogofilter   spam spam-use-bogofilter)
-    (gnus-group-spam-exit-processor-bsfilter    spam spam-use-bsfilter)
-    (gnus-group-spam-exit-processor-blacklist    spam spam-use-blacklist)
-    (gnus-group-spam-exit-processor-ifile        spam spam-use-ifile)
-    (gnus-group-spam-exit-processor-stat         spam spam-use-stat)
-    (gnus-group-spam-exit-processor-spamoracle   spam spam-use-spamoracle)
-    (nil spam spam-use-crm114)
-    (gnus-group-spam-exit-processor-spamassassin spam spam-use-spamassassin)
-    (gnus-group-ham-exit-processor-ifile         ham spam-use-ifile)
-    (gnus-group-ham-exit-processor-bogofilter    ham spam-use-bogofilter)
-    (gnus-group-ham-exit-processor-bsfilter      ham spam-use-bsfilter)
-    (gnus-group-ham-exit-processor-stat          ham spam-use-stat)
-    (gnus-group-ham-exit-processor-whitelist     ham spam-use-whitelist)
-    (gnus-group-ham-exit-processor-BBDB          ham spam-use-BBDB)
-    (gnus-group-ham-exit-processor-copy          ham spam-use-ham-copy)
-    (gnus-group-ham-exit-processor-spamassassin  ham spam-use-spamassassin)
-    (gnus-group-ham-exit-processor-spamoracle    ham spam-use-spamoracle)
-    (nil ham spam-use-crm114))
-  "The `spam-list-of-processors' list.
-This list contains pairs associating the obsolete ham/spam exit
-processor variables with a classification and a spam-use-*
-variable.  When the processor variable is nil, just the
-classification and spam-use-* check variable are used.")
+(defun spam-classifications ()
+  "Return list of valid classifications"
+  '(spam ham))
 
-(defun spam-group-processor-p (group check &optional classification)
-  "Checks if GROUP has a CHECK with CLASSIFICATION registered.
-Also accepts the obsolete processors, which can be found in
-gnus.el and in spam-list-of-processors."
-  (if (and (stringp group)
-          (symbolp check))
-      (let ((old-style (assq check spam-list-of-processors))
-           (parameters (nth 0 (gnus-parameter-spam-process group)))
-           found)
-       (if old-style  ; old-style processor
-           (spam-group-processor-p group (nth 2 old-style) (nth 1 old-style))
-         ;; now search for the parameter
-         (dolist (parameter parameters)
-           (when (and (null found)
-                      (listp parameter)
-                      (eq classification (nth 0 parameter))
-                      (eq check (nth 1 parameter)))
-             (setq found t)))
-         found))
-    nil))
+(defun spam-classification-valid-p (classification)
+  "Is CLASSIFICATION a valid spam/ham classification?"
+  (memq classification (spam-classifications)))
 
-(defun spam-report-articles-gmane (n)
-  "Report the current message as spam via Gmane.
-Respects the process/prefix convention."
-  (interactive "P")
-  (dolist (article (gnus-summary-work-articles n))
-    (gnus-summary-remove-process-mark article)
-    (spam-report-gmane article)))
-
-(defun spam-report-articles-resend (n)
-  "Report the current message as spam by resending it.
-Respects the process/prefix convention.  Also see
-`spam-report-resend-to'."
-  (interactive "P")
-  (let ((spam-report-resend-to 
-        (gnus-parameter-spam-resend-to gnus-newsgroup-name))
-       (articles (gnus-summary-work-articles n)))
-    (spam-report-resend articles)
+(defun spam-backend-properties ()
+  "Return list of valid classifications."
+  '(statistical mover check hrf srf huf suf))
+
+(defun spam-backend-property-valid-p (property)
+  "Is PROPERTY a valid backend property?"
+  (memq property (spam-backend-properties)))
+
+(defun spam-backend-function-type-valid-p (type)
+  (or (eq type 'registration)
+      (eq type 'unregistration)))
+
+(defun spam-process-type-valid-p (process-type)
+  (or (eq process-type 'incoming)
+      (eq process-type 'process)))
+
+(defun spam-list-articles (articles classification)
+  (let ((mark-check (if (eq classification 'spam)
+                       'spam-group-spam-m