:type 'boolean
:group 'spam)
+(defcustom spam-use-bsfilter-headers nil
+ "Whether bsfilter headers should be used by `spam-split'.
+Enable this if you pre-process messages with Bsfilter BEFORE Gnus sees them."
+ :type 'boolean
+ :group 'spam)
+
+(defcustom spam-use-bsfilter nil
+ "Whether bsfilter should be invoked by `spam-split'.
+Enable this if you want Gnus to invoke Bsfilter on new messages."
+ :type 'boolean
+ :group 'spam)
+
(defcustom spam-use-BBDB nil
"Whether BBDB should be used by `spam-split'."
:type 'boolean
spam-use-bogofilter-headers
spam-use-spamassassin
spam-use-spamassassin-headers
+ spam-use-bsfilter
+ spam-use-bsfilter-headers
spam-use-BBDB
spam-use-BBDB-exclusive
spam-use-ifile
(const :tag "Use the default"))
:group 'spam-bogofilter)
+(defgroup spam-bsfilter nil
+ "Spam bsfilter configuration."
+ :group 'spam)
+
+(defcustom spam-bsfilter-path (executable-find "bsfilter")
+ "File path of the Bsfilter executable program."
+ :type '(choice (file :tag "Location of bsfilter")
+ (const :tag "Bsfilter is not installed"))
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-header "X-Spam-Flag"
+ "The header inserted by Bsfilter to flag spam."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-probability-header "X-Spam-Probability"
+ "The header that Bsfilter inserts in messages."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-spam-switch "--add-spam"
+ "The switch that Bsfilter uses to register spam messages."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-ham-switch "--add-ham"
+ "The switch that Bsfilter uses to register ham messages."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-spam-strong-switch "--sub-spam"
+ "The switch that Bsfilter uses to unregister ham messages."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-ham-strong-switch "--sub-clean"
+ "The switch that Bsfilter uses to unregister spam messages."
+ :type 'string
+ :group 'spam-bsfilter)
+
+(defcustom spam-bsfilter-database-directory nil
+ "Directory path of the Bsfilter databases."
+ :type '(choice (directory
+ :tag "Location of the Bsfilter database directory")
+ (const :tag "Use the default"))
+ :group 'spam-bsfilter)
+
(defgroup spam-spamoracle nil
"Spam spamoracle configuration."
:group 'spam)
(defvar spam-list-of-processors
'((gnus-group-spam-exit-processor-report-gmane spam spam-use-gmane)
(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-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)
(return)))
(or score 0)))
-(defun spam-generic-score ()
+(defun spam-generic-score (&optional recheck)
"Invoke whatever scoring method we can."
- (interactive)
- (if (or
- spam-use-spamassassin
- spam-use-spamassassin-headers)
- (spam-spamassassin-score)
- (spam-bogofilter-score)))
+ (interactive "P")
+ (cond
+ ((or spam-use-spamassassin spam-use-spamassassin-headers)
+ (spam-spamassassin-score recheck))
+ ((or spam-use-bsfilter spam-use-bsfilter-headers)
+ (spam-bsfilter-score recheck))
+ (t (spam-bogofilter-score recheck))))
;;; Summary entry and exit processing.
(unless (and spam-move-spam-nonspam-groups-only
(spam-group-spam-contents-p gnus-newsgroup-name))
- (gnus-message 5 "Marking spam as expired and moving it to %s"
+ (gnus-message 6 "Marking spam as expired and moving it to %s"
(gnus-parameter-spam-process-destination
gnus-newsgroup-name))
(spam-mark-spam-as-expired-and-move-routine
;; now we redo spam-mark-spam-as-expired-and-move-routine to only
;; expire spam, in case the above did not expire them
- (gnus-message 5 "Marking spam as expired without moving it")
- (spam-mark-spam-as-expired-and-move-routine nil)
+ (when (< 0 (length (spam-list-articles
+ gnus-newsgroup-articles
+ 'spam)))
+ (gnus-message 6 "Marking spam as expired without moving it")
+ (spam-mark-spam-as-expired-and-move-routine nil))
(when (or (spam-group-ham-contents-p gnus-newsgroup-name)
(and (spam-group-spam-contents-p gnus-newsgroup-name)
(spam-register-routine classification check)))))
(when (spam-group-ham-processor-copy-p gnus-newsgroup-name)
- (gnus-message 5 "Copying ham")
+ (gnus-message 6 "Copying ham")
(spam-ham-copy-routine
(gnus-parameter-ham-process-destination gnus-newsgroup-name)))
;; now move all ham articles out of spam groups
(when (spam-group-spam-contents-p gnus-newsgroup-name)
- (gnus-message 5 "Moving ham messages from spam group")
+ (gnus-message 6 "Moving ham messages from spam group")
(spam-ham-move-routine
(gnus-parameter-ham-process-destination gnus-newsgroup-name))))
;; check the global list of group names spam-junk-mailgroups and the
;; group parameters
(when (spam-group-spam-contents-p gnus-newsgroup-name)
- (gnus-message 5 "Marking %s articles as spam"
+ (gnus-message 6 "Marking %s articles as spam"
(if spam-mark-only-unseen-as-spam
"unseen"
"unread"))
(mail-header-extra data-header))
(t
nil))
- (gnus-message 5 "Article %d has a nil data header" article)))))
+ (gnus-message 6 "Article %d has a nil data header" article)))))
(defun spam-fetch-field-from-fast (article &optional prepared-data-header)
(spam-fetch-field-fast article 'from prepared-data-header))
(spam-use-spamassassin-headers . spam-check-spamassassin-headers)
(spam-use-spamassassin . spam-check-spamassassin)
(spam-use-bogofilter-headers . spam-check-bogofilter-headers)
- (spam-use-bogofilter . spam-check-bogofilter))
+ (spam-use-bogofilter . spam-check-bogofilter)
+ (spam-use-bsfilter-headers . spam-check-bsfilter-headers)
+ (spam-use-bsfilter . spam-check-bsfilter))
"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,
spam-use-regex-body
spam-use-stat
spam-use-bogofilter
+ spam-use-bsfilter
spam-use-blackholes
spam-use-spamassassin
spam-use-spamoracle)
(and specific-checks (memq (car pair) specific-checks))
;; or, given no specific checks, spam-use-CHECK is set
(and (null specific-checks) (symbol-value (car pair))))
- (gnus-message 5 "spam-split: calling the %s function"
+ (gnus-message 6 "spam-split: calling the %s function"
(symbol-name (cdr pair)))
(setq decision (funcall (cdr pair)))
;; if we got a decision at all, save the current check
registry-lookup)
(unless id
- (gnus-message 5 "Article %d has no message ID!" article))
+ (gnus-message 6 "Article %d has no message ID!" article))
(when (and id spam-log-to-registry)
(setq registry-lookup (spam-log-registration-type id 'incoming))
(spam-use-bogofilter spam-bogofilter-register-ham-routine
spam-bogofilter-register-spam-routine
spam-bogofilter-unregister-ham-routine
- spam-bogofilter-unregister-spam-routine))
+ spam-bogofilter-unregister-spam-routine)
+ (spam-use-bsfilter spam-bsfilter-register-ham-routine
+ spam-bsfilter-register-spam-routine
+ spam-bsfilter-unregister-ham-routine
+ spam-bsfilter-unregister-spam-routine))
"The spam-registration-functions list contains pairs
associating a parameter variable with the ham and spam
registration functions, and the ham and spam unregistration
type
new-cell-list))
(progn
- (gnus-message 5 (format "%s call with bad ID, type, spam-check, or group"
+ (gnus-message 6 (format "%s call with bad ID, type, spam-check, or group"
"spam-log-undo-registration"))
nil))))
(with-temp-buffer
(insert headers)
(goto-char (point-min))
- (gnus-message 5 "Checking headers for relay addresses")
+ (gnus-message 6 "Checking headers for relay addresses")
(while (re-search-forward
"\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)" nil t)
(gnus-message 9 "Blackhole search found host IP %s." (match-string 1))
(if spam-use-dig
(let ((query-result (query-dig query-string)))
(when query-result
- (gnus-message 5 "(DIG): positive blackhole check '%s'"
+ (gnus-message 6 "(DIG): positive blackhole check '%s'"
query-result)
(push (list ip server query-result)
matches)))
;; else, if not using dig.el
(when (query-dns query-string)
- (gnus-message 5 "positive blackhole check")
+ (gnus-message 6 "positive blackhole check")
(push (list ip server (query-dns query-string 'TXT))
matches)))))))))
(when matches
(record (and net-address
(bbdb-search-simple nil net-address))))
(when net-address
- (gnus-message 5 "%s address %s %s BBDB"
+ (gnus-message 6 "%s address %s %s BBDB"
(if remove "Deleting" "Adding")
from
(if remove "from" "to"))
spam-split-group)))))
;; return something sensible if the score can't be determined
-(defun spam-bogofilter-score ()
+(defun spam-bogofilter-score (&optional recheck)
"Get the Bogofilter spamicity score"
- (interactive)
+ (interactive "P")
(save-window-excursion
(gnus-summary-show-article t)
(set-buffer gnus-article-buffer)
- (let ((score (or (spam-check-bogofilter-headers t)
+ (let ((score (or (unless recheck
+ (spam-check-bogofilter-headers t))
(spam-check-bogofilter t))))
(gnus-summary-show-article)
(message "Spamicity score %s" score)
(spam-check-spamassassin-headers score)))))
;; return something sensible if the score can't be determined
-(defun spam-spamassassin-score ()
+(defun spam-spamassassin-score (&optional recheck)
"Get the SpamAssassin score"
- (interactive)
+ (interactive "P")
(save-window-excursion
(gnus-summary-show-article t)
(set-buffer gnus-article-buffer)
- (let ((score (or (spam-check-spamassassin-headers t)
+ (let ((score (or (unless recheck
+ (spam-check-spamassassin-headers t))
(spam-check-spamassassin t))))
(gnus-summary-show-article)
(message "SpamAssassin score %s" score)
(defun spam-spamassassin-unregister-ham-routine (articles)
(spam-spamassassin-register-with-sa-learn articles nil t))
+
+\f
+;;;; Bsfilter
+;;; based mostly on the bogofilter code
+(defun spam-check-bsfilter-headers (&optional score)
+ (if score
+ (or (nnmail-fetch-field spam-bsfilter-probability-header)
+ "0")
+ (let ((header (nnmail-fetch-field spam-bsfilter-header))
+ (spam-split-group (if spam-split-symbolic-return
+ 'spam
+ spam-split-group)))
+ (when header ; return nil when no header
+ (when (string-match "YES" header)
+ spam-split-group)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-bsfilter-score (&optional recheck)
+ "Get the Bsfilter spamicity score"
+ (interactive "P")
+ (save-window-excursion
+ (gnus-summary-show-article t)
+ (set-buffer gnus-article-buffer)
+ (let ((score (or (unless recheck
+ (spam-check-bsfilter-headers t))
+ (spam-check-bsfilter t))))
+ (gnus-summary-show-article)
+ (message "Spamicity score %s" score)
+ (or score "0"))))
+
+(defun spam-check-bsfilter (&optional score)
+ "Check the Bsfilter backend for the classification of this message"
+ (let ((article-buffer-name (buffer-name))
+ (dir spam-bsfilter-database-directory)
+ return)
+ (with-temp-buffer
+ (let ((temp-buffer-name (buffer-name)))
+ (save-excursion
+ (set-buffer article-buffer-name)
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-bsfilter-path
+ nil temp-buffer-name nil
+ "--pipe"
+ "--insert-flag"
+ "--insert-probability"
+ (when dir
+ (list "--homedir" dir))))
+ (setq return (spam-check-bsfilter-headers score))))
+ return))
+
+(defun spam-bsfilter-register-with-bsfilter (articles
+ spam
+ &optional unregister)
+ "Register an article, given as a string, as spam or non-spam."
+ (dolist (article articles)
+ (let ((article-string (spam-get-article-as-string article))
+ (switch (if unregister
+ (if spam
+ spam-bsfilter-spam-strong-switch
+ spam-bsfilter-ham-strong-switch)
+ (if spam
+ spam-bsfilter-spam-switch
+ spam-bsfilter-ham-switch))))
+ (when (stringp article-string)
+ (with-temp-buffer
+ (insert article-string)
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-bsfilter-path
+ nil nil nil switch
+ "--update"
+ (when spam-bsfilter-database-directory
+ (list "--homedir"
+ spam-bsfilter-database-directory))))))))
+
+(defun spam-bsfilter-register-spam-routine (articles &optional unregister)
+ (spam-bsfilter-register-with-bsfilter articles t unregister))
+
+(defun spam-bsfilter-unregister-spam-routine (articles)
+ (spam-bsfilter-register-spam-routine articles t))
+
+(defun spam-bsfilter-register-ham-routine (articles &optional unregister)
+ (spam-bsfilter-register-with-bsfilter articles nil unregister))
+
+(defun spam-bsfilter-unregister-ham-routine (articles)
+ (spam-bsfilter-register-ham-routine articles t))
+
\f
;;;; Hooks