comparison lisp/mh-e/mh-junk.el @ 56673:e9a6cbc8ca5e

Upgraded to MH-E version 7.4.80. See etc/MH-E-NEWS and lisp/mh-e/ChangeLog for details.
author Bill Wohler <wohler@newt.com>
date Sun, 15 Aug 2004 22:00:06 +0000
parents d36b00b98db0
children 4f4f410e6fe8 d8411455de48
comparison
equal deleted inserted replaced
56672:83ab2b01744a 56673:e9a6cbc8ca5e
1 ;;; mh-junk.el --- Interface to anti-spam measures 1 ;;; mh-junk.el --- Interface to anti-spam measures
2 2
3 ;; Copyright (C) 2003 Free Software Foundation, Inc. 3 ;; Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 4
5 ;; Author: Satyaki Das <satyaki@theforce.stanford.edu>, 5 ;; Author: Satyaki Das <satyaki@theforce.stanford.edu>,
6 ;; Bill Wohler <wohler@newt.com> 6 ;; Bill Wohler <wohler@newt.com>
7 ;; Maintainer: Bill Wohler <wohler@newt.com> 7 ;; Maintainer: Bill Wohler <wohler@newt.com>
8 ;; Keywords: mail, spam 8 ;; Keywords: mail, spam
30 30
31 ;;; Change Log: 31 ;;; Change Log:
32 32
33 ;;; Code: 33 ;;; Code:
34 34
35 (eval-when-compile (require 'mh-acros))
36 (mh-require-cl)
35 (require 'mh-e) 37 (require 'mh-e)
36 38
37 ;; Interactive functions callable from the folder buffer 39 ;; Interactive functions callable from the folder buffer
38 ;;;###mh-autoload 40 ;;;###mh-autoload
39 (defun mh-junk-blacklist (range) 41 (defun mh-junk-blacklist (range)
40 "Blacklist RANGE as spam. 42 "Blacklist RANGE as spam.
41 43
42 Check the documentation of `mh-interactive-range' to see how RANGE is read in 44 This command trains the spam program in use (see the `mh-junk-program' option)
43 interactive use. 45 with the content of the range (see `mh-interactive-range') and then handles
44 46 the message(s) as specified by the `mh-junk-disposition' option.
45 First the appropriate function is called depending on the value of 47
46 `mh-junk-choice'. Then if `mh-junk-mail-folder' is a string then the message is 48 For more information about using your particular spam fighting program, see:
47 refiled to that folder. If nil, the message is deleted. 49
48 50 - `mh-spamassassin-blacklist'
49 To change the spam program being used, customize `mh-junk-program'. Directly
50 setting `mh-junk-choice' is not recommended.
51
52 The documentation for the following functions describes what setup is needed
53 for the different spam fighting programs:
54
55 - `mh-bogofilter-blacklist' 51 - `mh-bogofilter-blacklist'
56 - `mh-spamprobe-blacklist' 52 - `mh-spamprobe-blacklist'"
57 - `mh-spamassassin-blacklist'"
58 (interactive (list (mh-interactive-range "Blacklist"))) 53 (interactive (list (mh-interactive-range "Blacklist")))
59 (let ((blacklist-func (nth 1 (assoc mh-junk-choice mh-junk-function-alist)))) 54 (let ((blacklist-func (nth 1 (assoc mh-junk-choice mh-junk-function-alist))))
60 (unless blacklist-func 55 (unless blacklist-func
61 (error "Customize `mh-junk-program' appropriately")) 56 (error "Customize `mh-junk-program' appropriately"))
62 (let ((dest (cond ((null mh-junk-mail-folder) nil) 57 (let ((dest (cond ((null mh-junk-disposition) nil)
63 ((equal mh-junk-mail-folder "") "+") 58 ((equal mh-junk-disposition "") "+")
64 ((eq (aref mh-junk-mail-folder 0) ?+) 59 ((eq (aref mh-junk-disposition 0) ?+)
65 mh-junk-mail-folder) 60 mh-junk-disposition)
66 ((eq (aref mh-junk-mail-folder 0) ?@) 61 ((eq (aref mh-junk-disposition 0) ?@)
67 (concat mh-current-folder "/" 62 (concat mh-current-folder "/"
68 (substring mh-junk-mail-folder 1))) 63 (substring mh-junk-disposition 1)))
69 (t (concat "+" mh-junk-mail-folder))))) 64 (t (concat "+" mh-junk-disposition)))))
70 (mh-iterate-on-range msg range 65 (mh-iterate-on-range msg range
66 (message (format "Blacklisting message %d..." msg))
71 (funcall (symbol-function blacklist-func) msg) 67 (funcall (symbol-function blacklist-func) msg)
68 (message (format "Blacklisting message %d...done" msg))
69 (if (not (memq msg mh-seen-list))
70 (setq mh-seen-list (cons msg mh-seen-list)))
72 (if dest 71 (if dest
73 (mh-refile-a-msg nil (intern dest)) 72 (mh-refile-a-msg nil (intern dest))
74 (mh-delete-a-msg nil))) 73 (mh-delete-a-msg nil)))
75 (mh-next-msg)))) 74 (mh-next-msg))))
76 75
77 ;;;###mh-autoload 76 ;;;###mh-autoload
78 (defun mh-junk-whitelist (range) 77 (defun mh-junk-whitelist (range)
79 "Whitelist RANGE incorrectly classified as spam. 78 "Whitelist RANGE as ham.
80 79
81 Check the documentation of `mh-interactive-range' to see how RANGE is read in 80 This command reclassifies a range of messages (see `mh-interactive-range') as
82 interactive use. 81 ham if it were incorrectly classified as spam. It then refiles the message
83 82 into the `+inbox' folder.
84 First the appropriate function is called depending on the value of 83
85 `mh-junk-choice'. Then the message is refiled to `mh-inbox'. 84 The `mh-junk-program' option specifies the spam program in use."
86
87 To change the spam program being used, customize `mh-junk-program'. Directly
88 setting `mh-junk-choice' is not recommended."
89 (interactive (list (mh-interactive-range "Whitelist"))) 85 (interactive (list (mh-interactive-range "Whitelist")))
90 (let ((whitelist-func (nth 2 (assoc mh-junk-choice mh-junk-function-alist)))) 86 (let ((whitelist-func (nth 2 (assoc mh-junk-choice mh-junk-function-alist))))
91 (unless whitelist-func 87 (unless whitelist-func
92 (error "Customize `mh-junk-program' appropriately")) 88 (error "Customize `mh-junk-program' appropriately"))
93 (mh-iterate-on-range msg range 89 (mh-iterate-on-range msg range
90 (message (format "Whitelisting message %d..." msg))
94 (funcall (symbol-function whitelist-func) msg) 91 (funcall (symbol-function whitelist-func) msg)
92 (message (format "Whitelisting message %d...done" msg))
95 (mh-refile-a-msg nil (intern mh-inbox))) 93 (mh-refile-a-msg nil (intern mh-inbox)))
96 (mh-next-msg))) 94 (mh-next-msg)))
97 95
98 96
99 97
100 ;; Bogofilter Interface
101
102 (defvar mh-bogofilter-executable (executable-find "bogofilter"))
103
104 (defun mh-bogofilter-blacklist (msg)
105 "Classify MSG as spam.
106 Tell bogofilter that the message is spam.
107
108 Bogofilter is a Bayesian spam filtering program. Get it from your local
109 distribution or from:
110 http://bogofilter.sourceforge.net/
111
112 You first need to teach bogofilter. This is done by running
113
114 bogofilter -n < good-message
115
116 on every good message, and
117
118 bogofilter -s < spam-message
119
120 on every spam message. Most Bayesian filters need 1000 to 5000 of each to
121 start doing a good job.
122
123 To use bogofilter, add the following .procmailrc recipes which you can also
124 find in the bogofilter man page:
125
126 # Bogofilter
127 :0fw
128 | bogofilter -u -e -p
129
130 :0
131 * ^X-Bogosity: Yes, tests=bogofilter
132 $SPAM
133
134 Bogofilter continues to feed the messages it classifies back into its
135 database. Occasionally it misses, and those messages need to be reclassified.
136 MH-E can do this for you. Use \\[mh-junk-blacklist] to reclassify messges in
137 your +inbox as spam, and \\[mh-junk-whitelist] to reclassify messages in your
138 spambox as good messages."
139 (unless mh-bogofilter-executable
140 (error "Couldn't find the bogofilter executable"))
141 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
142 (call-process mh-bogofilter-executable msg-file 0 nil "-Ns")))
143
144 (defun mh-bogofilter-whitelist (msg)
145 "Reinstate incorrectly filtered MSG.
146 Train bogofilter to think of the message as non-spam."
147 (unless mh-bogofilter-executable
148 (error "Couldn't find the bogofilter executable"))
149 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
150 (call-process mh-bogofilter-executable msg-file 0 nil "-Sn")))
151
152
153
154 ;; Spamprobe Interface
155
156 (defvar mh-spamprobe-executable (executable-find "spamprobe"))
157
158 (defun mh-spamprobe-blacklist (msg)
159 "Classify MSG as spam.
160 Tell spamprobe that the message is spam.
161
162 Spamprobe is a Bayesian spam filtering program. More info about the program can
163 be found at:
164 http://spamprobe.sourceforge.net
165
166 Here is a procmail recipe to stores incoming spam mail into the folder +spam
167 and good mail in /home/user/Mail/mdrop/mbox. This recipe is provided as an
168 example in the spamprobe man page.
169
170 PATH=/bin:/usr/bin:/usr/local/bin
171 DEFAULT=/home/user/Mail/mdrop/mbox
172 SPAM=/home/user/Mail/spam/.
173
174 # Spamprobe filtering
175 :0
176 SCORE=| spamprobe receive
177 :0 wf
178 | formail -I \"X-SpamProbe: $SCORE\"
179 :0 a:
180 *^X-SpamProbe: SPAM
181 $SPAM
182
183 Occasionally some good mail gets misclassified as spam. You can use
184 \\[mh-junk-whitelist] to reclassify that as good mail."
185 (unless mh-spamprobe-executable
186 (error "Couldn't find the spamprobe executable"))
187 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
188 (call-process mh-spamprobe-executable msg-file 0 nil "spam")))
189
190 (defun mh-spamprobe-whitelist (msg)
191 "Reinstate incorrectly filtered MSG.
192 Train spamprobe to think of the message as non-spam."
193 (unless mh-spamprobe-executable
194 (error "Couldn't find the spamprobe executable"))
195 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
196 (call-process mh-spamprobe-executable msg-file 0 nil "good")))
197
198
199
200 ;; Spamassassin Interface 98 ;; Spamassassin Interface
201 99
202 (defvar mh-spamassassin-executable (executable-find "spamassassin")) 100 (defvar mh-spamassassin-executable (executable-find "spamassassin"))
203 (defvar mh-sa-learn-executable (executable-find "sa-learn")) 101 (defvar mh-sa-learn-executable (executable-find "sa-learn"))
204 102
205 (defun mh-spamassassin-blacklist (msg) 103 (defun mh-spamassassin-blacklist (msg)
206 "Blacklist MSG. 104 "Blacklist MSG with SpamAssassin.
207 This is done by sending the message to Razor and by appending the sender to 105
208 ~/.spamassassin/user_prefs in a blacklist_from rule. If sa-learn is available, 106 SpamAssassin is one of the more popular spam filtering programs. Get it from
209 the message is also recategorized as spam. 107 your local distribution or from http://spamassassin.org/.
210 108
211 Spamassassin is an excellent spam filter. For more information, see: 109 To use SpamAssassin, add the following recipes to `.procmailrc':
212 http://spamassassin.org/. 110
213 111 MAILDIR=$HOME/`mhparam Path`
214 I ran \"spamassassin -t\" on every mail message in my archive and ran an 112
215 analysis in Gnumeric to find that the standard deviation of good mail 113 # Fight spam with SpamAssassin.
216 scored under 5 (coincidentally, the spamassassin default for \"spam\"). 114 :0fw
217 115 | spamc
218 Furthermore, I observed that there weren't any messages with a score of 8 116
219 or more that were interesting, so I added a couple of points to be 117 # Anything with a spam level of 10 or more is junked immediately.
220 conservative and send any message with a score of 10 or more down the 118 :0:
221 drain. You might want to use a score of 12 or 13 to be really conservative. 119 * ^X-Spam-Level: ..........
222 I have found that this really decreases the amount of junk to review. 120 /dev/null
223 121
224 Messages with a score of 5-9 are set aside for later review. The major 122 :0:
225 weakness of rules-based filters is a plethora of false positives\; I catch one 123 * ^X-Spam-Status: Yes
226 or two legitimate messages in here a week, so it is worthwhile to check. 124 spam/.
227 125
228 You might choose to do this analysis yourself to pick a good score for 126 If you don't use `spamc', use `spamassassin -P -a'.
229 deleting spam sight unseen, or you might pick a score out of a hat, or you 127
230 might choose to be very conservative and not delete any messages at all. 128 Note that one of the recipes above throws away messages with a score greater
231 129 than or equal to 10. Here's how you can determine a value that works best for
232 Based upon this discussion, here is what the associated ~/.procmailrc 130 you.
233 entries look like. These rules appear before my list filters so that spam 131
234 sent to mailing lists gets pruned too. 132 First, run `spamassassin -t' on every mail message in your archive and use
235 133 Gnumeric to verify that the average plus the standard deviation of good mail
236 # 134 is under 5, the SpamAssassin default for \"spam\".
237 # Spam 135
238 # 136 Using Gnumeric, sort the messages by score and view the messages with the
239 :0fw 137 highest score. Determine the score which encompasses all of your interesting
240 | spamc 138 messages and add a couple of points to be conservative. Add that many dots to
241 139 the `X-Spam-Level:' header field above to send messages with that score down
242 # Anything with a spam level of 10 or more is junked immediately. 140 the drain.
243 :0: 141
244 * ^X-Spam-Level: .......... 142 In the example above, messages with a score of 5-9 are set aside in the
245 /dev/null 143 `+spam' folder for later review. The major weakness of rules-based filters is
246 144 a plethora of false positives so it is worthwhile to check.
247 :0 145
248 * ^X-Spam-Status: Yes 146 If SpamAssassin classifies a message incorrectly, or is unsure, you can use
249 $SPAM 147 the MH-E commands \\[mh-junk-blacklist] and \\[mh-junk-whitelist].
250 148
251 If you don't use \"spamc\", use \"spamassassin -P -a\". 149 The \\[mh-junk-blacklist] command adds a `blacklist_from' entry to
252 150 `~/spamassassin/user_prefs', deletes the message, and sends the message to the
253 A handful of spam does find its way into +inbox. In this case, use 151 Razor, so that others might not see this spam. If the `sa-learn' command is
254 \\[mh-junk-blacklist] to add a \"blacklist_from\" line to 152 available, the message is also recategorized as spam.
255 ~/spamassassin/user_prefs, delete the message, and send the message to the 153
256 Razor, so that others might not see this spam. 154 The \\[mh-junk-whitelist] command adds a `whitelist_from' rule to the
257 155 `~/.spamassassin/user_prefs' file. If the `sa-learn' command is available, the
258 Over time, you see some patterns in the blacklisted addresses and can 156 message is also recategorized as ham.
259 replace several lines with wildcards. For example, it is clear that High 157
260 Speed Media is the biggest bunch of jerks on the Net. Here are some of the 158 Over time, you'll observe that the same host or domain occurs repeatedly in
261 entries I have for them, and the list continues to grow. 159 the `blacklist_from' entries, so you might think that you could avoid future
262 160 spam by blacklisting all mail from a particular domain. The utility function
263 blacklist_from *@*-hsm-*.com 161 `mh-spamassassin-identify-spammers' helps you do precisely that. This function
264 blacklist_from *@*182*643*.com 162 displays a frequency count of the hosts and domains in the `blacklist_from'
265 blacklist_from *@*antarhsm*.com 163 entries from the last blank line in `~/.spamassassin/user_prefs' to the end of
266 blacklist_from *@*h*speed* 164 the file. This information can be used so that you can replace multiple
267 blacklist_from *@*hsm*182*.com 165 `blacklist_from' entries with a single wildcard entry such as:
268 blacklist_from *@*hsm*643*.com 166
269 blacklist_from *@*hsmridi2983cslt227.com 167 blacklist_from *@*amazingoffersdirect2u.com
270 blacklist_from *@*list*hsm*.com 168
271 blacklist_from *@h*s*media* 169 In versions of SpamAssassin (2.50 and on) that support a Bayesian classifier,
272 blacklist_from *@hsmdrct.com 170 \\[mh-junk-blacklist] uses the `sa-learn' program to recategorize the message
273 blacklist_from *@hsmridi2983csltsite.com 171 as spam. Neither MH-E, nor SpamAssassin, rebuilds the database after adding
274 172 words, so you will need to run `sa-learn --rebuild' periodically. This can be
275 The function `mh-spamassassin-identify-spammers' is provided that shows the 173 done by adding the following to your crontab:
276 frequency counts of the host and domain names in your blacklist_from 174
277 entries. This can be helpful when editing the blacklist_from entries. 175 0 * * * * sa-learn --rebuild > /dev/null 2>&1"
278
279 In versions of spamassassin (2.50 and on) that support a Bayesian classifier,
280 \\[mh-junk-blacklist] uses the sa-learn program to recategorize the message as
281 spam. Neither MH-E, nor spamassassin, rebuilds the database after adding
282 words, so you will need to run \"sa-learn --rebuild\" periodically. This can
283 be done by adding the following to your crontab:
284
285 0 * * * * sa-learn --rebuild > /dev/null 2>&1"
286 (unless mh-spamassassin-executable 176 (unless mh-spamassassin-executable
287 (error "Couldn't find the spamassassin executable")) 177 (error "Unable to find the spamassassin executable"))
288 (let ((current-folder mh-current-folder) 178 (let ((current-folder mh-current-folder)
289 (msg-file (mh-msg-filename msg mh-current-folder)) 179 (msg-file (mh-msg-filename msg mh-current-folder))
290 (sender)) 180 (sender))
291 (save-excursion 181 (save-excursion
292 (message "Giving this message the Razor...") 182 (message (format "Reporting message %d..." msg))
293 (mh-truncate-log-buffer) 183 (mh-truncate-log-buffer)
294 (call-process mh-spamassassin-executable msg-file mh-log-buffer nil 184 (call-process mh-spamassassin-executable msg-file mh-log-buffer nil
295 "--report" "--remove-from-whitelist") 185 ;;"--report" "--remove-from-whitelist"
186 "-r" "-R") ; spamassassin V2.20
296 (when mh-sa-learn-executable 187 (when mh-sa-learn-executable
297 (message "Recategorizing this message as spam...") 188 (message "Recategorizing this message as spam...")
298 (call-process mh-sa-learn-executable msg-file mh-log-buffer nil 189 (call-process mh-sa-learn-executable msg-file mh-log-buffer nil
299 "--single" "--spam" "--local" "--no-rebuild")) 190 "--single" "--spam" "--local" "--no-rebuild"))
300 (message "Blacklisting address...") 191 (message (format "Blacklisting message %d..." msg))
301 (set-buffer (get-buffer-create mh-temp-buffer)) 192 (set-buffer (get-buffer-create mh-temp-buffer))
302 (erase-buffer) 193 (erase-buffer)
303 (call-process (expand-file-name mh-scan-prog mh-progs) nil t nil 194 (call-process (expand-file-name mh-scan-prog mh-progs) mh-junk-background
195 t nil
304 (format "%s" msg) current-folder 196 (format "%s" msg) current-folder
305 "-format" "%<(mymbox{from})%|%(addr{from})%>") 197 "-format" "%<(mymbox{from})%|%(addr{from})%>")
306 (goto-char (point-min)) 198 (goto-char (point-min))
307 (if (search-forward-regexp "^\\(.+\\)$" nil t) 199 (if (search-forward-regexp "^\\(.+\\)$" nil t)
308 (progn 200 (progn
309 (setq sender (match-string 0)) 201 (setq sender (match-string 0))
310 (mh-spamassassin-add-rule "blacklist_from" sender) 202 (mh-spamassassin-add-rule "blacklist_from" sender)
311 (message "Blacklisting address...done")) 203 (message (format "Blacklisting message %d...done" msg)))
312 (message "Blacklisting address...not done (from my address)"))))) 204 (message (format "Blacklisting message %d...not done (from my address)" msg))))))
313 205
314 (defun mh-spamassassin-whitelist (msg) 206 (defun mh-spamassassin-whitelist (msg)
315 "Whitelist MSG. 207 "Whitelist MSG with SpamAssassin.
316 Add a whitelist_from rule to the ~/.spamassassin/user_prefs file. If sa-learn 208
317 is available, then the message is recategorized as ham." 209 The \\[mh-junk-whitelist] command adds a `whitelist_from' rule to the
210 `~/.spamassassin/user_prefs' file. If the `sa-learn' command is available, the
211 message is also recategorized as ham.
212
213 See `mh-spamassassin-blacklist' for more information."
318 (unless mh-spamassassin-executable 214 (unless mh-spamassassin-executable
319 (error "Couldn't find the spamassassin executable")) 215 (error "Unable to find the spamassassin executable"))
320 (let ((msg-file (mh-msg-filename msg mh-current-folder)) 216 (let ((msg-file (mh-msg-filename msg mh-current-folder))
321 (show-buffer (get-buffer mh-show-buffer)) 217 (show-buffer (get-buffer mh-show-buffer))
322 from) 218 from)
323 (save-excursion 219 (save-excursion
324 (set-buffer (get-buffer-create mh-temp-buffer)) 220 (set-buffer (get-buffer-create mh-temp-buffer))
325 (erase-buffer) 221 (erase-buffer)
326 (message "Removing spamassassin markup from message...") 222 (message "Removing spamassassin markup from message...")
327 (call-process mh-spamassassin-executable msg-file mh-temp-buffer nil 223 (call-process mh-spamassassin-executable msg-file mh-temp-buffer nil
328 "--remove-markup") 224 ;; "--remove-markup"
225 "-d") ; spamassassin V2.20
329 (if show-buffer 226 (if show-buffer
330 (kill-buffer show-buffer)) 227 (kill-buffer show-buffer))
331 (write-file msg-file) 228 (write-file msg-file)
332 (when mh-sa-learn-executable 229 (when mh-sa-learn-executable
333 (message "Recategorizing this message as ham...") 230 (message "Recategorizing this message as ham...")
334 (call-process mh-sa-learn-executable msg-file mh-temp-buffer nil 231 (call-process mh-sa-learn-executable msg-file mh-temp-buffer nil
335 "--single" "--ham" "--local --no-rebuild")) 232 "--single" "--ham" "--local --no-rebuild"))
336 (message "Whitelisting address...") 233 (message (format "Whitelisting message %d..." msg))
337 (setq from (car (ietf-drums-parse-address (mh-get-header-field "From:")))) 234 (setq from
235 (car (mh-funcall-if-exists
236 ietf-drums-parse-address (mh-get-header-field "From:"))))
338 (kill-buffer nil) 237 (kill-buffer nil)
339 (unless (equal from "") 238 (unless (or (null from) (equal from ""))
340 (mh-spamassassin-add-rule "whitelist_from" from)) 239 (mh-spamassassin-add-rule "whitelist_from" from))
341 (message "Whitelisting address...done")))) 240 (message (format "Whitelisting message %d...done" msg)))))
342 241
343 (defun mh-spamassassin-add-rule (rule body) 242 (defun mh-spamassassin-add-rule (rule body)
344 "Add a new rule to ~/.spamassassin/user_prefs. 243 "Add a new rule to `~/.spamassassin/user_prefs'.
345 The name of the rule is RULE and its body is BODY." 244 The name of the rule is RULE and its body is BODY."
346 (save-window-excursion 245 (save-window-excursion
347 (let* ((line (format "%s\t%s\n" rule body)) 246 (let* ((line (format "%s\t%s\n" rule body))
348 (case-fold-search t) 247 (case-fold-search t)
349 (file (expand-file-name "~/.spamassassin/user_prefs")) 248 (file (expand-file-name "~/.spamassassin/user_prefs"))
356 (save-buffer))) 255 (save-buffer)))
357 (if (not buffer-exists) 256 (if (not buffer-exists)
358 (kill-buffer nil))))) 257 (kill-buffer nil)))))
359 258
360 (defun mh-spamassassin-identify-spammers () 259 (defun mh-spamassassin-identify-spammers ()
361 "Identifies spammers who are repeat offenders. 260 "Identify spammers who are repeat offenders.
362 261
363 For each blacklist_from entry from the last blank line of 262 This function displays a frequency count of the hosts and domains in the
364 ~/.spamassassin/user_prefs to the end of the file, a list of host and domain 263 `blacklist_from' entries from the last blank line in
365 names along with their frequency counts is displayed. This information can be 264 `~/.spamassassin/user_prefs' to the end of the file. This information can be
366 used to replace multiple blacklist_from entries with a single wildcard entry 265 used so that you can replace multiple `blacklist_from' entries with a single
367 such as: 266 wildcard entry such as:
368 267
369 blacklist_from *@*amazingoffersdirect2u.com" 268 blacklist_from *@*amazingoffersdirect2u.com"
370 (interactive) 269 (interactive)
371 (let* ((file (expand-file-name "~/.spamassassin/user_prefs")) 270 (let* ((file (expand-file-name "~/.spamassassin/user_prefs"))
372 (domains (make-hash-table :test 'equal))) 271 (domains (make-hash-table :test 'equal)))
373 (find-file file) 272 (find-file file)
374 ;; Only consider entries between last blank line and end of file. 273 ;; Only consider entries between last blank line and end of file.
383 ;; Remove top-level-domain from hostname. 282 ;; Remove top-level-domain from hostname.
384 (setq host (cdr (reverse (split-string host "\\.")))) 283 (setq host (cdr (reverse (split-string host "\\."))))
385 ;; Add counts for each host and domain part. 284 ;; Add counts for each host and domain part.
386 (while host 285 (while host
387 (setq value (gethash (car host) domains)) 286 (setq value (gethash (car host) domains))
388 (puthash (car host) (1+ (if (not value) 0 value)) domains) 287 (setf (gethash (car host) domains) (1+ (if (not value) 0 value)))
389 (setq host (cdr host)))))) 288 (setq host (cdr host))))))
390 289
391 ;; Output 290 ;; Output
392 (delete-other-windows) 291 (delete-other-windows)
393 (pop-to-buffer (get-buffer-create "*MH-E Spammer Frequencies*")) 292 (pop-to-buffer (get-buffer-create "*MH-E Spammer Frequencies*"))
398 domains) 297 domains)
399 (sort-numeric-fields 2 (point-min) (point-max)) 298 (sort-numeric-fields 2 (point-min) (point-max))
400 (reverse-region (point-min) (point-max)) 299 (reverse-region (point-min) (point-max))
401 (goto-char (point-min)))) 300 (goto-char (point-min))))
402 301
302
303
304 ;; Bogofilter Interface
305
306 (defvar mh-bogofilter-executable (executable-find "bogofilter"))
307
308 (defun mh-bogofilter-blacklist (msg)
309 "Blacklist MSG with Bogofilter.
310
311 Bogofilter is a Bayesian spam filtering program. Get it from your local
312 distribution or from http://bogofilter.sourceforge.net/.
313
314 Bogofilter is taught by running:
315
316 bogofilter -n < good-message
317
318 on every good message, and
319
320 bogofilter -s < spam-message
321
322 on every spam message. This is called a full training; three other
323 training methods are described in the FAQ that is distributed with bogofilter.
324 Note that most Bayesian filters need 1000 to 5000 of each type of message to
325 start doing a good job.
326
327 To use Bogofilter, add the following recipes to `.procmailrc':
328
329 MAILDIR=$HOME/`mhparam Path`
330
331 # Fight spam with Bogofilter.
332 :0fw
333 | bogofilter -3 -e -p
334
335 :0:
336 * ^X-Bogosity: Yes, tests=bogofilter
337 spam/.
338
339 :0:
340 * ^X-Bogosity: Unsure, tests=bogofilter
341 spam/unsure/.
342
343 If Bogofilter classifies a message incorrectly, or is unsure, you can use the
344 MH-E commands \\[mh-junk-blacklist] and \\[mh-junk-whitelist] to update
345 Bogofilter's training.
346
347 The \"Bogofilter FAQ\" suggests that you run the following
348 occasionally to shrink the database:
349
350 bogoutil -d wordlist.db | bogoutil -l wordlist.db.new
351 mv wordlist.db wordlist.db.prv
352 mv wordlist.db.new wordlist.db
353
354 The \"Bogofilter tuning HOWTO\" describes how you can fine-tune Bogofilter."
355 (unless mh-bogofilter-executable
356 (error "Unable to find the bogofilter executable"))
357 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
358 (call-process mh-bogofilter-executable msg-file mh-junk-background
359 nil "-s")))
360
361 (defun mh-bogofilter-whitelist (msg)
362 "Whitelist MSG with Bogofilter.
363
364 See `mh-bogofilter-blacklist' for more information."
365 (unless mh-bogofilter-executable
366 (error "Unable to find the bogofilter executable"))
367 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
368 (call-process mh-bogofilter-executable msg-file mh-junk-background
369 nil "-n")))
370
371
372
373 ;; Spamprobe Interface
374
375 (defvar mh-spamprobe-executable (executable-find "spamprobe"))
376
377 (defun mh-spamprobe-blacklist (msg)
378 "Blacklist MSG with SpamProbe.
379
380 SpamProbe is a Bayesian spam filtering program. Get it from your local
381 distribution or from http://spamprobe.sourceforge.net.
382
383 To use SpamProbe, add the following recipes to `.procmailrc':
384
385 MAILDIR=$HOME/`mhparam Path`
386
387 # Fight spam with SpamProbe.
388 :0
389 SCORE=| spamprobe receive
390
391 :0 wf
392 | formail -I \"X-SpamProbe: $SCORE\"
393
394 :0:
395 *^X-SpamProbe: SPAM
396 spam/.
397
398 If SpamProbe classifies a message incorrectly, you can use the MH-E commands
399 \\[mh-junk-blacklist] and \\[mh-junk-whitelist] to update SpamProbe's
400 training."
401 (unless mh-spamprobe-executable
402 (error "Unable to find the spamprobe executable"))
403 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
404 (call-process mh-spamprobe-executable msg-file mh-junk-background
405 nil "spam")))
406
407 (defun mh-spamprobe-whitelist (msg)
408 "Whitelist MSG with SpamProbe.
409
410 See `mh-spamprobe-blacklist' for more information."
411 (unless mh-spamprobe-executable
412 (error "Unable to find the spamprobe executable"))
413 (let ((msg-file (mh-msg-filename msg mh-current-folder)))
414 (call-process mh-spamprobe-executable msg-file mh-junk-background
415 nil "good")))
416
403 (provide 'mh-junk) 417 (provide 'mh-junk)
404 418
405 ;;; Local Variables: 419 ;;; Local Variables:
406 ;;; indent-tabs-mode: nil 420 ;;; indent-tabs-mode: nil
407 ;;; sentence-end-double-space: nil 421 ;;; sentence-end-double-space: nil