comparison lisp/mail/uce.el @ 101694:977623d6c580

Tidy up commentary. (rmail-current-message): Remove unneeded declaration. (uce-message-text, uce-default-headers): Fix custom type. (rmail-buffer, rmail-msg-is-pruned): Declare. (uce-reply-to-uce): Add autoload cookie. Doc fix. Update for mbox Rmail.
author Glenn Morris <rgm@gnu.org>
date Sat, 31 Jan 2009 02:50:28 +0000
parents a51647f648b0
children 4c610ec5ed40
comparison
equal deleted inserted replaced
101693:d8e498f22523 101694:977623d6c580
1 ;;; uce.el --- facilitate reply to unsolicited commercial email 1 ;;; uce.el --- facilitate reply to unsolicited commercial email
2 2
3 ;; Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 3 ;; Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 ;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 4 ;; 2007, 2008, 2009 Free Software Foundation, Inc.
5 5
6 ;; Author: stanislav shalunov <shalunov@mccme.ru> 6 ;; Author: stanislav shalunov <shalunov@mccme.ru>
7 ;; Created: 10 Dec 1996 7 ;; Created: 10 Dec 1996
8 ;; Keywords: uce, unsolicited commercial email 8 ;; Keywords: mail, uce, unsolicited commercial email
9 9
10 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
11 11
12 ;; GNU Emacs is free software: you can redistribute it and/or modify 12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by 13 ;; it under the terms of the GNU General Public License as published by
22 ;; You should have received a copy of the GNU General Public License 22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. 23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 24
25 ;;; Commentary: 25 ;;; Commentary:
26 26
27 ;; Code in this file provides semi-automatic means of replying to 27 ;; The code in this file provides a semi-automatic means of replying
28 ;; UCE's you might get. It works currently only with Rmail and Gnus. 28 ;; to unsolicited commercial email (UCE) you might get. Currently, it
29 ;; If you would like to make it work with other mail readers, 29 ;; only works with Rmail and Gnus. If you would like to make it work
30 ;; Rmail-specific section is marked below. If you want to play with 30 ;; with other mail readers, see the mail-client dependent section of
31 ;; code, please let me know about your changes so I can incorporate 31 ;; uce-reply-to-uce. Please let me know about your changes so I can
32 ;; them. I'd appreciate it. 32 ;; incorporate them. I'd appreciate it.
33 33
34 ;; Function uce-reply-to-uce, if called when current message in RMAIL 34 ;; The command uce-reply-to-uce, if called when the current message
35 ;; buffer is a UCE, will setup *mail* buffer in the following way: it 35 ;; buffer is a UCE, will setup a reply *mail* buffer as follows. It
36 ;; scans full headers of message for 1) normal return address of 36 ;; scans the full headers of the message for: 1) the normal return
37 ;; sender (From, Reply-To lines); and puts these addresses into To: 37 ;; address of the sender (From, Reply-To lines), and puts these
38 ;; header, it also puts abuse@offenders.host address there 2) mailhub 38 ;; addresses into the To: header, along with abuse@offenders.host; 2)
39 ;; that first saw this message; and puts address of its postmaster 39 ;; the mailhub that first saw this message, and adds the address of
40 ;; into To: header 3) finally, it looks at Message-Id and adds 40 ;; its postmaster into the To: header; and 3), finally, it looks at
41 ;; posmaster of that host to the list of addresses. 41 ;; the Message-Id and adds the postmaster of that host to the list of
42 42 ;; addresses.
43 ;; Then, we add "Errors-To: nobody@localhost" header, so that if some 43
44 ;; of these addresses are not actually correct, we will never see 44 ;; Then, we add an "Errors-To: nobody@localhost" header, so that if
45 ;; some of these addresses are not actually correct, we will never see
45 ;; bounced mail. Also, mail-self-blind and mail-archive-file-name 46 ;; bounced mail. Also, mail-self-blind and mail-archive-file-name
46 ;; take no effect: the ideology is that we don't want to save junk or 47 ;; take no effect: the ideology is that we don't want to save junk or
47 ;; replies to junk. 48 ;; replies to junk.
48 49
49 ;; Then we put template into buffer (customizable message that 50 ;; Then we insert a template into the buffer (a customizable message
50 ;; explains what has happened), customizable signature, and the 51 ;; that explains what has happened), customizable signature, and the
51 ;; original message with full headers and envelope for postmasters. 52 ;; original message with full headers and envelope for postmasters.
52 ;; Then buffer is left for editing. 53 ;; Then the buffer is left for editing.
53 54
54 ;; The reason that function uce-reply-to-uce is Rmail dependant is 55 ;; The reason that the function uce-reply-to-uce is mail-client
55 ;; that we want full headers of the original message, nothing 56 ;; dependent is that we want the full headers of the original message,
56 ;; stripped. If we use normal means of inserting of the original 57 ;; nothing stripped. If we use the normal means of inserting the
57 ;; message into *mail* buffer headers like Received: (not really 58 ;; original message into the *mail* buffer, headers like Received:
58 ;; headers, but envelope lines) will be stripped while they bear 59 ;; (not really headers, but envelope lines) will be stripped, while
59 ;; valuable for us and postmasters information. I do wish that there 60 ;; they bear valuable information for us and postmasters. I do wish
60 ;; would be some way to write this function in some portable way, but 61 ;; that there would be some portable way to write this function, but I
61 ;; I am not aware of any. 62 ;; am not aware of any.
62 63
63 ;;; Change log: 64 ;; Usage:
65
66 ;; Place uce.el in your load-path (and optionally byte-compile it).
67 ;; Add the following line to your ~/.emacs:
68 ;; (autoload 'uce-reply-to-uce "uce" "Reply to UCEs" t nil)
69 ;; If you want to use it with Gnus rather than Rmail:
70 ;; (setq uce-mail-reader 'gnus)
71
72 ;; Options:
73
74 ;; uce-message-text is a template that will be inserted into buffer.
75 ;; It has a reasonable default. If you want to write some scarier
76 ;; one, please do so and send it to me. Please keep it polite.
77
78 ;; uce-signature behaves just like mail-signature. If nil, nothing is
79 ;; inserted, if t, file ~/.signature is used, if a string, its
80 ;; contents are inserted into buffer.
81
82 ;; uce-uce-separator is a line that separates your message from the
83 ;; UCE that you enclose.
84
85 ;; uce-subject-line will be used as the subject of the outgoing message.
86
87
88 ;;; Change Log:
64 89
65 ;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs 90 ;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs
66 91
67 ;; Dec 11, 1996 -- fixed some typos, and Francesco Potorti` 92 ;; Dec 11, 1996 -- fixed some typos, and Francesco Potorti`
68 ;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was 93 ;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was
81 ;; Aug 16, 2000 -- changes from Detlev Zundel 106 ;; Aug 16, 2000 -- changes from Detlev Zundel
82 ;; <detlev.zundel@stud.uni-karlsruhe.de> to make uce.el work with the 107 ;; <detlev.zundel@stud.uni-karlsruhe.de> to make uce.el work with the
83 ;; latest Gnus. Lars told him it should work for all versions of Gnus 108 ;; latest Gnus. Lars told him it should work for all versions of Gnus
84 ;; younger than three years. 109 ;; younger than three years.
85 110
86 ;; Setup:
87
88 ;; Add the following line to your ~/.emacs:
89
90 ;; (autoload 'uce-reply-to-uce "uce" "Reply to UCEs" t nil)
91
92 ;; If you want to use it with Gnus also use
93
94 ;; (setq uce-mail-reader 'gnus)
95
96 ;; store this file (uce.el) somewhere in load-path and byte-compile it.
97
98 ;;; Variables:
99
100 ;; uce-message-text is template that will be inserted into buffer. It
101 ;; has reasonable default. If you want to write some scarier one,
102 ;; please do so and send it to me. Please keep it polite.
103
104 ;; uce-signature behaves just like mail-signature. If nil, nothing is
105 ;; inserted, if t, file ~/.signature is used, if a string, its
106 ;; contents are inserted into buffer.
107
108 ;; uce-uce-separator is line that separates your message from the UCE
109 ;; that you enclose.
110
111 ;; uce-subject-line will be used as subject of outgoing message. If
112 ;; nil, left blank.
113 111
114 ;;; Code: 112 ;;; Code:
115 113
116 (defvar gnus-original-article-buffer) 114 (defvar gnus-original-article-buffer)
117 (defvar mail-reply-buffer) 115 (defvar mail-reply-buffer)
118 (defvar rmail-current-message)
119 116
120 (require 'sendmail) 117 (require 'sendmail)
121 ;; Those sections of code which are dependent upon 118 ;; Those sections of code which are dependent upon
122 ;; RMAIL are only evaluated if we have received a message with RMAIL... 119 ;; RMAIL are only evaluated if we have received a message with RMAIL...
123 ;;(require 'rmail) 120 ;;(require 'rmail)
182 to spam address email, and will remove people who put the word `remove' 179 to spam address email, and will remove people who put the word `remove'
183 on beginning of some line from the spamming list. So, when you set it 180 on beginning of some line from the spamming list. So, when you set it
184 up, it might be a good idea to actually use this feature. 181 up, it might be a good idea to actually use this feature.
185 182
186 Value nil means insert no text by default, lets you type it in." 183 Value nil means insert no text by default, lets you type it in."
187 :type 'string 184 :type '(choice (const nil) string)
188 :group 'uce) 185 :group 'uce)
189 186
190 (defcustom uce-uce-separator 187 (defcustom uce-uce-separator
191 "----- original unsolicited commercial email follows -----" 188 "----- original unsolicited commercial email follows -----"
192 "Line that will begin quoting of the UCE. 189 "Line that will begin quoting of the UCE.
204 201
205 (defcustom uce-default-headers 202 (defcustom uce-default-headers
206 "Errors-To: nobody@localhost\nPrecedence: bulk\n" 203 "Errors-To: nobody@localhost\nPrecedence: bulk\n"
207 "Additional headers to use when responding to a UCE with \\[uce-reply-to-uce]. 204 "Additional headers to use when responding to a UCE with \\[uce-reply-to-uce].
208 These are mostly meant for headers that prevent delivery errors reporting." 205 These are mostly meant for headers that prevent delivery errors reporting."
209 :type 'string 206 :type '(choice (const nil) string)
210 :group 'uce) 207 :group 'uce)
211 208
212 (defcustom uce-subject-line 209 (defcustom uce-subject-line
213 "Spam alert: unsolicited commercial e-mail" 210 "Spam alert: unsolicited commercial e-mail"
214 "Subject of the message that will be sent in response to a UCE." 211 "Subject of the message that will be sent in response to a UCE."
215 :type 'string 212 :type 'string
216 :group 'uce) 213 :group 'uce)
217 214
215 ;; End of user options.
216
217
218 (defvar rmail-buffer)
219 (declare-function rmail-msg-is-pruned "rmail" ())
218 (declare-function mail-strip-quoted-names "mail-utils" (address)) 220 (declare-function mail-strip-quoted-names "mail-utils" (address))
219 (declare-function rmail-maybe-set-message-counters "rmail" ()) 221 (declare-function rmail-maybe-set-message-counters "rmail" ())
220 (declare-function rmail-msgbeg "rmail" (n)) 222 (declare-function rmail-msgbeg "rmail" (n))
221 (declare-function rmail-msgend "rmail" (n)) 223 (declare-function rmail-msgend "rmail" (n))
222 (declare-function rmail-toggle-header "rmail" (&optional arg)) 224 (declare-function rmail-toggle-header "rmail" (&optional arg))
223 225
224 226 ;;;###autoload
225 (defun uce-reply-to-uce (&optional ignored) 227 (defun uce-reply-to-uce (&optional ignored)
226 "Send reply to UCE in Rmail. 228 "Compose a reply to unsolicited commercial email (UCE).
227 UCE stands for unsolicited commercial email. Function will set up reply 229 Sets up a reply buffer addressed to: the sender, his postmaster,
228 buffer with default To: to the sender, his postmaster, his abuse@ 230 his abuse@ address, and the postmaster of the mail relay used.
229 address, and postmaster of the mail relay used." 231 You might need to set `uce-mail-reader' before using this."
230 (interactive) 232 (interactive)
233 ;; Start of mail-client dependent section.
231 (let ((message-buffer 234 (let ((message-buffer
232 (cond ((eq uce-mail-reader 'gnus) gnus-original-article-buffer) 235 (cond ((eq uce-mail-reader 'gnus) gnus-original-article-buffer)
233 ((eq uce-mail-reader 'rmail) "RMAIL") 236 ((eq uce-mail-reader 'rmail) (bound-and-true-p rmail-buffer))
234 (t (error 237 (t (error
235 "Variable uce-mail-reader set to unrecognized value")))) 238 "Variable uce-mail-reader set to unrecognized value"))))
236 (full-header-p (and (eq uce-mail-reader 'rmail) 239 pruned)
237 (not (rmail-msg-is-pruned))))) 240 (or (and message-buffer (get-buffer message-buffer))
238 (or (get-buffer message-buffer) 241 (error "No mail buffer, cannot find UCE"))
239 (error "No buffer %s, cannot find UCE" message-buffer))
240 (switch-to-buffer message-buffer) 242 (switch-to-buffer message-buffer)
241 ;; We need the message with headers pruned. 243 ;; We need the message with headers pruned.
242 (if full-header-p 244 ;; Why? All we do is get the from and reply-to headers. ?
243 (rmail-toggle-header 1)) 245 (and (eq uce-mail-reader 'rmail)
246 (not (setq pruned (rmail-msg-is-pruned)))
247 (rmail-toggle-header 1))
244 (let ((to (mail-strip-quoted-names (mail-fetch-field "from" t))) 248 (let ((to (mail-strip-quoted-names (mail-fetch-field "from" t)))
245 (reply-to (mail-fetch-field "reply-to")) 249 (reply-to (mail-fetch-field "reply-to"))
246 temp) 250 temp)
247 ;; Initial setting of the list of recipients of our message; that's 251 ;; Initial setting of the list of recipients of our message; that's
248 ;; what they are pretending to be. 252 ;; what they are pretending to be.
249 (if to 253 (setq to (if to
250 (setq to (format "%s" (mail-strip-quoted-names to))) 254 (format "%s" (mail-strip-quoted-names to))
251 (setq to "")) 255 ""))
252 (if reply-to 256 (if reply-to
253 (setq to (format "%s, %s" to (mail-strip-quoted-names reply-to)))) 257 (setq to (format "%s, %s" to (mail-strip-quoted-names reply-to))))
254 (let (first-at-sign end-of-hostname sender-host) 258 (let (first-at-sign end-of-hostname sender-host)
255 (setq first-at-sign (string-match "@" to) 259 (setq first-at-sign (string-match "@" to)
256 end-of-hostname (string-match "[ ,>]" to first-at-sign) 260 end-of-hostname (string-match "[ ,>]" to first-at-sign)
258 (if (string-match "\\." sender-host) 262 (if (string-match "\\." sender-host)
259 (setq to (format "%s, postmaster%s, abuse%s" 263 (setq to (format "%s, postmaster%s, abuse%s"
260 to sender-host sender-host)))) 264 to sender-host sender-host))))
261 (setq mail-send-actions nil) 265 (setq mail-send-actions nil)
262 (setq mail-reply-buffer nil) 266 (setq mail-reply-buffer nil)
263 (cond ((eq uce-mail-reader 'gnus) 267 (when (eq uce-mail-reader 'rmail)
264 (copy-region-as-kill (point-min) (point-max))) 268 (rmail-toggle-header 0)
265 ((eq uce-mail-reader 'rmail) 269 (rmail-maybe-set-message-counters)) ; why?
266 (save-excursion 270 (copy-region-as-kill (point-min) (point-max))
267 (save-restriction 271 ;; Restore the initial header state we found.
268 (rmail-toggle-header 1) 272 (and pruned (rmail-toggle-header 1))
269 (widen)
270 (rmail-maybe-set-message-counters)
271 (copy-region-as-kill (rmail-msgbeg rmail-current-message)
272 (rmail-msgend rmail-current-message))))))
273 ;; Restore the pruned header state we found.
274 (if full-header-p
275 (rmail-toggle-header 0))
276 (switch-to-buffer "*mail*") 273 (switch-to-buffer "*mail*")
277 (erase-buffer) 274 (erase-buffer)
278 (setq temp (point))
279 (yank) 275 (yank)
280 (goto-char temp) 276 (goto-char (point-min))
281 (if (eq uce-mail-reader 'rmail) 277 ;; Delete any internal Rmail headers.
282 (progn 278 (when (eq uce-mail-reader 'rmail)
283 (forward-line 2) 279 (search-forward "\n\n")
284 (let ((case-fold-search t)) 280 (while (re-search-backward "^X-RMAIL" nil t)
285 (while (looking-at "Summary-Line:\\|Mail-From:") 281 (delete-region (point) (line-beginning-position 2)))
286 (forward-line 1))) 282 (goto-char (point-min)))
287 (delete-region temp (point))))
288 ;; Now find the mail hub that first accepted this message. 283 ;; Now find the mail hub that first accepted this message.
289 ;; This should try to find the last Received: header. 284 ;; This should try to find the last Received: header.
290 ;; Sometimes there may be other headers inbetween Received: headers. 285 ;; Sometimes there may be other headers inbetween Received: headers.
291 (cond ((eq uce-mail-reader 'gnus) 286 (cond ((eq uce-mail-reader 'gnus)
292 ;; Does Gnus always have Lines: in the end? 287 ;; Does Gnus always have Lines: in the end?
293 (re-search-forward "^Lines:") 288 (re-search-forward "^Lines:")
294 (beginning-of-line)) 289 (beginning-of-line))
295 ((eq uce-mail-reader 'rmail) 290 ((eq uce-mail-reader 'rmail)
296 (goto-char (point-min)) 291 (search-forward "\n\n")))
297 (search-forward "*** EOOH ***\n")
298 (beginning-of-line)
299 (forward-line -1)))
300 (re-search-backward "^Received:") 292 (re-search-backward "^Received:")
301 (beginning-of-line)
302 ;; Is this always good? It's the only thing I saw when I checked 293 ;; Is this always good? It's the only thing I saw when I checked
303 ;; a few messages. 294 ;; a few messages.
304 (let ((eol (save-excursion (end-of-line) (point)))) 295 ;;(if (not (re-search-forward ": \\(from\\|by\\) " eol t))
305 ;;(if (not (re-search-forward ": \\(from\\|by\\) " eol t)) 296 (unless (re-search-forward "\\(from\\|by\\) " (line-end-position) 'move)
306 (if (not (re-search-forward "\\(from\\|by\\) " eol t)) 297 (if (looking-at "[ \t\n]+\\(from\\|by\\) ")
307 (progn 298 (goto-char (match-end 0))
308 (goto-char eol) 299 (error "Failed to extract hub address")))
309 (if (looking-at "[ \t\n]+\\(from\\|by\\) ")
310 (goto-char (match-end 0))
311 (error "Failed to extract hub address")))))
312 (setq temp (point)) 300 (setq temp (point))
313 (search-forward " ") 301 (search-forward " ")
314 (forward-char -1) 302 (forward-char -1)
315 ;; And add its postmaster to the list of addresses. 303 ;; And add its postmaster to the list of addresses.
316 (if (string-match "\\." (buffer-substring temp (point))) 304 (if (string-match "\\." (buffer-substring temp (point)))
317 (setq to (format "%s, postmaster@%s" 305 (setq to (format "%s, postmaster@%s"
318 to (buffer-substring temp (point))))) 306 to (buffer-substring temp (point)))))
319 ;; Also look at the message-id, it helps *very* often. 307 ;; Also look at the message-id, it helps *very* often.
320 (if (and (search-forward "\nMessage-Id: " nil t) 308 (and (search-forward "\nMessage-Id: " nil t)
321 ;; Not all Message-Id:'s have an `@' sign. 309 ;; Not all Message-Id:'s have an `@' sign.
322 (let ((bol (point)) 310 (search-forward "@" (line-end-position) t)
323 eol) 311 (progn
324 (end-of-line) 312 (setq temp (point))
325 (setq eol (point)) 313 (search-forward ">")
326 (goto-char bol) 314 (forward-char -1)
327 (search-forward "@" eol t))) 315 (if (string-match "\\." (buffer-substring temp (point)))
328 (progn 316 (setq to (format "%s, postmaster@%s"
329 (setq temp (point)) 317 to (buffer-substring temp (point)))))))
330 (search-forward ">") 318 (when (eq uce-mail-reader 'gnus)
331 (forward-char -1) 319 ;; Does Gnus always have Lines: in the end?
332 (if (string-match "\\." (buffer-substring temp (point))) 320 (re-search-forward "^Lines:")
333 (setq to (format "%s, postmaster@%s" 321 (beginning-of-line)
334 to (buffer-substring temp (point))))))) 322 (setq temp (point))
335 (cond ((eq uce-mail-reader 'gnus) 323 (search-forward "\n\n" nil t)
336 ;; Does Gnus always have Lines: in the end? 324 (forward-line -1)
337 (re-search-forward "^Lines:") 325 (delete-region temp (point)))
338 (beginning-of-line)) 326 ;; End of mail-client dependent section.
339 ((eq uce-mail-reader 'rmail)
340 (search-forward "\n*** EOOH ***\n")
341 (forward-line -1)))
342 (setq temp (point))
343 (search-forward "\n\n" nil t)
344 (if (eq uce-mail-reader 'gnus)
345 (forward-line -1))
346 (delete-region temp (point))
347 ;; End of Rmail dependent section.
348 (auto-save-mode auto-save-default) 327 (auto-save-mode auto-save-default)
349 (mail-mode) 328 (mail-mode)
350 (goto-char (point-min)) 329 (goto-char (point-min))
351 (insert "To: ") 330 (insert "To: ")
352 (save-excursion 331 (save-excursion
385 (or (bolp) (newline))) 364 (or (bolp) (newline)))
386 ;; And go back to the beginning of text. 365 ;; And go back to the beginning of text.
387 (if to (goto-char to)) 366 (if to (goto-char to))
388 (or to (set-buffer-modified-p nil)) 367 (or to (set-buffer-modified-p nil))
389 ;; Run hooks before we leave buffer for editing. Reasonable usage 368 ;; Run hooks before we leave buffer for editing. Reasonable usage
390 ;; might be to set up special key bindings, replace standart 369 ;; might be to set up special key bindings, replace standard
391 ;; functions in mail-mode, etc. 370 ;; functions in mail-mode, etc.
392 (run-hooks 'mail-setup-hook 'uce-setup-hook)))) 371 (run-hooks 'mail-setup-hook 'uce-setup-hook))))
393 372
394 (defun uce-insert-ranting (&optional ignored) 373 (defun uce-insert-ranting (&optional ignored)
395 "Insert text of the usual reply to UCE into current buffer." 374 "Insert text of the usual reply to UCE into current buffer."