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