Synch to Gnus 200312140318.
authoryamaoka <yamaoka>
Sun, 14 Dec 2003 12:37:57 +0000 (12:37 +0000)
committeryamaoka <yamaoka>
Sun, 14 Dec 2003 12:37:57 +0000 (12:37 +0000)
lisp/ChangeLog
lisp/gnus.el
lisp/spam.el

index 183a915..a8b0baf 100644 (file)
@@ -1,3 +1,33 @@
+2003-12-13  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el: added some gnus-registry autoloads
+       (spam-split-symbolic-return): makes spam-split return 'spam
+       instead of the value of spam-split-group when spam is detected
+       (spam-split-symbolic-return-positive): makes spam-split return
+       'ham instead of nil when ham is detected
+       (spam-autodetect-recheck-messages): tells spam.el whether it
+       should recheck all messages in a group, or only the unseen ones
+       (spam-split-last-successful-check): spam-split will set this to
+       the last successful check; this was seen as a cleaner approach
+       than returning a cell like '(spam spam-use-bogofilter)
+       (spam-list-of-checks): documentation appended
+       (spam-split): accomodate the spam-split-symbolic-return and
+       spam-split-symbolic-return-positive variables
+       (spam-find-spam): new function called when the summary is built
+       (spam-log-registered-p): checks if a ham or spam registration has
+       already been done for an article
+       (spam-check-regex-headers, spam-check-blackholes, spam-check-BBDB)
+       (spam-check-ifile, spam-check-stat, spam-check-whitelist)
+       (spam-check-blacklist, spam-check-bogofilter-headers)
+       (spam-check-spamoracle): respect the spam-split-symbolic-return
+       and spam-split-symbolic-return-positive variables
+       (spam-initialize): add spam-find-spam to gnus-summary-prepare-hook
+       (spam-unload-hook): remove spam-find-spam from
+       gnus-summary-prepare-hook
+
+       * gnus.el (spam-autodetect, spam-autodetect-methods): new
+       configuration items for spam autodetection
+
 2003-12-12  Reiner Steib  <Reiner.Steib@gmx.de>
 
        * gnus-draft.el (gnus-draft-mode-map): Bind `e' to
index 8673c75..8aaddbd 100644 (file)
@@ -1998,6 +1998,88 @@ spam processing, associated with the appropriate processor."
    "Which spam or ham processors will be applied when the summary is exited.")
 
   (gnus-define-group-parameter
+   spam-autodetect
+   :type list
+   :parameter-type 
+   '(boolean :tag "Spam autodetection")
+   :function-document
+   "Should spam be autodetected (with spam-split) in this group?"
+   :variable gnus-spam-autodetect
+   :variable-default nil
+   :variable-document
+   "*Groups in which spam should be autodetected when they are entered.
+   Only unseen articles will be examined, unless
+   spam-autodetect-recheck-messages is set."
+   :variable-group spam
+   :variable-type 
+   '(repeat
+     :tag "Autodetection setting"
+     (list
+      (regexp :tag "Group Regexp")
+      boolean))
+   :parameter-document
+   "Spam autodetection.
+Only unseen articles will be examined, unless
+spam-autodetect-recheck-messages is set.")
+
+  (gnus-define-group-parameter
+   spam-autodetect-methods
+   :type list
+   :parameter-type 
+   '(choice :tag "Spam autodetection-specific methods"
+     (const none)
+     (const default)
+     (set :tag "Use specific methods"
+         (variable-item spam-use-blacklist)
+         (variable-item spam-use-regex-headers)
+         (variable-item spam-use-regex-body)
+         (variable-item spam-use-whitelist)
+         (variable-item spam-use-BBDB)
+         (variable-item spam-use-ifile)
+         (variable-item spam-use-spamoracle)
+         (variable-item spam-use-stat)
+         (variable-item spam-use-blackholes)
+         (variable-item spam-use-hashcash)
+         (variable-item spam-use-bogofilter-headers)
+         (variable-item spam-use-bogofilter)))
+   :function-document
+   "Methods to be used for autodetection in each group"
+   :variable gnus-spam-autodetect-methods
+   :variable-default nil
+   :variable-document
+   "*Methods for autodetecting spam per group.
+Requires the spam-autodetect parameter.  Only unseen articles
+will be examined, unless spam-autodetect-recheck-messages is
+set."
+   :variable-group spam
+   :variable-type 
+   '(repeat
+     :tag "Autodetection methods"
+     (list
+      (regexp :tag "Group Regexp")
+      (choice
+       (const none)
+       (const default)
+       (set :tag "Use specific methods"
+       (variable-item spam-use-blacklist)
+       (variable-item spam-use-regex-headers)
+       (variable-item spam-use-regex-body)
+       (variable-item spam-use-whitelist)
+       (variable-item spam-use-BBDB)
+       (variable-item spam-use-ifile)
+       (variable-item spam-use-spamoracle)
+       (variable-item spam-use-stat)
+       (variable-item spam-use-blackholes)
+       (variable-item spam-use-hashcash)
+       (variable-item spam-use-bogofilter-headers)
+       (variable-item spam-use-bogofilter)))))
+     :parameter-document
+   "Spam autodetection methods.  
+Requires the spam-autodetect parameter.  Only unseen articles
+will be examined, unless spam-autodetect-recheck-messages is
+set.")
+
+  (gnus-define-group-parameter
    spam-process-destination
    :type list
    :parameter-type 
index a8c1bc6..751d7ed 100644 (file)
@@ -60,6 +60,8 @@
 
 ;; autoload gnus-registry
 (eval-and-compile
+  (autoload 'gnus-registry-group-count "gnus-registry")
+  (autoload 'gnus-registry-add-group "gnus-registry")
   (autoload 'gnus-registry-store-extra-entry "gnus-registry")
   (autoload 'gnus-registry-fetch-extra "gnus-registry"))
 
@@ -95,6 +97,18 @@ spam groups."
   :type 'boolean
   :group 'spam)
 
+(defcustom spam-split-symbolic-return nil
+  "Whether spam-split should work with symbols or group names."
+  :type 'boolean
+  :group 'spam)
+
+(defcustom spam-split-symbolic-return-positive nil
+  "Whether spam-split should ALWAYS work with symbols or group
+  names.  Do not set this if you use spam-split in a fancy split
+  method."
+  :type 'boolean
+  :group 'spam)
+
 (defcustom spam-process-ham-in-spam-groups nil
   "Whether ham should be processed in spam groups."
   :type 'boolean
@@ -125,6 +139,12 @@ configuration."
   :type 'boolean
   :group 'spam)
 
+(defcustom spam-autodetect-recheck-messages nil
+  "Should spam.el recheck all meessages when autodetecting?
+Normally this is nil, so only unseen messages will be checked."
+  :type 'boolean
+  :group 'spam)
+
 (defcustom spam-whitelist (expand-file-name "whitelist" spam-directory)
   "The location of the whitelist.
 The file format is one regular expression per line.
@@ -414,6 +434,12 @@ spamoracle database."
 (defvar spam-old-spam-articles nil
   "List of old spam articles, generated when a group is entered.")
 
+(defvar spam-split-disabled nil
+  "If non-nil, spam-split is disabled, and always returns nil.")
+
+(defvar spam-split-last-successful-check nil
+  "spam-split will set this to nil or a spam-use-XYZ check if it
+  finds ham or spam.")
 
 ;; convenience functions
 (defun spam-xor (a b) ; logical exclusive or
@@ -814,16 +840,18 @@ spam-use-* variable.")
     (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
-variable with a spam checking function.  If the parameter variable is
-true, then the checking function is called, and its value decides what
-happens.  Each individual check may return nil, t, or a mailgroup
-name.  The value nil means that the check does not yield a decision,
-and so, that further checks are needed.  The value t means that the
-message is definitely not spam, and that further spam checks should be
-inhibited.  Otherwise, a mailgroup name is returned where the mail
-should go, and further checks are also inhibited.  The usual mailgroup
-name is the value of `spam-split-group', meaning that the message is
+  "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,
+and its value decides what happens.  Each individual check may
+return nil, t, or a mailgroup name.  The value nil means that the
+check does not yield a decision, and so, that further checks are
+needed.  The value t means that the message is definitely not
+spam, and that further spam checks should be inhibited.
+Otherwise, a mailgroup name or the symbol 'spam (depending on
+spam-split-symbolic-return) is returned where the mail should go,
+and further checks are also inhibited.  The usual mailgroup name
+is the value of `spam-split-group', meaning that the message is
 definitely a spam.")
 
 (defvar spam-list-of-statistical-checks 
@@ -835,9 +863,6 @@ definitely a spam.")
   "The spam-list-of-statistical-checks list contains all the mail
 splitters that need to have the full message body available.")
 
-(defvar spam-split-disabled nil
-  "If non-nil, spam-split is disabled, and always returns nil.")
-
 ;;;TODO: modify to invoke self with each check if invoked without specifics
 (defun spam-split (&rest specific-checks)
   "Split this message into the `spam' group if it is spam.
