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