;;; 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.
;; 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)
;; 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
: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
(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)
: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)
(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
: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.")
`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))
"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)
(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)))
(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