@@ -848,6 +873,7 @@ spam-split-group to that string.
 
 See the Info node `(gnus)Fancy Mail Splitting' for more details."
   (interactive)
+  (setq spam-split-last-successful-check nil)
   (unless spam-split-disabled
     (let ((spam-split-group-choice spam-split-group))
       (dolist (check specific-checks)
@@ -874,11 +900,69 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
                                 (memq (car pair) specific-checks)))
                    (gnus-message 5 "spam-split: calling the %s function" 
                                  (symbol-name (cdr pair)))
-                   (setq decision (funcall (cdr pair))))))
+                   (setq decision (funcall (cdr pair)))
+                   ;; if we got a decision at all, save the current check
+                   (when decision
+                     (setq spam-split-last-successful-check (car pair)))
+
+                   (when (eq decision 'spam)
+                     (if spam-split-symbolic-return
+                         (setq decision spam-split-group)
+                       (gnus-error
+                        5 
+                        (format "spam-split got %s but %s is nil"
+                                (symbol-name decision)
+                                (symbol-name spam-split-symbolic-return))))))))
              (if (eq decision t)
-                 nil
+                 (if spam-split-symbolic-return-positive 'ham nil)
                decision))))))))
 
+(defun spam-find-spam ()
+  "This function will detect spam in the current newsgroup using spam-split"
+  (interactive)
+  
+  (let* ((group gnus-newsgroup-name)
+        (autodetect (gnus-parameter-spam-autodetect group))
+        (methods (gnus-parameter-spam-autodetect-methods group))
+        (first-method (nth 0 methods)))
+  (when (and autodetect 
+            (not (equal first-method 'none)))
+    (mapcar
+     (lambda (article)
+       (let ((id (spam-fetch-field-message-id-fast article))
+            (subject (spam-fetch-field-subject-fast article))
+            (sender (spam-fetch-field-from-fast article)))
+        (unless (and spam-log-to-registry
+                     (spam-log-registered-p id 'incoming))
+          (let* ((spam-split-symbolic-return t)
+                 (spam-split-symbolic-return-positive t)
+                 (split-return
+                  (with-temp-buffer
+                    (gnus-request-article-this-buffer 
+                     article 
+                     group)
+                    (if (or (null first-method)
+                            (equal first-method 'default))
+                        (spam-split)
+                      (apply 'spam-split methods)))))
+            (if (equal split-return 'spam)
+                (gnus-summary-mark-article article gnus-spam-mark))
+
+            (when (and split-return spam-log-to-registry)
+              (when (zerop (gnus-registry-group-count id))
+                (gnus-registry-add-group
+                 id group subject sender))
+
+              (spam-log-processing-to-registry 
+               id
+               'incoming
+               split-return
+               spam-split-last-successful-check
+               group))))))
+     (if spam-autodetect-recheck-messages
+        gnus-newsgroup-articles
+       gnus-newsgroup-unseen)))))
+
 (defvar spam-registration-functions
   ;; first the ham register, second the spam register function
   ;; third the ham unregister, fourth the spam unregister function
@@ -1019,6 +1103,17 @@ functions")
       (gnus-message 5 (format "%s called with bad ID, type, classification, check, or group"
                              "spam-log-processing-to-registry")))))
 
+;;; check if a ham- or spam-processor registration has been done
+(defun spam-log-registered-p (id type)
+  (when spam-log-to-registry
+    (if (and (stringp id)
+            (spam-process-type-valid-p type))
+       (cdr-safe (gnus-registry-fetch-extra id type))
+      (progn 
+       (gnus-message 5 (format "%s called with bad ID, type, classification, or check"
+                               "spam-log-registered-p"))
+       nil))))
+
 ;;; check if a ham- or spam-processor registration needs to be undone
 (defun spam-log-unregistration-needed-p (id type classification check)
   (when spam-log-to-registry
@@ -1082,6 +1177,9 @@ functions")
 
 (defun spam-check-regex-headers (&optional body)
   (let ((type (if body "body" "header"))
+       (spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group))
        ret found)
     (dolist (h-regex spam-regex-headers-ham)
       (unless found
@@ -1110,6 +1208,9 @@ functions")
 (defun spam-check-blackholes ()
   "Check the Received headers for blackholed relays."
   (let ((headers (nnmail-fetch-field "received"))
+       (spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group))
        ips matches)
     (when headers
       (with-temp-buffer
@@ -1206,7 +1307,10 @@ functions")
 
       (defun spam-check-BBDB ()
        "Mail from people in the BBDB is classified as ham or non-spam"
-       (let ((who (nnmail-fetch-field "from")))
+       (let ((who (nnmail-fetch-field "from"))
+             (spam-split-group (if spam-split-symbolic-return
+                                   'spam 
+                                 spam-split-group)))
          (when who
            (setq who (nth 1 (gnus-extract-address-components who)))
            (if (bbdb-search-simple nil who)
@@ -1240,6 +1344,9 @@ functions")
 (defun spam-check-ifile ()
   "Check the ifile backend for the classification of this message"
   (let ((article-buffer-name (buffer-name)) 
+       (spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group))
        category return)
     (with-temp-buffer
       (let ((temp-buffer-name (buffer-name))
@@ -1302,7 +1409,10 @@ Uses `gnus-newsgroup-name' if category is nil (for ham registration)."
       
       (defun spam-check-stat ()
        "Check the spam-stat backend for the classification of this message"
-       (let ((spam-stat-split-fancy-spam-group spam-split-group) ; override
+       (let ((spam-split-group (if spam-split-symbolic-return
+                                   'spam 
+                                 spam-split-group))
+             (spam-stat-split-fancy-spam-group spam-split-group) ; override
              (spam-stat-buffer (buffer-name)) ; stat the current buffer
              category return)
          (spam-stat-split-fancy)))
@@ -1412,19 +1522,25 @@ REMOVE not nil, remove the ADDRESSES."
 ;;; spam-split-group otherwise
 (defun spam-check-whitelist ()
   ;; FIXME!  Should it detect when file timestamps change?
-  (unless spam-whitelist-cache
-    (setq spam-whitelist-cache (spam-parse-list spam-whitelist)))
-  (if (spam-from-listed-p spam-whitelist-cache) 
-      t
-    (if spam-use-whitelist-exclusive
-       spam-split-group
-      nil)))
+  (let ((spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group)))
+    (unless spam-whitelist-cache
+      (setq spam-whitelist-cache (spam-parse-list spam-whitelist)))
+    (if (spam-from-listed-p spam-whitelist-cache) 
+       t
+      (if spam-use-whitelist-exclusive
+         spam-split-group
+       nil))))
 
 (defun spam-check-blacklist ()
   ;; FIXME!  Should it detect when file timestamps change?
-  (unless spam-blacklist-cache
-    (setq spam-blacklist-cache (spam-parse-list spam-blacklist)))
-  (and (spam-from-listed-p spam-blacklist-cache) spam-split-group))
+  (let ((spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group)))
+    (unless spam-blacklist-cache
+      (setq spam-blacklist-cache (spam-parse-list spam-blacklist)))
+    (and (spam-from-listed-p spam-blacklist-cache) spam-split-group)))
 
 (defun spam-parse-list (file)
   (when (file-readable-p file)
@@ -1515,7 +1631,10 @@ REMOVE not nil, remove the ADDRESSES."
 \f
 ;;;; Bogofilter
 (defun spam-check-bogofilter-headers (&optional score)
-  (let ((header (nnmail-fetch-field spam-bogofilter-header)))
+  (let ((header (nnmail-fetch-field spam-bogofilter-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 "spamicity=\\([0-9.]+\\)" header)
@@ -1597,7 +1716,10 @@ REMOVE not nil, remove the ADDRESSES."
 ;;;; spamoracle
 (defun spam-check-spamoracle ()
   "Run spamoracle on an article to determine whether it's spam."
-  (let ((article-buffer-name (buffer-name)))
+  (let ((article-buffer-name (buffer-name))
+       (spam-split-group (if spam-split-symbolic-return
+                             'spam 
+                           spam-split-group)))
     (with-temp-buffer
       (let ((temp-buffer-name (buffer-name)))
        (save-excursion
@@ -1670,7 +1792,8 @@ REMOVE not nil, remove the ADDRESSES."
   (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))
+  (add-hook 'gnus-get-new-news-hook 'spam-setup-widening)
+  (add-hook 'gnus-summary-prepare-hook 'spam-find-spam))
 
 (defun spam-unload-hook ()
   "Uninstall the spam.el hooks"
@@ -1680,7 +1803,8 @@ REMOVE not nil, remove the ADDRESSES."
   (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))
+  (remove-hook 'gnus-get-new-news-hook 'spam-setup-widening)
+  (remove-hook 'gnus-summary-prepare-hook 'spam-find-spam))
 
 (when spam-install-hooks
   (spam-initialize))