53730
|
1 ;;; rmail-spam-filter.el --- spam filter for rmail, the emacs mail reader.
|
49862
|
2
|
75347
|
3 ;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
49862
|
4 ;; Keywords: email, spam, filter, rmail
|
53730
|
5 ;; Author: Eli Tziperman <eli AT deas.harvard.edu>
|
49862
|
6
|
|
7 ;; This file is part of GNU Emacs.
|
|
8
|
|
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
10 ;; it under the terms of the GNU General Public License as published by
|
78232
|
11 ;; the Free Software Foundation; either version 3, or (at your option)
|
49862
|
12 ;; any later version.
|
|
13
|
|
14 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 ;; GNU General Public License for more details.
|
|
18
|
|
19 ;; You should have received a copy of the GNU General Public License
|
|
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
64085
|
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
22 ;; Boston, MA 02110-1301, USA.
|
49862
|
23
|
|
24 ;;; Commentary:
|
53730
|
25 ;;; -----------
|
49862
|
26
|
53730
|
27 ;;; Automatically recognize and delete junk email before it is
|
|
28 ;;; displayed in rmail/rmail-summary. Spam emails are defined by
|
|
29 ;;; specifying one or more of the sender, subject and contents.
|
54002
|
30 ;;; URL: http://www.weizmann.ac.il/~eli/Downloads/rmail-spam-filter/
|
49862
|
31
|
53730
|
32 ;;; Usage:
|
|
33 ;;; ------
|
49862
|
34
|
53730
|
35 ;;; put in your .emacs:
|
49862
|
36
|
53730
|
37 ;;; (load "rmail-spam-filter.el")
|
|
38
|
|
39 ;;; and use customize (in rmail-spam-filter group) to:
|
49862
|
40
|
53730
|
41 ;;; (*) turn on the variable rmail-use-spam-filter,
|
49862
|
42
|
53730
|
43 ;;; (*) specify in variable rsf-definitions-alist what sender,
|
|
44 ;;; subject and contents make an email be considered spam.
|
49862
|
45
|
53730
|
46 ;;; in addition, you may:
|
49862
|
47
|
53730
|
48 ;;; (*) Block future mail with the subject or sender of a message
|
|
49 ;;; while reading it in RMAIL: just click on the "Spam" item on the
|
|
50 ;;; menubar, and add the subject or sender to the list of spam
|
|
51 ;;; definitions using the mouse and the appropriate menu item. You
|
|
52 ;;; need to later also save the list of spam definitions using the
|
|
53 ;;; same menu item, or alternatively, see variable
|
|
54 ;;; `rsf-autosave-newly-added-definitions'.
|
49862
|
55
|
53730
|
56 ;;; (*) specify if blind-cc'ed mail (no "To:" header field) is to be
|
|
57 ;;; treated as spam (variable rsf-no-blind-cc; Thanks to Ethan
|
|
58 ;;; Brown <ethan@gso.saic.com> for this).
|
|
59
|
|
60 ;;; (*) specify if rmail-spam-filter should ignore case of spam
|
|
61 ;;; definitions (variable rsf-ignore-case; Thanks to
|
|
62 ;;; Ethan Brown <ethan@gso.saic.com> for the suggestion).
|
49862
|
63
|
53730
|
64 ;;; (*) Specify a "white-list" of trusted senders. If any
|
|
65 ;;; rsf-white-list string matches a substring of the "From"
|
|
66 ;;; header, the message is flagged as a valid, non-spam message (Ethan
|
|
67 ;;; Brown <ethan@gso.saic.com>).
|
49862
|
68
|
53730
|
69 ;;; (*) rmail-spam-filter is best used with a general purpose spam
|
|
70 ;;; filter such as the procmail-based http://www.spambouncer.org/.
|
|
71 ;;; Spambouncer is set to only mark messages as spam/blocked/bulk/OK
|
|
72 ;;; via special headers, and these headers may then be defined in
|
|
73 ;;; rmail-spam-filter such that the spam is rejected by
|
|
74 ;;; rmail-spam-filter itself.
|
49862
|
75
|
53730
|
76 ;;; (*) rmail spam filter also works with bbdb to prevent spam senders
|
|
77 ;;; from entering into the .bbdb file. See variable
|
|
78 ;;; "rsf-auto-delete-spam-bbdb-entries". This is done
|
|
79 ;;; in two ways: (a) bbdb is made not to auto-create entries for
|
|
80 ;;; messages that are deleted by the rmail-spam-filter, (b) when a
|
|
81 ;;; message is deleted in rmail, the user is offered to delete the
|
|
82 ;;; sender's bbdb entry as well _if_ it was created at the same day.
|
49862
|
83
|
|
84 (require 'rmail)
|
54002
|
85 (if (> emacs-major-version 20)
|
|
86 (require 'rmailsum)
|
|
87 (if (not (fboundp 'rmail-make-summary-line)) (load-library "rmailsum")))
|
49862
|
88
|
65209
afdca0591e8c
(bbdb/mail_auto_create_p, rmail-summary-mode-map): Add defvars.
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
89 (defvar bbdb/mail_auto_create_p)
|
afdca0591e8c
(bbdb/mail_auto_create_p, rmail-summary-mode-map): Add defvars.
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
90 (defvar rmail-summary-mode-map)
|
afdca0591e8c
(bbdb/mail_auto_create_p, rmail-summary-mode-map): Add defvars.
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
91
|
53730
|
92 ;; For find-if and other cool common lisp functions we may want to use.
|
53685
|
93 (eval-when-compile
|
|
94 (require 'cl))
|
49862
|
95
|
|
96 (defgroup rmail-spam-filter nil
|
|
97 "Spam filter for RMAIL, the mail reader for Emacs."
|
|
98 :group 'rmail)
|
|
99
|
|
100 (defcustom rmail-use-spam-filter nil
|
|
101 "*Non-nil to activate the rmail spam filter.
|
53730
|
102 Specify `rsf-definitions-alist' to define what you consider spam
|
49862
|
103 emails."
|
|
104 :type 'boolean
|
|
105 :group 'rmail-spam-filter )
|
|
106
|
53730
|
107 (defcustom rsf-file "~/XRMAIL-SPAM"
|
49862
|
108 "*Name of rmail file for optionally saving some of the spam.
|
|
109 Spam may be either just deleted, or saved in a separate spam file to
|
|
110 be looked at at a later time. Whether the spam is just deleted or
|
|
111 also saved in a separete spam file is specified for each definition of
|
53730
|
112 spam, as one of the fields of `rsf-definitions-alist'"
|
49862
|
113 :type 'string
|
|
114 :group 'rmail-spam-filter )
|
|
115
|
53730
|
116 (defcustom rsf-no-blind-cc nil
|
49862
|
117 "*Non-nil to treat blind CC (no To: header) as spam."
|
|
118 :type 'boolean
|
|
119 :group 'rmail-spam-filter )
|
|
120
|
53730
|
121 (defcustom rsf-ignore-case nil
|
|
122 "*Non-nil to ignore case in `rsf-definitions-alist'."
|
49862
|
123 :type 'boolean
|
|
124 :group 'rmail-spam-filter )
|
|
125
|
53730
|
126 (defcustom rsf-beep nil
|
49862
|
127 "*Non-nil to beep if spam is found."
|
|
128 :type 'boolean
|
|
129 :group 'rmail-spam-filter )
|
|
130
|
53730
|
131 (defcustom rsf-sleep-after-message 2.0
|
49862
|
132 "*Seconds to wait after display of message that spam was found."
|
|
133 :type 'number
|
|
134 :group 'rmail-spam-filter )
|
53685
|
135
|
53730
|
136 (defcustom rsf-min-region-to-spam-list 7
|
72643
|
137 "*Minimum size of region that you can add to the spam list.
|
|
138 This is a size limit on text that you can specify as
|
|
139 indicating a message is spam. The aim is to avoid
|
|
140 accidentally adding a too short region, which would result
|
|
141 in false positive identification of spam."
|
53730
|
142 :type 'integer
|
|
143 :group 'rmail-spam-filter )
|
|
144
|
|
145 (defcustom rsf-auto-delete-spam-bbdb-entries nil
|
49862
|
146 "*Non-nil to make sure no entries are made in bbdb for spam emails.
|
|
147 This is done in two ways: (1) bbdb is made not to auto-create entries
|
|
148 for messages that are deleted by the `rmail-spam-filter', (2) when a
|
|
149 message is deleted in rmail, the user is offered to delete the
|
|
150 sender's bbdb entry as well if it was created at the same day. Note
|
|
151 that Emacs needs to be restarted after setting this option for it to
|
|
152 take an effect."
|
|
153 :type 'boolean
|
|
154 :group 'rmail-spam-filter )
|
|
155
|
53730
|
156 (defcustom rsf-autosave-newly-added-definitions nil
|
49862
|
157 "*Non-nil to auto save new spam entries.
|
|
158 New entries entered via the spam menu bar item are then saved to
|
|
159 customization file immediately after being added via the menu bar, and
|
|
160 do not require explicitly saving the file after adding the new
|
|
161 entries."
|
|
162 :type 'boolean
|
|
163 :group 'rmail-spam-filter )
|
|
164
|
53730
|
165 (defcustom rsf-white-list nil
|
49862
|
166 "*List of strings to identify valid senders.
|
53730
|
167 If any rsf-white-list string matches a substring of the 'From'
|
49862
|
168 header, the message is flagged as a valid, non-spam message. Example:
|
|
169 If your domain is emacs.com then including 'emacs.com' in your
|
53730
|
170 rsf-white-list would flag all mail from your colleagues as
|
49862
|
171 valid."
|
|
172 :type '(repeat string)
|
|
173 :group 'rmail-spam-filter )
|
|
174
|
53730
|
175 (defcustom rsf-definitions-alist nil
|
49862
|
176 "*Alist matching strings defining what messages are considered spam.
|
|
177 Each definition may contain specifications of one or more of the
|
|
178 elements {subject, sender, recipients or contents}, as well as a
|
|
179 definition of what to do with the spam (action item). A spam e-mail
|
|
180 is defined as one that fits all of the specified elements of any one
|
|
181 of the spam definitions. The strings that specify spam subject,
|
|
182 sender, etc, may be regexp. For example, to specify that the subject
|
|
183 may be either 'this is spam' or 'another spam', use the regexp: 'this
|
53730
|
184 is spam\\|another spam' (without the single quotes). To specify that
|
|
185 if the contents contain both this and that the message is spam,
|
|
186 specify 'this\\&that' in the appropriate spam definition field."
|
64754
|
187 :type '(repeat
|
49862
|
188 (list :format "%v"
|
|
189 (cons :format "%v" :value (from . "")
|
|
190 (const :format "" from)
|
|
191 (string :tag "From" ""))
|
|
192 (cons :format "%v" :value (to . "")
|
|
193 (const :format "" to)
|
|
194 (string :tag "To" ""))
|
|
195 (cons :format "%v" :value (subject . "")
|
|
196 (const :format "" subject)
|
|
197 (string :tag "Subject" ""))
|
53730
|
198 (cons :format "%v" :value (content-type . "")
|
|
199 (const :format "" content-type)
|
|
200 (string :tag "Content-Type" ""))
|
49862
|
201 (cons :format "%v" :value (contents . "")
|
|
202 (const :format "" contents)
|
|
203 (string :tag "Contents" ""))
|
|
204 (cons :format "%v" :value (action . output-and-delete)
|
|
205 (const :format "" action)
|
64754
|
206 (choice :tag "Action selection"
|
49862
|
207 (const :tag "output to spam folder and delete" output-and-delete)
|
|
208 (const :tag "delete spam" delete-spam)
|
|
209 ))
|
|
210 ))
|
|
211 :group 'rmail-spam-filter)
|
|
212
|
53730
|
213 (defvar rsf-scanning-messages-now nil
|
73649
|
214 "Non-nil when `rmail-spam-filter' scans messages.
|
72643
|
215 This is for interaction with `rsf-bbdb-auto-delete-spam-entries'.")
|
53730
|
216
|
|
217 ;; the advantage over the automatic filter definitions is the AND conjunction
|
|
218 ;; of in-one-definition-elements
|
54002
|
219 (defun check-field (field-symbol message-data definition result)
|
53730
|
220 "Check if field-symbol is in `rsf-definitions-alist'.
|
|
221 Capture maybe-spam and this-is-a-spam-email in a cons in result,
|
64754
|
222 where maybe-spam is in first and this-is-a-spam-email is in rest.
|
53730
|
223 The values are returned by destructively changing result.
|
|
224 If FIELD-SYMBOL field does not exist AND is not specified,
|
|
225 this may still be spam due to another element...
|
|
226 if (first result) is nil, we already have a contradiction in another
|
|
227 field"
|
|
228 (let ((definition-field (cdr (assoc field-symbol definition))))
|
|
229 (if (and (first result) (> (length definition-field) 0))
|
|
230 ;; only in this case can maybe-spam change from t to nil
|
|
231 ;; ... else, if FIELD-SYMBOL field does appear in the message,
|
|
232 ;; and it also appears in spam definition list, this
|
|
233 ;; is potentially a spam:
|
|
234 (if (and message-data
|
|
235 (string-match definition-field message-data))
|
|
236 ;; if we do not get a contradiction from another field, this is
|
|
237 ;; spam
|
|
238 (setf (rest result) t)
|
|
239 ;; the message data contradicts the specification, this is no spam
|
|
240 (setf (first result) nil)))))
|
49862
|
241
|
|
242 (defun rmail-spam-filter (msg)
|
53730
|
243 "Return nil if msg is spam based on rsf-definitions-alist.
|
|
244 If spam, optionally output msg to a file `rsf-file' and delete
|
49862
|
245 it from rmail file. Called for each new message retrieved by
|
|
246 `rmail-get-new-mail'."
|
|
247
|
|
248 (let ((old-message)
|
|
249 (return-value)
|
|
250 (this-is-a-spam-email)
|
|
251 (maybe-spam)
|
|
252 (message-sender)
|
|
253 (message-recipients)
|
|
254 (message-subject)
|
53730
|
255 (message-content-type)
|
49862
|
256 (num-spam-definition-elements)
|
|
257 (num-element 0)
|
|
258 (exit-while-loop nil)
|
|
259 (saved-case-fold-search case-fold-search)
|
|
260 (save-current-msg)
|
53730
|
261 (rsf-saved-bbdb/mail_auto_create_p nil)
|
49862
|
262 )
|
64754
|
263
|
49862
|
264 ;; make sure bbdb does not create entries for messages while spam
|
|
265 ;; filter is scanning the rmail file:
|
53730
|
266 (setq rsf-saved-bbdb/mail_auto_create_p 'bbdb/mail_auto_create_p)
|
49862
|
267 (setq bbdb/mail_auto_create_p nil)
|
53730
|
268 ;; let `rsf-bbdb-auto-delete-spam-entries' know that rmail spam
|
49862
|
269 ;; filter is running, so that deletion of rmail messages should be
|
|
270 ;; ignored for now:
|
53730
|
271 (setq rsf-scanning-messages-now t)
|
49862
|
272 (save-excursion
|
|
273 (save-restriction
|
|
274 (setq this-is-a-spam-email nil)
|
|
275 ;; Narrow buffer to header of message and get Sender and
|
|
276 ;; Subject fields to be used below:
|
|
277 (save-restriction
|
|
278 (goto-char (rmail-msgbeg msg))
|
|
279 (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
|
|
280 (setq message-sender (mail-fetch-field "From"))
|
53730
|
281 (setq message-recipients
|
|
282 (concat (mail-fetch-field "To")
|
|
283 (if (mail-fetch-field "Cc")
|
|
284 (concat ", " (mail-fetch-field "Cc")))))
|
49862
|
285 (setq message-subject (mail-fetch-field "Subject"))
|
53730
|
286 (setq message-content-type (mail-fetch-field "Content-Type"))
|
49862
|
287 )
|
|
288 ;; Find number of spam-definition elements in the list
|
53730
|
289 ;; rsf-definitions-alist specified by user:
|
49862
|
290 (setq num-spam-definition-elements (safe-length
|
53730
|
291 rsf-definitions-alist))
|
49862
|
292
|
|
293 ;;; do we want to ignore case in spam definitions:
|
53730
|
294 (setq case-fold-search rsf-ignore-case)
|
64754
|
295
|
49862
|
296 ;; Check for blind CC condition. Set vars such that while
|
53730
|
297 ;; loop will be bypassed and spam condition will trigger
|
|
298 (if (and rsf-no-blind-cc
|
49862
|
299 (null message-recipients))
|
53730
|
300 (setq exit-while-loop t
|
|
301 maybe-spam t
|
|
302 this-is-a-spam-email t))
|
53685
|
303
|
53730
|
304 ;; Check white list, and likewise cause while loop
|
|
305 ;; bypass.
|
58182
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
306 (if (and message-sender
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
307 (let ((white-list rsf-white-list)
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
308 (found nil))
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
309 (while (and (not found) white-list)
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
310 (if (string-match (car white-list) message-sender)
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
311 (setq found t)
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
312 (setq white-list (cdr white-list))))
|
875255640d7a
(rmail-spam-filter): Only check white list if `message-sender' is non-nil.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
313 found))
|
53730
|
314 (setq exit-while-loop t
|
|
315 maybe-spam nil
|
|
316 this-is-a-spam-email nil))
|
53685
|
317
|
53730
|
318 ;; maybe-spam is in first, this-is-a-spam-email in rest, this
|
54002
|
319 ;; simplifies the call to check-field
|
53730
|
320 (setq maybe-spam (cons maybe-spam this-is-a-spam-email))
|
|
321
|
|
322 ;; scan all elements of the list rsf-definitions-alist
|
49862
|
323 (while (and
|
|
324 (< num-element num-spam-definition-elements)
|
|
325 (not exit-while-loop))
|
53730
|
326 (let ((definition (nth num-element rsf-definitions-alist)))
|
49862
|
327 ;; Initialize maybe-spam which is set to t in one of two
|
|
328 ;; cases: (1) unspecified definition-elements are found in
|
53730
|
329 ;; rsf-definitions-alist, (2) empty field is found
|
49862
|
330 ;; in the message being scanned (e.g. empty subject,
|
|
331 ;; sender, recipients, etc). The variable is set to nil
|
|
332 ;; if a non empty field of the scanned message does not
|
|
333 ;; match a specified field in
|
53730
|
334 ;; rsf-definitions-alist.
|
|
335
|
49862
|
336 ;; initialize this-is-a-spam-email to nil. This variable
|
|
337 ;; is set to t if one of the spam definitions matches a
|
|
338 ;; field in the scanned message.
|
53730
|
339 (setq maybe-spam (cons t nil))
|
49862
|
340
|
|
341 ;; start scanning incoming message:
|
|
342 ;;---------------------------------
|
64754
|
343
|
53730
|
344 ;; Maybe the different fields should also be done in a
|
|
345 ;; loop to make the whole thing more flexible
|
|
346 ;; if sender field is not specified in message being
|
49862
|
347 ;; scanned, AND if "from" field does not appear in spam
|
|
348 ;; definitions for this element, this may still be spam
|
|
349 ;; due to another element...
|
54002
|
350 (check-field 'from message-sender definition maybe-spam)
|
53730
|
351 ;; next, if spam was not ruled out already, check recipients:
|
54002
|
352 (check-field 'to message-recipients definition maybe-spam)
|
53730
|
353 ;; next, if spam was not ruled out already, check subject:
|
54002
|
354 (check-field 'subject message-subject definition maybe-spam)
|
53730
|
355 ;; next, if spam was not ruled out already, check content-type:
|
64754
|
356 (check-field 'content-type message-content-type
|
53730
|
357 definition maybe-spam)
|
49862
|
358 ;; next, if spam was not ruled out already, check
|
|
359 ;; contents: if contents field is not specified, this may
|
|
360 ;; still be spam due to another element...
|
64754
|
361 (check-field 'contents
|
53730
|
362 (buffer-substring
|
|
363 (rmail-msgbeg msg) (rmail-msgend msg))
|
|
364 definition maybe-spam)
|
64754
|
365
|
53730
|
366 ;; if the search in rsf-definitions-alist found
|
49862
|
367 ;; that this email is spam, output the email to the spam
|
|
368 ;; rmail file, mark the email for deletion, leave the
|
|
369 ;; while loop and return nil so that an rmail summary line
|
|
370 ;; wont be displayed for this message:
|
53730
|
371 (if (and (first maybe-spam) (rest maybe-spam))
|
49862
|
372 ;; found that this is spam, no need to look at the
|
53730
|
373 ;; rest of the rsf-definitions-alist, exit
|
49862
|
374 ;; loop:
|
|
375 (setq exit-while-loop t)
|
|
376 ;; else, spam was not yet found, increment number of
|
53730
|
377 ;; element in rsf-definitions-alist and proceed
|
49862
|
378 ;; to next element:
|
|
379 (setq num-element (+ num-element 1)))
|
|
380 )
|
53730
|
381 )
|
64754
|
382
|
53730
|
383 ;; (BK) re-set originally used variables
|
|
384 (setq this-is-a-spam-email (rest maybe-spam)
|
|
385 maybe-spam (first maybe-spam))
|
|
386
|
49862
|
387 (if (and this-is-a-spam-email maybe-spam)
|
|
388 (progn
|
|
389 ;;(message "Found spam!")
|
|
390 ;;(ding 1) (sleep-for 2)
|
|
391
|
|
392 ;; temprarily set rmail-current-message in order to
|
|
393 ;; output and delete the spam msg if needed:
|
|
394 (setq save-current-msg rmail-current-message)
|
|
395 (setq rmail-current-message msg)
|
53730
|
396 ;; check action item and rsf-definitions-alist
|
49862
|
397 ;; and do it:
|
|
398 (cond
|
|
399 ((equal (cdr (assoc 'action
|
53730
|
400 (nth num-element rsf-definitions-alist)))
|
49862
|
401 'output-and-delete)
|
|
402 (progn
|
53730
|
403 (rmail-output-to-rmail-file rsf-file 1 t)
|
|
404 ;; Don't delete if automatic deletion after output
|
|
405 ;; is turned on
|
|
406 (unless rmail-delete-after-output (rmail-delete-message))
|
49862
|
407 ))
|
|
408 ((equal (cdr (assoc 'action
|
53730
|
409 (nth num-element rsf-definitions-alist)))
|
49862
|
410 'delete-spam)
|
|
411 (progn
|
|
412 (rmail-delete-message)
|
|
413 ))
|
|
414 )
|
|
415 (setq rmail-current-message save-current-msg)
|
53730
|
416 (setq bbdb/mail_auto_create_p
|
|
417 'rsf-saved-bbdb/mail_auto_create_p)
|
49862
|
418 ;; set return value. These lines must be last in the
|
|
419 ;; function, so that they will determine the value
|
|
420 ;; returned by rmail-spam-filter:
|
|
421 (setq return-value nil))
|
|
422 (setq return-value t))))
|
|
423 (setq case-fold-search saved-case-fold-search)
|
53730
|
424 (setq rsf-scanning-messages-now nil)
|
49862
|
425 return-value))
|
|
426
|
|
427
|
|
428 ;; define functions for interactively adding sender/subject of a
|
|
429 ;; specific message to the spam definitions while reading it, using
|
|
430 ;; the menubar:
|
53730
|
431 (defun rsf-add-subject-to-spam-list ()
|
49862
|
432 (interactive)
|
|
433 (set-buffer rmail-buffer)
|
|
434 (let ((message-subject))
|
|
435 (setq message-subject (mail-fetch-field "Subject"))
|
|
436 ;; note the use of a backquote and comma on the subject line here,
|
|
437 ;; to make sure message-subject is actually evaluated and its value
|
|
438 ;; substituted:
|
53730
|
439 (add-to-list 'rsf-definitions-alist
|
49862
|
440 (list '(from . "")
|
|
441 '(to . "")
|
|
442 `(subject . ,message-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)
|
65587
|
451 (message "%s" (concat "added subject \n <<< \n" message-subject
|
49862
|
452 " \n >>> \n to list of spam definitions. \n"
|
|
453 "and saved the spam definitions to file.")))
|
65587
|
454 (message "%s" (concat "added subject \n <<< \n" message-subject
|
49862
|
455 " \n >>> \n to list of spam definitions. \n"
|
53730
|
456 "Don't forget to save the spam definitions to file using the spam
|
|
457 menu"))
|
49862
|
458 )))
|
|
459
|
53730
|
460 (defun rsf-add-sender-to-spam-list ()
|
49862
|
461 (interactive)
|
|
462 (set-buffer rmail-buffer)
|
|
463 (let ((message-sender))
|
|
464 (setq message-sender (mail-fetch-field "From"))
|
|
465 ;; note the use of a backquote and comma on the "from" line here,
|
|
466 ;; to make sure message-sender is actually evaluated and its value
|
|
467 ;; substituted:
|
53730
|
468 (add-to-list 'rsf-definitions-alist
|
49862
|
469 (list `(from . ,message-sender)
|
|
470 '(to . "")
|
|
471 '(subject . "")
|
53730
|
472 '(content-type . "")
|
49862
|
473 '(contents . "")
|
|
474 '(action . output-and-delete))
|
|
475 t)
|
53730
|
476 (customize-mark-to-save 'rsf-definitions-alist)
|
|
477 (if rsf-autosave-newly-added-definitions
|
49862
|
478 (progn
|
|
479 (custom-save-all)
|
65587
|
480 (message "%s" (concat "added sender \n <<< \n" message-sender
|
49862
|
481 " \n >>> \n to list of spam definitions. \n"
|
|
482 "and saved the spam definitions to file.")))
|
65587
|
483 (message "%s" (concat "added sender \n <<< \n " message-sender
|
49862
|
484 " \n >>> \n to list of spam definitions."
|
53730
|
485 "Don't forget to save the spam definitions to file using the spam
|
|
486 menu"))
|
49862
|
487 )))
|
|
488
|
|
489
|
53730
|
490 (defun rsf-add-region-to-spam-list ()
|
|
491 "Add the region makred by user in the rmail buffer to spam list.
|
|
492 Added to spam definitions as a contents field."
|
49862
|
493 (interactive)
|
|
494 (set-buffer rmail-buffer)
|
|
495 (let ((region-to-spam-list))
|
|
496 ;; check if region is inactive or has zero size:
|
|
497 (if (not (and mark-active (not (= (region-beginning) (region-end)))))
|
|
498 ;; if inactive, print error message:
|
|
499 (message "you need to first highlight some text in the rmail buffer")
|
53730
|
500 (if (< (- (region-end) (region-beginning)) rsf-min-region-to-spam-list)
|
|
501 (message
|
|
502 (concat "highlighted region is too small; min length set by variable \n"
|
|
503 "rsf-min-region-to-spam-list"
|
|
504 " is " (number-to-string rsf-min-region-to-spam-list)))
|
|
505 ;; if region active and long enough, add to list of spam definisions:
|
|
506 (progn
|
|
507 (setq region-to-spam-list (buffer-substring (region-beginning) (region-end)))
|
|
508 ;; note the use of a backquote and comma on the "from" line here,
|
|
509 ;; to make sure message-sender is actually evaluated and its value
|
|
510 ;; substituted:
|
|
511 (add-to-list 'rsf-definitions-alist
|
|
512 (list '(from . "")
|
|
513 '(to . "")
|
|
514 '(subject . "")
|
|
515 '(content-type . "")
|
|
516 `(contents . ,region-to-spam-list)
|
|
517 '(action . output-and-delete))
|
|
518 t)
|
|
519 (customize-mark-to-save 'rsf-definitions-alist)
|
|
520 (if rsf-autosave-newly-added-definitions
|
|
521 (progn
|
|
522 (custom-save-all)
|
65587
|
523 (message "%s" (concat "added highlighted text \n <<< \n" region-to-spam-list
|
53730
|
524 " \n >>> \n to list of spam definitions. \n"
|
|
525 "and saved the spam definitions to file.")))
|
65587
|
526 (message "%s" (concat "added highlighted text \n <<< \n " region-to-spam-list
|
53730
|
527 " \n >>> \n to list of spam definitions."
|
|
528 "Don't forget to save the spam definitions to file using the
|
|
529 spam menu"))
|
|
530 ))))))
|
49862
|
531
|
|
532
|
53730
|
533 (defun rsf-customize-spam-definitions ()
|
49862
|
534 (interactive)
|
53730
|
535 (customize-variable (quote rsf-definitions-alist)))
|
49862
|
536
|
53730
|
537 (defun rsf-customize-group ()
|
49862
|
538 (interactive)
|
|
539 (customize-group (quote rmail-spam-filter)))
|
|
540
|
53730
|
541 (defun rsf-custom-save-all ()
|
49862
|
542 (interactive)
|
|
543 (custom-save-all))
|
|
544
|
|
545 ;; add the actual menu items and keyboard shortcuts to both rmail and
|
|
546 ;; rmail-summary menu-bars::
|
|
547 (define-key rmail-summary-mode-map [menu-bar spam]
|
|
548 (cons "Spam" (make-sparse-keymap "Spam")))
|
|
549 (define-key rmail-mode-map [menu-bar spam]
|
|
550 (cons "Spam" (make-sparse-keymap "Spam")))
|
|
551
|
|
552 (define-key rmail-summary-mode-map [menu-bar spam customize-group]
|
53730
|
553 '("Browse customizations of rmail spam filter" . rsf-customize-group))
|
49862
|
554 (define-key rmail-mode-map [menu-bar spam customize-group]
|
53730
|
555 '("Browse customizations of rmail spam filter" . rsf-customize-group))
|
|
556 (define-key rmail-summary-mode-map "\C-cSg" 'rsf-customize-group)
|
|
557 (define-key rmail-mode-map "\C-cSg" 'rsf-customize-group)
|
49862
|
558
|
|
559 (define-key rmail-summary-mode-map [menu-bar spam customize-spam-list]
|
53730
|
560 '("Customize list of spam definitions" . rsf-customize-spam-definitions))
|
49862
|
561 (define-key rmail-mode-map [menu-bar spam customize-spam-list]
|
53730
|
562 '("Customize list of spam definitions" . rsf-customize-spam-definitions))
|
|
563 (define-key rmail-summary-mode-map "\C-cSd" 'rsf-customize-spam-definitions)
|
|
564 (define-key rmail-mode-map "\C-cSd" 'rsf-customize-spam-definitions)
|
49862
|
565
|
|
566 (define-key rmail-summary-mode-map [menu-bar spam lambda] '("----"))
|
|
567 (define-key rmail-mode-map [menu-bar spam lambda] '("----"))
|
|
568
|
|
569 (define-key rmail-summary-mode-map [menu-bar spam my-custom-save-all]
|
53730
|
570 '("save newly added spam definitions to customization file" . rsf-custom-save-all))
|
49862
|
571 (define-key rmail-mode-map [menu-bar spam my-custom-save-all]
|
53730
|
572 '("save newly added spam definitions to customization file" . rsf-custom-save-all))
|
|
573 (define-key rmail-summary-mode-map "\C-cSa" 'rsf-custom-save-all)
|
|
574 (define-key rmail-mode-map "\C-cSa" 'rsf-custom-save-all)
|
49862
|
575
|
|
576 (define-key rmail-summary-mode-map [menu-bar spam add-region-to-spam-list]
|
53730
|
577 '("add region to spam list" . rsf-add-region-to-spam-list))
|
49862
|
578 (define-key rmail-mode-map [menu-bar spam add-region-to-spam-list]
|
53730
|
579 '("add region to spam list" . rsf-add-region-to-spam-list))
|
|
580 (define-key rmail-summary-mode-map "\C-cSn" 'rsf-add-region-to-spam-list)
|
|
581 (define-key rmail-mode-map "\C-cSn" 'rsf-add-region-to-spam-list)
|
49862
|
582
|
|
583 (define-key rmail-summary-mode-map [menu-bar spam add-sender-to-spam-list]
|
53730
|
584 '("add sender to spam list" . rsf-add-sender-to-spam-list))
|
49862
|
585 (define-key rmail-mode-map [menu-bar spam add-sender-to-spam-list]
|
53730
|
586 '("add sender to spam list" . rsf-add-sender-to-spam-list))
|
|
587 (define-key rmail-summary-mode-map "\C-cSr" 'rsf-add-sender-to-spam-list)
|
|
588 (define-key rmail-mode-map "\C-cSr" 'rsf-add-sender-to-spam-list)
|
49862
|
589
|
|
590 (define-key rmail-summary-mode-map [menu-bar spam add-subject-to-spam-list]
|
53730
|
591 '("add subject to spam list" . rsf-add-subject-to-spam-list))
|
49862
|
592 (define-key rmail-mode-map [menu-bar spam add-subject-to-spam-list]
|
53730
|
593 '("add subject to spam list" . rsf-add-subject-to-spam-list))
|
|
594 (define-key rmail-summary-mode-map "\C-cSt" 'rsf-add-subject-to-spam-list)
|
|
595 (define-key rmail-mode-map "\C-cSt" 'rsf-add-subject-to-spam-list)
|
49862
|
596
|
53730
|
597 (defun rsf-add-content-type-field ()
|
72643
|
598 "Maintain backward compatibility for `rmail-spam-filter'.
|
|
599 The most recent version of `rmail-spam-filter' checks the contents
|
53730
|
600 field of the incoming mail to see if it spam. The format of
|
|
601 `rsf-definitions-alist' has therefore changed. This function
|
|
602 checks to see if old format is used, and if it is, it converts
|
|
603 `rsf-definitions-alist' to the new format. Invoked
|
|
604 automatically, no user input is required."
|
49862
|
605 (interactive)
|
53730
|
606 (if (and rsf-definitions-alist
|
|
607 (not (assoc 'content-type (car rsf-definitions-alist))))
|
|
608 (let ((result nil)
|
|
609 (current nil)
|
|
610 (definitions rsf-definitions-alist))
|
|
611 (while definitions
|
|
612 (setq current (car definitions))
|
|
613 (setq definitions (cdr definitions))
|
64754
|
614 (setq result
|
53730
|
615 (append result
|
64754
|
616 (list
|
53730
|
617 (list (assoc 'from current)
|
|
618 (assoc 'to current)
|
|
619 (assoc 'subject current)
|
|
620 (cons 'content-type "")
|
|
621 (assoc 'contents current)
|
|
622 (assoc 'action current))))))
|
|
623 (setq rsf-definitions-alist result)
|
|
624 (customize-mark-to-save 'rsf-definitions-alist)
|
|
625 (if rsf-autosave-newly-added-definitions
|
|
626 (progn
|
|
627 (custom-save-all)
|
|
628 (message (concat "converted spam definitions to new format\n"
|
|
629 "and saved the spam definitions to file.")))
|
|
630 (message (concat "converted spam definitions to new format\n"
|
|
631 "Don't forget to save the spam definitions to file using the
|
|
632 spam menu"))
|
|
633 ))))
|
49862
|
634
|
|
635 (provide 'rmail-spam-filter)
|
|
636
|
54018
|
637 ;;; arch-tag: 03e1d45d-b72f-4dd7-8f04-e7fd78249746
|
53730
|
638 ;;; rmail-spam-fitler ends here
|