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))