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