* gnus.el (spam-process, spam-autodetect-methods): Add
authorTSUCHIYA Masatoshi <tsuchiya@namazu.org>
Fri, 30 Apr 2004 14:33:59 +0000 (14:33 +0000)
committerTSUCHIYA Masatoshi <tsuchiya@namazu.org>
Fri, 30 Apr 2004 14:33:59 +0000 (14:33 +0000)
bsfilter and bsfilter-headers.

* spam.el (spam-bsfilter): New customize group.
(spam-use-bsfilter, spam-use-bsfilter-headers, spam-bsfilter-path)
(spam-bsfilter-header, spam-bsfilter-probability-header)
(spam-bsfilter-spam-switch, spam-bsfilter-ham-switch)
(spam-bsfilter-spam-strong-switch, spam-bsfilter-ham-strong-switch)
(spam-bsfilter-database-directory): New options.
(spam-install-hooks, spam-list-of-processors, spam-list-of-checks)
(spam-list-of-statistical-checks, spam-registration-functions):
Add `spam-use-bsfilter' and `spam-use-bsfilter-headers'.
(spam-bsfilter-score): New command.
(spam-check-bsfilter-headers, spam-check-bsfilter)
(spam-bsfilter-register-with-bsfilter)
(spam-bsfilter-register-spam-routine)
(spam-bsfilter-unregister-spam-routine)
(spam-bsfilter-register-ham-routine)
(spam-bsfilter-unregister-ham-routine): New functions.
(spam-generic-score): Supprt bsfilter; Accept an optional argument
to recalcurate spam score even if scoring header has already been
added.
(spam-bogofilter-score, spam-spamassassin-score): Accept an
optional argument to recalcurate spam score even if scoring header
has already been added.

lisp/ChangeLog
lisp/gnus.el
lisp/spam.el

index f962bd4..f888ea0 100644 (file)
@@ -1,3 +1,31 @@
+2004-04-30  TSUCHIYA Masatoshi  <tsuchiya@namazu.org>
+
+       * gnus.el (spam-process, spam-autodetect-methods): Add
+       bsfilter and bsfilter-headers.
+
+       * spam.el (spam-bsfilter): New customize group.
+       (spam-use-bsfilter, spam-use-bsfilter-headers, spam-bsfilter-path)
+       (spam-bsfilter-header, spam-bsfilter-probability-header)
+       (spam-bsfilter-spam-switch, spam-bsfilter-ham-switch)
+       (spam-bsfilter-spam-strong-switch, spam-bsfilter-ham-strong-switch)
+       (spam-bsfilter-database-directory): New options.
+       (spam-install-hooks, spam-list-of-processors, spam-list-of-checks)
+       (spam-list-of-statistical-checks, spam-registration-functions):
+       Add `spam-use-bsfilter' and `spam-use-bsfilter-headers'.
+       (spam-bsfilter-score): New command.
+       (spam-check-bsfilter-headers, spam-check-bsfilter)
+       (spam-bsfilter-register-with-bsfilter)
+       (spam-bsfilter-register-spam-routine)
+       (spam-bsfilter-unregister-spam-routine)
+       (spam-bsfilter-register-ham-routine)
+       (spam-bsfilter-unregister-ham-routine): New functions.
+       (spam-generic-score): Supprt bsfilter; Accept an optional argument
+       to recalcurate spam score even if scoring header has already been
+       added.
+       (spam-bogofilter-score, spam-spamassassin-score): Accept an
+       optional argument to recalcurate spam score even if scoring header
+       has already been added.
+
 2004-04-29  Jesper Harder  <harder@ifa.au.dk>
 
        * nnrss.el (nnrss-get-namespace-prefix): Use string= to compare
index 2503dde..dfcbcfb 100644 (file)
@@ -1893,21 +1893,23 @@ Only applicable to non-spam (unclassified and ham) groups.")
            (variable-item gnus-group-ham-exit-processor-BBDB)
            (variable-item gnus-group-ham-exit-processor-spamoracle)
            (variable-item gnus-group-ham-exit-processor-copy)
-           (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
            (const :tag "Spam: Bogofilter"    (spam spam-use-bogofilter))
            (const :tag "Spam: Blacklist"     (spam spam-use-blacklist))
-           (const :tag "Spam: ifile"         (spam spam-use-ifile))
-           (const :tag "Spam: Spam-stat"     (spam spam-use-stat))
+           (const :tag "Spam: Bsfilter"      (spam spam-use-bsfilter))
+           (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
+           (const :tag "Spam: ifile"         (spam spam-use-ifile))
            (const :tag "Spam: Spam Oracle"   (spam spam-use-spamoracle))
+           (const :tag "Spam: Spam-stat"     (spam spam-use-stat))
            (const :tag "Spam: SpamAssassin"  (spam spam-use-spamassassin))
-           (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
-           (const :tag "Ham: ifile"          (ham spam-use-ifile))
+           (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
            (const :tag "Ham: Bogofilter"     (ham spam-use-bogofilter))
+           (const :tag "Ham: Bsfilter"       (ham spam-use-bsfilter))
+           (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
+           (const :tag "Ham: ifile"          (ham spam-use-ifile))
+           (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle))
            (const :tag "Ham: Spam-stat"      (ham spam-use-stat))
-           (const :tag "Ham: Whitelist"      (ham spam-use-whitelist))
-           (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
-           (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
-           (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle)))))
+           (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
+           (const :tag "Ham: Whitelist"      (ham spam-use-whitelist)))))
    :function-document
    "Which spam or ham processors will be applied when the summary is exited."
    :variable gnus-spam-process-newsgroups
