;;; Code:
+(eval-when-compile (require 'cl))
+
(require 'gnus-sum)
(require 'gnus-uu) ; because of key prefix issues
(require 'gnus) ; for the definitions of group content classification and spam processors
(require 'message) ;for the message-fetch-field functions
+;; for nnimap-split-download-body-default
+(eval-when-compile (require 'nnimap))
+
;; autoload executable-find
(eval-and-compile
;; executable-find is not autoloaded in Emacs 20
(eval-and-compile
(autoload 'query-dig "dig"))
+;; autoload spam-report
+(eval-and-compile
+ (autoload 'spam-report-gmane "spam-report"))
+
;; autoload query-dns
(eval-and-compile
(autoload 'query-dns "dns"))
to the spam-process-destination. When t, spam will also be moved from
spam groups."
:type 'boolean
- :group 'spam-ifile)
+ :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
+spam. Set this if you want to leave an article unread in a spam group
+without losing it to the automatic spam-marking process."
+ :type 'boolean
+ :group 'spam)
+
+(defcustom spam-mark-ham-unread-before-move-from-spam-group nil
+ "Whether ham should be marked unread before it's moved out of a spam
+group according to ham-process-destination. This variable is an
+official entry in the international Longest Variable Name
+Competition."
+ :type 'boolean
+ :group 'spam)
(defcustom spam-whitelist (expand-file-name "whitelist" spam-directory)
"The location of the whitelist.
:type 'boolean
:group 'spam)
+(defcustom spam-use-hashcash nil
+ "Whether hashcash payments should be detected by spam-split."
+ :type 'boolean
+ :group 'spam)
+
(defcustom spam-use-regex-headers nil
"Whether a header regular expression match should be used by spam-split.
-Also see the variable `spam-spam-regex-headers' and `spam-ham-regex-headers'."
+Also see the variables `spam-regex-headers-spam' and `spam-regex-headers-ham'."
:type 'boolean
:group 'spam)
: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
:type 'regexp
:group 'spam)
-(defcustom spam-ham-marks (list 'gnus-del-mark 'gnus-read-mark
- 'gnus-killed-mark 'gnus-kill-file-mark
- 'gnus-low-score-mark)
- "Marks considered as being ham (positively not spam).
-Such articles will be processed as ham (non-spam) on group exit."
- :type '(set
- (variable-item gnus-del-mark)
- (variable-item gnus-read-mark)
- (variable-item gnus-killed-mark)
- (variable-item gnus-kill-file-mark)
- (variable-item gnus-low-score-mark))
- :group 'spam)
-
-(defcustom spam-spam-marks (list 'gnus-spam-mark)
- "Marks considered as being spam (positively spam).
-Such articles will be transmitted to `bogofilter -s' on group exit."
- :type '(set
- (variable-item gnus-spam-mark)
- (variable-item gnus-killed-mark)
- (variable-item gnus-kill-file-mark)
- (variable-item gnus-low-score-mark))
- :group 'spam)
-
(defcustom spam-face 'gnus-splash-face
"Face for spam-marked articles"
:type 'face
:type 'string
:group 'spam-bogofilter)
+(defcustom spam-bogofilter-spam-switch "-s"
+ "The switch that Bogofilter uses to register spam messages."
+ :type 'string
+ :group 'spam-bogofilter)
+
+(defcustom spam-bogofilter-ham-switch "-n"
+ "The switch that Bogofilter uses to register ham messages."
+ :type 'string
+ :group 'spam-bogofilter)
+
(defcustom spam-bogofilter-bogosity-positive-spam-header "^\\(Yes\\|Spam\\)"
"The regex on `spam-bogofilter-header' for positive spam identification."
:type 'regexp
(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
gnus-summary-highlight)
;; convenience functions
+(defun spam-group-ham-mark-p (group mark &optional spam)
+ (when (stringp group)
+ (let* ((marks (spam-group-ham-marks group spam))
+ (marks (if (symbolp mark)
+ marks
+ (mapcar 'symbol-value marks))))
+ (memq mark marks))))
+
+(defun spam-group-spam-mark-p (group mark)
+ (spam-group-ham-mark-p group mark t))
+
+(defun spam-group-ham-marks (group &optional spam)
+ (when (stringp group)
+ (let* ((marks (if spam
+ (gnus-parameter-spam-marks group)
+ (gnus-parameter-ham-marks group)))
+ (marks (car marks))
+ (marks (if (listp (car marks)) (car marks) marks)))
+ marks)))
+
+(defun spam-group-spam-marks (group)
+ (spam-group-ham-marks group t))
+
(defun spam-group-spam-contents-p (group)
(if (stringp group)
(or (member group spam-junk-mailgroups)
(member processor (car (gnus-parameter-spam-process group)))
nil))
+(defun spam-group-spam-processor-report-gmane-p (group)
+ (spam-group-processor-p group 'gnus-group-spam-exit-processor-report-gmane))
+
(defun spam-group-spam-processor-bogofilter-p (group)
(spam-group-processor-p group 'gnus-group-spam-exit-processor-bogofilter))
(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-BBDB-p (group)
(spam-group-processor-p group 'gnus-group-ham-exit-processor-BBDB))
+(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 ()
- ;; The spam processors are invoked for any group, spam or ham or neither
- (gnus-message 6 "Exiting summary buffer and applying spam rules")
- (when (and spam-bogofilter-path
- (spam-group-spam-processor-bogofilter-p gnus-newsgroup-name))
- (gnus-message 5 "Registering spam with bogofilter")
- (spam-bogofilter-register-spam-routine))
+ (unless gnus-group-is-exiting-without-update-p
+ (gnus-message 6 "Exiting summary buffer and applying spam rules")
+ (when (and spam-bogofilter-path
+ (spam-group-spam-processor-bogofilter-p gnus-newsgroup-name))
+ (gnus-message 5 "Registering spam with bogofilter")
+ (spam-bogofilter-register-spam-routine))
- (when (and spam-ifile-path
- (spam-group-spam-processor-ifile-p gnus-newsgroup-name))
- (gnus-message 5 "Registering spam with ifile")
- (spam-ifile-register-spam-routine))
+ (when (and spam-ifile-path
+ (spam-group-spam-processor-ifile-p gnus-newsgroup-name))
+ (gnus-message 5 "Registering spam with ifile")
+ (spam-ifile-register-spam-routine))
- (when (spam-group-spam-processor-stat-p gnus-newsgroup-name)
- (gnus-message 5 "Registering spam with spam-stat")
- (spam-stat-register-spam-routine))
-
- (when (spam-group-spam-processor-blacklist-p gnus-newsgroup-name)
- (gnus-message 5 "Registering spam with the blacklist")
- (spam-blacklist-register-routine))
-
- (if spam-move-spam-nonspam-groups-only
- (when (not (spam-group-spam-contents-p gnus-newsgroup-name))
- (spam-mark-spam-as-expired-and-move-routine
- (gnus-parameter-spam-process-destination gnus-newsgroup-name)))
- (gnus-message 5 "Marking spam as expired and moving it")
- (spam-mark-spam-as-expired-and-move-routine
- (gnus-parameter-spam-process-destination gnus-newsgroup-name)))
-
- ;; now we redo spam-mark-spam-as-expired-and-move-routine to only
- ;; expire spam, in case the above did not expire them
- (spam-mark-spam-as-expired-and-move-routine nil)
-
- (when (spam-group-ham-contents-p gnus-newsgroup-name)
- (when (spam-group-ham-processor-whitelist-p gnus-newsgroup-name)
- (gnus-message 5 "Registering ham with the whitelist")
- (spam-whitelist-register-routine))
- (when (spam-group-ham-processor-ifile-p gnus-newsgroup-name)
- (gnus-message 5 "Registering ham with ifile")
- (spam-ifile-register-ham-routine))
- (when (spam-group-ham-processor-bogofilter-p gnus-newsgroup-name)
- (gnus-message 5 "Registering ham with Bogofilter")
- (spam-bogofilter-register-ham-routine))
- (when (spam-group-ham-processor-stat-p gnus-newsgroup-name)
- (gnus-message 5 "Registering ham with spam-stat")
- (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)))
-
- ;; 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")
- (spam-ham-move-routine
- (gnus-parameter-ham-process-destination gnus-newsgroup-name))))
-
-(add-hook 'gnus-summary-prepare-exit-hook 'spam-summary-prepare-exit)
+ (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))
+
+ (when (spam-group-spam-processor-blacklist-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering spam with the blacklist")
+ (spam-blacklist-register-routine))
+
+ (when (spam-group-spam-processor-report-gmane-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering spam with the Gmane report")
+ (spam-report-gmane-register-routine))
+
+ (if spam-move-spam-nonspam-groups-only
+ (when (not (spam-group-spam-contents-p gnus-newsgroup-name))
+ (spam-mark-spam-as-expired-and-move-routine
+ (gnus-parameter-spam-process-destination gnus-newsgroup-name)))
+ (gnus-message 5 "Marking spam as expired and moving it to %s" gnus-newsgroup-name)
+ (spam-mark-spam-as-expired-and-move-routine
+ (gnus-parameter-spam-process-destination gnus-newsgroup-name)))
+
+ ;; 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 (spam-group-ham-contents-p gnus-newsgroup-name)
+ (when (spam-group-ham-processor-whitelist-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering ham with the whitelist")
+ (spam-whitelist-register-routine))
+ (when (spam-group-ham-processor-ifile-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering ham with ifile")
+ (spam-ifile-register-ham-routine))
+ (when (spam-group-ham-processor-bogofilter-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering ham with Bogofilter")
+ (spam-bogofilter-register-ham-routine))
+ (when (spam-group-ham-processor-stat-p gnus-newsgroup-name)
+ (gnus-message 5 "Registering ham with spam-stat")
+ (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))
+ (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) t))
+
+ ;; 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")
+ (spam-ham-move-routine
+ (gnus-parameter-ham-process-destination gnus-newsgroup-name)))))
(defun spam-mark-junk-as-spam-routine ()
;; 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 unread articles as spam")
- (let ((articles gnus-newsgroup-articles)
- article)
- (while articles
- (setq article (pop articles))
- (when (eq (gnus-summary-article-mark article) gnus-unread-mark)
- (gnus-summary-mark-article article gnus-spam-mark))))))
+ (gnus-message 5 "Marking %s articles as spam"
+ (if spam-mark-only-unseen-as-spam
+ "unseen"
+ "unread"))
+ (let ((articles (if spam-mark-only-unseen-as-spam
+ gnus-newsgroup-unseen
+ gnus-newsgroup-unreads)))
+ (dolist (article articles)
+ (gnus-summary-mark-article article gnus-spam-mark)))))
(defun spam-mark-spam-as-expired-and-move-routine (&optional group)
+ (gnus-summary-kill-process-mark)
(let ((articles gnus-newsgroup-articles)
article tomove)
(dolist (article articles)
- (gnus-summary-remove-process-mark article)
(when (eq (gnus-summary-article-mark article) gnus-spam-mark)
(gnus-summary-mark-article article gnus-expirable-mark)
(push article tomove)))
;; now do the actual move
- (when (stringp group)
+ (when (and tomove
+ (stringp group))
(dolist (article tomove)
(gnus-summary-set-process-mark article))
- (when tomove (gnus-summary-move-article nil group)))))
+ (when tomove (gnus-summary-move-article nil group))))
+ (gnus-summary-yank-process-mark))
-(defun spam-ham-move-routine (&optional group)
+(defun spam-ham-move-routine (&optional group copy)
+ (gnus-summary-kill-process-mark)
(let ((articles gnus-newsgroup-articles)
- article ham-mark-values mark tomove)
+ article mark tomove)
(when (stringp group) ; this routine will do nothing
; without a valid group
- (dolist (mark spam-ham-marks)
- (push (symbol-value mark) ham-mark-values))
(dolist (article articles)
- (gnus-summary-remove-process-mark article)
- (when (memq (gnus-summary-article-mark article) ham-mark-values)
+ (when (spam-group-ham-mark-p gnus-newsgroup-name
+ (gnus-summary-article-mark article))
(push article tomove)))
;; now do the actual move
- (dolist (article tomove)
- (gnus-summary-set-process-mark article))
- (when tomove (gnus-summary-move-article nil group)))))
+ (when tomove
+ (dolist (article tomove)
+ (when spam-mark-ham-unread-before-move-from-spam-group
+ (gnus-summary-mark-article article gnus-unread-mark))
+ (gnus-summary-set-process-mark article))
+ (if copy
+ (gnus-summary-copy-article nil group)
+ (gnus-summary-move-article nil group)))))
+ (gnus-summary-yank-process-mark))
(defun spam-generic-register-routine (spam-func ham-func)
(let ((articles gnus-newsgroup-articles)
- article mark ham-articles spam-articles spam-mark-values
- ham-mark-values)
-
- ;; marks are stored as symbolic values, so we have to dereference
- ;; them for memq to work. we wouldn't have to do this if
- ;; gnus-summary-article-mark returned a symbol.
- (dolist (mark spam-ham-marks)
- (push (symbol-value mark) ham-mark-values))
-
- (dolist (mark spam-spam-marks)
- (push (symbol-value mark) spam-mark-values))
+ article mark ham-articles spam-articles)
(while articles
(setq article (pop articles)
mark (gnus-summary-article-mark article))
- (cond ((memq mark spam-mark-values) (push article spam-articles))
+ (cond ((spam-group-spam-mark-p gnus-newsgroup-name mark)
+ (push article spam-articles))
((memq article gnus-newsgroup-saved))
- ((memq mark ham-mark-values) (push article ham-articles))))
+ ((spam-group-ham-mark-p gnus-newsgroup-name mark)
+ (push article ham-articles))))
+
(when (and ham-articles ham-func)
(mapc ham-func ham-articles)) ; we use mapc because unlike
; mapcar it discards the
(setq article-buffer (get-buffer gnus-article-buffer))))
article-buffer))
-(defun spam-get-article-as-filename (article)
- (let ((article-filename))
- (when (numberp article)
- (nnml-possibly-change-directory (gnus-group-real-name gnus-newsgroup-name))
- (setq article-filename (expand-file-name (int-to-string article) nnml-current-directory)))
- (if (file-exists-p article-filename)
- article-filename
- nil)))
+;; disabled for now
+;; (defun spam-get-article-as-filename (article)
+;; (let ((article-filename))
+;; (when (numberp article)
+;; (nnml-possibly-change-directory (gnus-group-real-name gnus-newsgroup-name))
+;; (setq article-filename (expand-file-name (int-to-string article) nnml-current-directory)))
+;; (if (file-exists-p article-filename)
+;; article-filename
+;; nil)))
(defun spam-fetch-field-from-fast (article)
"Fetch the `from' field quickly, using the internal gnus-data-list function"
(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)
(spam-use-bogofilter-headers . spam-check-bogofilter-headers)
(spam-use-bogofilter . spam-check-bogofilter))
"The spam-list-of-checks list contains pairs associating a parameter
name is the value of `spam-split-group', meaning that the message is
definitely a spam.")
-(defun spam-split ()
+(defvar spam-list-of-statistical-checks
+ '(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.")
+
+(defun spam-split (&rest specific-checks)
"Split this message into the `spam' group if it is spam.
This function can be used as an entry in `nnmail-split-fancy', for
-example like this: (: spam-split)
+example like this: (: spam-split). It can take checks as parameters.
See the Info node `(gnus)Fancy Mail Splitting' for more details."
(interactive)
+ (save-excursion
+ (save-restriction
+ (dolist (check spam-list-of-statistical-checks)
+ (when (symbol-value check)
+ (widen)
+ (gnus-message 8 "spam-split: widening the buffer (%s requires it)"
+ (symbol-name check))
+ (return)))
+ ;; (progn (widen) (debug (buffer-string)))
+ (let ((list-of-checks spam-list-of-checks)
+ decision)
+ (while (and list-of-checks (not decision))
+ (let ((pair (pop list-of-checks)))
+ (when (and (symbol-value (car pair))
+ (or (null specific-checks)
+ (memq (car pair) specific-checks)))
+ (gnus-message 5 "spam-split: calling the %s function" (symbol-name (cdr pair)))
+ (setq decision (funcall (cdr pair))))))
+ (if (eq decision t)
+ nil
+ decision)))))
- ;; load the spam-stat tables if needed
- (when spam-use-stat (spam-stat-load))
-
- (let ((list-of-checks spam-list-of-checks)
- decision)
- (while (and list-of-checks (not decision))
- (let ((pair (pop list-of-checks)))
- (when (symbol-value (car pair))
- (gnus-message 5 "spam-split: calling the %s function" (symbol-name (cdr pair)))
- (setq decision (funcall (cdr pair))))))
- (if (eq decision t)
- nil
- decision)))
+(defun spam-setup-widening ()
+ (dolist (check spam-list-of-statistical-checks)
+ (when (symbol-value check)
+ (setq nnimap-split-download-body-default t))))
+
\f
;;;; Regex headers
(if spam-use-dig
(let ((query-result (query-dig query-string)))
(when query-result
- (gnus-message 5 "(DIG): positive blackhole check '%s'" query-result)
+ (gnus-message 5 "(DIG): positive blackhole check '%s'"
+ query-result)
(push (list ip server query-result)
matches)))
;; else, if not using dig.el
(when matches
spam-split-group)))
\f
+;;;; Hashcash.
+
+(condition-case nil
+ (progn
+ (require 'hashcash)
+
+ (defun spam-check-hashcash ()
+ "Check the headers for hashcash payments."
+ (mail-check-payment))) ;mail-check-payment returns a boolean
+
+ (file-error (progn
+ (defalias 'mail-check-payment 'ignore)
+ (defalias 'spam-check-hashcash 'ignore))))
+\f
;;;; BBDB
;;; original idea for spam-check-BBDB from Alexander Kotelnikov
(let ((category (or category gnus-newsgroup-name))
(db-param (spam-get-ifile-database-parameter)))
(with-temp-buffer
- (insert-string article-string)
+ (insert article-string)
(if db-param
(call-process-region (point-min) (point-max) spam-ifile-path
nil nil nil
(lambda (article)
(let ((article-string (spam-get-article-as-string article)))
(with-temp-buffer
- (insert-string article-string)
+ (insert article-string)
(spam-stat-buffer-is-spam))))
- nil)
- (spam-stat-save))
+ nil))
(defun spam-stat-register-ham-routine ()
(spam-generic-register-routine
(lambda (article)
(let ((article-string (spam-get-article-as-string article)))
(with-temp-buffer
- (insert-string article-string)
- (spam-stat-buffer-is-non-spam)))))
- (spam-stat-save)))
+ (insert article-string)
+ (spam-stat-buffer-is-non-spam))))))
+
+ (defun spam-maybe-spam-stat-load ()
+ (when spam-use-stat (spam-stat-load)))
+
+ (defun spam-maybe-spam-stat-save ()
+ (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-enter-whitelist from))))))
\f
-;;;; Bogofilter
+;;;; Spam-report glue
+(defun spam-report-gmane-register-routine ()
+ (spam-generic-register-routine
+ 'spam-report-gmane
+ nil))
+\f
+;;;; Bogofilter
(defun spam-check-bogofilter-headers (&optional score)
(let ((header (message-fetch-field spam-bogofilter-header)))
(when (and header
(save-window-excursion
(gnus-summary-show-article t)
(set-buffer gnus-article-buffer)
- (let ((score (spam-check-bogofilter t)))
+ (let ((score (or (spam-check-bogofilter-headers t)
+ (spam-check-bogofilter t))))
(message "Spamicity score %s" score)
(or score "0"))))
(defun spam-bogofilter-register-with-bogofilter (article-string spam)
"Register an article, given as a string, as spam or non-spam."
(when (stringp article-string)
- (let ((switch (if spam "-s" "-n")))
+ (let ((switch (if spam spam-bogofilter-spam-switch
+ spam-bogofilter-ham-switch)))
(with-temp-buffer
- (insert-string article-string)
+ (insert article-string)
(if spam-bogofilter-database-directory
(call-process-region (point-min) (point-max)
spam-bogofilter-path
(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.