+ (unless (eq 0 status)
+ (error "Error running spamoracle: %s" status)))))))
+
+(defun spam-spamoracle-learn-ham (articles &optional unregister)
+ (spam-spamoracle-learn articles nil unregister))
+
+(defun spam-spamoracle-unlearn-ham (articles &optional unregister)
+ (spam-spamoracle-learn-ham articles t))
+
+(defun spam-spamoracle-learn-spam (articles &optional unregister)
+ (spam-spamoracle-learn articles t unregister))
+
+(defun spam-spamoracle-unlearn-spam (articles &optional unregister)
+ (spam-spamoracle-learn-spam articles t))
+
+\f
+;;;; SpamAssassin
+;;; based mostly on the bogofilter code
+(defun spam-check-spamassassin-headers (&optional score)
+ "Check the SpamAssassin headers for the classification of this message."
+ (if score ; scoring mode
+ (let ((header (message-fetch-field spam-spamassassin-spam-status-header)))
+ (when header
+ (if (string-match "hits=\\(-?[0-9.]+\\)" header)
+ (match-string 1 header)
+ "0")))
+ ;; spam detection mode
+ (let ((header (message-fetch-field spam-spamassassin-spam-flag-header))
+ (spam-split-group (if spam-split-symbolic-return
+ 'spam
+ spam-split-group)))
+ (when header ; return nil when no header
+ (when (string-match spam-spamassassin-positive-spam-flag-header
+ header)
+ spam-split-group)))))
+
+(defun spam-check-spamassassin (&optional score)
+ "Check the SpamAssassin backend for the classification of this message."
+ (let ((article-buffer-name (buffer-name)))
+ (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-spamassassin-path
+ nil temp-buffer-name nil spam-spamassassin-arguments))
+ ;; check the return now (we're back in the temp buffer)
+ (goto-char (point-min))
+ (spam-check-spamassassin-headers score)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-spamassassin-score (&optional recheck)
+ "Get the SpamAssassin score"
+ (interactive "P")
+ (save-window-excursion
+ (gnus-summary-show-article t)
+ (set-buffer gnus-article-buffer)
+ (let ((score (or (unless recheck
+ (spam-check-spamassassin-headers t))
+ (spam-check-spamassassin t))))
+ (gnus-summary-show-article)
+ (message "SpamAssassin score %s" score)
+ (or score "0"))))
+
+(defun spam-spamassassin-register-with-sa-learn (articles spam
+ &optional unregister)
+ "Register articles with spamassassin's sa-learn as spam or non-spam."
+ (if articles
+ (let ((action (if unregister spam-sa-learn-unregister-switch
+ (if spam spam-sa-learn-spam-switch
+ spam-sa-learn-ham-switch)))
+ (summary-buffer-name (buffer-name)))
+ (with-temp-buffer
+ ;; group the articles into mbox format
+ (dolist (article articles)
+ (let (article-string)
+ (save-excursion
+ (set-buffer summary-buffer-name)
+ (setq article-string (spam-get-article-as-string article)))
+ (when (stringp article-string)
+ (insert "From \n") ; mbox separator (sa-learn only checks the
+ ; first five chars, so we can get away with
+ ; a bogus line))
+ (insert article-string)
+ (insert "\n"))))
+ ;; call sa-learn on all messages at the same time
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-sa-learn-path
+ nil nil nil "--mbox"
+ (if spam-sa-learn-rebuild
+ (list action)
+ `("--no-rebuild" ,action)))))))
+
+(defun spam-spamassassin-register-spam-routine (articles &optional unregister)
+ (spam-spamassassin-register-with-sa-learn articles t unregister))
+
+(defun spam-spamassassin-register-ham-routine (articles &optional unregister)
+ (spam-spamassassin-register-with-sa-learn articles nil unregister))
+
+(defun spam-spamassassin-unregister-spam-routine (articles)
+ (spam-spamassassin-register-with-sa-learn articles t t))
+
+(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
+;;;; CRM114 Mailfilter
+(defun spam-check-crm114-headers (&optional score)
+ (let ((header (message-fetch-field spam-crm114-header))
+ (spam-split-group (if spam-split-symbolic-return
+ 'spam
+ spam-split-group)))
+ (when header ; return nil when no header
+ (if score ; scoring mode
+ (if (string-match "( pR: \\([0-9.-]+\\)" header)
+ (match-string 1 header)
+ "0")
+ ;; spam detection mode
+ (when (string-match spam-crm114-positive-spam-header
+ header)
+ spam-split-group)))))
+
+;; return something sensible if the score can't be determined
+(defun spam-crm114-score ()
+ "Get the CRM114 Mailfilter pR"
+ (interactive)
+ (save-window-excursion
+ (gnus-summary-show-article t)
+ (set-buffer gnus-article-buffer)
+ (let ((score (or (spam-check-crm114-headers t)
+ (spam-check-crm114 t))))
+ (gnus-summary-show-article)
+ (message "pR: %s" score)
+ (or score "0"))))
+
+(defun spam-check-crm114 (&optional score)
+ "Check the CRM114 Mailfilter backend for the classification of this message"
+ (let ((article-buffer-name (buffer-name))
+ (db spam-crm114-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-crm114-program
+ nil temp-buffer-name nil
+ (when db (list (concat "--fileprefix=" db)))))
+ (setq return (spam-check-crm114-headers score))))
+ return))
+
+(defun spam-crm114-register-with-crm114 (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))
+ (db spam-crm114-database-directory)
+ (switch (if unregister
+ (if spam
+ spam-crm114-spam-strong-switch
+ spam-crm114-ham-strong-switch)
+ (if spam
+ spam-crm114-spam-switch
+ spam-crm114-ham-switch))))
+ (when (stringp article-string)
+ (with-temp-buffer
+ (insert article-string)
+
+ (apply 'call-process-region
+ (point-min) (point-max)
+ spam-crm114-program
+ nil nil nil
+ (when db (list switch (concat "--fileprefix=" db)))))))))
+
+(defun spam-crm114-register-spam-routine (articles &optional unregister)
+ (spam-crm114-register-with-crm114 articles t unregister))
+
+(defun spam-crm114-unregister-spam-routine (articles)
+ (spam-crm114-register-spam-routine articles t))
+
+(defun spam-crm114-register-ham-routine (articles &optional unregister)
+ (spam-crm114-register-with-crm114 articles nil unregister))
+
+(defun spam-crm114-unregister-ham-routine (articles)
+ (spam-crm114-register-ham-routine articles t))
+