@@ -1937,21 +1939,23 @@ spam processing, associated with the appropriate processor."
                   (variable-item gnus-group-ham-exit-processor-BBDB)
                   (variable-item gnus-group-ham-exit-processor-spamoracle)
                   (variable-item gnus-group-ham-exit-processor-copy)
-                  (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
                   (const :tag "Spam: Bogofilter"    (spam spam-use-bogofilter))
                   (const :tag "Spam: Blacklist"     (spam spam-use-blacklist))
-                  (const :tag "Spam: ifile"         (spam spam-use-ifile))
+                  (const :tag "Spam: Bsfilter"      (spam spam-use-bsfilter))
+                  (const :tag "Spam: ifile"         (spam spam-use-ifile))
+                  (const :tag "Spam: Gmane Report"  (spam spam-use-gmane))
                   (const :tag "Spam: Spam-stat"     (spam spam-use-stat))
                   (const :tag "Spam: Spam Oracle"   (spam spam-use-spamoracle))
                   (const :tag "Spam: SpamAssassin"  (spam spam-use-spamassassin))
-                  (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
-                  (const :tag "Ham: ifile"          (ham spam-use-ifile))
+                  (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
                   (const :tag "Ham: Bogofilter"     (ham spam-use-bogofilter))
-                  (const :tag "Ham: Spam-stat"      (ham spam-use-stat))
-                  (const :tag "Ham: Whitelist"      (ham spam-use-whitelist))
-                  (const :tag "Ham: BBDB"           (ham spam-use-BBDB))
-                  (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
-                  (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle)))))
+                  (const :tag "Ham: Bsfilter"       (ham spam-use-bsfilter))
+                  (const :tag "Ham: Copy"           (ham spam-use-ham-copy))
+                  (const :tag "Ham: ifile"          (ham spam-use-ifile))
+                  (const :tag "Ham: Spam-stat"      (ham spam-use-stat))
+                  (const :tag "Ham: Spam Oracle"    (ham spam-use-spamoracle))
+                  (const :tag "Ham: SpamAssassin"   (ham spam-use-spamassassin))
+                  (const :tag "Ham: Whitelist"      (ham spam-use-whitelist)))))
 
    :parameter-document
    "Which spam or ham processors will be applied when the summary is exited.")
@@ -1999,6 +2003,8 @@ spam-autodetect-recheck-messages is set.")
          (variable-item spam-use-spamoracle)
          (variable-item spam-use-spamassassin)
          (variable-item spam-use-spamassassin-headers)
+         (variable-item spam-use-bsfilter)
+         (variable-item spam-use-bsfilter-headers)
          (variable-item spam-use-stat)
          (variable-item spam-use-blackholes)
          (variable-item spam-use-hashcash)
@@ -2036,6 +2042,8 @@ set."
        (variable-item spam-use-hashcash)
        (variable-item spam-use-spamassassin)
        (variable-item spam-use-spamassassin-headers)
+       (variable-item spam-use-bsfilter)
+       (variable-item spam-use-bsfilter-headers)
        (variable-item spam-use-bogofilter-headers)
        (variable-item spam-use-bogofilter)))))
      :parameter-document
index 54a17a2..d2d1464 100644 (file)
@@ -223,6 +223,18 @@ Enable this if you want Gnus to invoke Bogofilter on new messages."
   :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
@@ -277,6 +289,8 @@ them."
                               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
@@ -434,6 +448,53 @@ your main source of newsgroup names."
                 (const :tag "Use the default"))
   :group 'spam-bogofilter)
 
+(defgroup spam-bsfilter nil
+  "Spam bsfilter configuration."
+  :group 'spam)
+
+(defcustom spam-bsfilter-path (exec-installed-p "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)
@@ -600,6 +661,7 @@ finds ham or 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)
@@ -607,6 +669,7 @@ finds ham or spam.")
     (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)
@@ -736,14 +799,15 @@ Will not return a nil score."
        (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.
 
@@ -1057,7 +1121,9 @@ When either list is nil, the other is returned."
     (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,
@@ -1077,6 +1143,7 @@ definitely a spam.")
     spam-use-regex-body
     spam-use-stat
     spam-use-bogofilter
+    spam-use-bsfilter
     spam-use-blackholes
     spam-use-spamassassin
     spam-use-spamoracle)
@@ -1260,7 +1327,11 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
     (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
@@ -1994,13 +2065,14 @@ REMOVE not nil, remove the ADDRESSES."
          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)
@@ -2159,13 +2231,14 @@ REMOVE not nil, remove the ADDRESSES."
        (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)
@@ -2212,6 +2285,94 @@ REMOVE not nil, remove the ADDRESSES."
 
 (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