(gnus-summary-remove-process-mark article)
(spam-report-gmane article)))
+(defun spam-necessary-extra-headers ()
+ "Return the extra headers spam.el thinks are necessary."
+ (let (list)
+ (when (or spam-use-spamassassin
+ spam-use-spamassassin-headers
+ spam-use-regex-headers)
+ (push 'X-Spam-Status list))
+ list))
+
+(defun spam-user-format-function-S (headers)
+ (when headers
+ (spam-summary-score headers)))
+
+(defun spam-article-sort-by-spam-status (h1 h2)
+ "Sort articles by score."
+ (let (result)
+ (dolist (header (spam-necessary-extra-headers))
+ (let ((s1 (spam-summary-score h1 header))
+ (s2 (spam-summary-score h2 header)))
+ (unless (= s1 s2)
+ (setq result (< s1 s2))
+ (return))))
+ result))
+
+(defun spam-extra-header-to-number (header headers)
+ "Transform an extra header to a number."
+ (if (gnus-extra-header header headers)
+ (cond
+ ((eq header 'X-Spam-Status)
+ (string-to-number (gnus-replace-in-string
+ (gnus-extra-header header headers)
+ ".*hits=" "")))
+ (t nil))
+ nil))
+
+(defun spam-summary-score (headers &optional specific-header)
+ "Score an article for the summary buffer, as fast as possible.
+With SPECIFIC-HEADER, returns only that header's score.
+Will not return a nil score."
+ (let (score)
+ (dolist (header
+ (if specific-header
+ (list specific-header)
+ (spam-necessary-extra-headers)))
+ (setq score
+ (spam-extra-header-to-number header headers))
+ (when score
+ (return)))
+ (or score 0)))
+
(defun spam-generic-score ()
- (interactive)
"Invoke whatever scoring method we can."
+ (interactive)
(if (or
spam-use-spamassassin
spam-use-spamassassin-headers)
(new-articles (spam-list-articles
gnus-newsgroup-articles
classification))
- (changed-articles (gnus-set-difference new-articles old-articles)))
+ (changed-articles (spam-set-difference new-articles old-articles)))
;; now that we have the changed articles, we go through the processors
(dolist (processor-param spam-list-of-processors)
(let ((processor (nth 0 processor-param))
;; call spam-register-routine with specific articles to unregister,
;; when there are articles to unregister and the check is enabled
(when (and unregister-list (symbol-value check))
- (spam-register-routine classification check t unregister-list))))))
+ (spam-register-routine
+ classification check t unregister-list))))))
;; find all the spam processors applicable to this group
(dolist (processor-param spam-list-of-processors)
(spam-group-processor-p gnus-newsgroup-name processor))
(spam-register-routine classification check))))
- (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)))
+ (unless (and spam-move-spam-nonspam-groups-only
+ (spam-group-spam-contents-p gnus-newsgroup-name))
(gnus-message 5 "Marking spam as expired and moving it to %s"
- gnus-newsgroup-name)
+ (gnus-parameter-spam-process-destination
+ gnus-newsgroup-name))
(spam-mark-spam-as-expired-and-move-routine
(gnus-parameter-spam-process-destination gnus-newsgroup-name)))
(setq spam-old-ham-articles nil)
(setq spam-old-spam-articles nil))
+(defun spam-set-difference (list1 list2)
+ "Return a set difference of LIST1 and LIST2.
+When either list is nil, the other is returned."
+ (if (and list1 list2)
+ ;; we have two non-nil lists
+ (progn
+ (dolist (item (append list1 list2))
+ (when (and (memq item list1) (memq item list2))
+ (setq list1 (delq item list1))
+ (setq list2 (delq item list2))))
+ (append list1 list2))
+ ;; if either of the lists was nil, return the other one
+ (if list1 list1 list2)))
+
(defun spam-mark-junk-as-spam-routine ()
;; check the global list of group names spam-junk-mailgroups and the
;; group parameters
(mail-header-extra data-header))
(t
nil))
- (gnus-error 5 "Article %d has a nil data header" article)))))
+ (gnus-message 5 "Article %d has a nil data header" article)))))
(defun spam-fetch-field-from-fast (article &optional prepared-data-header)
(spam-fetch-field-fast article 'from prepared-data-header))
(spam-fetch-field-fast article 'xref dh))
(when (spam-fetch-field-fast article 'extra dh)
(format "%s\n" (spam-fetch-field-fast article 'extra dh))))
- (gnus-error
+ (gnus-message
5
"spam-generate-fake-headers: article %d didn't have a valid header"
article))))
(defun spam-fetch-article-header (article)
(save-excursion
(set-buffer gnus-summary-buffer)
+ (gnus-read-header article)
(nth 3 (assq article gnus-newsgroup-data))))
\f
registry-lookup)
(unless id
- (gnus-error 5 "Article %d has no message ID!" article))
+ (gnus-message 5 "Article %d has no message ID!" article))
(when (and id spam-log-to-registry)
(setq registry-lookup (spam-log-registration-type id 'incoming))
(let ((mark-check (if (eq classification 'spam)
'spam-group-spam-mark-p
'spam-group-ham-mark-p))
- list mark-cache-yes mark-cache-no)
+ alist mark-cache-yes mark-cache-no)
(dolist (article articles)
(let ((mark (gnus-summary-article-mark article)))
- (unless (memq mark mark-cache-no)
- (if (memq mark mark-cache-yes)
- (push article list)
- ;; else, we have to actually check the mark
- (if (funcall mark-check
- gnus-newsgroup-name
- mark)
- (progn
- (push article list)
- (push mark mark-cache-yes))
- (push mark mark-cache-no))))))
- list))
+ (unless (or (memq mark mark-cache-yes)
+ (memq mark mark-cache-no))
+ (if (funcall mark-check
+ gnus-newsgroup-name
+ mark)
+ (push mark mark-cache-yes)
+ (push mark mark-cache-no)))
+ (when (memq mark mark-cache-yes)
+ (push article alist))))
+ alist))
(defun spam-register-routine (classification
check
type
cell-list))
- (gnus-error
+ (gnus-message
5
(format "%s call with bad ID, type, classification, spam-check, or group"
"spam-log-processing-to-registry")))))
(spam-process-type-valid-p type))
(cdr-safe (gnus-registry-fetch-extra id type))
(progn
- (gnus-error
+ (gnus-message
5
(format "%s called with bad ID, type, classification, or spam-check"
"spam-log-registered-p"))
(setq found t))))
found)
(progn
- (gnus-error
+ (gnus-message
5
(format "%s called with bad ID, type, classification, or spam-check"
"spam-log-unregistration-needed-p"))
type
new-cell-list))
(progn
- (gnus-error 5 (format "%s call with bad ID, type, spam-check, or group"
- "spam-log-undo-registration"))
+ (gnus-message 5 (format "%s call with bad ID, type, spam-check, or group"
+ "spam-log-undo-registration"))
nil))))
;;; set up IMAP widening if it's necessary
(if blacklist 'spam-enter-blacklist 'spam-enter-whitelist))
(remove-function
(if blacklist 'spam-enter-whitelist 'spam-enter-blacklist))
- from addresses unregister-list)
+ from addresses unregister-list article-unregister-list)
(dolist (article articles)
(let ((from (spam-fetch-field-from-fast article))
(id (spam-fetch-field-message-id-fast article))
(null unregister)
(spam-log-unregistration-needed-p
id 'process declassification de-symbol))
+ (push article article-unregister-list)
(push from unregister-list))
(unless sender-ignored
(push from addresses)))))
(funcall enter-function addresses t) ; unregister all these addresses
;; else, register normally and unregister what we need to
(funcall remove-function unregister-list t)
- (dolist (article unregister-list)
+ (dolist (article article-unregister-list)
(spam-log-undo-registration
(spam-fetch-field-message-id-fast article)
'process
;;;; Hooks
;;;###autoload
-(defun spam-initialize ()
- "Install the spam.el hooks and do other initialization"
+(defun spam-initialize (&rest symbols)
+ "Install the spam.el hooks and do other initialization.
+When SYMBOLS is given, set those variables to t. This is so you
+can call spam-initialize before you set spam-use-* variables on
+explicitly, and matters only if you need the extra headers
+installed through spam-necessary-extra-headers."
(interactive)
+
+ (dolist (var symbols)
+ (set var t))
+
+ (dolist (header (spam-necessary-extra-headers))
+ (add-to-list 'nnmail-extra-headers header)
+ (add-to-list 'gnus-extra-headers header))
+
(setq spam-install-hooks t)
;; TODO: How do we redo this every time spam-face is customized?
(push '((eq mark gnus-spam-mark) . spam-face)