:type 'boolean
:group 'spam)
+(defcustom spam-use-spamoracle nil
+ "Whether spamoracle should be used by spam-split."
+ :type 'boolean
+ :group 'spam)
+
+(defcustom spam-install-hooks (or
+ spam-use-dig
+ spam-use-blacklist
+ spam-use-whitelist
+ spam-use-whitelist-exclusive
+ spam-use-blackholes
+ spam-use-hashcash
+ spam-use-regex-headers
+ spam-use-bogofilter-headers
+ spam-use-bogofilter
+ spam-use-BBDB
+ spam-use-BBDB-exclusive
+ spam-use-ifile
+ spam-use-stat
+ spam-use-spamoracle)
+ "Whether the spam hooks should be installed, default to t if one of
+the spam-use-* variables is set."
+ :group 'gnus-registry
+ :type 'boolean)
+
(defcustom spam-split-group "spam"
"Group name where incoming spam should be put by spam-split."
:type 'string
(const :tag "Use the default"))
:group 'spam-ifile)
+(defgroup spam-spamoracle nil
+ "Spam ifile configuration."
+ :group 'spam)
+
+(defcustom spam-spamoracle-database nil
+ "Location of spamoracle database file. When nil, use the default
+spamoracle database."
+ :type '(choice (directory :tag "Location of spamoracle database file.")
+ (const :tag "Use the default"))
+ :group 'spam-spamoracle)
+
+(defcustom spam-spamoracle-binary (executable-find "spamoracle")
+ "Location of the spamoracle binary."
+ :type '(choice (directory :tag "Location of the spamoracle binary")
+ (const :tag "Use the default"))
+ :group 'spam-spamoracle)
+
;;; Key bindings for spam control.
(gnus-define-keys gnus-summary-mode-map
(defun spam-group-ham-processor-ifile-p (group)
(spam-group-processor-p group 'gnus-group-ham-exit-processor-ifile))
+(defun spam-group-spam-processor-spamoracle-p (group)
+ (spam-group-processor-p group 'gnus-group-spam-exit-processor-spamoracle))
+
(defun spam-group-ham-processor-bogofilter-p (group)
(spam-group-processor-p group 'gnus-group-ham-exit-processor-bogofilter))
(defun spam-group-ham-processor-copy-p (group)
(spam-group-processor-p group 'gnus-group-ham-exit-processor-copy))
+(defun spam-group-ham-processor-spamoracle-p (group)
+ (spam-group-processor-p group 'gnus-group-ham-exit-processor-spamoracle))
+
;;; Summary entry and exit processing.
(defun spam-summary-prepare ()
(spam-mark-junk-as-spam-routine))
-(add-hook 'gnus-summary-prepare-hook 'spam-summary-prepare)
-
;; The spam processors are invoked for any group, spam or ham or neither
(defun spam-summary-prepare-exit ()
(unless gnus-group-is-exiting-without-update-p
(gnus-message 5 "Registering spam with ifile")
(spam-ifile-register-spam-routine))
+ (when (spam-group-spam-processor-spamoracle-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering spam with spamoracle")
+ (spam-spamoracle-learn-spam))
+
(when (spam-group-spam-processor-stat-p gnus-newsgroup-name)
(gnus-message 5 "Registering spam with spam-stat")
(spam-stat-register-spam-routine))
(spam-stat-register-ham-routine))
(when (spam-group-ham-processor-BBDB-p gnus-newsgroup-name)
(gnus-message 5 "Registering ham with the BBDB")
- (spam-BBDB-register-routine)))
+ (spam-BBDB-register-routine))
+ (when (spam-group-ham-processor-spamoracle-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering ham with spamoracle")
+ (spam-spamoracle-learn-ham)))
(when (spam-group-ham-processor-copy-p gnus-newsgroup-name)
(gnus-message 5 "Copying ham")
(spam-ham-move-routine
(gnus-parameter-ham-process-destination gnus-newsgroup-name)))))
-(add-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
-
(defun spam-mark-junk-as-spam-routine ()
;; check the global list of group names spam-junk-mailgroups and the
;; group parameters
(spam-use-whitelist . spam-check-whitelist)
(spam-use-BBDB . spam-check-BBDB)
(spam-use-ifile . spam-check-ifile)
+ (spam-use-spamoracle . spam-check-spamoracle)
(spam-use-stat . spam-check-stat)
(spam-use-blackholes . spam-check-blackholes)
(spam-use-hashcash . spam-check-hashcash)
definitely a spam.")
(defvar spam-list-of-statistical-checks
- '(spam-use-ifile spam-use-stat spam-use-bogofilter)
+ '(spam-use-ifile spam-use-stat spam-use-bogofilter spam-use-spamoracle)
"The spam-list-of-statistical-checks list contains all the mail
splitters that need to have the full message body available.")
(when (symbol-value check)
(setq nnimap-split-download-body-default t))))
-(add-hook 'gnus-get-new-news-hook 'spam-setup-widening)
-
\f
;;;; Regex headers
(when spam-use-stat (spam-stat-load)))
(defun spam-maybe-spam-stat-save ()
- (when spam-use-stat (spam-stat-save)))
-
- ;; Add hooks for loading and saving the spam stats
- (add-hook 'gnus-save-newsrc-hook 'spam-maybe-spam-stat-save)
- (add-hook 'gnus-get-top-new-news-hook 'spam-maybe-spam-stat-load)
- (add-hook 'gnus-startup-hook 'spam-maybe-spam-stat-load))
+ (when spam-use-stat (spam-stat-save))))
(file-error (progn
+ (defalias 'spam-maybe-spam-stat-load 'ignore)
+ (defalias 'spam-maybe-spam-stat-save 'ignore)
(defalias 'spam-stat-register-ham-routine 'ignore)
(defalias 'spam-stat-register-spam-routine 'ignore)
(defalias 'spam-stat-buffer-is-spam 'ignore)
(spam-bogofilter-register-with-bogofilter
(spam-get-article-as-string article) nil))))
+\f
+;;;; spamoracle
+(defun spam-check-spamoracle ()
+ "Run spamoracle on an article to determine whether it's spam."
+ (let ((article-buffer-name (buffer-name)))
+ (with-temp-buffer
+ (let ((temp-buffer-name (buffer-name)))
+ (save-excursion
+ (set-buffer article-buffer-name)
+ (let ((status
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-spamoracle-binary
+ nil temp-buffer-name nil
+ (if spam-spamoracle-database
+ `("-f" ,spam-spamoracle-database "mark")
+ '("mark")))))
+ (if (zerop status)
+ (progn
+ (set-buffer temp-buffer-name)
+ (goto-char (point-min))
+ (when (re-search-forward "^X-Spam: yes;" nil t)
+ spam-split-group))
+ (error "Error running spamoracle" status))))))))
+
+(defun spam-spamoracle-learn (article article-is-spam-p)
+ "Run spamoracle in training mode."
+ (with-temp-buffer
+ (let ((temp-buffer-name (buffer-name)))
+ (save-excursion
+ (goto-char (point-min))
+ (insert-string (spam-get-article-as-string article))
+ (let* ((arg (if article-is-spam-p "-spam" "-good"))
+ (status
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-spamoracle-binary
+ nil temp-buffer-name nil
+ (if spam-spamoracle-database
+ `("-f" ,spam-spamoracle-database
+ "add" ,arg)
+ `("add" ,arg)))))
+ (when (not (zerop status))
+ (error "Error running spamoracle" status)))))))
+
+(defun spam-spamoracle-learn-ham ()
+ (spam-generic-register-routine
+ nil
+ (lambda (article)
+ (spam-spamoracle-learn article nil))))
+
+(defun spam-spamoracle-learn-spam ()
+ (spam-generic-register-routine
+ (lambda (article)
+ (spam-spamoracle-learn article t))
+ nil))
+\f
+;;;; Hooks
+
+(defun spam-install-hooks-function ()
+ "Install the spam.el hooks"
+ (interactive)
+ ;; Add hooks for loading and saving the spam stats
+ (when spam-use-stat
+ (add-hook 'gnus-save-newsrc-hook 'spam-maybe-spam-stat-save)
+ (add-hook 'gnus-get-top-new-news-hook 'spam-maybe-spam-stat-load)
+ (add-hook 'gnus-startup-hook 'spam-maybe-spam-stat-load))
+ (add-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
+ (add-hook 'gnus-summary-prepare-hook 'spam-summary-prepare)
+ (add-hook 'gnus-get-new-news-hook 'spam-setup-widening))
+
+(defun spam-unload-hook ()
+ "Uninstall the spam.el hooks"
+ (interactive)
+ (remove-hook 'gnus-save-newsrc-hook 'spam-maybe-spam-stat-save)
+ (remove-hook 'gnus-get-top-new-news-hook 'spam-maybe-spam-stat-load)
+ (remove-hook 'gnus-startup-hook 'spam-maybe-spam-stat-load)
+ (remove-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
+ (remove-hook 'gnus-summary-prepare-hook 'spam-summary-prepare)
+ (remove-hook 'gnus-get-new-news-hook 'spam-setup-widening))
+
+(when spam-install-hooks
+ (spam-install-hooks-function))
+
(provide 'spam)
;;; spam.el ends here.