Function: rmail-spam-filter
rmail-spam-filter is a byte-compiled function defined in
rmail-spam-filter.el.gz.
Signature
(rmail-spam-filter MSG)
Documentation
Return nil if message number MSG is spam based on rsf-definitions-alist.
If spam, optionally output message to a file rsf-file and delete
it from rmail file. Called for each new message retrieved by
rmail-get-new-mail.
Source Code
;; Defined in /usr/src/emacs/lisp/mail/rmail-spam-filter.el.gz
(defun rmail-spam-filter (msg)
"Return nil if message number MSG is spam based on `rsf-definitions-alist'.
If spam, optionally output message to a file `rsf-file' and delete
it from rmail file. Called for each new message retrieved by
`rmail-get-new-mail'."
(let ((return-value)
;; maybe-spam is in the car, this-is-a-spam-email in cdr.
(maybe-spam '(nil . nil))
message-sender message-to message-cc message-recipients
message-subject message-content-type message-spam-status
(num-spam-definition-elements (safe-length rsf-definitions-alist))
(num-element 0)
(exit-while-loop nil)
;; Do we want to ignore case in spam definitions.
(case-fold-search rsf-ignore-case)
;; make sure bbdb does not create entries for messages while spam
;; filter is scanning the rmail file:
(bbdb/mail_auto_create_p nil)
;; Other things may wish to know if we are running (nothing
;; uses this at present).
(rsf-scanning-messages-now t))
(save-excursion
;; Narrow buffer to header of message and get Sender and
;; Subject fields to be used below:
(save-restriction
(goto-char (rmail-msgbeg msg))
(narrow-to-region (point) (progn (search-forward "\n\n") (point)))
(setq message-sender (mail-fetch-field "From"))
(setq message-to (mail-fetch-field "To")
message-cc (mail-fetch-field "Cc")
message-recipients (or (and message-to message-cc
(concat message-to ", " message-cc))
message-to
message-cc))
(setq message-subject (mail-fetch-field "Subject"))
(setq message-content-type (mail-fetch-field "Content-Type"))
(setq message-spam-status (mail-fetch-field "X-Spam-Status")))
;; Check for blind cc condition. Set vars such that while
;; loop will be bypassed and spam condition will trigger.
(and rsf-no-blind-cc
(null message-recipients)
(setq exit-while-loop t
maybe-spam '(t . t)))
;; Check white list, and likewise cause while loop bypass.
(and message-sender
(let ((white-list rsf-white-list)
(found nil))
(while (and (not found) white-list)
(if (string-match (car white-list) message-sender)
(setq found t)
(setq white-list (cdr white-list))))
found)
(setq exit-while-loop t
maybe-spam '(nil . nil)))
;; Scan all elements of the list rsf-definitions-alist.
(while (and (< num-element num-spam-definition-elements)
(not exit-while-loop))
(let ((definition (nth num-element rsf-definitions-alist)))
;; Initialize car, which is set to t in one of two cases:
;; (1) unspecified definition-elements are found in
;; rsf-definitions-alist, (2) empty field is found in the
;; message being scanned (e.g. empty subject, sender,
;; recipients, etc). It is set to nil if a non-empty field
;; of the scanned message does not match a specified field
;; in rsf-definitions-alist.
;; FIXME the car is never set to t?!
;; Initialize cdr to nil. This is set to t if one of the
;; spam definitions matches a field in the scanned message.
(setq maybe-spam (cons t nil))
;; Maybe the different fields should also be done in a
;; loop to make the whole thing more flexible.
;; If sender field is not specified in message being
;; scanned, AND if "from" field does not appear in spam
;; definitions for this element, this may still be spam due
;; to another element...
(rsf-check-field 'from message-sender definition maybe-spam)
;; Next, if spam was not ruled out already, check recipients:
(rsf-check-field 'to message-recipients definition maybe-spam)
;; Next, if spam was not ruled out already, check subject:
(rsf-check-field 'subject message-subject definition maybe-spam)
;; Next, if spam was not ruled out already, check content-type:
(rsf-check-field 'content-type message-content-type
definition maybe-spam)
;; Next, if spam was not ruled out already, check contents:
;; If contents field is not specified, this may still be
;; spam due to another element...
(rsf-check-field 'contents
(buffer-substring-no-properties
(rmail-msgbeg msg) (rmail-msgend msg))
definition maybe-spam)
;; Finally, check the X-Spam-Status header. You will typically
;; look for the "Yes" string in this header field.
(rsf-check-field 'x-spam-status message-spam-status
definition maybe-spam)
;; If the search in rsf-definitions-alist found
;; that this email is spam, output the email to the spam
;; rmail file, mark the email for deletion, leave the
;; while loop and return nil so that an rmail summary line
;; won't be displayed for this message: (FIXME ?)
(if (and (car maybe-spam) (cdr maybe-spam))
(setq exit-while-loop t)
;; Else, spam was not yet found, proceed to next element
;; in rsf-definitions-alist:
(setq num-element (1+ num-element)))))
(if (and (car maybe-spam) (cdr maybe-spam))
;; Temporarily set rmail-current-message in order to output
;; and delete the spam msg if needed:
(let ((action (cdr (assq 'action
(nth num-element rsf-definitions-alist))))
(newfile (not (file-exists-p rsf-file))))
;; Check action item in rsf-definitions-alist and do it.
(cond
((eq action 'output-and-delete)
;; Else the prompt to write a new file leaves the raw
;; mbox buffer visible.
(and newfile
(rmail-show-message (rsf--rmail-last-seen-message) t))
(rmail-output rsf-file)
;; Swap back, else rmail-get-new-mail-1 gets confused.
(when newfile
(rmail-swap-buffers-maybe)
(widen))
;; Don't delete if automatic deletion after output is on.
(or rmail-delete-after-output (rmail-delete-message)))
((eq action 'delete-spam)
(rmail-delete-message)))
(setq return-value nil))
(setq return-value t)))
return-value))