(require 'dns)
(require 'message)
-(autoload 'bbdb-records "bbdb-com")
-
;; Attempt to load BBDB macros
(eval-when-compile
(condition-case nil
(require 'bbdb-com)
- (file-error (defalias 'bbdb-search 'ignore))
- (error)))
+ (file-error (defalias 'bbdb-search 'ignore))))
;; autoload executable-find
-(autoload 'executable-find "executable")
+(eval-and-compile
+ ;; executable-find is not autoloaded in Emacs 20
+ (autoload 'executable-find "executable"))
+
+;; autoload ifile-spam-filter
+(eval-and-compile
+ (autoload 'ifile-spam-filter "ifile-gnus"))
+
+;; autoload query-dig
+(eval-and-compile
+ (autoload 'query-dig "dig"))
;;; Main parameters.
+(defvar spam-use-dig t
+ "True if query-dig should be used instead of query-dns.")
+
(defvar spam-use-blacklist t
"True if the blacklist should be used.")
-(defvar spam-use-whitelist t
+(defvar spam-use-whitelist nil
"True if the whitelist should be used.")
(defvar spam-use-blackholes nil
- ;; FIXME! Turned off for now. The DNS routines are said to be flaky.
"True if blackholes should be used.")
-(defvar spam-use-bogofilter t
+(defvar spam-use-bogofilter nil
"True if bogofilter should be used.")
+(defvar spam-use-bbdb nil
+ "True if BBDB should be used.")
+
+(defvar spam-use-ifile nil
+ "True if ifile should be used.")
+
(defvar spam-split-group "spam"
"Usual group name where spam should be split.")
(gnus-define-keys gnus-summary-mode-map
"St" spam-bogofilter-score
"Sx" gnus-summary-mark-as-spam
+ "Mst" spam-bogofilter-score
+ "Msx" gnus-summary-mark-as-spam
"\M-d" gnus-summary-mark-as-spam)
;;; How to highlight a spam summary line.
\f
;;;; Spam determination.
-;; The following list contains pairs associating a parameter variable with a
-;; spam checking function. If the parameter variable is true, then the
-;; checking function is called, and its value decides what happens. Each
-;; individual check may return `nil', `t', or a mailgroup name. The value
-;; `nil' means that the check does not yield a decision, and so, that further
-;; checks are needed. The value `t' means that the message is definitely not
-;; spam, and that further spam checks should be inhibited. Otherwise, a
-;; mailgroup name is returned where the mail should go, and further checks are
-;; also inhibited. The usual mailgroup name is the value of
-;; `spam-split-group', meaning that the message is definitely a spam.
(defvar spam-list-of-checks
'((spam-use-blacklist . spam-check-blacklist)
(spam-use-whitelist . spam-check-whitelist)
(spam-use-bbdb . spam-check-bbdb)
+ (spam-use-ifile . spam-check-ifile)
(spam-use-blackholes . spam-check-blackholes)
- (spam-use-bogofilter . spam-check-bogofilter)))
+ (spam-use-bogofilter . spam-check-bogofilter))
+"The spam-list-of-checks list contains pairs associating a parameter
+variable with a spam checking function. If the parameter variable is
+true, then the checking function is called, and its value decides what
+happens. Each individual check may return `nil', `t', or a mailgroup
+name. The value `nil' means that the check does not yield a decision,
+and so, that further checks are needed. The value `t' means that the
+message is definitely not spam, and that further spam checks should be
+inhibited. Otherwise, a mailgroup name is returned where the mail
+should go, and further checks are also inhibited. The usual mailgroup
+name is the value of `spam-split-group', meaning that the message is
+definitely a spam.")
(defun spam-split ()
"Split this message into the `spam' group if it is spam.
decision)
(while (and list-of-checks (not decision))
(let ((pair (pop list-of-checks)))
- (when (eval (car pair))
- (setq decision (apply (cdr pair))))))
+ (when (symbol-value (car pair))
+ (setq decision (funcall (cdr pair))))))
(if (eq decision t)
nil
decision)))
(defvar spam-blackhole-servers '("bl.spamcop.net"
"relays.ordb.org"
"dev.null.dk"
- "relays.visi.com"
- "rbl.maps.vix.com")
+ "relays.visi.com")
"List of blackhole servers.")
(defun spam-check-blackholes ()
- "Check the Receieved headers for blackholed relays."
+ "Check the Received headers for blackholed relays."
(let ((headers (message-fetch-field "received"))
ips matches)
(when headers
ips)))
(dolist (server spam-blackhole-servers)
(dolist (ip ips)
- (when (query-dns (concat ip "." server))
- (push (list ip server (query-dns (concat ip "." server) 'TXT))
- matches)))))
+ (let ((query-string (concat ip "." server)))
+ (if spam-use-dig
+ (let ((query-result (query-dig query-string)))
+ (when query-result
+ (message "spam detected with blackhole check of relay %s (dig query result '%s')" query-string query-result)
+ (push (list ip server query-result)
+ matches)))
+ ;; else, if not using dig.el
+ (when (query-dns query-string)
+ (push (list ip server (query-dns query-string 'TXT))
+ matches)))))))
(when matches
spam-split-group)))
\f
(setq spam-whitelist-cache (spam-parse-list spam-whitelist)))
(if (spam-from-listed-p spam-whitelist-cache) nil spam-split-group))
-;;; copied from code by Alexander Kotelnikov <sacha@giotto.sj.ru>
-(defun spam-check-bbdb ()
- "We want messages from people who are in the BBDB not to be split to spam"
- (let ((who (message-fetch-field "from")))
- (when who
- (setq who (regexp-quote (cadr (gnus-extract-address-components who))))
- (if (bbdb-search (bbdb-records) nil nil who) nil spam-split-group))))
-
-;; let spam-check-bbdb be nil if the BBDB can't be loaded
+;;; original idea from Alexander Kotelnikov <sacha@giotto.sj.ru>
(condition-case nil
- (require 'bbdb)
- (file-error (defalias 'spam-check-bbdb 'ignore)))
+ (progn
+ (require 'bbdb-com)
+ (defun spam-check-bbdb ()
+ "We want messages from people who are in the BBDB not to be split to spam"
+ (let ((who (message-fetch-field "from")))
+ (when who
+ (setq who (regexp-quote (cadr (gnus-extract-address-components who))))
+ (if (bbdb-search (bbdb-records) nil nil who) nil spam-split-group)))))
+ (file-error (setq spam-list-of-checks
+ (delete (assoc 'spam-use-bbdb spam-list-of-checks)
+ spam-list-of-checks))))
+
+;;; check the ifile backend; return nil if the mail was NOT classified as spam
+(condition-case nil
+ (progn
+ (require 'ifile-gnus)
+ ;;;
+ (defun spam-check-ifile ()
+ (let ((ifile-primary-spam-group spam-split-group))
+ (ifile-spam-filter nil))))
+ (file-error (setq spam-list-of-checks
+ (delete (assoc 'spam-use-ifile spam-list-of-checks)
+ spam-list-of-checks))))
(defun spam-check-blacklist ()
;; FIXME! Should it detect when file timestamps change?
(setq found t
cache nil)))
found))
+
\f
;;;; Training via Bogofilter. Last updated 2002-09-02.
;;; make install
;;;
;;; Here as well, you need to become super-user for the last step. Now,
-;;; initialises your word lists by doing, under your own identity:
+;;; initialize your word lists by doing, under your own identity:
;;;
;;; mkdir ~/.bogofilter
;;; touch ~/.bogofilter/badlist
(interactive)
(when (and spam-use-bogofilter spam-bogofilter-path)
(spam-bogofilter-articles nil "-v" (list (gnus-summary-article-number)))
- (save-excursion
- (set-buffer spam-output-buffer-name)
- (unless (= (point-min) (point-max))
- (display-message-or-buffer (current-buffer)
- spam-output-buffer-name)))))
+ (with-current-buffer spam-output-buffer-name
+ (unless (zerop (buffer-size))
+ (if (<= (count-lines (point-min) (point-max)) 1)
+ (progn
+ (goto-char (point-max))
+ (when (bolp)
+ (backward-char 1))
+ (message "%s" (buffer-substring (point-min) (point))))
+ (goto-char (point-min))
+ (display-buffer (current-buffer)))))))
(defun spam-bogofilter-register-routine ()
(when (and spam-use-bogofilter spam-bogofilter-path)
(message "%s %d" prefix counter))
(setq article (pop articles))
(gnus-summary-goto-subject article)
- (gnus-summary-select-article)
+ (gnus-summary-show-article t)
(gnus-eval-in-buffer-window article-copy
(insert-buffer-substring gnus-original-article-buffer)
;; Remove spam classification redundant headers: they may induce