1 ;;; wl-spam.el --- Spam filtering interface for Wanderlust.
3 ;; Copyright (C) 2003 Hiroya Murata <lapis-lazuli@pop06.odn.ne.jp>
4 ;; Copyright (C) 2003 Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Author: Hiroya Murata <lapis-lazuli@pop06.odn.ne.jp>
7 ;; Keywords: mail, net news, spam
9 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
33 (eval-when-compile (require 'cl))
38 (require 'wl-highlight)
41 "Spam configuration for wanderlust."
44 (defcustom wl-spam-folder-name "+spam"
49 (defcustom wl-spam-undecided-folder-regexp-list '("inbox")
50 "*List of folder regexp which is contained undecided domain."
51 :type '(repeat (regexp :tag "Folder Regexp"))
54 (defcustom wl-spam-ignored-folder-regexp-list
55 (list (regexp-opt (list wl-draft-folder
58 "*List of folder regexp which is contained ignored domain."
59 :type '(repeat (regexp :tag "Folder Regexp"))
62 (defcustom wl-spam-auto-check-folder-regexp-list '("[+.]inbox")
63 "*List of Folder regexp which check spam automatically."
64 :type '(repeat (regexp :tag "Folder Regexp"))
67 (defcustom wl-spam-auto-check-marks
68 (list wl-summary-new-mark)
69 "Persistent marks to check spam automatically."
70 :type '(choice (const :tag "All marks" all)
71 (repeat (string :tag "Mark")))
74 (wl-defface wl-highlight-summary-spam-face
79 (:foreground "LightSlateGray")))
80 "Face used for displaying messages mark as spam."
81 :group 'wl-summary-faces
84 (defcustom wl-spam-mark-action-list
88 wl-summary-register-temp-mark
89 wl-summary-exec-action-spam
90 wl-highlight-summary-spam-face
91 "Mark messages as spam."))
92 "A variable to define Mark & Action for spam.
93 Append this value to `wl-summary-mark-action-list' by `wl-spam-setup'.
95 See `wl-summary-mark-action-list' for the detail of element."
96 :type '(repeat (string :tag "Temporary mark")
97 (symbol :tag "Set mark function")
98 (symbol :tag "Unset mark function")
99 (symbol :tag "Exec function")
100 (symbol :tag "Face symbol")
101 (string :tag "Document string"))
104 (defun wl-spam-folder-guess-domain (folder-name)
105 (cond ((string= folder-name wl-spam-folder-name)
107 ((wl-string-match-member folder-name
108 wl-spam-undecided-folder-regexp-list)
110 ((wl-string-match-member folder-name
111 wl-spam-ignored-folder-regexp-list)
116 (defsubst wl-spam-auto-check-message-p (folder number)
117 (or (eq wl-spam-auto-check-marks 'all)
118 (member (wl-summary-message-mark folder number)
119 wl-spam-auto-check-marks)))
121 (defsubst wl-spam-map-spam-messages (folder numbers function &rest args)
122 (let ((total (length numbers)))
123 (message "Checking spam...")
124 (elmo-with-progress-display (> total elmo-display-progress-threshold)
125 (elmo-spam-check-spam total "Checking spam...")
126 (dolist (number (elmo-spam-list-spam-messages (elmo-spam-processor)
129 (apply function number args)))
130 (message "Checking spam...done")))
132 (defun wl-spam-register-spam-messages (folder numbers)
133 (let ((total (length numbers)))
134 (message "Registering spam...")
135 (elmo-with-progress-display (> total elmo-display-progress-threshold)
136 (elmo-spam-register total "Registering spam...")
137 (elmo-spam-register-spam-messages (elmo-spam-processor)
138 wl-summary-buffer-elmo-folder
140 (message "Registering spam...done")))
142 (defun wl-spam-register-good-messages (folder numbers)
143 (let ((total (length numbers)))
144 (message "Registering good...")
145 (elmo-with-progress-display (> total elmo-display-progress-threshold)
146 (elmo-spam-register total "Registering good...")
147 (elmo-spam-register-good-messages (elmo-spam-processor)
148 wl-summary-buffer-elmo-folder
150 (message "Registering good...done")))
152 (defun wl-spam-save-status (&optional force)
154 (let ((processor (elmo-spam-processor)))
155 (when (or force (elmo-spam-modified-p processor))
156 (elmo-spam-save-status processor))))
158 ;; insinuate into summary mode
159 (defvar wl-summary-spam-map nil)
161 (unless wl-summary-spam-map
162 (let ((map (make-sparse-keymap)))
163 (define-key map "m" 'wl-summary-spam)
164 (define-key map "c" 'wl-summary-test-spam)
165 (define-key map "C" 'wl-summary-mark-spam)
166 (define-key map "s" 'wl-summary-register-as-spam)
167 (define-key map "S" 'wl-summary-register-as-spam-all)
168 (define-key map "n" 'wl-summary-register-as-good)
169 (define-key map "N" 'wl-summary-register-as-good-all)
170 (setq wl-summary-spam-map map)))
173 ;; Avoid compile warnings
174 (defalias-maybe 'wl-summary-spam 'ignore))
176 (defun wl-summary-test-spam (&optional folder number)
178 (let ((folder (or folder wl-summary-buffer-elmo-folder))
179 (number (or number (wl-summary-message-number)))
181 (message "Cheking spam...")
182 (when (setq spam (elmo-spam-message-spam-p (elmo-spam-processor)
184 (wl-summary-spam number))
185 (message "Cheking spam...done")
186 (when (interactive-p)
187 (message "No: %d is %sa spam message." number (if spam "" "not ")))))
189 (defun wl-summary-mark-spam (&optional all)
190 "Set spam mark to messages which is spam classification."
194 (setq numbers wl-summary-buffer-number-list)
195 (dolist (number wl-summary-buffer-number-list)
196 (when (wl-spam-auto-check-message-p wl-summary-buffer-elmo-folder
198 (setq numbers (cons number numbers)))))
200 (wl-spam-map-spam-messages wl-summary-buffer-elmo-folder
203 (message "No message to test."))))
205 (defun wl-summary-register-as-spam ()
207 (let ((number (wl-summary-message-number)))
209 (wl-spam-register-spam-messages wl-summary-buffer-elmo-folder
212 (defun wl-summary-register-as-spam-all ()
214 (wl-spam-register-spam-messages wl-summary-buffer-elmo-folder
215 wl-summary-buffer-number-list))
217 (defun wl-summary-target-mark-register-as-spam ()
220 (goto-char (point-min))
221 (let ((inhibit-read-only t)
222 (buffer-read-only nil)
223 wl-summary-buffer-disp-msg)
224 (wl-spam-register-spam-messages wl-summary-buffer-elmo-folder
225 wl-summary-buffer-target-mark-list)
226 (dolist (number wl-summary-buffer-target-mark-list)
227 (wl-summary-unset-mark number)))))
229 (defun wl-summary-register-as-good ()
231 (let ((number (wl-summary-message-number)))
233 (wl-spam-register-good-messages wl-summary-buffer-elmo-folder
236 (defun wl-summary-register-as-good-all ()
238 (wl-spam-register-good-messages wl-summary-buffer-elmo-folder
239 wl-summary-buffer-number-list))
241 (defun wl-summary-target-mark-register-as-good ()
244 (goto-char (point-min))
245 (let ((inhibit-read-only t)
246 (buffer-read-only nil)
247 wl-summary-buffer-disp-msg)
248 (wl-spam-register-good-messages wl-summary-buffer-elmo-folder
249 wl-summary-buffer-target-mark-list)
250 (dolist (number wl-summary-buffer-target-mark-list)
251 (wl-summary-unset-mark number)))))
253 ;; hook functions and other
254 (defun wl-summary-auto-check-spam ()
255 (when (elmo-string-match-member (wl-summary-buffer-folder-name)
256 wl-spam-auto-check-folder-regexp-list)
257 (wl-summary-mark-spam)))
259 (defun wl-summary-exec-action-spam (mark-list)
260 (let ((folder wl-summary-buffer-elmo-folder)
261 (total (length mark-list)))
262 (when (eq (wl-spam-folder-guess-domain (elmo-folder-name-internal folder))
264 (message "Registering spam...")
265 (elmo-with-progress-display (> total elmo-display-progress-threshold)
266 (elmo-spam-register total "Registering spam...")
267 (elmo-spam-register-spam-messages (elmo-spam-processor)
269 (mapcar #'car mark-list)))
270 (message "Registering spam...done"))
271 (wl-summary-move-mark-list-messages mark-list
273 "Refiling spam...")))
275 (defun wl-summary-exec-action-refile-with-register (mark-list)
276 (let ((processor (elmo-spam-processor))
277 (folder wl-summary-buffer-elmo-folder)
278 spam-list good-list total)
279 (when (eq (wl-spam-folder-guess-domain
280 (elmo-folder-name-internal folder))
282 (message "Registering spam...")
283 (dolist (info mark-list)
284 (case (wl-spam-folder-guess-domain (nth 2 info))
286 (setq spam-list (cons (car info) spam-list)))
288 (setq good-list (cons (car info) good-list)))))
289 (setq total (+ (length spam-list) (length good-list)))
290 (elmo-with-progress-display (> total elmo-display-progress-threshold)
291 (elmo-spam-register total "Registering spam...")
293 (elmo-spam-register-spam-messages processor folder spam-list))
295 (elmo-spam-register-good-messages processor folder good-list)))
296 (message "Registering spam...done"))
297 ;; execute refile messages
298 (wl-summary-exec-action-refile mark-list)))
300 (defun wl-message-check-spam ()
301 (let ((original (wl-message-get-original-buffer))
302 (number wl-message-buffer-cur-number)
304 (message "Cheking spam...")
305 (when (elmo-spam-buffer-spam-p (elmo-spam-processor) original)
306 (with-current-buffer wl-message-buffer-cur-summary-buffer
307 (wl-summary-spam number)))
308 (message "Cheking spam...done")
309 (when (interactive-p)
310 (message "No: %d is %sa spam message." number (if spam "" "not ")))))
312 (defun wl-refile-guess-by-spam (entity)
313 (when (elmo-spam-message-spam-p (elmo-spam-processor)
314 wl-summary-buffer-elmo-folder
315 (elmo-message-entity-number entity))
316 wl-spam-folder-name))
318 (defun wl-spam-setup ()
319 (when wl-spam-mark-action-list
320 (setq wl-summary-mark-action-list (append
321 wl-summary-mark-action-list
322 wl-spam-mark-action-list))
323 (dolist (action wl-spam-mark-action-list)
324 (setq wl-summary-reserve-mark-list
325 (cons (wl-summary-action-mark action)
326 wl-summary-reserve-mark-list))
327 (setq wl-summary-skip-mark-list
328 (cons (wl-summary-action-mark action)
329 wl-summary-skip-mark-list))))
330 (define-key wl-summary-mode-map "k" wl-summary-spam-map)
331 (define-key wl-summary-mode-map "ms" 'wl-summary-target-mark-register-as-spam)
332 (define-key wl-summary-mode-map "mn" 'wl-summary-target-mark-register-as-good))
335 (product-provide (provide 'wl-spam) (require 'wl-version))
337 (unless noninteractive
340 ;;; wl-spam.el ends here