comparison shared/mail-extras.el @ 0:107d592c5f4a

DICE versions, used by pers/common, recursive, I think/hope
author Henry S. Thompson <ht@inf.ed.ac.uk>
date Mon, 08 Feb 2021 11:44:37 +0000
parents
children 0a81352bd7d0
comparison
equal deleted inserted replaced
-1:000000000000 0:107d592c5f4a
1 ;; Last edited: Fri Nov 2 10:26:24 1990
2 ;; extra widgets for rmail and rmailsum
3 ;; Copyright (C) 1990 Henry S. Thompson
4
5 ;; This file is part of GNU Emacs.
6
7 ;; GNU Emacs is distributed in the hope that it will be useful,
8 ;; but WITHOUT ANY WARRANTY. No author or distributor
9 ;; accepts responsibility to anyone for the consequences of using it
10 ;; or for whether it serves any particular purpose or works at all,
11 ;; unless he says so in writing. Refer to the GNU Emacs General Public
12 ;; License for full details.
13
14 ;; Everyone is granted permission to copy, modify and redistribute
15 ;; GNU Emacs, but only under the conditions described in the
16 ;; GNU Emacs General Public License. A copy of this license is
17 ;; supposed to have been given to you along with GNU Emacs so you
18 ;; can know your rights and responsibilities. It should be in a
19 ;; file named COPYING. Among other things, the copyright notice
20 ;; and this notice must be preserved on all copies.
21
22 (provide 'mail-extras)
23 (require 'rmail)
24 (require 'sendmail)
25
26
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 ;; mods and fixes for reading mail ;;
29 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30
31 (defvar ht-last-file (expand-file-name "~/XMAIL")
32 "default for moving mail to")
33 (make-variable-buffer-local 'ht-last-file)
34
35 (defvar rmht-always-recompress t
36 "If non-nil, when saving into compressed babyl file,
37 always recompress and save immediately")
38
39 (defvar rmht-allow-autosave t
40 "if non-nil, leaves autosave alone for compressed babyl files,
41 otherwise turns it off")
42
43 (add-hook 'rmail-mode-hook 'rmail-mode-fun1)
44 (add-hook 'rmail-mode-hook 'rmail-mode-fun2)
45
46 ;; run the first time in to RMAIL
47 (defun rmail-mode-fun1 ()
48 "add ht's mods to RMAIL"
49 (define-key rmail-mode-map "R" 'reply-w/o-cc)
50 (define-key rmail-mode-map "M" 'rmht-output)
51 (define-key rmail-mode-map "H" 'print-buffer)
52 (define-key rmail-mode-map "W" 'edit-and-move-to-diary)
53 (define-key rmail-mode-map "D" 'update-default-diary)
54 (define-key rmail-mode-map "F" 're-post-failed-mail)
55 (define-key rmail-mode-map "B" 'ht-write-body-to-file)
56 (define-key rmail-mode-map "E" 'extract-attachment)
57 ;; fix the doc string
58 (repl-comment 'rmail-mode
59 "Rmail Mode is used by \\[rmail] for editing Rmail files.
60 All normal editing commands are turned off.
61 Instead, these commands are available (additions from ht's mail-extras.el
62 indicated by *:
63
64 . Move point to front of this message (same as \\[beginning-of-buffer]).
65 SPC Scroll to next screen of this message.
66 DEL Scroll to previous screen of this message.
67 n Move to Next non-deleted message.
68 p Move to Previous non-deleted message.
69 M-n Move to Next message whether deleted or not.
70 M-p Move to Previous message whether deleted or not.
71 > Move to the last message in Rmail file.
72 j Jump to message specified by numeric position in file.
73 M-s Search for string and show message it is found in.
74 d Delete this message, move to next nondeleted.
75 C-d Delete this message, move to previous nondeleted.
76 u Undelete message. Tries current message, then earlier messages
77 till a deleted message is found.
78 e Expunge deleted messages.
79 s Expunge and save the file.
80 q Quit Rmail: expunge, save, then switch to another buffer.
81 C-x C-s Save without expunging.
82 g Move new mail from system spool directory or mbox into this file.
83 m Mail a message (same as \\[mail-other-window]).
84 c Continue composing outgoing message started before.
85 r Reply to this message. Like m but initializes some fields.
86 R * Like r, but reply to originator only.
87 f Forward this message to another user.
88 F * like f, but assumes message is \"failed mail\" for re-sending
89 o Output this message to an Rmail file (append it).
90 C-o Output this message to a Unix-format mail file (append it).
91 M * Output this message to a file,
92 in format determined by extension (babyl for RMAIL/msg for Unix).
93 B * Write the body of the message to a file, leaving a pointer
94 H * Print the message (same as \\<global-map>\\[print-buffer]).\\<rmail-mode-map>
95 i Input Rmail file. Run Rmail on that file.
96 a Add label to message. It will be displayed in the mode line.
97 k Kill label. Remove a label from current message.
98 C-M-n Move to Next message with specified label
99 (label defaults to last one specified).
100 Standard labels: filed, unseen, answered, forwarded, deleted.
101 Any other label is present only if you add it with `a'.
102 C-M-p Move to Previous message with specified label
103 h, C-M-h Show headers buffer, with a one line summary of each message.
104 l, C-M-l Like h only just messages with particular label(s) are summarized.
105 C-M-r Like h only just messages with particular recipient(s) are summarized.
106 t Toggle header, show Rmail header if unformatted or vice versa.
107 w Edit the current message. C-c C-c to return to Rmail.
108 W * Edit the subject field. C-c C-c to move the message to the Diary.
109 D * Update the Diary.
110
111 Messages for the diary (see also \\[describe-mode] in rmail-summary mode
112 or \\[describe-function] rmail-summary-mode) should have a subject field
113 which begins with the date and optional time of the event described therein.
114 These must be in the form
115 d m y t
116 where d is one or two digits for the day,
117 m is either the full month name or the first three letters thereof,
118 y is two digits for the year,
119 and t, if present, is 4 digits for the time,
120 thus for example
121 31 Jun 91 1530
122 ")
123 (remove-hook 'rmail-mode-hook 'rmail-mode-fun1))
124
125 (defun rmail-mode-fun2 ()
126 "always run in RMAIL mode"
127 (setq case-fold-search t))
128
129 (defun reply-w/o-cc ()
130 "Reply as r, but without sending to other recipients"
131 (interactive)
132 (rmail-reply t))
133
134 (defun rmht-output (&optional file-name gnus)
135 "Move to a file, determining format by extension (babyl/msg)"
136 (interactive)
137 (if (not file-name)
138 (setq file-name (car (get-move-file-name))))
139 (if (string-match "\\.g?[zZ]$" file-name)
140 (let ((clean-file-name (substring file-name 0 (match-beginning 0)))
141 there)
142 (if (setq there (get-file-buffer clean-file-name))
143 nil
144 (save-window-excursion (rmail clean-file-name)
145 (setq there
146 (get-file-buffer clean-file-name))))
147 (rmht-output clean-file-name gnus)
148 (if rmht-always-recompress
149 (save-excursion
150 (set-buffer there)
151 (save-buffer))
152 (if (not rmht-allow-autosave)
153 (save-excursion
154 (set-buffer there)
155 (auto-save-mode -1)))))
156 (setq file-name (expand-file-name file-name))
157 (save-excursion
158 (if (string-match "\\.babyl$" file-name)
159 (if gnus
160 (gnus-output-to-rmail file-name)
161 (rmail-output-to-rmail-file file-name 1))
162 (if (string-match "\\.msg$" file-name)
163 (if (or (get-file-buffer file-name)
164 (file-exists-p file-name)
165 (yes-or-no-p
166 (concat "\"" file-name "\" does not exist, create it? ")))
167 (rmail-output file-name 1)
168 (error "Output file does not exist"))
169 (error "not a valid mail file: %s" file-name))))
170 (setq ht-last-file file-name)
171 (if (not gnus) (ht-rmail-delete-forward))))
172
173 (defun get-move-file-name ()
174 "get a file name for moving a message to"
175 (list (read-file-name
176 (concat "Output message to file: (default "
177 (file-name-nondirectory ht-last-file)
178 ") ")
179 (file-name-directory ht-last-file)
180 ht-last-file)))
181
182 (defun re-post-failed-mail ()
183 "try to salvage the original from failed mail and prepare to resend it"
184 (interactive)
185 (rmail-forward nil)
186 (let ((top (point))
187 subjp textp)
188 (re-search-forward "^Subject: ")
189 (kill-line nil)
190 (setq subjp (point))
191 (re-search-forward "^From: ") ; the bouncer
192 (re-search-forward "^From: ") ; should be us
193 (re-search-forward "^Subject: ")
194 (kill-line nil)
195 (save-excursion (goto-char subjp)
196 (yank))
197 (beginning-of-line 3)
198 (setq textp (point))
199 (goto-char top)
200 (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
201 (beginning-of-line 2)
202 (delete-region (point) textp)
203 (goto-char top)))
204
205 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
206 ;; mods and fixes for mail summaries ;;
207 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208
209 (add-hook 'rmail-summary-mode-hook 'rmail-summary-mode-fun1)
210
211 ;; run the first time we make a summary window
212 (defun rmail-summary-mode-fun1 ()
213 "install ht's mods"
214 (define-key rmail-summary-mode-map "r" 'rms-reply-w-cc)
215 (define-key rmail-summary-mode-map "R" 'rms-reply-w/o-cc)
216 (define-key rmail-summary-mode-map "s" 'diary-save)
217 (define-key rmail-summary-mode-map "m" 'rms-move)
218 (define-key rmail-summary-mode-map "d" 'rms-delete)
219 (define-key rmail-summary-mode-map "h" 'rms-hardcopy)
220 (define-key rmail-summary-mode-map " " 'ht-rmailsum-scroll-msg-up)
221 (define-key rmail-summary-mode-map "\177" 'ht-rmailsum-scroll-msg-down)
222 ;; fix the doc string
223 (repl-comment 'rmail-summary-mode
224 "Major mode in effect in Rmail summary buffer.
225 A subset of the Rmail mode commands are supported in this mode.
226 As commands are issued in the summary buffer the corresponding
227 mail message is displayed in the rmail buffer.
228 Modifications from ht's mail-extras.el indicated with *:
229
230 n Move to next undeleted message, or arg messages.
231 p Move to previous undeleted message, or arg messages.
232 C-n Move to next, or forward arg messages.
233 C-p Move to previous, or previous arg messages.
234 j Jump to the message at the cursor location.
235 d Delete the message at the cursor location and move to next message.
236 u Undelete this or previous deleted message.
237 q Quit Rmail.
238 x Exit and kill the summary window.
239 space * If cursor is on line of current message,
240 scroll message window forward. Otherwise, jump to indicated message.
241 delete * same as space, but scrolls backward.
242 r * Same as r in rmail window. Reply to current message.
243 R * Same as R in rmail window. Reply to current message, originator only.
244 s * Update and save the rmail file, and re-summarise. Re-sorts if Diary.
245 m * Same as M in rmail window. Moves message to file.
246 h * Same as H in rmail window. Prints message on line printer.
247
248 Entering this mode calls value of hook variable rmail-summary-mode-hook.
249
250 If the file summarised is called by the name given in ht-diary-file-name,
251 which defaults to diary.babyl,
252 then the summary will be called *Diary*, sorted in date order and
253 formated in a special way.
254
255 Messages in the diary should have a subject field
256 which begins with the date and optional time of the event described therein.
257 These must be in the form
258 d m y t
259 where d is one or two digits for the day,
260 m is either the full month name or the first three letters thereof,
261 y is two digits for the year,
262 and t, if present, is 4 digits for the time,
263 thus for example
264 Subject: 31 Jun 91 1530 Hades freezing ceremony followed by champagne reception
265 ")
266 (remove-hook 'rmail-summary-mode-hook 'rmail-summary-mode-fun1))
267
268 (defun rmht-sum-reply (sender-only)
269 "reply to current message"
270 (rmail-summary-goto-msg)
271 (pop-to-buffer rmail-buffer)
272 (rmail-reply sender-only)
273 (switch-to-buffer rmail-summary-buffer)
274 (switch-to-buffer "*mail*")
275 )
276
277 (defun rms-reply-w-cc ()
278 "Do r in RMAIL - reply to everybody"
279 (interactive)
280 (rmht-sum-reply nil))
281
282 (defun rms-reply-w/o-cc ()
283 "Do R in RMAIL - reply to sender only"
284 (interactive)
285 (rmht-sum-reply t))
286
287 (defun rms-save ()
288 "expunge deleted messages, save RMAIL file and re-display headers"
289 (interactive)
290 (pop-to-buffer rmail-buffer)
291 (rmail-expunge-and-save)
292 (rmail-summary))
293
294 (defun rms-delete ()
295 "delete current and move down to next in summary buffer"
296 (interactive)
297 (rmail-summary-goto-msg)
298 (save-excursion
299 (rmail-summary-delete-forward nil))
300 (rms-del))
301
302 (defun rms-move ()
303 "Move to a file, mode determined by file extension (babyl/msg)"
304 (interactive)
305 (rmail-summary-goto-msg)
306 (save-excursion
307 (set-buffer rmail-buffer)
308 (rmht-output))
309 (rms-del))
310
311 (defun rms-del ()
312 "mark current summary line as deleted and move down"
313 (let ((buffer-read-only nil))
314 (skip-chars-forward " ")
315 (skip-chars-forward "[0-9]")
316 (delete-char 1)
317 (insert "D"))
318 (forward-line 1))
319
320 (defun rms-hardcopy ()
321 "hardcopy the current message"
322 (interactive)
323 (pop-to-buffer rmail-buffer)
324 (print-buffer)
325 (pop-to-buffer rmail-summary-buffer))
326
327
328 ;; fix interpretation of SPACE and DEL in summary windows to
329 ;; 1) scroll the right window regardless of how many panes are up;
330 ;; 2) go to the message associated with the current line if not already there,
331 ;; a la gnus, for instance
332
333 (defun ht-rmailsum-normalise ()
334 "if not already showing message named on current line, go to it & return t"
335 (beginning-of-line)
336 (let ((current-msg-num (cdr (assoc 'rmail-current-message
337 (buffer-local-variables
338 (or rmail-buffer
339 (error
340 "not in a summary buffer"))))))
341 (line-message-num (string-to-int
342 (buffer-substring
343 (point)
344 (min (point-max)(+ 5 (point)))))))
345 (if (= current-msg-num line-message-num)
346 nil
347 (rmail-summary-goto-msg line-message-num)
348 t)))
349
350 (defun ht-rmailsum-scroll-msg-up (&optional dist)
351 "goto other message or scroll current message forward"
352 (interactive "P")
353 (if (ht-rmailsum-normalise)
354 nil
355 (pop-to-buffer rmail-buffer)
356 (scroll-up dist)
357 (pop-to-buffer rmail-summary-buffer)))
358
359 (defun ht-rmailsum-scroll-msg-down (&optional dist)
360 "goto other message or scroll current message backward"
361 (interactive "P")
362 (if (ht-rmailsum-normalise)
363 nil
364 (pop-to-buffer rmail-buffer)
365 (scroll-down dist)
366 (pop-to-buffer rmail-summary-buffer)))
367
368 (autoload 'edit-and-move-to-diary "diary")
369 (autoload 'update-diary "diary")
370 (autoload 'diary-save "diary")
371
372 ;; unfortunately, gnus mucks about with the buffers before calling
373 ;; mail, so we have to intervene to make the about-to-mail-hook work right
374
375 (defun ht-Subject-mode-fun ()
376 "fix the map to save window state"
377 ; (define-key gnus-summary-mode-map "r" 'ht-Subject-mail-reply)
378 ; (define-key gnus-summary-mode-map "R" 'ht-Subject-mail-reply-with-original)
379 ; (define-key gnus-summary-mode-map "m" 'ht-Subject-mail-other-window)
380 (define-key gnus-summary-save-map "M" 'ht-Subject-move)
381 (remove-hook 'gnus-summary-mode-hook 'ht-Subject-mode-fun))
382
383 (add-hook 'gnus-summary-mode-hook 'ht-Subject-mode-fun)
384
385 (defun ht-Subject-mail-reply (yank)
386 "Runs about-to-mail-hook, then calls gnus-summary-mail-reply"
387 (interactive "P")
388 (require 'sendmail)
389 (run-hooks 'about-to-mail-hook)
390 (let (about-to-mail-hook)
391 (gnus-summary-reply yank)))
392
393 (defun ht-Subject-mail-reply-with-original ()
394 "Runs about-to-mail-hook, then calls gnus-summary-mail-reply-with-original"
395 (interactive)
396 (require 'sendmail)
397 (run-hooks 'about-to-mail-hook)
398 (let (about-to-mail-hook)
399 (gnus-summary-reply-with-original)))
400
401 (defun ht-Subject-mail-other-window ()
402 "Runs about-to-mail-hook, then calls gnus-summary-mail-other-window"
403 (interactive)
404 (require 'sendmail)
405 (run-hooks 'about-to-mail-hook)
406 (let (about-to-mail-hook)
407 (gnus-summary-mail-other-window)))
408
409 (defun ht-Subject-move ()
410 "Move article to a file, mode determined by file extension (babyl/msg)"
411 (interactive)
412 (gnus-summary-select-article)
413 (save-excursion
414 (set-buffer gnus-article-buffer)
415 (rmht-output nil t)))
416
417
418 (defun ht-write-body-to-file (file)
419 "Write the body of the message to a file and replace it with a pointer"
420 (interactive "FFile to save in: ")
421 (goto-char (point-min))
422 (or (search-forward "\n\n" nil t)
423 (error "Can't find text"))
424 (write-region (point)(point-max) file)
425 (rmail-edit-current-message)
426 (delete-region (point)(point-max))
427 (insert "\n>> " file "\n")
428 (rmail-cease-edit)
429 (rmht-output))
430
431 (defun extract-attachment ()
432 "extract attachments from a multi-part mime message"
433 (interactive)
434 (rmail-toggle-header)
435 (mime/viewer-mode)
436 (let ((pt 0))
437 (while (progn
438 (mime-viewer/next-content)
439 (and
440 (equal "*Preview-RMAIL*" (buffer-name (current-buffer)))
441 (not (= pt (point)))))
442 (setq pt (point))
443 (if (looking-at "^\\[[0-9]* [^ ]+ <")
444 (mime-viewer/extract-content))))
445 (if (not (equal "*Preview-RMAIL*" (buffer-name (current-buffer))))
446 ;; we fell off the end
447 (rmail-previous-undeleted-message 1))
448 (kill-buffer "*Preview-RMAIL*")
449 )
450
451 ;; see message-citation-line-function in message.el
452 (defun safe-citation ()
453 (when message-reply-headers
454 (let ((from (mail-header-from message-reply-headers)))
455 (cond ((string-match "^\"?\\([^\"]*\\)\"? <.*>$" from)
456 (insert (match-string 1 from) " writes:\n\n"))
457 ((string-match "^\\([^<@]*\\)@" from)
458 (insert (match-string 1 from) " writes:\n\n"))
459 (t
460 (insert "[anon] writes:\n\n"))))))
461
462
463 (setq message-citation-line-function (function safe-citation))
464
465 ;(load-library "mailcrypt") ; provides "mc-setversion"
466 ;(mc-setversion "gpg") ; for PGP 2.6 (default); also "5.0" and "gpg"
467 ;(autoload 'mc-install-write-mode "mailcrypt" nil t)
468 ;(autoload 'mc-install-read-mode "mailcrypt" nil t)
469 ;(add-hook 'mail-mode-hook 'mc-install-write-mode)
470 ;(add-hook 'gnus-summary-mode-hook 'mc-install-read-mode)
471 ;(add-hook 'message-mode-hook 'mc-install-write-mode)
472 ;(add-hook 'news-reply-mode-hook 'mc-install-write-mode)
473 ;(setq mc-passwd-timeout 6000)
474 ;;; Key server at Cambridge University (Cambridge, England)
475 ;(setq mc-pgp-fetch-methods '(mc-pgp-fetch-from-keyrings
476 ; mc-pgp-fetch-from-http))
477 ;(require 'pgg)
478 ;(add-hook 'message-send-hook 'my-sign-message)
479 (setq hack-yn-map (copy-keymap query-replace-map))
480 (define-key hack-yn-map 'return 'act)
481
482 (defun my-sign-message ()
483 (goto-char (point-min))
484 (unless
485 (or
486 (re-search-forward "<#\\(part\\|mml\\) " nil t)
487 ; signing attachments doesn't seem
488 ; to work well
489 (search-forward "\n-- \nHenry S. Thompson, Central Edinburgh LM" nil t)
490 ; Don't sign Quaker mail
491 )
492 (let* ((headers (mail-header-extract-no-properties))
493 (cc (mail-header 'cc))
494 (to (mail-header 'to)))
495 (if (and to
496 (not (string-match "htcalendar[@]markup\.co\.uk" to))
497 (not (string-match "^ht$" to))
498 (or
499 (string-match "w3.org" to)
500 (and cc (string-match "w3.org" cc))
501 (let ((query-replace-map hack-yn-map))
502 (y-or-n-p "Sign message? "))))
503 (mml-secure-message-sign-pgp)))))