102087
|
1 ;;; rmail-spam-filter.el --- spam filter for Rmail, the Emacs mail reader
|
49862
|
2
|
101540
|
3 ;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
|
4 ;; Free Software Foundation, Inc.
|
49862
|
5 ;; Keywords: email, spam, filter, rmail
|
53730
|
6 ;; Author: Eli Tziperman <eli AT deas.harvard.edu>
|
49862
|
7
|
|
8 ;; This file is part of GNU Emacs.
|
|
9
|
94674
|
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
|
49862
|
11 ;; it under the terms of the GNU General Public License as published by
|
94674
|
12 ;; the Free Software Foundation, either version 3 of the License, or
|
|
13 ;; (at your option) any later version.
|
49862
|
14
|
|
15 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18 ;; GNU General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
94674
|
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
49862
|
22
|
|
23 ;;; Commentary:
|
53730
|
24 ;;; -----------
|
49862
|
25
|
53730
|
26 ;;; Automatically recognize and delete junk email before it is
|
|
27 ;;; displayed in rmail/rmail-summary. Spam emails are defined by
|
|
28 ;;; specifying one or more of the sender, subject and contents.
|
54002
|
29 ;;; URL: http://www.weizmann.ac.il/~eli/Downloads/rmail-spam-filter/
|
49862
|
30
|
53730
|
31 ;;; Usage:
|
|
32 ;;; ------
|
49862
|
33
|
53730
|
34 ;;; put in your .emacs:
|
49862
|
35
|
101540
|
36 ;;; (require 'rmail-spam-filter)
|
53730
|
37
|
|
38 ;;; and use customize (in rmail-spam-filter group) to:
|
49862
|
39
|
53730
|
40 ;;; (*) turn on the variable rmail-use-spam-filter,
|
49862
|
41
|
53730
|
42 ;;; (*) specify in variable rsf-definitions-alist what sender,
|
|
43 ;;; subject and contents make an email be considered spam.
|
49862
|
44
|
53730
|
45 ;;; in addition, you may:
|
49862
|
46
|
53730
|
47 ;;; (*) Block future mail with the subject or sender of a message
|
|
48 ;;; while reading it in RMAIL: just click on the "Spam" item on the
|
|
49 ;;; menubar, and add the subject or sender to the list of spam
|
|
50 ;;; definitions using the mouse and the appropriate menu item. You
|
|
51 ;;; need to later also save the list of spam definitions using the
|
|
52 ;;; same menu item, or alternatively, see variable
|
|
53 ;;; `rsf-autosave-newly-added-definitions'.
|
49862
|
54
|
53730
|
55 ;;; (*) specify if blind-cc'ed mail (no "To:" header field) is to be
|
|
56 ;;; treated as spam (variable rsf-no-blind-cc; Thanks to Ethan
|
|
57 ;;; Brown <ethan@gso.saic.com> for this).
|
|
58
|
|
59 ;;; (*) specify if rmail-spam-filter should ignore case of spam
|
|
60 ;;; definitions (variable rsf-ignore-case; Thanks to
|
|
61 ;;; Ethan Brown <ethan@gso.saic.com> for the suggestion).
|
49862
|
62
|
53730
|
63 ;;; (*) Specify a "white-list" of trusted senders. If any
|
|
64 ;;; rsf-white-list string matches a substring of the "From"
|
|
65 ;;; header, the message is flagged as a valid, non-spam message (Ethan
|
|
66 ;;; Brown <ethan@gso.saic.com>).
|
49862
|
67
|
53730
|
68 ;;; (*) rmail-spam-filter is best used with a general purpose spam
|
|
69 ;;; filter such as the procmail-based http://www.spambouncer.org/.
|
|
70 ;;; Spambouncer is set to only mark messages as spam/blocked/bulk/OK
|
|
71 ;;; via special headers, and these headers may then be defined in
|
|
72 ;;; rmail-spam-filter such that the spam is rejected by
|
|
73 ;;; rmail-spam-filter itself.
|
49862
|
74
|
101540
|
75 (require 'rmail)
|
|
76 (require 'rmailsum)
|
49862
|
77
|
|
78 (defgroup rmail-spam-filter nil
|
102087
|
79 "Spam filter for Rmail, the Emacs mail reader."
|
49862
|
80 :group 'rmail)
|
|
81
|
|
82 (defcustom rmail-use-spam-filter nil
|
102087
|
83 "Non-nil to activate the Rmail spam filter.
|
|
84 Set `rsf-definitions-alist' to define what you consider spam emails."
|
49862
|
85 :type 'boolean
|
102087
|
86 :group 'rmail-spam-filter)
|
49862
|
87
|
53730
|
88 (defcustom rsf-file "~/XRMAIL-SPAM"
|
102087
|
89 "Name of Rmail file for optionally saving some of the spam.
|
|
90 You can either just delete spam, or save it in this file for
|
|
91 later review. Which action to take for each spam definition is
|
|
92 specified by the \"action\" element of the definition."
|
49862
|
93 :type 'string
|
102087
|
94 :group 'rmail-spam-filter)
|
49862
|
95
|
53730
|
96 (defcustom rsf-no-blind-cc nil
|
102087
|
97 "Non-nil means mail with no explicit To: or Cc: is spam."
|
49862
|
98 :type 'boolean
|
102087
|
99 :group 'rmail-spam-filter)
|
49862
|
100
|
53730
|
101 (defcustom rsf-ignore-case nil
|
102087
|
102 "Non-nil means to ignore case in `rsf-definitions-alist'."
|
49862
|
103 :type 'boolean
|
102087
|
104 :group 'rmail-spam-filter)
|
49862
|
105
|
53730
|
106 (defcustom rsf-beep nil
|
102087
|
107 "Non-nil means to beep if spam is found."
|
49862
|
108 :type 'boolean
|
102087
|
109 :group 'rmail-spam-filter)
|
49862
|
110
|
53730
|
111 (defcustom rsf-sleep-after-message 2.0
|
102087
|
112 "Seconds to wait after displaying a message that spam was found."
|
49862
|
113 :type 'number
|
102087
|
114 :group 'rmail-spam-filter)
|
53685
|
115
|
53730
|
116 (defcustom rsf-min-region-to-spam-list 7
|
101540
|
117 "Minimum size of region that you can add to the spam list.
|
102087
|
118 The aim is to avoid adding too short a region, which could result
|
|
119 in false positive identification of a valid message as spam."
|
53730
|
120 :type 'integer
|
102087
|
121 :group 'rmail-spam-filter)
|
53730
|
122
|
|
123 (defcustom rsf-autosave-newly-added-definitions nil
|
102087
|
124 "Non-nil to auto-save new spam entries.
|
|
125 Any time you add an entry via the \"Spam\" menu, immediately saves
|
|
126 the custom file."
|
49862
|
127 :type 'boolean
|
102087
|
128 :group 'rmail-spam-filter)
|
49862
|
129
|
53730
|
130 (defcustom rsf-white-list nil
|
102087
|
131 "List of regexps to identify valid senders.
|
|
132 If any element matches the \"From\" header, the message is
|
|
133 flagged as a valid, non-spam message. E.g., if your domain is
|
|
134 \"emacs.com\" then including \"emacs\\\\.com\" in this list would
|
|
135 flag all mail (purporting to be) from your colleagues as valid."
|
49862
|
136 :type '(repeat string)
|
102087
|
137 :group 'rmail-spam-filter)
|
49862
|
138
|
53730
|
139 (defcustom rsf-definitions-alist nil
|
102087
|
140 "A list of rules (definitions) matching spam messages.
|
|
141 Each rule is an alist, with elements of the form (FIELD . REGEXP).
|
|
142 The recognized FIELDS are: from, to, subject, content-type,
|
|
143 x-spam-status, and contents. The \"contents\" element refers to
|
|
144 the entire text of the message; all the other elements refer to
|
|
145 message headers of the same name.
|
|
146
|
|
147 Using an empty-string for REGEXP is the same as omitting that
|
|
148 element altogether.
|
|
149
|
|
150 Each rule should contain one \"action\" element, saying what to do
|
|
151 if the rule is matched. This has the form (action . CHOICE), where
|
|
152 CHOICE may be either `output-and-delete' (save to `rsf-file', then delete),
|
|
153 or `delete-spam' (just delete).
|
|
154
|
|
155 A rule matches only if all the specified elements match."
|
64754
|
156 :type '(repeat
|
49862
|
157 (list :format "%v"
|
|
158 (cons :format "%v" :value (from . "")
|
|
159 (const :format "" from)
|
|
160 (string :tag "From" ""))
|
|
161 (cons :format "%v" :value (to . "")
|
|
162 (const :format "" to)
|
|
163 (string :tag "To" ""))
|
|
164 (cons :format "%v" :value (subject . "")
|
|
165 (const :format "" subject)
|
|
166 (string :tag "Subject" ""))
|
53730
|
167 (cons :format "%v" :value (content-type . "")
|
|
168 (const :format "" content-type)
|
|
169 (string :tag "Content-Type" ""))
|
49862
|
170 (cons :format "%v" :value (contents . "")
|
|
171 (const :format "" contents)
|
|
172 (string :tag "Contents" ""))
|
91817
f0b22bbb77fb
;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail
Bastien Guerry <bzg@altern.org>
diff
changeset
|
173 (cons :format "%v" :value (x-spam-status . "")
|
f0b22bbb77fb
;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail
Bastien Guerry <bzg@altern.org>
diff
changeset
|
174 (const :format "" x-spam-status)
|
f0b22bbb77fb
;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail
Bastien Guerry <bzg@altern.org>
diff
changeset
|
175 (string :tag "X-Spam-Status" ""))
|
49862
|
176 (cons :format "%v" :value (action . output-and-delete)
|
|
177 (const :format "" action)
|
64754
|
178 (choice :tag "Action selection"
|
102087
|
179 (const :tag "Output and delete" output-and-delete)
|
|
180 (const :tag "Delete" delete-spam)
|
|
181 ))))
|
49862
|
182 :group 'rmail-spam-filter)
|
|
183
|
102087
|
184 ;; FIXME nothing uses this, and it could just be let-bound.
|
53730
|
185 (defvar rsf-scanning-messages-now nil
|
101540
|
186 "Non-nil when `rmail-spam-filter' scans messages.")
|
53730
|
187
|
|
188 ;; the advantage over the automatic filter definitions is the AND conjunction
|
|
189 ;; of in-one-definition-elements
|
101540
|
190 (defun rsf-check-field (field-symbol message-data definition result)
|
102087
|
191 "Check if a message appears to be spam.
|
|
192 FIELD-SYMBOL is one of the possible keys of a `rsf-definitions-alist'
|
|
193 rule; e.g. from, to. MESSAGE-DATA is a string giving the value of
|
|
194 FIELD-SYMBOL in the current message. DEFINITION is the element of
|
|
195 `rsf-definitions-alist' currently being checked.
|
|
196
|
|
197 RESULT is a cons of the form (MAYBE-SPAM . IS-SPAM). If the car
|
|
198 is nil, or if the entry for FIELD-SYMBOL in this DEFINITION is
|
|
199 absent or the empty string, this function does nothing.
|
|
200
|
|
201 Otherwise, if MESSAGE-DATA is non-nil and the entry matches it,
|
|
202 the cdr is set to t. Else, the car is set to nil."
|
53730
|
203 (let ((definition-field (cdr (assoc field-symbol definition))))
|
102087
|
204 ;; Only in this case can maybe-spam change from t to nil.
|
101540
|
205 (if (and (car result) (> (length definition-field) 0))
|
102087
|
206 ;; If FIELD-SYMBOL field appears in the message, and also in
|
|
207 ;; spam definition list, this is potentially a spam.
|
53730
|
208 (if (and message-data
|
|
209 (string-match definition-field message-data))
|
102087
|
210 ;; If we do not get a contradiction from another field, this is spam
|
|
211 (setcdr result t)
|
|
212 ;; The message data contradicts the specification, this is not spam.
|
|
213 ;; Note that the total absence of a header specified in the
|
|
214 ;; rule means this cannot be spam.
|
|
215 (setcar result nil)))))
|
49862
|
216
|
|
217 (defun rmail-spam-filter (msg)
|
102087
|
218 "Return nil if message number MSG is spam based on `rsf-definitions-alist'.
|
|
219 If spam, optionally output message to a file `rsf-file' and delete
|
49862
|
220 it from rmail file. Called for each new message retrieved by
|
|
221 `rmail-get-new-mail'."
|
102087
|
222 (let ((return-value)
|
|
223 ;; maybe-spam is in the car, this-is-a-spam-email in cdr.
|
|
224 (maybe-spam '(nil . nil))
|
|
225 message-sender message-to message-cc message-recipients
|
|
226 message-subject message-content-type message-spam-status
|
|
227 (num-spam-definition-elements (safe-length rsf-definitions-alist))
|
49862
|
228 (num-element 0)
|
|
229 (exit-while-loop nil)
|
102087
|
230 ;; Do we want to ignore case in spam definitions.
|
|
231 (case-fold-search rsf-ignore-case)
|
101540
|
232 ;; make sure bbdb does not create entries for messages while spam
|
|
233 ;; filter is scanning the rmail file:
|
|
234 (bbdb/mail_auto_create_p nil)
|
102087
|
235 ;; Other things may wish to know if we are running (nothing
|
|
236 ;; uses this at present).
|
|
237 (rsf-scanning-messages-now t))
|
49862
|
238 (save-excursion
|
102087
|
239 ;; Narrow buffer to header of message and get Sender and
|
|
240 ;; Subject fields to be used below:
|
49862
|
241 (save-restriction
|
102087
|
242 (goto-char (rmail-msgbeg msg))
|
|
243 (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
|
|
244 (setq message-sender (mail-fetch-field "From"))
|
|
245 (setq message-to (mail-fetch-field "To")
|
|
246 message-cc (mail-fetch-field "Cc")
|
|
247 message-recipients (or (and message-to message-cc
|
|
248 (concat message-to ", " message-cc))
|
|
249 message-to
|
|
250 message-cc))
|
|
251 (setq message-subject (mail-fetch-field "Subject"))
|
|
252 (setq message-content-type (mail-fetch-field "Content-Type"))
|
|
253 (setq message-spam-status (mail-fetch-field "X-Spam-Status")))
|
|
254 ;; Check for blind CC condition. Set vars such that while
|
|
255 ;; loop will be bypassed and spam condition will trigger.
|
|
256 (and rsf-no-blind-cc
|
|
257 (null message-recipients)
|
|
258 (setq exit-while-loop t
|
|
259 maybe-spam '(t . t)))
|
|
260 ;; Check white list, and likewise cause while loop bypass.
|
|
261 (and message-sender
|
|
262 (let ((white-list rsf-white-list)
|
|
263 (found nil))
|
|
264 (while (and (not found) white-list)
|
|
265 (if (string-match (car white-list) message-sender)
|
|
266 (setq found t)
|
|
267 (setq white-list (cdr white-list))))
|
|
268 found)
|
|
269 (setq exit-while-loop t
|
|
270 maybe-spam '(nil . nil)))
|
|
271 ;; Scan all elements of the list rsf-definitions-alist.
|
|
272 (while (and (< num-element num-spam-definition-elements)
|
|
273 (not exit-while-loop))
|
|
274 (let ((definition (nth num-element rsf-definitions-alist)))
|
|
275 ;; Initialize car, which is set to t in one of two cases:
|
|
276 ;; (1) unspecified definition-elements are found in
|
|
277 ;; rsf-definitions-alist, (2) empty field is found in the
|
|
278 ;; message being scanned (e.g. empty subject, sender,
|
|
279 ;; recipients, etc). It is set to nil if a non-empty field
|
|
280 ;; of the scanned message does not match a specified field
|
|
281 ;; in rsf-definitions-alist.
|
|
282 ;; FIXME the car is never set to t?!
|
53685
|
283
|
102087
|
284 ;; Initialize cdr to nil. This is set to t if one of the
|
|
285 ;; spam definitions matches a field in the scanned message.
|
|
286 (setq maybe-spam (cons t nil))
|
53730
|
287
|
102087
|
288 ;; Maybe the different fields should also be done in a
|
|
289 ;; loop to make the whole thing more flexible.
|
64754
|
290
|
102087
|
291 ;; If sender field is not specified in message being
|
|
292 ;; scanned, AND if "from" field does not appear in spam
|
|
293 ;; definitions for this element, this may still be spam due
|
|
294 ;; to another element...
|
|
295 (rsf-check-field 'from message-sender definition maybe-spam)
|
|
296 ;; Next, if spam was not ruled out already, check recipients:
|
|
297 (rsf-check-field 'to message-recipients definition maybe-spam)
|
|
298 ;; Next, if spam was not ruled out already, check subject:
|
|
299 (rsf-check-field 'subject message-subject definition maybe-spam)
|
|
300 ;; Next, if spam was not ruled out already, check content-type:
|
|
301 (rsf-check-field 'content-type message-content-type
|
|
302 definition maybe-spam)
|
|
303 ;; Next, if spam was not ruled out already, check contents:
|
|
304 ;; If contents field is not specified, this may still be
|
|
305 ;; spam due to another element...
|
|
306 (rsf-check-field 'contents
|
|
307 (buffer-substring-no-properties
|
|
308 (rmail-msgbeg msg) (rmail-msgend msg))
|
|
309 definition maybe-spam)
|
64754
|
310
|
102087
|
311 ;; Finally, check the X-Spam-Status header. You will typically
|
|
312 ;; look for the "Yes" string in this header field.
|
|
313 (rsf-check-field 'x-spam-status message-spam-status
|
|
314 definition maybe-spam)
|
91817
f0b22bbb77fb
;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail
Bastien Guerry <bzg@altern.org>
diff
changeset
|
315
|
102087
|
316 ;; If the search in rsf-definitions-alist found
|
|
317 ;; that this email is spam, output the email to the spam
|
|
318 ;; rmail file, mark the email for deletion, leave the
|
|
319 ;; while loop and return nil so that an rmail summary line
|
|
320 ;; wont be displayed for this message: (FIXME ?)
|
|
321 (if (and (car maybe-spam) (cdr maybe-spam))
|
|
322 (setq exit-while-loop t)
|
|
323 ;; Else, spam was not yet found, proceed to next element
|
|
324 ;; in rsf-definitions-alist:
|
|
325 (setq num-element (1+ num-element)))))
|
49862
|
326
|
102087
|
327 (if (and (car maybe-spam) (cdr maybe-spam))
|
|
328 ;; Temporarily set rmail-current-message in order to output
|
|
329 ;; and delete the spam msg if needed:
|
|
330 (let ((rmail-current-message msg) ; FIXME does this do anything?
|
|
331 (action (cdr (assq 'action
|
102096
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
332 (nth num-element rsf-definitions-alist))))
|
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
333 (newfile (not (file-exists-p rsf-file))))
|
102087
|
334 ;; Check action item in rsf-definitions-alist and do it.
|
|
335 (cond
|
|
336 ((eq action 'output-and-delete)
|
102096
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
337 ;; Else the prompt to write a new file leaves the raw
|
102087
|
338 ;; mbox buffer visible.
|
102096
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
339 (and newfile
|
102112
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
340 (rmail-show-message (rmail-first-unseen-message) t))
|
102087
|
341 (rmail-output rsf-file)
|
102096
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
342 ;; Swap back, else rmail-get-new-mail-1 gets confused.
|
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
343 (when newfile
|
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
344 (rmail-swap-buffers-maybe)
|
7053d753a548
(rmail-spam-filter): Show a message rather than the raw mbox while prompting.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
345 (widen))
|
102087
|
346 ;; Don't delete if automatic deletion after output is on.
|
|
347 (or rmail-delete-after-output (rmail-delete-message)))
|
|
348 ((eq action 'delete-spam)
|
|
349 (rmail-delete-message)))
|
|
350 (setq return-value nil))
|
|
351 (setq return-value t)))
|
49862
|
352 return-value))
|
|
353
|
102110
|
354 (defun rmail-get-new-mail-filter-spam (nnew)
|
102112
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
355 "Check the most NNEW recent messages for spam.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
356 This is called at the end of `rmail-get-new-mail-1' if there is new mail."
|
102110
|
357 (let* ((nold (- rmail-total-messages nnew))
|
|
358 (nspam 0)
|
102112
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
359 (nscan (1+ nold))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
360 ;; Save the original deleted state of all the messages.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
361 (rdv-old rmail-deleted-vector)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
362 errflag)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
363 ;; Set all messages undeleted so that the expunge only affects spam.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
364 (setq rmail-deleted-vector (make-string (1+ rmail-total-messages) ?\s))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
365 (while (and (not errflag) (<= nscan rmail-total-messages))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
366 (condition-case nil
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
367 (or (rmail-spam-filter nscan)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
368 (setq nspam (1+ nspam)))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
369 (error (setq errflag nscan)))
|
102110
|
370 (setq nscan (1+ nscan)))
|
102112
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
371 (unwind-protect
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
372 (if errflag
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
373 (progn
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
374 (setq rmail-use-spam-filter nil)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
375 (if rsf-beep (ding t))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
376 (message "Spam filter error for new message %d, disabled" errflag)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
377 (sleep-for rsf-sleep-after-message))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
378 (when (> nspam 0)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
379 ;; Otherwise sleep or expunge prompt leaves raw mbox buffer showing.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
380 (rmail-show-message (or (rmail-first-unseen-message) 1) t)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
381 (unwind-protect
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
382 (progn
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
383 (if rsf-beep (ding t))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
384 (message "Rmail spam-filter detected and deleted %d spam \
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
385 message%s"
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
386 nspam (if (= 1 nspam) "" "s"))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
387 (sleep-for rsf-sleep-after-message)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
388 (if (rmail-expunge-confirmed) (rmail-only-expunge t)))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
389 ;; Swap back, else get-new-mail-1 gets confused.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
390 (rmail-swap-buffers-maybe)
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
391 (widen))))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
392 ;; Restore the original deleted state. Character N refers to message N.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
393 (setq rmail-deleted-vector
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
394 (concat (substring rdv-old 0 (1+ nold))
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
395 ;; This still works if we deleted all the new mail.
|
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
396 (substring rmail-deleted-vector (1+ nold)))))
|
102110
|
397 ;; Return a message based on the number of spam messages found.
|
|
398 (cond
|
102112
c9da83f185a6
(rmail-get-new-mail-filter-spam): Be more careful about error-handling.
Glenn Morris <rgm@gnu.org>
diff
changeset
|
399 (errflag ", error in spam filter")
|
102110
|
400 ((zerop nspam) "")
|
|
401 ((= 1 nnew) ", and it appears to be spam")
|
|
402 ((= nspam nnew) ", and all appear to be spam")
|
|
403 (t (format ", and %d appear%s to be spam" nspam
|
|
404 (if (= 1 nspam) "s" ""))))))
|
|
405
|
49862
|
406 ;; define functions for interactively adding sender/subject of a
|
|
407 ;; specific message to the spam definitions while reading it, using
|
|
408 ;; the menubar:
|
53730
|
409 (defun rsf-add-subject-to-spam-list ()
|
102087
|
410 "Add the \"Subject\" header to the spam list."
|
49862
|
411 (interactive)
|
102087
|
412 (let ((message-subject (regexp-quote (rmail-get-header "Subject"))))
|
|
413 ;; Note the use of a backquote and comma on the subject line here,
|
49862
|
414 ;; to make sure message-subject is actually evaluated and its value
|
102087
|
415 ;; substituted.
|
53730
|
416 (add-to-list 'rsf-definitions-alist
|
102087
|
417 ;; Note that an empty elment is treated the same as
|
|
418 ;; an absent one, so why does it bother to add them?
|
49862
|
419 (list '(from . "")
|
|
420 '(to . "")
|
|
421 `(subject . ,message-subject)
|
53730
|
422 '(content-type . "")
|
49862
|
423 '(contents . "")
|
|
424 '(action . output-and-delete))
|
|
425 t)
|
53730
|
426 (customize-mark-to-save 'rsf-definitions-alist)
|
|
427 (if rsf-autosave-newly-added-definitions
|
49862
|
428 (progn
|
|
429 (custom-save-all)
|
102087
|
430 (message "Added subject `%s' to spam list, and saved it"
|
|
431 message-subject))
|
|
432 (message "Added subject `%s' to spam list (remember to save it)"
|
|
433 message-subject))))
|
49862
|
434
|
53730
|
435 (defun rsf-add-sender-to-spam-list ()
|
102087
|
436 "Add the \"From\" address to the spam list."
|
49862
|
437 (interactive)
|
102087
|
438 (let ((message-sender (regexp-quote (rmail-get-header "From"))))
|
53730
|
439 (add-to-list 'rsf-definitions-alist
|
49862
|
440 (list `(from . ,message-sender)
|
|
441 '(to . "")
|
|
442 '(subject . "")
|
53730
|
443 '(content-type . "")
|
49862
|
444 '(contents . "")
|
|
445 '(action . output-and-delete))
|
|
446 t)
|
53730
|
447 (customize-mark-to-save 'rsf-definitions-alist)
|
|
448 (if rsf-autosave-newly-added-definitions
|
49862
|
449 (progn
|
|
450 (custom-save-all)
|
102087
|
451 (message "Added sender `%s' to spam list, and saved it"
|
|
452 message-sender))
|
|
453 (message "Added sender `%s' to spam list (remember to save it)"
|
|
454 message-sender))))
|
49862
|
455
|
53730
|
456 (defun rsf-add-region-to-spam-list ()
|
102087
|
457 "Add the marked region in the Rmail buffer to the spam list.
|
|
458 Adds to spam definitions as a \"contents\" field."
|
49862
|
459 (interactive)
|
|
460 (set-buffer rmail-buffer)
|
102087
|
461 ;; Check if region is inactive or has zero size.
|
|
462 (if (not (and mark-active (not (= (region-beginning) (region-end)))))
|
|
463 ;; If inactive, print error message.
|
|
464 (message "You must highlight some text in the Rmail buffer")
|
|
465 (if (< (- (region-end) (region-beginning)) rsf-min-region-to-spam-list)
|
|
466 (message "Region is too small (minimum %d characters)"
|
|
467 rsf-min-region-to-spam-list)
|
|
468 ;; If region active and long enough, add to list of spam definitions.
|
|
469 (let ((region-to-spam-list (regexp-quote
|
|
470 (buffer-substring-no-properties
|
|
471 (region-beginning) (region-end)))))
|
|
472 (add-to-list 'rsf-definitions-alist
|
|
473 (list '(from . "")
|
|
474 '(to . "")
|
|
475 '(subject . "")
|
|
476 '(content-type . "")
|
|
477 `(contents . ,region-to-spam-list)
|
|
478 '(action . output-and-delete))
|
|
479 t)
|
|
480 (customize-mark-to-save 'rsf-definitions-alist)
|
|
481 (if rsf-autosave-newly-added-definitions
|
|
482 (progn
|
|
483 (custom-save-all)
|
|
484 (message "Added highlighted text:\n%s\n\
|
|
485 to the spam list, and saved it" region-to-spam-list))
|
|
486 (message "Added highlighted text:\n%s\n\
|
|
487 to the spam list (remember to save it)" region-to-spam-list))))))
|
49862
|
488
|
53730
|
489 (defun rsf-customize-spam-definitions ()
|
102087
|
490 "Customize `rsf-definitions-alist'."
|
49862
|
491 (interactive)
|
102087
|
492 (customize-variable 'rsf-definitions-alist))
|
49862
|
493
|
53730
|
494 (defun rsf-customize-group ()
|
102087
|
495 "Customize the rmail-spam-filter group."
|
49862
|
496 (interactive)
|
102087
|
497 (customize-group 'rmail-spam-filter))
|
49862
|
498
|
53730
|
499 (defun rsf-custom-save-all ()
|
102087
|
500 "Interactive version of `custom-save-all'."
|
49862
|
501 (interactive)
|
|
502 (custom-save-all))
|
|
503
|
102087
|
504 ;; Add menu items (and keyboard shortcuts) to both rmail and rmail-summary.
|
|
505 (dolist (map (list rmail-summary-mode-map rmail-mode-map))
|
|
506 (easy-menu-define nil map nil
|
|
507 '("Spam"
|
|
508 ["Add subject to spam list" rsf-add-subject-to-spam-list]
|
|
509 ["Add sender to spam list" rsf-add-sender-to-spam-list]
|
|
510 ["Add region to spam list" rsf-add-region-to-spam-list]
|
|
511 ["Save spam definitions" rsf-custom-save-all]
|
|
512 "--"
|
|
513 ["Customize spam definitions" rsf-customize-spam-definitions]
|
|
514 ["Browse spam customizations" rsf-customize-group]
|
|
515 ))
|
|
516 (define-key map "\C-cSt" 'rsf-add-subject-to-spam-list)
|
|
517 (define-key map "\C-cSr" 'rsf-add-sender-to-spam-list)
|
|
518 (define-key map "\C-cSn" 'rsf-add-region-to-spam-list)
|
|
519 (define-key map "\C-cSa" 'rsf-custom-save-all)
|
|
520 (define-key map "\C-cSd" 'rsf-customize-spam-definitions)
|
|
521 (define-key map "\C-cSg" 'rsf-customize-group))
|
49862
|
522
|
53730
|
523 (defun rsf-add-content-type-field ()
|
72643
|
524 "Maintain backward compatibility for `rmail-spam-filter'.
|
102087
|
525 The most recent version of `rmail-spam-filter' checks the content-type
|
|
526 field of the incoming mail to see if it is spam. The format of
|
53730
|
527 `rsf-definitions-alist' has therefore changed. This function
|
102087
|
528 checks to see if the old format is used, and updates it if necessary."
|
49862
|
529 (interactive)
|
53730
|
530 (if (and rsf-definitions-alist
|
|
531 (not (assoc 'content-type (car rsf-definitions-alist))))
|
|
532 (let ((result nil)
|
|
533 (current nil)
|
|
534 (definitions rsf-definitions-alist))
|
|
535 (while definitions
|
|
536 (setq current (car definitions))
|
|
537 (setq definitions (cdr definitions))
|
64754
|
538 (setq result
|
53730
|
539 (append result
|
64754
|
540 (list
|
53730
|
541 (list (assoc 'from current)
|
|
542 (assoc 'to current)
|
|
543 (assoc 'subject current)
|
|
544 (cons 'content-type "")
|
|
545 (assoc 'contents current)
|
|
546 (assoc 'action current))))))
|
|
547 (setq rsf-definitions-alist result)
|
|
548 (customize-mark-to-save 'rsf-definitions-alist)
|
|
549 (if rsf-autosave-newly-added-definitions
|
|
550 (progn
|
|
551 (custom-save-all)
|
102087
|
552 (message "Spam definitions converted to new format, and saved"))
|
|
553 (message "Spam definitions converted to new format (remember to save)")))))
|
49862
|
554
|
|
555 (provide 'rmail-spam-filter)
|
|
556
|
93975
|
557 ;; arch-tag: 03e1d45d-b72f-4dd7-8f04-e7fd78249746
|
53730
|
558 ;;; rmail-spam-fitler ends here
|