Mercurial > hg > xemacs-beta
comparison lisp/vm/vm-reply.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; Mailing, forwarding, and replying commands for VM | |
2 ;;; Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995 Kyle E. Jones | |
3 ;;; | |
4 ;;; This program is free software; you can redistribute it and/or modify | |
5 ;;; it under the terms of the GNU General Public License as published by | |
6 ;;; the Free Software Foundation; either version 1, or (at your option) | |
7 ;;; any later version. | |
8 ;;; | |
9 ;;; This program is distributed in the hope that it will be useful, | |
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 ;;; GNU General Public License for more details. | |
13 ;;; | |
14 ;;; You should have received a copy of the GNU General Public License | |
15 ;;; along with this program; if not, write to the Free Software | |
16 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 | |
18 (provide 'vm-reply) | |
19 | |
20 (defun vm-do-reply (to-all include-text count) | |
21 (let ((mlist (vm-select-marked-or-prefixed-messages count)) | |
22 (dir default-directory) | |
23 (message-pointer vm-message-pointer) | |
24 (case-fold-search t) | |
25 to cc subject mp in-reply-to references tmp tmp2 newsgroups) | |
26 (setq mp mlist) | |
27 (while mp | |
28 (cond | |
29 ((eq mlist mp) | |
30 (cond ((setq to | |
31 (let ((reply-to | |
32 (vm-get-header-contents (car mp) "Reply-To:"))) | |
33 (if (vm-ignored-reply-to reply-to) | |
34 nil | |
35 reply-to )))) | |
36 ((setq to (vm-get-header-contents (car mp) "From:"))) | |
37 ;; bad, but better than nothing for some | |
38 ((setq to (vm-grok-From_-author (car mp)))) | |
39 (t (error "No From: or Reply-To: header in message"))) | |
40 (setq subject (vm-get-header-contents (car mp) "Subject:") | |
41 in-reply-to | |
42 (and vm-in-reply-to-format | |
43 (let ((vm-summary-uninteresting-senders nil)) | |
44 (vm-sprintf 'vm-in-reply-to-format (car mp)))) | |
45 in-reply-to (and (not (equal "" in-reply-to)) in-reply-to)) | |
46 (and subject vm-reply-subject-prefix | |
47 (let ((case-fold-search t)) | |
48 (not | |
49 (equal | |
50 (string-match (regexp-quote vm-reply-subject-prefix) | |
51 subject) | |
52 0))) | |
53 (setq subject (concat vm-reply-subject-prefix subject)))) | |
54 (t (cond ((setq tmp (vm-get-header-contents (car mp) "Reply-To:")) | |
55 (setq to (concat to "," tmp))) | |
56 ((setq tmp (vm-get-header-contents (car mp) "From:")) | |
57 (setq to (concat to "," tmp))) | |
58 ;; bad, but better than nothing for some | |
59 ((setq tmp (vm-grok-From_-author (car mp))) | |
60 (setq to (concat to "," tmp))) | |
61 (t (error "No From: or Reply-To: header in message"))))) | |
62 (if to-all | |
63 (progn | |
64 (setq tmp (vm-get-header-contents (car mp) "To:")) | |
65 (setq tmp2 (vm-get-header-contents (car mp) "Cc:")) | |
66 (if tmp | |
67 (if cc | |
68 (setq cc (concat cc "," tmp)) | |
69 (setq cc tmp))) | |
70 (if tmp2 | |
71 (if cc | |
72 (setq cc (concat cc "," tmp2)) | |
73 (setq cc tmp2))))) | |
74 (setq references | |
75 (cons (vm-get-header-contents (car mp) "References:") | |
76 (cons (vm-get-header-contents (car mp) "In-reply-to:") | |
77 (cons (vm-get-header-contents (car mp) "Message-ID:") | |
78 references)))) | |
79 (setq newsgroups | |
80 (cons (or (and to-all (vm-get-header-contents (car mp) "Followup-To:")) | |
81 (vm-get-header-contents (car mp) "Newsgroups:")) | |
82 newsgroups)) | |
83 (setq mp (cdr mp))) | |
84 (if vm-strip-reply-headers | |
85 (let ((mail-use-rfc822 t)) | |
86 (and to (setq to (mail-strip-quoted-names to))) | |
87 (and cc (setq cc (mail-strip-quoted-names cc))))) | |
88 (setq to (vm-parse-addresses to) | |
89 cc (vm-parse-addresses cc)) | |
90 (if vm-reply-ignored-addresses | |
91 (setq to (vm-strip-ignored-addresses to) | |
92 cc (vm-strip-ignored-addresses cc))) | |
93 (setq to (vm-delete-duplicates to nil t)) | |
94 (setq cc (vm-delete-duplicates | |
95 (append (vm-delete-duplicates cc nil t) | |
96 to (copy-sequence to)) | |
97 t t)) | |
98 (and to (setq to (mapconcat 'identity to ",\n "))) | |
99 (and cc (setq cc (mapconcat 'identity cc ",\n "))) | |
100 (and (null to) (setq to cc cc nil)) | |
101 (setq references (delq nil references) | |
102 references (mapconcat 'identity references " ") | |
103 references (vm-parse references "[^<]*\\(<[^>]+>\\)") | |
104 references (vm-delete-duplicates references) | |
105 references (if references (mapconcat 'identity references "\n\t"))) | |
106 (setq newsgroups (delq nil newsgroups) | |
107 newsgroups (mapconcat 'identity newsgroups ",") | |
108 newsgroups (vm-parse newsgroups "[ \t\f\r\n,]*\\([^ \t\f\r\n,]+\\)") | |
109 newsgroups (vm-delete-duplicates newsgroups) | |
110 newsgroups (if newsgroups (mapconcat 'identity newsgroups ","))) | |
111 (vm-mail-internal | |
112 (format "reply to %s%s" (vm-su-full-name (car mlist)) | |
113 (if (cdr mlist) ", ..." "")) | |
114 to subject in-reply-to cc references newsgroups) | |
115 (make-local-variable 'vm-reply-list) | |
116 (setq vm-system-state 'replying | |
117 vm-reply-list mlist | |
118 default-directory dir) | |
119 (if include-text | |
120 (save-excursion | |
121 (goto-char (point-min)) | |
122 (let ((case-fold-search nil)) | |
123 (re-search-forward | |
124 (concat "^" (regexp-quote mail-header-separator) "$") nil 0)) | |
125 (forward-char 1) | |
126 (while mlist | |
127 (vm-yank-message (car mlist)) | |
128 (goto-char (point-max)) | |
129 (setq mlist (cdr mlist))))) | |
130 (run-hooks 'vm-reply-hook) | |
131 (run-hooks 'vm-mail-mode-hook))) | |
132 | |
133 (defun vm-strip-ignored-addresses (addresses) | |
134 (setq addresses (copy-sequence addresses)) | |
135 (let (re-list list addr-list) | |
136 (setq re-list vm-reply-ignored-addresses) | |
137 (while re-list | |
138 (setq addr-list addresses) | |
139 (while addr-list | |
140 (if (string-match (car re-list) (car addr-list)) | |
141 (setq addresses (delq (car addr-list) addresses))) | |
142 (setq addr-list (cdr addr-list))) | |
143 (setq re-list (cdr re-list)))) | |
144 addresses ) | |
145 | |
146 (defun vm-ignored-reply-to (reply-to) | |
147 (if reply-to | |
148 (let (re-list result) | |
149 (setq re-list vm-reply-ignored-reply-tos) | |
150 (while re-list | |
151 (if (string-match (car re-list) reply-to) | |
152 (setq result t re-list nil) | |
153 (setq re-list (cdr re-list)))) | |
154 result ))) | |
155 | |
156 (defun vm-mail-yank-default (message) | |
157 (save-excursion | |
158 (vm-reorder-message-headers nil vm-included-text-headers | |
159 vm-included-text-discard-header-regexp) | |
160 ;; if all the headers are gone, delete the trailing blank line, too. | |
161 (if (eq (following-char) ?\n) | |
162 (delete-char 1)) | |
163 (if vm-included-text-attribution-format | |
164 (let ((vm-summary-uninteresting-senders nil)) | |
165 (insert (vm-sprintf 'vm-included-text-attribution-format message)))) | |
166 ; turn off zmacs-regions for Lucid Emacs 19 | |
167 ; and get around transient-mark-mode in FSF Emacs 19 | |
168 ; all this so that (mark) does what it did in v18, sheesh. | |
169 (let* ((zmacs-regions nil) | |
170 (mark-even-if-inactive t) | |
171 (end (mark-marker))) | |
172 (while (< (point) end) | |
173 (insert vm-included-text-prefix) | |
174 (forward-line 1))))) | |
175 | |
176 (defun vm-yank-message-other-folder (folder) | |
177 "Like vm-yank-message except the message is yanked from a folder other | |
178 than the one that spawned the current Mail mode buffer. The name of the | |
179 folder is read from the minibuffer. | |
180 | |
181 Don't call this function from a program." | |
182 (interactive | |
183 (list | |
184 (let ((dir (if vm-folder-directory | |
185 (expand-file-name vm-folder-directory) | |
186 default-directory)) | |
187 (last-command last-command) | |
188 (this-command this-command)) | |
189 (read-file-name "Yank from folder: " dir nil t)))) | |
190 (let ((b (current-buffer)) newbuf sumbuf default result prompt mp) | |
191 (set-buffer (or (vm-get-file-buffer folder) (find-file-noselect folder))) | |
192 (setq newbuf (current-buffer)) | |
193 (if (not (eq major-mode 'vm-mode)) | |
194 (vm-mode)) | |
195 (if (null vm-message-pointer) | |
196 (error "No messages in folder %s" folder)) | |
197 (setq default (vm-number-of (car vm-message-pointer))) | |
198 (save-excursion | |
199 (save-window-excursion | |
200 (save-window-excursion | |
201 (vm-summarize)) | |
202 (vm-display vm-summary-buffer t '(vm-yank-message-other-folder) | |
203 '(vm-yank-message-other-folder composing-message)) | |
204 (setq sumbuf (current-buffer)) | |
205 (setq prompt (format "Yank message number: (default %s) " default) | |
206 result 0) | |
207 (while (zerop result) | |
208 (setq result (read-string prompt)) | |
209 (and (string= result "") default (setq result default)) | |
210 (setq result (string-to-int result))) | |
211 (if (null (setq mp (nthcdr (1- result) vm-message-list))) | |
212 (error "No such message.")))) | |
213 (set-buffer b) | |
214 (unwind-protect | |
215 (let ((vm-mail-buffer newbuf)) | |
216 (vm-yank-message (car mp))) | |
217 (vm-bury-buffer newbuf) | |
218 (vm-bury-buffer sumbuf)))) | |
219 | |
220 (defun vm-yank-message (message) | |
221 "Yank message number N into the current buffer at point. | |
222 When called interactively N is always read from the minibuffer. When | |
223 called non-interactively the first argument is expected to be a | |
224 message struct. | |
225 | |
226 This command is meant to be used in VM created Mail mode buffers; the | |
227 yanked message comes from the mail buffer containing the message you | |
228 are replying to, forwarding, or invoked VM's mail command from. | |
229 | |
230 All message headers are yanked along with the text. Point is | |
231 left before the inserted text, the mark after. Any hook | |
232 functions bound to mail-citation-hook are run, after inserting | |
233 the text and setting point and mark. For backward compatibility, | |
234 if mail-citation-hook is set to nil, `mail-yank-hooks' is run | |
235 instead. | |
236 | |
237 If mail-citation-hook and mail-yank-hooks are both nil, this | |
238 default action is taken: the yanked headers are trimmed as | |
239 specified by vm-included-text-headers and | |
240 vm-included-text-discard-header-regexp, and the value of | |
241 vm-included-text-prefix is prepended to every yanked line." | |
242 (interactive | |
243 (list | |
244 ;; What we really want for the first argument is a message struct, | |
245 ;; but if called interactively, we let the user type in a message | |
246 ;; number instead. | |
247 (let (mp default | |
248 (result 0) | |
249 prompt | |
250 (last-command last-command) | |
251 (this-command this-command)) | |
252 (save-excursion | |
253 (vm-select-folder-buffer) | |
254 (setq default (and vm-message-pointer | |
255 (vm-number-of (car vm-message-pointer))) | |
256 prompt (if default | |
257 (format "Yank message number: (default %s) " | |
258 default) | |
259 "Yank message number: ")) | |
260 (while (zerop result) | |
261 (setq result (read-string prompt)) | |
262 (and (string= result "") default (setq result default)) | |
263 (setq result (string-to-int result))) | |
264 (if (null (setq mp (nthcdr (1- result) vm-message-list))) | |
265 (error "No such message."))) | |
266 (car mp)))) | |
267 (if (not (bufferp vm-mail-buffer)) | |
268 (error "This is not a VM Mail mode buffer.")) | |
269 (if (null (buffer-name vm-mail-buffer)) | |
270 (error "The folder buffer containing message %d has been killed." | |
271 (vm-number-of message))) | |
272 (vm-display nil nil '(vm-yank-message) '(vm-yank-message composing-message)) | |
273 (setq message (vm-real-message-of message)) | |
274 (let ((b (current-buffer)) (start (point)) end) | |
275 (save-restriction | |
276 (widen) | |
277 (save-excursion | |
278 (set-buffer (vm-buffer-of message)) | |
279 (save-restriction | |
280 (widen) | |
281 (append-to-buffer b (vm-headers-of message) (vm-text-end-of message)) | |
282 (setq end (vm-marker (+ start (- (vm-text-end-of message) | |
283 (vm-headers-of message))) b)))) | |
284 (push-mark end) | |
285 (cond (mail-citation-hook (run-hooks 'mail-citation-hook)) | |
286 (mail-yank-hooks (run-hooks 'mail-yank-hooks)) | |
287 (t (vm-mail-yank-default message)))))) | |
288 | |
289 (defun vm-mail-send-and-exit (arg) | |
290 "Just like mail-send-and-exit except that VM flags the appropriate message(s) | |
291 as having been replied to, if appropriate." | |
292 (interactive "P") | |
293 (let ((b (current-buffer))) | |
294 (vm-mail-send) | |
295 (cond ((null (buffer-name b)) ;; dead buffer | |
296 (vm-display nil nil '(vm-mail-send-and-exit) | |
297 '(vm-mail-send-and-exit reading-message startup))) | |
298 (t | |
299 (vm-display b nil '(vm-mail-send-and-exit) | |
300 '(vm-mail-send-and-exit reading-message startup)) | |
301 (vm-bury-buffer b))))) | |
302 | |
303 (defun vm-keep-mail-buffer (buffer) | |
304 ;; keep this buffer if the user demands it | |
305 (if (memq buffer vm-kept-mail-buffers) | |
306 (setq vm-kept-mail-buffers | |
307 (delq buffer vm-kept-mail-buffers))) | |
308 (setq vm-kept-mail-buffers (cons buffer vm-kept-mail-buffers) | |
309 vm-kept-mail-buffers (vm-delete 'buffer-name | |
310 vm-kept-mail-buffers t)) | |
311 (if (not (eq vm-keep-sent-messages t)) | |
312 (let ((extras (nthcdr (or vm-keep-sent-messages 0) | |
313 vm-kept-mail-buffers))) | |
314 (mapcar (function | |
315 (lambda (b) | |
316 (and (buffer-name b) (kill-buffer b)))) | |
317 extras) | |
318 (and vm-kept-mail-buffers extras | |
319 (setcdr (memq (car extras) vm-kept-mail-buffers) nil))))) | |
320 | |
321 (defun vm-help-tale () | |
322 (save-excursion | |
323 (goto-char (point-min)) | |
324 (while (vm-match-header) | |
325 (if (not (vm-match-header "To:\\|Resent-To:\\|Cc:\\|Resent-Cc:")) | |
326 (goto-char (vm-matched-header-end)) | |
327 (goto-char (vm-matched-header-contents-start)) | |
328 (if (re-search-forward "[^, \t][ \t]*\n[ \t\n]+[^ \t\n]" | |
329 (vm-matched-header-contents-end) | |
330 t) | |
331 (error "tale is an idiot, and so are you. :-)")) | |
332 (goto-char (vm-matched-header-end)))))) | |
333 | |
334 (defun vm-mail-send () | |
335 "Just like mail-send except that VM flags the appropriate message(s) | |
336 as replied to, forwarded, etc, if appropriate." | |
337 (interactive) | |
338 (if vm-tale-is-an-idiot | |
339 (vm-help-tale)) | |
340 (if (and vm-confirm-mail-send | |
341 (not (y-or-n-p "Send the message? "))) | |
342 (error "Message not sent.")) | |
343 ;; this to prevent Emacs 19 from asking whether a message that | |
344 ;; has already been sent should be sent again. VM renames mail | |
345 ;; buffers after the message has been sent, so the user should | |
346 ;; already know that the message has been sent. | |
347 (set-buffer-modified-p t) | |
348 ;; don't want a buffer change to occur here | |
349 ;; save-excursion to be sure. | |
350 (save-excursion | |
351 (mail-send)) | |
352 (vm-rename-current-mail-buffer) | |
353 (cond ((eq vm-system-state 'replying) | |
354 (vm-mail-mark-replied)) | |
355 ((eq vm-system-state 'forwarding) | |
356 (vm-mail-mark-forwarded)) | |
357 ((eq vm-system-state 'redistributing) | |
358 (vm-mail-mark-redistributed))) | |
359 (vm-keep-mail-buffer (current-buffer)) | |
360 (vm-display nil nil '(vm-mail-send) '(vm-mail-send))) | |
361 | |
362 (defun vm-rename-current-mail-buffer () | |
363 (if vm-rename-current-buffer-function | |
364 (funcall vm-rename-current-buffer-function) | |
365 (let ((case-fold-search nil)) | |
366 (if (not (string-match "^sent " (buffer-name))) | |
367 (let (prefix name n) | |
368 (if (not (= ?* (aref (buffer-name) 0))) | |
369 (setq prefix (format "sent %s" (buffer-name))) | |
370 (let (recipients) | |
371 (cond ((not (zerop (length (setq recipients | |
372 (mail-fetch-field "To")))))) | |
373 ((not (zerop (length (setq recipients | |
374 (mail-fetch-field "Cc")))))) | |
375 ((not (zerop (length (setq recipients | |
376 (mail-fetch-field "Bcc")))))) | |
377 ; can't happen?!? | |
378 (t (setq recipients "the horse with no name"))) | |
379 (setq prefix (format "sent mail to %s" recipients)))) | |
380 (if (> (length prefix) 44) | |
381 (setq prefix (concat (substring prefix 0 40) " ..."))) | |
382 (setq name prefix n 2) | |
383 (while (get-buffer name) | |
384 (setq name (format "%s<%d>" prefix n)) | |
385 (vm-increment n)) | |
386 (rename-buffer name)))))) | |
387 | |
388 (defun vm-mail-mark-replied () | |
389 (save-excursion | |
390 (let ((mp vm-reply-list)) | |
391 (while mp | |
392 (if (null (buffer-name (vm-buffer-of (car mp)))) | |
393 () | |
394 (set-buffer (vm-buffer-of (car mp))) | |
395 (cond ((and (memq (car mp) vm-message-list) | |
396 (null (vm-replied-flag (car mp)))) | |
397 (vm-set-replied-flag (car mp) t)))) | |
398 (setq mp (cdr mp))) | |
399 (vm-update-summary-and-mode-line)))) | |
400 | |
401 (defun vm-mail-mark-forwarded () | |
402 (save-excursion | |
403 (let ((mp vm-forward-list)) | |
404 (while mp | |
405 (if (null (buffer-name (vm-buffer-of (car mp)))) | |
406 () | |
407 (set-buffer (vm-buffer-of (car mp))) | |
408 (cond ((and (memq (car mp) vm-message-list) | |
409 (null (vm-forwarded-flag (car mp)))) | |
410 (vm-set-forwarded-flag (car mp) t)))) | |
411 (setq mp (cdr mp))) | |
412 (vm-update-summary-and-mode-line)))) | |
413 | |
414 (defun vm-mail-mark-redistributed () | |
415 (save-excursion | |
416 (let ((mp vm-redistribute-list)) | |
417 (while mp | |
418 (if (null (buffer-name (vm-buffer-of (car mp)))) | |
419 () | |
420 (set-buffer (vm-buffer-of (car mp))) | |
421 (cond ((and (memq (car mp) vm-message-list) | |
422 (null (vm-redistributed-flag (car mp)))) | |
423 (vm-set-redistributed-flag (car mp) t)))) | |
424 (setq mp (cdr mp))) | |
425 (vm-update-summary-and-mode-line)))) | |
426 | |
427 (defun vm-reply (count) | |
428 "Reply to the sender of the current message. | |
429 Numeric prefix argument N means to reply to the current message plus the | |
430 next N-1 messages. A negative N means reply to the current message and | |
431 the previous N-1 messages. | |
432 | |
433 If invoked on marked messages (via vm-next-command-uses-marks), | |
434 all marked messages will be replied to. | |
435 | |
436 You will be placed into a standard Emacs Mail mode buffer to compose and | |
437 send your message. See the documentation for the function `mail' for | |
438 more info. | |
439 | |
440 Note that the normal binding of C-c C-y in the reply buffer is | |
441 automatically changed to vm-yank-message during a reply. This | |
442 allows you to yank any message from the current folder into a | |
443 reply. | |
444 | |
445 Normal VM commands may be accessed in the reply buffer by prefixing them | |
446 with C-c C-v." | |
447 (interactive "p") | |
448 (vm-follow-summary-cursor) | |
449 (vm-select-folder-buffer) | |
450 (vm-check-for-killed-summary) | |
451 (vm-error-if-folder-empty) | |
452 (vm-do-reply nil nil count)) | |
453 | |
454 (defun vm-reply-include-text (count) | |
455 "Reply to the sender (only) of the current message and include text | |
456 from the message. See the documentation for function vm-reply for details." | |
457 (interactive "p") | |
458 (vm-follow-summary-cursor) | |
459 (vm-select-folder-buffer) | |
460 (vm-check-for-killed-summary) | |
461 (vm-error-if-folder-empty) | |
462 (vm-do-reply nil t count)) | |
463 | |
464 (defun vm-followup (count) | |
465 "Reply to all recipients of the current message. | |
466 See the documentation for the function vm-reply for details." | |
467 (interactive "p") | |
468 (vm-follow-summary-cursor) | |
469 (vm-select-folder-buffer) | |
470 (vm-check-for-killed-summary) | |
471 (vm-error-if-folder-empty) | |
472 (vm-do-reply t nil count)) | |
473 | |
474 (defun vm-followup-include-text (count) | |
475 "Reply to all recipients of the current message and include text from | |
476 the message. See the documentation for the function vm-reply for details." | |
477 (interactive "p") | |
478 (vm-follow-summary-cursor) | |
479 (vm-select-folder-buffer) | |
480 (vm-check-for-killed-summary) | |
481 (vm-error-if-folder-empty) | |
482 (vm-do-reply t t count)) | |
483 | |
484 (defun vm-forward-message-all-headers () | |
485 "Like vm-forward-message but always forwards all the headers." | |
486 (interactive) | |
487 (let ((vm-forwarded-headers nil) | |
488 (vm-unforwarded-header-regexp "only-drop-this-header")) | |
489 (vm-forward-message))) | |
490 | |
491 (defun vm-forward-message () | |
492 "Forward the current message to one or more recipients. | |
493 You will be placed in a Mail mode buffer as you would with a | |
494 reply, but you must fill in the To: header and perhaps the | |
495 Subject: header manually." | |
496 (interactive) | |
497 (vm-follow-summary-cursor) | |
498 (vm-select-folder-buffer) | |
499 (vm-check-for-killed-summary) | |
500 (vm-error-if-folder-empty) | |
501 (if (eq last-command 'vm-next-command-uses-marks) | |
502 (let ((vm-digest-send-type vm-forwarding-digest-type)) | |
503 (setq this-command 'vm-next-command-uses-marks) | |
504 (command-execute 'vm-send-digest)) | |
505 (let ((dir default-directory) | |
506 (mp vm-message-pointer)) | |
507 (save-restriction | |
508 (widen) | |
509 (vm-mail-internal | |
510 (format "forward of %s's note re: %s" | |
511 (vm-su-full-name (car vm-message-pointer)) | |
512 (vm-su-subject (car vm-message-pointer))) | |
513 nil | |
514 (and vm-forwarding-subject-format | |
515 (let ((vm-summary-uninteresting-senders nil)) | |
516 (vm-sprintf 'vm-forwarding-subject-format (car mp))))) | |
517 (make-local-variable 'vm-forward-list) | |
518 (setq vm-system-state 'forwarding | |
519 vm-forward-list (list (car mp)) | |
520 default-directory dir) | |
521 (goto-char (point-min)) | |
522 (re-search-forward | |
523 (concat "^" (regexp-quote mail-header-separator) "\n") nil 0) | |
524 (cond ((equal vm-forwarding-digest-type "rfc934") | |
525 (vm-rfc934-encapsulate-messages | |
526 vm-forward-list vm-forwarded-headers | |
527 vm-unforwarded-header-regexp)) | |
528 ((equal vm-forwarding-digest-type "rfc1153") | |
529 (vm-rfc1153-encapsulate-messages | |
530 vm-forward-list vm-forwarded-headers | |
531 vm-unforwarded-header-regexp)) | |
532 ((equal vm-forwarding-digest-type nil) | |
533 (vm-no-frills-encapsulate-message | |
534 (car vm-forward-list) vm-forwarded-headers | |
535 vm-unforwarded-header-regexp))) | |
536 (mail-position-on-field "To")) | |
537 (run-hooks 'vm-forward-message-hook) | |
538 (run-hooks 'vm-mail-mode-hook)))) | |
539 | |
540 (defun vm-resend-bounced-message () | |
541 "Extract the original text from a bounced message and resend it. | |
542 You will be placed in a Mail mode buffer with the extracted message and | |
543 you can change the recipient address before resending the message." | |
544 (interactive) | |
545 (vm-follow-summary-cursor) | |
546 (vm-select-folder-buffer) | |
547 (vm-check-for-killed-summary) | |
548 (vm-error-if-folder-empty) | |
549 (let ((b (current-buffer)) start | |
550 (dir default-directory) | |
551 (lim (vm-text-end-of (car vm-message-pointer)))) | |
552 (save-restriction | |
553 (widen) | |
554 (save-excursion | |
555 (goto-char (vm-text-of (car vm-message-pointer))) | |
556 (let ((case-fold-search t)) | |
557 ;; What a wonderful world it would be if mailers used a single | |
558 ;; message encapsulation standard instead all the weird variants | |
559 ;; It is useless to try to cover them all. | |
560 ;; This simple rule should cover the sanest of the formats | |
561 (if (not (re-search-forward "^Received:" lim t)) | |
562 (error "This doesn't look like a bounced message.")) | |
563 (beginning-of-line) | |
564 (setq start (point)))) | |
565 ;; briefly nullify vm-mail-header-from to keep vm-mail-internal | |
566 ;; from inserting another From header. | |
567 (let ((vm-mail-header-from nil)) | |
568 (vm-mail-internal | |
569 (format "retry of bounce from %s" | |
570 (vm-su-from (car vm-message-pointer))))) | |
571 (goto-char (point-min)) | |
572 (insert-buffer-substring b start lim) | |
573 (delete-region (point) (point-max)) | |
574 (goto-char (point-min)) | |
575 ;; delete all but pertinent headers | |
576 (vm-reorder-message-headers nil nil "\\(X-VM-\\|Status:\\|Sender:\\)") | |
577 (vm-reorder-message-headers nil vm-resend-bounced-headers | |
578 vm-resend-bounced-discard-header-regexp) | |
579 (if (search-forward "\n\n" nil t) | |
580 (replace-match "") | |
581 (goto-char (point-max))) | |
582 (insert ?\n mail-header-separator ?\n) | |
583 (mail-position-on-field "To") | |
584 (setq default-directory dir))) | |
585 (run-hooks 'vm-resend-bounced-message-hook) | |
586 (run-hooks 'vm-mail-mode-hook)) | |
587 | |
588 (defun vm-resend-message () | |
589 "Resend the current message to someone else. | |
590 The current message will be copied to a Mail mode buffer and you | |
591 can edit the message and send it as usual. | |
592 | |
593 NOTE: since you are doing a resend, a Resent-To header is | |
594 provided for you to fill in. If you don't fill it in, when you | |
595 send the message it will go to the original recipients listed in | |
596 the To and Cc headers. You may also create a Resent-Cc header." | |
597 (interactive) | |
598 (vm-follow-summary-cursor) | |
599 (vm-select-folder-buffer) | |
600 (vm-check-for-killed-summary) | |
601 (vm-error-if-folder-empty) | |
602 (save-restriction | |
603 (widen) | |
604 (let ((b (current-buffer)) | |
605 (dir default-directory) | |
606 (vmp vm-message-pointer) | |
607 (start (vm-headers-of (car vm-message-pointer))) | |
608 (lim (vm-text-end-of (car vm-message-pointer)))) | |
609 ;; briefly nullify vm-mail-header-from to keep vm-mail-internal | |
610 ;; from inserting another From header. | |
611 (let ((vm-mail-header-from nil)) | |
612 (vm-mail-internal | |
613 (format "resend of %s's note re: %s" | |
614 (vm-su-full-name (car vm-message-pointer)) | |
615 (vm-su-subject (car vm-message-pointer))))) | |
616 (goto-char (point-min)) | |
617 (insert-buffer-substring b start lim) | |
618 (delete-region (point) (point-max)) | |
619 (goto-char (point-min)) | |
620 (if vm-mail-header-from | |
621 (insert "Resent-From: " vm-mail-header-from ?\n)) | |
622 (insert "Resent-To: \n") | |
623 (if mail-self-blind | |
624 (insert "Bcc: " (user-login-name) ?\n)) | |
625 (if mail-archive-file-name | |
626 (insert "FCC: " mail-archive-file-name ?\n)) | |
627 ;; delete all but pertinent headers | |
628 (vm-reorder-message-headers nil nil "\\(X-VM-\\|Status:\\|Sender:\\)") | |
629 (vm-reorder-message-headers nil vm-resend-headers | |
630 vm-resend-discard-header-regexp) | |
631 (if (search-forward "\n\n" nil t) | |
632 (replace-match "")) | |
633 (insert ?\n mail-header-separator ?\n) | |
634 (goto-char (point-min)) | |
635 (mail-position-on-field "Resent-To") | |
636 (make-local-variable 'vm-redistribute-list) | |
637 (setq vm-system-state 'redistributing | |
638 vm-redistribute-list (list (car vmp)) | |
639 default-directory dir) | |
640 (run-hooks 'vm-resend-message-hook) | |
641 (run-hooks 'vm-mail-mode-hook)))) | |
642 | |
643 (defun vm-send-digest (&optional prefix) | |
644 "Send a digest of all messages in the current folder to recipients. | |
645 The type of the digest is specified by the variable vm-digest-send-type. | |
646 You will be placed in a Mail mode buffer as is usual with replies, but you | |
647 must fill in the To: and Subject: headers manually. | |
648 | |
649 Prefix arg means to insert a list of preamble lines at the beginning of | |
650 the digest. One line is generated for each message being digestified. | |
651 The variable vm-digest-preamble-format determines the format of the | |
652 preamble lines. | |
653 | |
654 If invoked on marked messages (via vm-next-command-uses-marks), | |
655 only marked messages will be put into the digest." | |
656 (interactive "P") | |
657 (vm-select-folder-buffer) | |
658 (vm-check-for-killed-summary) | |
659 (vm-error-if-folder-empty) | |
660 (let ((dir default-directory) | |
661 (mp vm-message-pointer) | |
662 ;; prefix arg doesn't have "normal" meaning here, so only call | |
663 ;; vm-select-marked-or-prefixed-messages if we're using marks. | |
664 (mlist (if (eq last-command 'vm-next-command-uses-marks) | |
665 (vm-select-marked-or-prefixed-messages 0) | |
666 vm-message-list)) | |
667 start) | |
668 (save-restriction | |
669 (widen) | |
670 (vm-mail-internal (format "digest from %s" (buffer-name))) | |
671 (make-local-variable 'vm-forward-list) | |
672 (setq vm-system-state 'forwarding | |
673 vm-forward-list mlist | |
674 default-directory dir) | |
675 (goto-char (point-min)) | |
676 (re-search-forward (concat "^" (regexp-quote mail-header-separator) | |
677 "\n")) | |
678 (goto-char (match-end 0)) | |
679 (setq start (point) | |
680 mp mlist) | |
681 (vm-unsaved-message "Building %s digest..." vm-digest-send-type) | |
682 (cond ((equal vm-digest-send-type "rfc934") | |
683 (vm-rfc934-encapsulate-messages | |
684 mlist vm-rfc934-digest-headers | |
685 vm-rfc934-digest-discard-header-regexp)) | |
686 ((equal vm-digest-send-type "rfc1153") | |
687 (vm-rfc1153-encapsulate-messages | |
688 mlist vm-rfc1153-digest-headers | |
689 vm-rfc1153-digest-discard-header-regexp))) | |
690 (goto-char start) | |
691 (setq mp mlist) | |
692 (if prefix | |
693 (progn | |
694 (vm-unsaved-message "Building digest preamble...") | |
695 (while mp | |
696 (let ((vm-summary-uninteresting-senders nil)) | |
697 (insert (vm-sprintf 'vm-digest-preamble-format (car mp)) "\n")) | |
698 (if vm-digest-center-preamble | |
699 (progn | |
700 (forward-char -1) | |
701 (center-line) | |
702 (forward-char 1))) | |
703 (setq mp (cdr mp))))) | |
704 (mail-position-on-field "To") | |
705 (message "Building %s digest... done" vm-digest-send-type))) | |
706 (run-hooks 'vm-send-digest-hook) | |
707 (run-hooks 'vm-mail-mode-hook)) | |
708 | |
709 (defun vm-send-rfc934-digest (&optional preamble) | |
710 "Like vm-send-digest but always sends an RFC 934 digest." | |
711 (interactive "P") | |
712 (let ((vm-digest-send-type "rfc934")) | |
713 (vm-send-digest preamble))) | |
714 | |
715 (defun vm-send-rfc1153-digest (&optional preamble) | |
716 "Like vm-send-digest but always sends an RFC 1153 digest." | |
717 (interactive "P") | |
718 (let ((vm-digest-send-type "rfc1153")) | |
719 (vm-send-digest preamble))) | |
720 | |
721 (defun vm-continue-composing-message (&optional not-picky) | |
722 "Find and select the most recently used mail composition buffer. | |
723 If the selected buffer is already a Mail mode buffer then it is | |
724 buried before beginning the search. Non Mail mode buffers and | |
725 unmodified Mail buffers are skipped. Prefix arg means unmodified | |
726 Mail mode buffers are not skipped. If no suitable buffer is | |
727 found, the current buffer remains selected." | |
728 (interactive "P") | |
729 (if (eq major-mode 'mail-mode) | |
730 (vm-bury-buffer (current-buffer))) | |
731 (let ((b (vm-find-composition-buffer not-picky))) | |
732 (if (not (or (null b) (eq b (current-buffer)))) | |
733 (progn | |
734 ;; avoid having the window configuration code choose a | |
735 ;; different composition buffer. | |
736 (vm-unbury-buffer b) | |
737 (set-buffer b) | |
738 (if (and vm-frame-per-composition (vm-multiple-frames-possible-p) | |
739 ;; only pop up a frame if there's an undisplay | |
740 ;; hook in place to make the frame go away. | |
741 vm-undisplay-buffer-hook) | |
742 (let ((w (vm-get-buffer-window b))) | |
743 (if (null w) | |
744 (vm-goto-new-frame 'composition) | |
745 (select-window w) | |
746 (and vm-warp-mouse-to-new-frame | |
747 (vm-warp-mouse-to-frame-maybe (vm-window-frame w)))) | |
748 ;; need to do this here too, since XEmacs has per | |
749 ;; frame buffer lists. | |
750 (vm-unbury-buffer b) | |
751 (vm-set-hooks-for-frame-deletion))) | |
752 (vm-display b t '(vm-continue-composing-message) | |
753 '(vm-continue-composing-message composing-message))) | |
754 (message "No composition buffers found")))) | |
755 | |
756 ;; to quiet the v19 byte compiler | |
757 (defvar mail-mode-map) | |
758 (defvar mail-aliases) | |
759 (defvar mail-default-reply-to) | |
760 (defvar mail-signature-file) | |
761 | |
762 (defun vm-mail-internal | |
763 (&optional buffer-name to subject in-reply-to cc references newsgroups) | |
764 (let ((folder-buffer nil)) | |
765 (if (memq major-mode '(vm-mode vm-virtual-mode)) | |
766 (setq folder-buffer (current-buffer))) | |
767 (set-buffer (generate-new-buffer (or buffer-name "*VM-mail*"))) | |
768 ;; avoid trying to write auto-save files in potentially | |
769 ;; unwritable directories. | |
770 (setq default-directory (or vm-folder-directory (expand-file-name "~/"))) | |
771 (auto-save-mode (if auto-save-default 1 -1)) | |
772 (mail-mode) | |
773 (use-local-map vm-mail-mode-map) | |
774 ;; make mail-mode-map the parent of this vm-mail-mode-map, if we can. | |
775 ;; do it only once. | |
776 (if (not vm-mail-mode-map-parented) | |
777 (cond ((fboundp 'set-keymap-parents) | |
778 (set-keymap-parents vm-mail-mode-map (list mail-mode-map))) | |
779 ((consp mail-mode-map) | |
780 (nconc vm-mail-mode-map mail-mode-map) | |
781 (setq vm-mail-mode-map-parented t)))) | |
782 (setq vm-mail-buffer folder-buffer | |
783 mode-popup-menu (and vm-use-menus | |
784 (vm-menu-support-possible-p) | |
785 (vm-menu-mode-menu))) | |
786 ;; sets up popup menu for FSF Emacs | |
787 (and vm-use-menus (vm-menu-support-possible-p) | |
788 (vm-menu-install-mail-mode-menu)) | |
789 (if (fboundp 'mail-aliases-setup) ; use mail-abbrevs.el if present | |
790 (mail-aliases-setup) | |
791 (if (eq mail-aliases t) | |
792 (progn | |
793 (setq mail-aliases nil) | |
794 (if (file-exists-p "~/.mailrc") | |
795 (build-mail-aliases))))) | |
796 (if (stringp vm-mail-header-from) | |
797 (insert "From: " vm-mail-header-from "\n")) | |
798 (insert "To: " (or to "") "\n") | |
799 (and cc (insert "Cc: " cc "\n")) | |
800 (insert "Subject: " (or subject "") "\n") | |
801 (and newsgroups (insert "Newsgroups: " newsgroups "\n")) | |
802 (and in-reply-to (insert "In-Reply-To: " in-reply-to "\n")) | |
803 (and references (insert "References: " references "\n")) | |
804 ;; REPLYTO support for FSF Emacs v19.29 | |
805 (and (eq mail-default-reply-to t) | |
806 (setq mail-default-reply-to (getenv "REPLYTO"))) | |
807 (if mail-default-reply-to | |
808 (insert "Reply-To: " mail-default-reply-to "\n")) | |
809 (if mail-self-blind | |
810 (insert "Bcc: " (user-login-name) "\n")) | |
811 (if mail-archive-file-name | |
812 (insert "FCC: " mail-archive-file-name "\n")) | |
813 (if mail-default-headers | |
814 (insert mail-default-headers)) | |
815 (if (not (= (preceding-char) ?\n)) | |
816 (insert ?\n)) | |
817 (insert mail-header-separator "\n") | |
818 (cond ((stringp mail-signature) | |
819 (save-excursion | |
820 (insert mail-signature))) | |
821 ((eq mail-signature t) | |
822 (save-excursion | |
823 (insert "-- \n") | |
824 (insert-file-contents (or (and (boundp 'mail-signature-file) | |
825 (stringp mail-signature-file) | |
826 mail-signature-file) | |
827 "~/.signature"))))) | |
828 ;; move this buffer to the head of the buffer list so window | |
829 ;; config stuff will select it as the composition buffer. | |
830 (vm-unbury-buffer (current-buffer)) | |
831 ;; make a new frame if the user wants it. | |
832 (if (and vm-frame-per-composition (vm-multiple-frames-possible-p)) | |
833 (progn | |
834 (vm-goto-new-frame 'composition) | |
835 (vm-set-hooks-for-frame-deletion))) | |
836 ;; now do window configuration | |
837 (vm-display (current-buffer) t | |
838 '(vm-mail | |
839 vm-mail-other-frame | |
840 vm-mail-other-window | |
841 vm-reply | |
842 vm-reply-other-frame | |
843 vm-reply-include-text | |
844 vm-reply-include-text-other-frame | |
845 vm-followup | |
846 vm-followup-other-frame | |
847 vm-followup-include-text | |
848 vm-followup-include-text-other-frame | |
849 vm-send-digest | |
850 vm-send-digest-other-frame | |
851 vm-send-rfc934-digest | |
852 vm-send-rfc934-digest-other-frame | |
853 vm-send-rfc1153-digest | |
854 vm-send-rfc1153-digest-other-frame | |
855 vm-forward-message | |
856 vm-forward-message-other-frame | |
857 vm-forward-message-all-headers | |
858 vm-forward-message-all-headers-other-frame | |
859 vm-resend-message | |
860 vm-resend-message-other-frame | |
861 vm-resend-bounced-message | |
862 vm-resend-bounced-message-other-frame) | |
863 (list this-command 'composing-message)) | |
864 (if (null to) | |
865 (mail-position-on-field "To")) | |
866 (run-hooks 'mail-setup-hook))) | |
867 | |
868 (defun vm-reply-other-frame (count) | |
869 "Like vm-reply, but run in a newly created frame." | |
870 (interactive "p") | |
871 (if (vm-multiple-frames-possible-p) | |
872 (vm-goto-new-frame 'composition)) | |
873 (let ((vm-frame-per-composition nil) | |
874 (vm-search-other-frames nil)) | |
875 (vm-reply count)) | |
876 (if (vm-multiple-frames-possible-p) | |
877 (vm-set-hooks-for-frame-deletion))) | |
878 | |
879 (defun vm-reply-include-text-other-frame (count) | |
880 "Like vm-reply-include-text, but run in a newly created frame." | |
881 (interactive "p") | |
882 (if (vm-multiple-frames-possible-p) | |
883 (vm-goto-new-frame 'composition)) | |
884 (let ((vm-frame-per-composition nil) | |
885 (vm-search-other-frames nil)) | |
886 (vm-reply-include-text count)) | |
887 (if (vm-multiple-frames-possible-p) | |
888 (vm-set-hooks-for-frame-deletion))) | |
889 | |
890 (defun vm-followup-other-frame (count) | |
891 "Like vm-followup, but run in a newly created frame." | |
892 (interactive "p") | |
893 (if (vm-multiple-frames-possible-p) | |
894 (vm-goto-new-frame 'composition)) | |
895 (let ((vm-frame-per-composition nil) | |
896 (vm-search-other-frames nil)) | |
897 (vm-followup count)) | |
898 (if (vm-multiple-frames-possible-p) | |
899 (vm-set-hooks-for-frame-deletion))) | |
900 | |
901 (defun vm-followup-include-text-other-frame (count) | |
902 "Like vm-followup-include-text, but run in a newly created frame." | |
903 (interactive "p") | |
904 (if (vm-multiple-frames-possible-p) | |
905 (vm-goto-new-frame 'composition)) | |
906 (let ((vm-frame-per-composition nil) | |
907 (vm-search-other-frames nil)) | |
908 (vm-followup-include-text count)) | |
909 (if (vm-multiple-frames-possible-p) | |
910 (vm-set-hooks-for-frame-deletion))) | |
911 | |
912 (defun vm-forward-message-all-headers-other-frame () | |
913 "Like vm-forward-message-all-headers, but run in a newly created frame." | |
914 (interactive) | |
915 (if (vm-multiple-frames-possible-p) | |
916 (vm-goto-new-frame 'composition)) | |
917 (let ((vm-frame-per-composition nil) | |
918 (vm-search-other-frames nil)) | |
919 (vm-forward-message-all-headers)) | |
920 (if (vm-multiple-frames-possible-p) | |
921 (vm-set-hooks-for-frame-deletion))) | |
922 | |
923 (defun vm-forward-message-other-frame () | |
924 "Like vm-forward-message, but run in a newly created frame." | |
925 (interactive) | |
926 (if (vm-multiple-frames-possible-p) | |
927 (vm-goto-new-frame 'composition)) | |
928 (let ((vm-frame-per-composition nil) | |
929 (vm-search-other-frames nil)) | |
930 (vm-forward-message)) | |
931 (if (vm-multiple-frames-possible-p) | |
932 (vm-set-hooks-for-frame-deletion))) | |
933 | |
934 (defun vm-resend-message-other-frame () | |
935 "Like vm-resend-message, but run in a newly created frame." | |
936 (interactive) | |
937 (if (vm-multiple-frames-possible-p) | |
938 (vm-goto-new-frame 'composition)) | |
939 (let ((vm-frame-per-composition nil) | |
940 (vm-search-other-frames nil)) | |
941 (vm-resend-message)) | |
942 (if (vm-multiple-frames-possible-p) | |
943 (vm-set-hooks-for-frame-deletion))) | |
944 | |
945 (defun vm-resend-bounced-message-other-frame () | |
946 "Like vm-resend-bounced-message, but run in a newly created frame." | |
947 (interactive) | |
948 (if (vm-multiple-frames-possible-p) | |
949 (vm-goto-new-frame 'composition)) | |
950 (let ((vm-frame-per-composition nil) | |
951 (vm-search-other-frames nil)) | |
952 (vm-resend-bounced-message)) | |
953 (if (vm-multiple-frames-possible-p) | |
954 (vm-set-hooks-for-frame-deletion))) | |
955 | |
956 (defun vm-send-digest-other-frame (&optional prefix) | |
957 "Like vm-send-digest, but run in a newly created frame." | |
958 (interactive "P") | |
959 (if (vm-multiple-frames-possible-p) | |
960 (vm-goto-new-frame 'composition)) | |
961 (let ((vm-frame-per-composition nil) | |
962 (vm-search-other-frames nil)) | |
963 (vm-send-digest prefix)) | |
964 (if (vm-multiple-frames-possible-p) | |
965 (vm-set-hooks-for-frame-deletion))) | |
966 | |
967 (defun vm-send-rfc934-digest-other-frame (&optional prefix) | |
968 "Like vm-send-rfc934-digest, but run in a newly created frame." | |
969 (interactive "P") | |
970 (if (vm-multiple-frames-possible-p) | |
971 (vm-goto-new-frame 'composition)) | |
972 (let ((vm-frame-per-composition nil) | |
973 (vm-search-other-frames nil)) | |
974 (vm-send-rfc934-digest prefix)) | |
975 (if (vm-multiple-frames-possible-p) | |
976 (vm-set-hooks-for-frame-deletion))) | |
977 | |
978 (defun vm-send-rfc1153-digest-other-frame (&optional prefix) | |
979 "Like vm-send-rfc1153-digest, but run in a newly created frame." | |
980 (interactive "P") | |
981 (if (vm-multiple-frames-possible-p) | |
982 (vm-goto-new-frame 'composition)) | |
983 (let ((vm-frame-per-composition nil) | |
984 (vm-search-other-frames nil)) | |
985 (vm-send-rfc1153-digest prefix)) | |
986 (if (vm-multiple-frames-possible-p) | |
987 (vm-set-hooks-for-frame-deletion))) |