Mercurial > emacs
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 |