Commit | Line | Data |
---|---|---|
bf078b46 RS |
1 | ;;; uce.el --- facilitate reply to unsolicited commercial email |
2 | ||
9f08b141 | 3 | ;; Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
114f9c96 | 4 | ;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc. |
bf078b46 | 5 | |
dc99d85e | 6 | ;; Author: stanislav shalunov <shalunov@mccme.ru> |
bf078b46 | 7 | ;; Created: 10 Dec 1996 |
9f08b141 | 8 | ;; Keywords: mail, uce, unsolicited commercial email |
bf078b46 RS |
9 | |
10 | ;; This file is part of GNU Emacs. | |
11 | ||
b1fc2b50 | 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
2be7dabc | 13 | ;; it under the terms of the GNU General Public License as published by |
b1fc2b50 GM |
14 | ;; the Free Software Foundation, either version 3 of the License, or |
15 | ;; (at your option) any later version. | |
2be7dabc GM |
16 | |
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
bf078b46 RS |
21 | |
22 | ;; You should have received a copy of the GNU General Public License | |
b1fc2b50 | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
bf078b46 RS |
24 | |
25 | ;;; Commentary: | |
26 | ||
9f08b141 GM |
27 | ;; The code in this file provides a semi-automatic means of replying |
28 | ;; to unsolicited commercial email (UCE) you might get. Currently, it | |
29 | ;; only works with Rmail and Gnus. If you would like to make it work | |
30 | ;; with other mail readers, see the mail-client dependent section of | |
31 | ;; uce-reply-to-uce. Please let me know about your changes so I can | |
32 | ;; incorporate them. I'd appreciate it. | |
33 | ||
34 | ;; The command uce-reply-to-uce, if called when the current message | |
35 | ;; buffer is a UCE, will setup a reply *mail* buffer as follows. It | |
36 | ;; scans the full headers of the message for: 1) the normal return | |
37 | ;; address of the sender (From, Reply-To lines), and puts these | |
38 | ;; addresses into the To: header, along with abuse@offenders.host; 2) | |
39 | ;; the mailhub that first saw this message, and adds the address of | |
40 | ;; its postmaster into the To: header; and 3), finally, it looks at | |
41 | ;; the Message-Id and adds the postmaster of that host to the list of | |
42 | ;; addresses. | |
43 | ||
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 | |
bf078b46 RS |
46 | ;; bounced mail. Also, mail-self-blind and mail-archive-file-name |
47 | ;; take no effect: the ideology is that we don't want to save junk or | |
48 | ;; replies to junk. | |
49 | ||
9f08b141 GM |
50 | ;; Then we insert a template into the buffer (a customizable message |
51 | ;; that explains what has happened), customizable signature, and the | |
bf078b46 | 52 | ;; original message with full headers and envelope for postmasters. |
9f08b141 | 53 | ;; Then the buffer is left for editing. |
bf078b46 | 54 | |
9f08b141 GM |
55 | ;; The reason that the function uce-reply-to-uce is mail-client |
56 | ;; dependent is that we want the full headers of the original message, | |
57 | ;; nothing stripped. If we use the normal means of inserting the | |
58 | ;; original message into the *mail* buffer, headers like Received: | |
59 | ;; (not really headers, but envelope lines) will be stripped, while | |
60 | ;; they bear valuable information for us and postmasters. I do wish | |
61 | ;; that there would be some portable way to write this function, but I | |
62 | ;; am not aware of any. | |
bf078b46 | 63 | |
9f08b141 GM |
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: | |
bf078b46 RS |
89 | |
90 | ;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs | |
91 | ||
92 | ;; Dec 11, 1996 -- fixed some typos, and Francesco Potorti` | |
93 | ;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was | |
94 | ;; weird, suggested fix, and added let form. | |
95 | ||
96 | ;; Dec 17, 1996 -- made scanning for host names little bit more clever | |
97 | ;; (obviously bogus stuff like localhost is now ignored). | |
98 | ||
dc99d85e RS |
99 | ;; Nov 11, 1997 -- incorporated changes from Mikael Djurfeldt |
100 | ;; <mdj@nada.kth.se> to make uce.el work with Gnus. Changed the text | |
101 | ;; of message that is sent. | |
102 | ||
103 | ;; Dec 3, 1997 -- changes from Gareth Jones <gdj1@gdjones.demon.co.uk> | |
104 | ;; handling Received headers following some line like `From:'. | |
105 | ||
db214408 GM |
106 | ;; Aug 16, 2000 -- changes from Detlev Zundel |
107 | ;; <detlev.zundel@stud.uni-karlsruhe.de> to make uce.el work with the | |
108 | ;; latest Gnus. Lars told him it should work for all versions of Gnus | |
109 | ;; younger than three years. | |
bf078b46 | 110 | |
bf078b46 RS |
111 | |
112 | ;;; Code: | |
113 | ||
ea9a034c JB |
114 | (defvar gnus-original-article-buffer) |
115 | (defvar mail-reply-buffer) | |
ea9a034c | 116 | |
bf078b46 | 117 | (require 'sendmail) |
dc99d85e RS |
118 | ;; Those sections of code which are dependent upon |
119 | ;; RMAIL are only evaluated if we have received a message with RMAIL... | |
a1506d29 | 120 | ;;(require 'rmail) |
dc99d85e | 121 | |
0b5bb3ec SE |
122 | (defgroup uce nil |
123 | "Facilitate reply to unsolicited commercial email." | |
124 | :prefix "uce-" | |
125 | :group 'mail) | |
126 | ||
e13d531d RS |
127 | (defcustom uce-mail-reader 'rmail |
128 | "A symbol indicating which mail reader you are using. | |
129 | Choose from: `gnus', `rmail'." | |
130 | :type '(choice (const gnus) (const rmail)) | |
131 | :version "20.3" | |
132 | :group 'uce) | |
133 | ||
0b5bb3ec | 134 | (defcustom uce-setup-hook nil |
bf078b46 | 135 | "Hook to run after UCE rant message is composed. |
e13d531d | 136 | This hook is run after `mail-setup-hook', which is run as well." |
0b5bb3ec SE |
137 | :type 'hook |
138 | :group 'uce) | |
bf078b46 | 139 | |
a1506d29 | 140 | (defcustom uce-message-text |
bf078b46 RS |
141 | "Recently, I have received an Unsolicited Commercial E-mail from you. |
142 | I do not like UCE's and I would like to inform you that sending | |
143 | unsolicited messages to someone while he or she may have to pay for | |
144 | reading your message may be illegal. Anyway, it is highly annoying | |
145 | and not welcome by anyone. It is rude, after all. | |
146 | ||
147 | If you think that this is a good way to advertise your products or | |
148 | services you are mistaken. Spamming will only make people hate you, not | |
149 | buy from you. | |
150 | ||
a1506d29 JB |
151 | If you have any list of people you send unsolicited commercial emails to, |
152 | REMOVE me from such list immediately. I suggest that you make this list | |
bf078b46 RS |
153 | just empty. |
154 | ||
dc99d85e RS |
155 | ---------------------------------------------------- |
156 | ||
157 | If you are not an administrator of any site and still have received | |
158 | this message then your email address is being abused by some spammer. | |
159 | They fake your address in From: or Reply-To: header. In this case, | |
160 | you might want to show this message to your system administrator, and | |
161 | ask him/her to investigate this matter. | |
162 | ||
bf078b46 | 163 | Note to the postmaster(s): I append the text of UCE in question to |
dc99d85e | 164 | this message; I would like to hear from you about action(s) taken. |
bf078b46 | 165 | This message has been sent to postmasters at the host that is |
dc99d85e RS |
166 | mentioned as original sender's host (I do realize that it may be |
167 | faked, but I think that if your domain name is being abused this way | |
168 | you might want to learn about it, and take actions) and to the | |
169 | postmaster whose host was used as mail relay for this message. If | |
170 | message was sent not by your user, could you please compare time when | |
171 | this message was sent (use time in Received: field of the envelope | |
172 | rather than Date: field) with your sendmail logs and see what host was | |
173 | using your sendmail at this moment of time. | |
bf078b46 RS |
174 | |
175 | Thank you." | |
176 | ||
e13d531d | 177 | "This is the text that `uce-reply-to-uce' command will put in reply buffer. |
bf078b46 RS |
178 | Some of spamming programs in use will be set up to read all incoming |
179 | to spam address email, and will remove people who put the word `remove' | |
180 | on beginning of some line from the spamming list. So, when you set it | |
181 | up, it might be a good idea to actually use this feature. | |
182 | ||
0b5bb3ec | 183 | Value nil means insert no text by default, lets you type it in." |
9f08b141 | 184 | :type '(choice (const nil) string) |
0b5bb3ec | 185 | :group 'uce) |
bf078b46 | 186 | |
0b5bb3ec | 187 | (defcustom uce-uce-separator |
bf078b46 RS |
188 | "----- original unsolicited commercial email follows -----" |
189 | "Line that will begin quoting of the UCE. | |
0b5bb3ec SE |
190 | Value nil means use no separator." |
191 | :type '(choice (const nil) string) | |
192 | :group 'uce) | |
bf078b46 | 193 | |
0b5bb3ec | 194 | (defcustom uce-signature mail-signature |
a1506d29 | 195 | "Text to put as your signature after the note to UCE sender. |
e13d531d | 196 | Value nil means none, t means insert `~/.signature' file (if it happens |
bf078b46 | 197 | to exist), if this variable is a string this string will be inserted |
0b5bb3ec SE |
198 | as your signature." |
199 | :type '(choice (const nil) (const t) string) | |
200 | :group 'uce) | |
bf078b46 | 201 | |
0b5bb3ec | 202 | (defcustom uce-default-headers |
bf078b46 RS |
203 | "Errors-To: nobody@localhost\nPrecedence: bulk\n" |
204 | "Additional headers to use when responding to a UCE with \\[uce-reply-to-uce]. | |
0b5bb3ec | 205 | These are mostly meant for headers that prevent delivery errors reporting." |
9f08b141 | 206 | :type '(choice (const nil) string) |
0b5bb3ec | 207 | :group 'uce) |
bf078b46 | 208 | |
0b5bb3ec | 209 | (defcustom uce-subject-line |
bf078b46 | 210 | "Spam alert: unsolicited commercial e-mail" |
0b5bb3ec SE |
211 | "Subject of the message that will be sent in response to a UCE." |
212 | :type 'string | |
213 | :group 'uce) | |
bf078b46 | 214 | |
9f08b141 GM |
215 | ;; End of user options. |
216 | ||
217 | ||
218 | (defvar rmail-buffer) | |
219 | (declare-function rmail-msg-is-pruned "rmail" ()) | |
2b54af74 | 220 | (declare-function mail-strip-quoted-names "mail-utils" (address)) |
73e72da4 | 221 | (declare-function rmail-maybe-set-message-counters "rmail" ()) |
73e72da4 DN |
222 | (declare-function rmail-toggle-header "rmail" (&optional arg)) |
223 | ||
9f08b141 | 224 | ;;;###autoload |
bf078b46 | 225 | (defun uce-reply-to-uce (&optional ignored) |
9f08b141 GM |
226 | "Compose a reply to unsolicited commercial email (UCE). |
227 | Sets up a reply buffer addressed to: the sender, his postmaster, | |
228 | his abuse@ address, and the postmaster of the mail relay used. | |
229 | You might need to set `uce-mail-reader' before using this." | |
dc99d85e | 230 | (interactive) |
9f08b141 | 231 | ;; Start of mail-client dependent section. |
dc99d85e | 232 | (let ((message-buffer |
db214408 | 233 | (cond ((eq uce-mail-reader 'gnus) gnus-original-article-buffer) |
9f08b141 | 234 | ((eq uce-mail-reader 'rmail) (bound-and-true-p rmail-buffer)) |
a1506d29 | 235 | (t (error |
f04f5c76 | 236 | "Variable uce-mail-reader set to unrecognized value")))) |
9f08b141 GM |
237 | pruned) |
238 | (or (and message-buffer (get-buffer message-buffer)) | |
239 | (error "No mail buffer, cannot find UCE")) | |
dc99d85e | 240 | (switch-to-buffer message-buffer) |
f04f5c76 | 241 | ;; We need the message with headers pruned. |
9f08b141 GM |
242 | ;; Why? All we do is get the from and reply-to headers. ? |
243 | (and (eq uce-mail-reader 'rmail) | |
244 | (not (setq pruned (rmail-msg-is-pruned))) | |
245 | (rmail-toggle-header 1)) | |
dc99d85e RS |
246 | (let ((to (mail-strip-quoted-names (mail-fetch-field "from" t))) |
247 | (reply-to (mail-fetch-field "reply-to")) | |
248 | temp) | |
249 | ;; Initial setting of the list of recipients of our message; that's | |
250 | ;; what they are pretending to be. | |
9f08b141 GM |
251 | (setq to (if to |
252 | (format "%s" (mail-strip-quoted-names to)) | |
253 | "")) | |
dc99d85e RS |
254 | (if reply-to |
255 | (setq to (format "%s, %s" to (mail-strip-quoted-names reply-to)))) | |
256 | (let (first-at-sign end-of-hostname sender-host) | |
257 | (setq first-at-sign (string-match "@" to) | |
258 | end-of-hostname (string-match "[ ,>]" to first-at-sign) | |
259 | sender-host (substring to first-at-sign end-of-hostname)) | |
260 | (if (string-match "\\." sender-host) | |
a1506d29 | 261 | (setq to (format "%s, postmaster%s, abuse%s" |
dc99d85e RS |
262 | to sender-host sender-host)))) |
263 | (setq mail-send-actions nil) | |
264 | (setq mail-reply-buffer nil) | |
9f08b141 GM |
265 | (when (eq uce-mail-reader 'rmail) |
266 | (rmail-toggle-header 0) | |
267 | (rmail-maybe-set-message-counters)) ; why? | |
268 | (copy-region-as-kill (point-min) (point-max)) | |
269 | ;; Restore the initial header state we found. | |
270 | (and pruned (rmail-toggle-header 1)) | |
dc99d85e RS |
271 | (switch-to-buffer "*mail*") |
272 | (erase-buffer) | |
dc99d85e | 273 | (yank) |
9f08b141 GM |
274 | (goto-char (point-min)) |
275 | ;; Delete any internal Rmail headers. | |
276 | (when (eq uce-mail-reader 'rmail) | |
277 | (search-forward "\n\n") | |
278 | (while (re-search-backward "^X-RMAIL" nil t) | |
279 | (delete-region (point) (line-beginning-position 2))) | |
280 | (goto-char (point-min))) | |
dc99d85e RS |
281 | ;; Now find the mail hub that first accepted this message. |
282 | ;; This should try to find the last Received: header. | |
283 | ;; Sometimes there may be other headers inbetween Received: headers. | |
284 | (cond ((eq uce-mail-reader 'gnus) | |
285 | ;; Does Gnus always have Lines: in the end? | |
286 | (re-search-forward "^Lines:") | |
287 | (beginning-of-line)) | |
288 | ((eq uce-mail-reader 'rmail) | |
9f08b141 | 289 | (search-forward "\n\n"))) |
dc99d85e | 290 | (re-search-backward "^Received:") |
dc99d85e RS |
291 | ;; Is this always good? It's the only thing I saw when I checked |
292 | ;; a few messages. | |
9f08b141 GM |
293 | ;;(if (not (re-search-forward ": \\(from\\|by\\) " eol t)) |
294 | (unless (re-search-forward "\\(from\\|by\\) " (line-end-position) 'move) | |
295 | (if (looking-at "[ \t\n]+\\(from\\|by\\) ") | |
296 | (goto-char (match-end 0)) | |
297 | (error "Failed to extract hub address"))) | |
dc99d85e RS |
298 | (setq temp (point)) |
299 | (search-forward " ") | |
300 | (forward-char -1) | |
301 | ;; And add its postmaster to the list of addresses. | |
302 | (if (string-match "\\." (buffer-substring temp (point))) | |
a1506d29 | 303 | (setq to (format "%s, postmaster@%s" |
dc99d85e RS |
304 | to (buffer-substring temp (point))))) |
305 | ;; Also look at the message-id, it helps *very* often. | |
9f08b141 GM |
306 | (and (search-forward "\nMessage-Id: " nil t) |
307 | ;; Not all Message-Id:'s have an `@' sign. | |
308 | (search-forward "@" (line-end-position) t) | |
309 | (progn | |
310 | (setq temp (point)) | |
311 | (search-forward ">") | |
312 | (forward-char -1) | |
313 | (if (string-match "\\." (buffer-substring temp (point))) | |
314 | (setq to (format "%s, postmaster@%s" | |
315 | to (buffer-substring temp (point))))))) | |
316 | (when (eq uce-mail-reader 'gnus) | |
317 | ;; Does Gnus always have Lines: in the end? | |
318 | (re-search-forward "^Lines:") | |
319 | (beginning-of-line) | |
320 | (setq temp (point)) | |
321 | (search-forward "\n\n" nil t) | |
322 | (forward-line -1) | |
323 | (delete-region temp (point))) | |
324 | ;; End of mail-client dependent section. | |
dc99d85e RS |
325 | (auto-save-mode auto-save-default) |
326 | (mail-mode) | |
327 | (goto-char (point-min)) | |
328 | (insert "To: ") | |
329 | (save-excursion | |
330 | (if to | |
331 | (let ((fill-prefix "\t") | |
332 | (address-start (point))) | |
333 | (insert to "\n") | |
334 | (fill-region-as-paragraph address-start (point))) | |
335 | (newline)) | |
336 | (insert "Subject: " uce-subject-line "\n") | |
337 | (if uce-default-headers | |
338 | (insert uce-default-headers)) | |
339 | (if mail-default-headers | |
340 | (insert mail-default-headers)) | |
341 | (if mail-default-reply-to | |
342 | (insert "Reply-to: " mail-default-reply-to "\n")) | |
343 | (insert mail-header-separator "\n") | |
344 | ;; Insert all our text. Then go back to the place where we started. | |
345 | (if to (setq to (point))) | |
346 | ;; Text of ranting. | |
347 | (if uce-message-text | |
348 | (insert uce-message-text)) | |
349 | ;; Signature. | |
350 | (cond ((eq uce-signature t) | |
351 | (if (file-exists-p "~/.signature") | |
352 | (progn | |
353 | (insert "\n\n-- \n") | |
38926103 | 354 | (forward-char (cadr (insert-file-contents "~/.signature")))))) |
dc99d85e RS |
355 | (uce-signature |
356 | (insert "\n\n-- \n" uce-signature))) | |
357 | ;; And text of the original message. | |
358 | (if uce-uce-separator | |
359 | (insert "\n\n" uce-uce-separator "\n")) | |
360 | ;; If message doesn't end with a newline, insert it. | |
361 | (goto-char (point-max)) | |
362 | (or (bolp) (newline))) | |
363 | ;; And go back to the beginning of text. | |
364 | (if to (goto-char to)) | |
365 | (or to (set-buffer-modified-p nil)) | |
366 | ;; Run hooks before we leave buffer for editing. Reasonable usage | |
9f08b141 | 367 | ;; might be to set up special key bindings, replace standard |
dc99d85e RS |
368 | ;; functions in mail-mode, etc. |
369 | (run-hooks 'mail-setup-hook 'uce-setup-hook)))) | |
a1506d29 | 370 | |
bf078b46 RS |
371 | (defun uce-insert-ranting (&optional ignored) |
372 | "Insert text of the usual reply to UCE into current buffer." | |
373 | (interactive "P") | |
374 | (insert uce-message-text)) | |
375 | ||
376 | (provide 'uce) | |
377 | ||
cbee283d | 378 | ;; arch-tag: 44b68c87-9b29-47bd-822c-3feee3883221 |
bf078b46 | 379 | ;;; uce.el ends here |