1 ;;; vm-reply.el --- Mailing, forwarding, and replying commands
3 ;; Copyright (C) 1989-2001 Kyle E. Jones
4 ;; Copyright (C) 2003-2006 Robert Widhopf-Fenk
6 ;; This program is free software; you can redistribute it and/or modify
7 ;; it under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation; either version 2 of the License, or
9 ;; (at your option) any later version.
11 ;; This program is distributed in the hope that it will be useful,
12 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;; GNU General Public License for more details.
16 ;; You should have received a copy of the GNU General Public License along
17 ;; with this program; if not, write to the Free Software Foundation, Inc.,
18 ;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 (defun vm-add-reply-subject-prefix (message &optional start)
25 (goto-char (point-min))
26 (re-search-forward (regexp-quote mail-header-separator) (point-max))
30 (if (and message vm-included-text-attribution-format)
31 (let ((vm-summary-uninteresting-senders nil))
32 (insert (vm-summary-sprintf
33 vm-included-text-attribution-format
35 (while (re-search-forward "^" (point-max) t)
36 (insert vm-included-text-prefix)))
39 (defun vm-do-reply (to-all include-text count)
40 (let ((mlist (vm-select-marked-or-prefixed-messages count))
41 (dir default-directory)
42 (message-pointer vm-message-pointer)
44 to cc subject in-reply-to references
45 mp tmp tmp2 newsgroups)
48 (cond ((add-to-list 'to
50 (vm-get-header-contents (car mp) "Reply-To:"
52 (if (vm-ignored-reply-to reply-to)
55 ((add-to-list 'to (vm-get-header-contents (car mp) "From:"
57 ;; bad, but better than nothing for some
58 ((add-to-list 'to (vm-grok-From_-author (car mp))))
59 (t (error "No From: or Reply-To: header in message")))
61 (let ((this-subject (vm-get-header-contents (car mp) "Subject:"))
62 (this-reply-to (and vm-in-reply-to-format
63 (let ((vm-summary-uninteresting-senders nil))
64 (vm-summary-sprintf vm-in-reply-to-format
66 (if (and this-subject vm-reply-subject-prefix
67 (not (string-match vm-reply-subject-prefix this-subject)))
68 (setq this-subject (concat vm-reply-subject-prefix
72 (setq subject (concat this-subject
74 (format " [and %d more messages]"
75 (length (cdr mlist)))))))
76 (setq in-reply-to (if in-reply-to
77 (concat in-reply-to ",\n\t" this-reply-to)
80 (cond ((setq tmp (vm-get-header-contents (car mp) "Reply-To:" ", "))
81 (if (not (vm-ignored-reply-to tmp))
82 (add-to-list 'to tmp)))
83 ((setq tmp (vm-get-header-contents (car mp) "From:" ", "))
84 (add-to-list 'to tmp))
85 ;; bad, but better than nothing for some
86 ((setq tmp (vm-grok-From_-author (car mp)))
87 (add-to-list 'to tmp))
88 (t (error "No From: or Reply-To: header in message")))
92 (setq tmp (vm-get-header-contents (car mp) "To:" ", "))
93 (setq tmp2 (vm-get-header-contents (car mp) "Cc:" ", "))
96 (setq cc (concat cc "," tmp))
100 (setq cc (concat cc "," tmp2))
103 (cons (or (vm-get-header-contents (car mp) "References:" " ")
104 (vm-get-header-contents (car mp) "In-reply-to:" " "))
105 (cons (vm-get-header-contents (car mp) "Message-ID:" " ")
108 (cons (or (and to-all
109 (vm-get-header-contents (car mp)
111 (vm-get-header-contents (car mp) "Newsgroups:" ","))
119 (setq tmp (concat tmp ", " (car to)))
123 (if vm-strip-reply-headers
124 (let ((mail-use-rfc822 t))
125 (and to (setq to (mail-strip-quoted-names to)))
126 (and cc (setq cc (mail-strip-quoted-names cc)))))
127 (setq to (vm-parse-addresses to)
128 cc (vm-parse-addresses cc))
129 (if vm-reply-ignored-addresses
130 (setq to (vm-strip-ignored-addresses to)
131 cc (vm-strip-ignored-addresses cc)))
132 (setq to (vm-delete-duplicates to nil t))
133 (setq cc (vm-delete-duplicates
134 (append (vm-delete-duplicates cc nil t)
135 to (copy-sequence to))
137 (and to (setq to (mapconcat 'identity to ",\n ")))
138 (and cc (setq cc (mapconcat 'identity cc ",\n ")))
139 (and (null to) (setq to cc cc nil))
140 (setq references (delq nil references)
141 references (mapconcat 'identity references " ")
142 references (vm-parse references "[^<]*\\(<[^>]+>\\)")
143 references (vm-delete-duplicates references)
144 references (if references (mapconcat 'identity references "\n\t")))
145 (setq newsgroups (delq nil newsgroups)
146 newsgroups (mapconcat 'identity newsgroups ",")
147 newsgroups (vm-parse newsgroups "[ \t\f\r\n,]*\\([^ \t\f\r\n,]+\\)")
148 newsgroups (vm-delete-duplicates newsgroups)
149 newsgroups (if newsgroups (mapconcat 'identity newsgroups ",")))
151 (format "reply to %s%s" (vm-su-full-name (car mlist))
152 (if (cdr mlist) ", ..." ""))
153 to subject in-reply-to cc references newsgroups)
154 (make-local-variable 'vm-reply-list)
155 (setq vm-system-state 'replying
157 default-directory dir)
160 (goto-char (point-min))
161 (let ((case-fold-search nil))
163 (concat "^" (regexp-quote mail-header-separator) "$") nil 0))
167 (narrow-to-region (point) (point))
168 (vm-yank-message (car mlist))
169 (goto-char (point-max)))
170 (setq mlist (cdr mlist)))))
171 (run-hooks 'vm-reply-hook)
172 (run-hooks 'vm-mail-mode-hook)))
174 (defun vm-strip-ignored-addresses (addresses)
175 (setq addresses (copy-sequence addresses))
176 (let (re-list list addr-list)
177 (setq re-list vm-reply-ignored-addresses)
179 (setq addr-list addresses)
181 (if (string-match (car re-list) (car addr-list))
182 (setq addresses (delq (car addr-list) addresses)))
183 (setq addr-list (cdr addr-list)))
184 (setq re-list (cdr re-list))))
187 (defun vm-ignored-reply-to (reply-to)
188 (if (and reply-to (not (string= reply-to "")))
189 (let (re-list result)
190 (setq re-list vm-reply-ignored-reply-tos)
192 (if (string-match (car re-list) reply-to)
193 (setq result t re-list nil)
194 (setq re-list (cdr re-list))))
198 (defun vm-mail-yank-default (&optional message)
200 (vm-reorder-message-headers nil vm-included-text-headers
201 vm-included-text-discard-header-regexp)
202 ;; if all the headers are gone, delete the trailing blank line, too.
203 (if (eq (following-char) ?\n)
205 (if (and message vm-included-text-attribution-format)
206 (let ((vm-summary-uninteresting-senders nil))
207 (insert (vm-summary-sprintf vm-included-text-attribution-format
209 ; turn off zmacs-regions for Lucid Emacs 19
210 ; and get around transient-mark-mode in FSF Emacs 19
211 ; all this so that (mark) does what it did in v18, sheesh.
212 (let* ((zmacs-regions nil)
213 (mark-even-if-inactive t)
215 (while (< (point) end)
216 (insert vm-included-text-prefix)
220 (defun vm-yank-message-other-folder (folder)
221 "Like vm-yank-message except the message is yanked from a folder other
222 than the one that spawned the current Mail mode buffer. The name of the
223 folder is read from the minibuffer.
225 Don't call this function from a program."
228 (let ((dir (if vm-folder-directory
229 (expand-file-name vm-folder-directory)
231 (last-command last-command)
232 (this-command this-command))
233 (read-file-name "Yank from folder: " dir nil t))))
234 (let ((b (current-buffer)) newbuf sumbuf default result prompt mp)
235 (set-buffer (or (vm-get-file-buffer folder) (find-file-noselect folder)))
236 (setq newbuf (current-buffer))
237 (if (not (eq major-mode 'vm-mode))
239 (if vm-presentation-buffer-handle
240 (vm-bury-buffer vm-presentation-buffer-handle))
241 (if (null vm-message-pointer)
242 (error "No messages in folder %s" folder))
243 (setq default (vm-number-of (car vm-message-pointer)))
245 (save-window-excursion
246 (save-window-excursion
248 (vm-display vm-summary-buffer t '(vm-yank-message-other-folder)
249 '(vm-yank-message-other-folder composing-message))
250 (setq sumbuf (current-buffer))
251 (setq prompt (format "Yank message number: (default %s) " default)
253 (while (zerop result)
254 (setq result (read-string prompt))
255 (and (string= result "") default (setq result default))
256 (setq result (string-to-number result)))
257 (if (null (setq mp (nthcdr (1- result) vm-message-list)))
258 (error "No such message."))))
261 (let ((vm-mail-buffer newbuf))
262 (vm-yank-message (car mp)))
263 (vm-bury-buffer newbuf)
264 (vm-bury-buffer sumbuf))))
267 (defun vm-yank-message (message)
268 "Yank message number N into the current buffer at point.
269 When called interactively N is always read from the minibuffer. When
270 called non-interactively the first argument is expected to be a
273 This command is meant to be used in VM created Mail mode buffers; the
274 yanked message comes from the mail buffer containing the message you
275 are replying to, forwarding, or invoked VM's mail command from.
277 All message headers are yanked along with the text. Point is
278 left before the inserted text, the mark after. Any hook
279 functions bound to `mail-citation-hook' are run, after inserting
280 the text and setting point and mark. For backward compatibility,
281 if mail-citation-hook is set to nil, `mail-yank-hooks' is run
284 If mail-citation-hook and mail-yank-hooks are both nil, this
285 default action is taken: the yanked headers are trimmed as
286 specified by `vm-included-text-headers' and
287 `vm-included-text-discard-header-regexp', and the value of
288 `vm-included-text-prefix' is prepended to every yanked line."
291 ;; What we really want for the first argument is a message struct,
292 ;; but if called interactively, we let the user type in a message
297 (last-command last-command)
298 (this-command this-command))
300 (vm-select-folder-buffer)
301 (setq default (and vm-message-pointer
302 (vm-number-of (car vm-message-pointer)))
304 (format "Yank message number: (default %s) "
306 "Yank message number: "))
307 (while (zerop result)
308 (setq result (read-string prompt))
309 (and (string= result "") default (setq result default))
310 (setq result (string-to-number result)))
311 (if (null (setq mp (nthcdr (1- result) vm-message-list)))
312 (error "No such message.")))
314 (if (not (bufferp vm-mail-buffer))
315 (error "This is not a VM Mail mode buffer."))
316 (if (null (buffer-name vm-mail-buffer))
317 (error "The folder buffer containing message %d has been killed."
318 (vm-number-of message)))
319 (vm-display nil nil '(vm-yank-message) '(vm-yank-message composing-message))
320 (setq message (vm-real-message-of message))
321 (let ((b (current-buffer)) (start (point)) end insert-start)
325 (if vm-reply-include-presentation
328 (vm-select-folder-buffer)
329 ;; ensure the current message is presented
330 (vm-show-current-message)
331 (vm-select-folder-buffer)
332 (if vm-presentation-buffer
333 (set-buffer vm-presentation-buffer))
334 (vm-buffer-substring-no-properties (point-min) (point-max)))))
336 (setq end (point-marker)))
337 (if (vectorp (vm-mm-layout message))
338 (let* ((o (vm-mm-layout message))
340 (type (car (vm-mm-layout-type o)))
343 (vm-insert-region-from-buffer (vm-buffer-of message)
344 (vm-headers-of message)
345 (vm-text-of message))
347 (setq layout (car parts))
348 (cond ((vm-mime-text-type-layout-p layout)
349 (if (cond ((vm-mime-types-match
351 (car (vm-mm-layout-type layout)))
352 (vm-mime-display-internal-text/enriched
354 ((vm-mime-types-match
356 (car (vm-mm-layout-type layout)))
357 (vm-mime-display-internal-message/rfc822
359 ;; no text/html for now
360 ;; ((vm-mime-types-match
362 ;; (car (vm-mm-layout-type layout)))
363 ;; (vm-mime-display-internal-text/html
365 ((member (downcase (car (vm-mm-layout-type
367 vm-included-mime-types-list)
368 (vm-mime-display-internal-text/plain
370 ;; convert the layout if possible
371 ((and (not (vm-mm-layout-is-converted layout))
372 (vm-mime-can-convert (car (vm-mm-layout-type
375 (vm-mime-convert-undisplayable-layout
377 (vm-decode-mime-layout new-layout)))
378 ;; we have found a part to insert, thus skip the
379 ;; remaining alternatives
380 (while (> alternatives 1)
381 (setq parts (cdr parts)
382 alternatives (1- alternatives)))
384 (if (not (member (downcase (car (vm-mm-layout-type
386 vm-included-mime-types-list))
388 ;; charset problems probably
389 ;; just dump the raw bits
390 (setq insert-start (point))
391 (vm-mime-insert-mime-body layout)
392 (vm-mime-transfer-decode-region layout
395 (setq alternatives (1- alternatives))
396 (setq parts (cdr parts)))
397 ;; burst composite types
398 ((vm-mime-composite-type-p
399 (car (vm-mm-layout-type layout)))
400 (setq alternatives (length (vm-mm-layout-parts (car parts))))
401 (setq parts (nconc (copy-sequence
405 ;; skip non-text parts
407 (setq alternatives (1- alternatives))
408 (setq parts (cdr parts)))))
409 (setq end (point-marker)))
410 (set-buffer (vm-buffer-of message))
413 ;; decode MIME encoded words so supercite and other
414 ;; mail-citation-hook denizens won't have to eat 'em.
415 (append-to-buffer b (vm-headers-of message)
416 (vm-text-end-of message))
418 (setq end (point-marker))
419 (if vm-display-using-mime
421 (narrow-to-region start end)
422 (vm-decode-mime-encoded-words)))))))
423 ;; get rid of read-only text properties on the text, as
424 ;; they will only cause trouble.
425 (let ((inhibit-read-only t))
426 (remove-text-properties (point-min) (point-max)
427 '(read-only nil invisible nil)
430 ;; decode MIME encoded words so supercite and other
431 ;; mail-citation-hook denizens won't have to eat 'em.
432 (if vm-display-using-mime
434 (narrow-to-region start end)
435 (vm-decode-mime-encoded-words))))
438 (cond (mail-citation-hook (run-hooks 'mail-citation-hook))
439 (mail-yank-hooks (run-hooks 'mail-yank-hooks))
440 (t (vm-mail-yank-default message)))))
443 (defun vm-mail-send-and-exit (&rest ignored)
444 "Send message and maybe delete the composition buffer.
445 The value of `vm-keep-sent-mesages' determines whether the composition buffer
446 is deleted. If the composition is a reply to a message in a currently visited
447 folder, that message is marked as having been replied to."
449 (vm-check-for-killed-folder)
450 (if (and (boundp 'mail-alias-file)
452 (not (eq (user-uid) 0)))
453 (error "Must be superuser to use mail-alias-file. Please set mail-alias-file to nil."))
454 (let ((b (current-buffer)))
456 (cond ((null (buffer-name b)) ;; dead buffer
457 ;; This improves window configuration behavior in
458 ;; XEmacs. It avoids taking the folder buffer from
459 ;; one frame and attaching it to the selected frame.
460 (set-buffer (window-buffer (selected-window)))
461 (vm-display nil nil '(vm-mail-send-and-exit)
462 '(vm-mail-send-and-exit
466 (vm-display b nil '(vm-mail-send-and-exit)
467 '(vm-mail-send-and-exit reading-message startup))
468 (vm-bury-buffer b)))))
470 (defun vm-keep-mail-buffer (buffer)
471 (vm-keep-some-buffers buffer 'vm-kept-mail-buffers vm-keep-sent-messages))
473 (defun vm-help-tale ()
475 (goto-char (point-min))
476 (while (vm-match-header)
477 (if (not (vm-match-header "To:\\|Resent-To:\\|Cc:\\|Resent-Cc:"))
478 (goto-char (vm-matched-header-end))
479 (goto-char (vm-matched-header-contents-start))
480 (if (re-search-forward "[^, \t][ \t]*\n[ \t\n]+[^ \t\n]"
481 (vm-matched-header-contents-end)
483 (error "tale is an idiot, and so are you. :-)"))
484 (goto-char (vm-matched-header-end))))))
486 (defun vm-mail-mode-insert-message-id-maybe ()
487 (if (not vm-mail-header-insert-message-id)
492 (if (or (vm-mail-mode-get-header-contents "Resent-To:")
493 (vm-mail-mode-get-header-contents "Resent-Cc:")
494 (vm-mail-mode-get-header-contents "Resent-Bcc:"))
496 (vm-mail-mode-remove-header "Resent-Message-ID:")
498 (vm-mail-mode-remove-header "Message-ID:"))
500 (goto-char (point-min))
501 (insert (format "%sMessage-ID: %s\n"
502 (if resent "Resent-" "")
503 (vm-make-message-id))))))))
505 (defun vm-mail-mode-insert-date-maybe ()
506 (if (not vm-mail-header-insert-date)
510 (let* ((timezone (car (current-time-zone)))
511 (hour (/ timezone 3600))
512 (min (/ (- timezone (* hour 3600)) 60))
513 (time (current-time))
515 (if (or (vm-mail-mode-get-header-contents "Resent-To:")
516 (vm-mail-mode-get-header-contents "Resent-Cc:")
517 (vm-mail-mode-get-header-contents "Resent-Bcc:"))
519 (vm-mail-mode-remove-header "Resent-Date:")
521 (vm-mail-mode-remove-header "Date:"))
523 (goto-char (point-min))
524 (insert (format "%sDate: " (if resent "Resent-" ""))
526 (car (nth (string-to-number (format-time-string "%w" time))
529 ;; %e generated " 2". Go from string to int
530 ;; to string to get rid of the blank.
533 (format-time-string "%e" time)))
537 (1- (string-to-number (format-time-string "%m" time)))
539 (format-time-string " %Y %H:%M:%S" time)
540 (format " %s%02d%02d"
541 (if (< timezone 0) "-" "+")
544 ;; localization in Europe and elsewhere can cause %Z to return
545 ;; 8-bit chars, which are forbidden in headers.
546 ;; (format-time-string " (%Z)" time)
549 (defun vm-mail-mode-remove-message-id-maybe ()
550 (if vm-mail-header-insert-message-id
552 (if (or (vm-mail-mode-get-header-contents "Resent-To:")
553 (vm-mail-mode-get-header-contents "Resent-Cc:")
554 (vm-mail-mode-get-header-contents "Resent-Bcc:"))
556 (vm-mail-mode-remove-header "Resent-Message-ID:")
558 (vm-mail-mode-remove-header "Message-ID:")))))
560 (defun vm-mail-mode-remove-date-maybe ()
561 (if vm-mail-header-insert-date
563 (if (or (vm-mail-mode-get-header-contents "Resent-To:")
564 (vm-mail-mode-get-header-contents "Resent-Cc:")
565 (vm-mail-mode-get-header-contents "Resent-Bcc:"))
567 (vm-mail-mode-remove-header "Resent-Date:")
569 (vm-mail-mode-remove-header "Date:")))))
571 (defvar vm-dont-ask-coding-system-question nil)
573 (cond ((and vm-fsfemacs-mule-p
574 (fboundp 'select-message-coding-system)
575 (not (fboundp 'vm-old-select-message-coding-system)))
576 (fset 'vm-old-select-message-coding-system
577 (symbol-function 'select-message-coding-system))
578 (defun select-message-coding-system (&rest ignored)
579 (if vm-dont-ask-coding-system-question
581 (apply 'vm-old-select-message-coding-system ignored)))))
583 (defvar select-safe-coding-system-function)
585 (defvar coding-system-for-write)
588 (defun vm-mail-send ()
589 "Just like mail-send except that VM flags the appropriate message(s)
590 as replied to, forwarded, etc, if appropriate."
592 (if vm-tale-is-an-idiot
594 ;; protect value of this-command from minibuffer read
595 (let ((this-command this-command))
596 (if (and vm-confirm-mail-send
597 (not (y-or-n-p "Send the message? ")))
598 (error "Message not sent.")))
599 (save-excursion (run-hooks 'vm-mail-send-hook))
600 (vm-mail-mode-insert-date-maybe)
601 (vm-mail-mode-insert-message-id-maybe)
602 ;; send mail using MIME if user requests it and if the buffer
603 ;; has not already been MIME encoded.
604 (if (and vm-send-using-mime
605 (null (vm-mail-mode-get-header-contents "MIME-Version:")))
606 (vm-mime-encode-composition))
607 ;; this to prevent Emacs 19 from asking whether a message that
608 ;; has already been sent should be sent again. VM renames mail
609 ;; buffers after the message has been sent, so the user should
610 ;; already know that the message has been sent.
611 (set-buffer-modified-p t)
612 (let ((composition-buffer (current-buffer))
613 ;; preserve these in case the composition buffer gets
615 (vm-reply-list vm-reply-list)
616 (vm-forward-list vm-forward-list)
617 (vm-redistribute-list vm-redistribute-list))
618 ;; fragment message using message/partial if it is too big.
619 (if (and vm-send-using-mime
620 (integerp vm-mime-max-message-size)
621 (> (buffer-size) vm-mime-max-message-size))
623 (setq list (vm-mime-fragment-composition vm-mime-max-message-size))
626 (set-buffer (car list))
628 (kill-buffer (car list)))
629 (setq list (cdr list)))
630 ;; what mail-send would have done
631 (set-buffer-modified-p nil))
632 ;; don't want a buffer change to occur here
633 ;; save-excursion to be sure.
635 ;; also protect value of this-command from minibuffer reads
636 (let ((this-command this-command)
637 ;; set up coding-system-for-write so that FCC uses
638 ;; the correct coding system to save the message into
640 (coding-system-for-write
641 (if (stringp mail-archive-file-name)
642 (vm-get-file-line-ending-coding-system
643 mail-archive-file-name)
644 (and (boundp 'coding-system-for-write)
645 coding-system-for-write)))
647 (mail-send-nonascii t)
648 (sendmail-coding-system (vm-binary-coding-system))
649 (vm-dont-ask-coding-system-question t)
650 (select-safe-coding-system-function nil))
653 ;; be careful, something could have killed the composition
654 ;; buffer inside mail-send.
655 (if (eq (current-buffer) composition-buffer)
657 (cond ((eq vm-system-state 'replying)
658 (vm-mail-mark-replied))
659 ((eq vm-system-state 'forwarding)
660 (vm-mail-mark-forwarded))
661 ((eq vm-system-state 'redistributing)
662 (vm-mail-mark-redistributed)))
663 (vm-rename-current-mail-buffer)
664 (vm-keep-mail-buffer (current-buffer))))
665 (vm-display nil nil '(vm-mail-send) '(vm-mail-send))))
668 (defun vm-mail-mode-get-header-contents (header-name-regexp)
670 (setq regexp (concat "^\\(" header-name-regexp "\\)\\|\\(^"
671 (regexp-quote mail-header-separator) "$\\)"))
675 (goto-char (point-min))
676 (let ((case-fold-search t))
677 (if (and (re-search-forward regexp nil t)
679 (progn (goto-char (match-beginning 0))
681 (vm-matched-header-contents)
685 (defun vm-mail-mode-remove-header (header-name-regexp)
687 (setq regexp (concat "^\\(" header-name-regexp "\\)\\|\\(^"
688 (regexp-quote mail-header-separator) "$\\)"))
692 (goto-char (point-min))
693 (let ((case-fold-search t))
694 (if (and (re-search-forward regexp nil t)
696 (progn (goto-char (match-beginning 0))
698 (delete-region (vm-matched-header-start) (vm-matched-header-end))
701 (defun vm-rename-current-mail-buffer ()
702 (if vm-rename-current-buffer-function
703 (funcall vm-rename-current-buffer-function)
704 (let ((case-fold-search nil))
705 (if (not (string-match "^sent " (buffer-name)))
707 (if (not (string-match "^mail to \\?" (buffer-name)))
708 (setq prefix (format "sent %s" (buffer-name)))
710 (cond ((not (zerop (length (setq recipients
711 (mail-fetch-field "To"))))))
712 ((not (zerop (length (setq recipients
713 (mail-fetch-field "Cc"))))))
714 ((not (zerop (length (setq recipients
715 (mail-fetch-field "Bcc"))))))
717 (t (setq recipients "the horse with no name")))
718 (setq prefix (format "sent mail to %s" recipients))))
719 (if (> (length prefix) 44)
720 (setq prefix (concat (substring prefix 0 40) " ...")))
721 (setq name prefix n 2)
722 (while (get-buffer name)
723 (setq name (format "%s<%d>" prefix n))
725 (rename-buffer name))))))
727 (defun vm-mail-mark-replied ()
729 (let ((mp vm-reply-list))
731 (if (null (buffer-name (vm-buffer-of (car mp))))
733 (set-buffer (vm-buffer-of (car mp)))
734 (cond ((and (memq (car mp) vm-message-list)
735 (null (vm-replied-flag (car mp))))
736 (vm-set-replied-flag (car mp) t))))
738 (vm-update-summary-and-mode-line))))
740 (defun vm-mail-mark-forwarded ()
742 (let ((mp vm-forward-list))
744 (if (null (buffer-name (vm-buffer-of (car mp))))
746 (set-buffer (vm-buffer-of (car mp)))
747 (cond ((and (memq (car mp) vm-message-list)
748 (null (vm-forwarded-flag (car mp))))
749 (vm-set-forwarded-flag (car mp) t))))
751 (vm-update-summary-and-mode-line))))
753 (defun vm-mail-mark-redistributed ()
755 (let ((mp vm-redistribute-list))
757 (if (null (buffer-name (vm-buffer-of (car mp))))
759 (set-buffer (vm-buffer-of (car mp)))
760 (cond ((and (memq (car mp) vm-message-list)
761 (null (vm-redistributed-flag (car mp))))
762 (vm-set-redistributed-flag (car mp) t))))
764 (vm-update-summary-and-mode-line))))
767 (defun vm-reply (count)
768 "Reply to the sender of the current message.
769 Numeric prefix argument N means to reply to the current message plus the
770 next N-1 messages. A negative N means reply to the current message and
771 the previous N-1 messages.
773 If invoked on marked messages (via vm-next-command-uses-marks),
774 all marked messages will be replied to.
776 You will be placed into a standard Emacs Mail mode buffer to compose and
777 send your message. See the documentation for the function `mail' for
780 Note that the normal binding of C-c C-y in the reply buffer is
781 automatically changed to vm-yank-message during a reply. This
782 allows you to yank any message from the current folder into a
785 Normal VM commands may be accessed in the reply buffer by prefixing them
788 (vm-follow-summary-cursor)
789 (vm-select-folder-buffer)
790 (vm-check-for-killed-summary)
791 (vm-error-if-folder-empty)
792 (vm-do-reply nil nil count))
795 (defun vm-reply-include-text (count)
796 "Reply to the sender (only) of the current message and include text
797 from the message. See the documentation for function vm-reply for details."
799 (vm-follow-summary-cursor)
800 (vm-select-folder-buffer)
801 (vm-check-for-killed-summary)
802 (vm-error-if-folder-empty)
803 (vm-do-reply nil t count))
806 (defun vm-followup (count)
807 "Reply to all recipients of the current message.
808 See the documentation for the function vm-reply for details."
810 (vm-follow-summary-cursor)
811 (vm-select-folder-buffer)
812 (vm-check-for-killed-summary)
813 (vm-error-if-folder-empty)
814 (vm-do-reply t nil count))
817 (defun vm-followup-include-text (count)
818 "Reply to all recipients of the current message and include text from
819 the message. See the documentation for the function vm-reply for details."
821 (vm-follow-summary-cursor)
822 (vm-select-folder-buffer)
823 (vm-check-for-killed-summary)
824 (vm-error-if-folder-empty)
825 (vm-do-reply t t count))
828 (defun vm-forward-message-all-headers ()
829 "Like vm-forward-message but always forwards all the headers."
831 (let ((vm-forwarded-headers nil)
832 (vm-unforwarded-header-regexp "only-drop-this-header")
833 ;; set these because vm-forward-message calls vm-send-digest
834 ;; if there is more than one message to be forwarded.
835 (vm-rfc934-digest-headers nil)
836 (vm-rfc934-digest-discard-header-regexp "only-drop-this-header")
837 (vm-rfc1153-digest-headers nil)
838 (vm-rfc1153-digest-discard-header-regexp "only-drop-this-header")
839 (vm-mime-digest-headers nil)
840 (vm-mime-digest-discard-header-regexp "only-drop-this-header"))
841 (vm-forward-message)))
844 (defun vm-forward-message ()
845 "Forward the current message to one or more recipients.
846 You will be placed in a Mail mode buffer as you would with a
847 reply, but you must fill in the To: header and perhaps the
848 Subject: header manually."
850 (vm-follow-summary-cursor)
851 (vm-select-folder-buffer)
852 (vm-check-for-killed-summary)
853 (vm-error-if-folder-empty)
854 (if (and (eq last-command 'vm-next-command-uses-marks)
855 (cdr (vm-select-marked-or-prefixed-messages 0)))
856 (let ((vm-digest-send-type vm-forwarding-digest-type))
857 (setq this-command 'vm-next-command-uses-marks)
858 (command-execute 'vm-send-digest))
859 (let ((dir default-directory)
860 (miming (and vm-send-using-mime
861 (equal vm-forwarding-digest-type "mime")))
864 (mp (vm-select-marked-or-prefixed-messages 1)))
868 (format "forward of %s's note re: %s"
869 (vm-su-full-name (car vm-message-pointer))
870 (vm-su-subject (car vm-message-pointer)))
872 (and vm-forwarding-subject-format
873 (let ((vm-summary-uninteresting-senders nil))
874 (vm-summary-sprintf vm-forwarding-subject-format
876 (make-local-variable 'vm-forward-list)
877 (setq vm-system-state 'forwarding
878 vm-forward-list (list (car mp))
879 default-directory dir)
882 (setq mail-buffer (current-buffer))
883 (set-buffer (vm-make-work-buffer "*vm-forward-buffer*"))
884 (setq header-end (point))
886 (goto-char (point-min))
887 (re-search-forward (concat "^" (regexp-quote mail-header-separator)
889 (goto-char (match-end 0))
890 (setq header-end (match-beginning 0)))
891 (cond ((equal vm-forwarding-digest-type "mime")
892 (vm-mime-encapsulate-messages (list (car mp))
894 vm-unforwarded-header-regexp
896 (goto-char header-end)
897 (insert "MIME-Version: 1.0\n")
898 (insert "Content-Type: message/rfc822\n")
899 (insert "Content-Transfer-Encoding: "
900 (vm-determine-proper-content-transfer-encoding
904 (insert "Content-Description: forwarded message\n")
905 ;; eight bit chars will get \201 prepended if we
907 (if vm-fsfemacs-mule-p
908 (set-buffer-multibyte t)))
909 ((equal vm-forwarding-digest-type "rfc934")
910 (vm-rfc934-encapsulate-messages
911 vm-forward-list vm-forwarded-headers
912 vm-unforwarded-header-regexp))
913 ((equal vm-forwarding-digest-type "rfc1153")
914 (vm-rfc1153-encapsulate-messages
915 vm-forward-list vm-forwarded-headers
916 vm-unforwarded-header-regexp))
917 ((equal vm-forwarding-digest-type nil)
918 (vm-no-frills-encapsulate-message
919 (car vm-forward-list) vm-forwarded-headers
920 vm-unforwarded-header-regexp)))
922 (let ((b (current-buffer)))
923 (set-buffer mail-buffer)
925 (vm-mime-attach-object b "message/rfc822" nil
926 "forwarded message" t)
927 (add-hook 'kill-buffer-hook
929 (list 'if (list 'eq mail-buffer '(current-buffer))
930 (list 'kill-buffer b))))))
931 (mail-position-on-field "To"))
932 (run-hooks 'vm-forward-message-hook)
933 (run-hooks 'vm-mail-mode-hook))))
936 (defun vm-resend-bounced-message ()
937 "Extract the original text from a bounced message and resend it.
938 You will be placed in a Mail mode buffer with the extracted message and
939 you can change the recipient address before resending the message."
941 (vm-follow-summary-cursor)
942 (vm-select-folder-buffer)
943 (vm-check-for-killed-summary)
944 (vm-error-if-folder-empty)
945 (let ((b (current-buffer)) start
946 (dir default-directory)
947 (layout (vm-mm-layout (car vm-message-pointer)))
948 (lim (vm-text-end-of (car vm-message-pointer))))
951 (if (or (not (vectorp layout))
952 (not (setq layout (vm-mime-layout-contains-type
953 layout "message/rfc822"))))
955 (goto-char (vm-text-of (car vm-message-pointer)))
956 (let ((case-fold-search t))
957 ;; What a wonderful world it would be if mailers
958 ;; used a single message encapsulation standard
959 ;; instead of all the weird variants. It is
960 ;; useless to try to cover them all. This simple
961 ;; rule should cover the sanest of the formats
962 (if (not (re-search-forward "^Received:" lim t))
963 (error "This doesn't look like a bounced message."))
965 (setq start (point)))))
966 ;; briefly nullify vm-mail-header-from to keep vm-mail-internal
967 ;; from inserting another From header.
968 (let ((vm-mail-header-from nil))
970 (format "retry of bounce from %s"
971 (vm-su-from (car vm-message-pointer)))))
972 (goto-char (point-min))
976 (vm-mime-insert-mime-body layout)
977 (vm-mime-transfer-decode-region layout start (point)))
978 (insert-buffer-substring b start lim))
979 (delete-region (point) (point-max))
980 (goto-char (point-min))
981 ;; delete all but pertinent headers
982 (vm-reorder-message-headers nil nil "\\(X-VM-\\|Status:\\|Sender:\\)")
983 (vm-reorder-message-headers nil vm-resend-bounced-headers
984 vm-resend-bounced-discard-header-regexp)
985 (if (search-forward "\n\n" nil t)
987 (goto-char (point-max)))
988 (insert ?\n mail-header-separator ?\n)
989 (goto-char (point-min))
990 (if vm-mail-header-from
991 (insert "Resent-From: " vm-mail-header-from ?\n))
992 (if (vm-mail-mode-get-header-contents "Resent-To:")
993 (mail-position-on-field "Resent-To")
994 (insert "Resent-To: \n")
996 (setq default-directory dir)))
997 (run-hooks 'vm-resend-bounced-message-hook)
998 (run-hooks 'vm-mail-mode-hook))
1001 (defun vm-resend-message ()
1002 "Resend the current message to someone else.
1003 The current message will be copied to a Mail mode buffer and you
1004 can edit the message and send it as usual.
1006 NOTE: since you are doing a resend, a Resent-To header is provided
1007 for you to fill in the new recipient list. If you don't fill in
1008 this header, what happens when you send the message is undefined.
1009 You may also create a Resent-Cc header."
1011 (vm-follow-summary-cursor)
1012 (vm-select-folder-buffer)
1013 (vm-check-for-killed-summary)
1014 (vm-error-if-folder-empty)
1017 (let ((b (current-buffer))
1018 (dir default-directory)
1019 (vmp vm-message-pointer)
1020 (start (vm-headers-of (car vm-message-pointer)))
1021 (lim (vm-text-end-of (car vm-message-pointer))))
1022 ;; briefly nullify vm-mail-header-from to keep vm-mail-internal
1023 ;; from inserting another From header.
1024 (let ((vm-mail-header-from nil))
1026 (format "resend of %s's note re: %s"
1027 (vm-su-full-name (car vm-message-pointer))
1028 (vm-su-subject (car vm-message-pointer)))))
1029 (goto-char (point-min))
1030 (insert-buffer-substring b start lim)
1031 (delete-region (point) (point-max))
1032 (goto-char (point-min))
1033 (if vm-mail-header-from
1034 (insert "Resent-From: " vm-mail-header-from ?\n))
1035 (insert "Resent-To: \n")
1038 (cond ((and vm-xemacs-p (fboundp 'user-mail-address))
1039 (user-mail-address))
1040 ((and (boundp 'user-mail-address)
1041 (stringp user-mail-address))
1043 (t (user-login-name)))
1045 (if mail-archive-file-name
1046 (insert "FCC: " mail-archive-file-name ?\n))
1047 ;; delete all but pertinent headers
1048 (vm-reorder-message-headers nil nil "\\(X-VM-\\|Status:\\|Sender:\\)")
1049 (vm-reorder-message-headers nil vm-resend-headers
1050 vm-resend-discard-header-regexp)
1051 (if (search-forward "\n\n" nil t)
1053 (insert ?\n mail-header-separator ?\n)
1054 (goto-char (point-min))
1055 (mail-position-on-field "Resent-To")
1056 (make-local-variable 'vm-redistribute-list)
1057 (setq vm-system-state 'redistributing
1058 vm-redistribute-list (list (car vmp))
1059 default-directory dir)
1060 (run-hooks 'vm-resend-message-hook)
1061 (run-hooks 'vm-mail-mode-hook))))
1064 (defun vm-send-digest (&optional prefix)
1065 "Send a digest of all messages in the current folder to recipients.
1066 The type of the digest is specified by the variable vm-digest-send-type.
1067 You will be placed in a Mail mode buffer as is usual with replies, but you
1068 must fill in the To: and Subject: headers manually.
1070 Prefix arg means to insert a list of preamble lines at the beginning of
1071 the digest. One line is generated for each message being digestified.
1072 The variable vm-digest-preamble-format determines the format of the
1075 If invoked on marked messages (via vm-next-command-uses-marks),
1076 only marked messages will be put into the digest."
1078 (vm-select-folder-buffer)
1079 (vm-check-for-killed-summary)
1080 (vm-error-if-folder-empty)
1081 (let ((dir default-directory)
1082 (miming (and vm-send-using-mime (equal vm-digest-send-type "mime")))
1084 ;; prefix arg doesn't have "normal" meaning here, so only call
1085 ;; vm-select-marked-or-prefixed-messages if we're using marks.
1086 (mlist (if (eq last-command 'vm-next-command-uses-marks)
1087 (vm-select-marked-or-prefixed-messages 0)
1089 start header-end boundary)
1093 (format "digest from %s" (buffer-name))
1095 (and vm-forwarding-subject-format
1096 (let ((vm-summary-uninteresting-senders nil))
1097 (concat (vm-summary-sprintf vm-forwarding-subject-format (car mlist))
1099 (format " [and %d more messages]"
1100 (length (cdr mlist))))))))
1101 (make-local-variable 'vm-forward-list)
1102 (setq vm-system-state 'forwarding
1103 vm-forward-list mlist
1104 default-directory dir)
1107 (setq mail-buffer (current-buffer))
1108 (set-buffer (vm-make-work-buffer "*vm-digest-buffer*"))
1109 (setq header-end (point))
1111 (setq start (point-marker)))
1112 (goto-char (point-min))
1113 (re-search-forward (concat "^" (regexp-quote mail-header-separator)
1115 (goto-char (match-end 0))
1116 (setq start (point-marker)
1117 header-end (match-beginning 0)))
1118 (message "Building %s digest..." vm-digest-send-type)
1119 (cond ((equal vm-digest-send-type "mime")
1120 (setq boundary (vm-mime-encapsulate-messages
1121 mlist vm-mime-digest-headers
1122 vm-mime-digest-discard-header-regexp
1124 (goto-char header-end)
1125 (insert "MIME-Version: 1.0\n")
1126 (insert (if vm-mime-avoid-folding-content-type
1127 "Content-Type: multipart/digest; boundary=\""
1128 "Content-Type: multipart/digest;\n\tboundary=\"")
1130 (insert "Content-Transfer-Encoding: "
1131 (vm-determine-proper-content-transfer-encoding
1135 ((equal vm-digest-send-type "rfc934")
1136 (vm-rfc934-encapsulate-messages
1137 mlist vm-rfc934-digest-headers
1138 vm-rfc934-digest-discard-header-regexp))
1139 ((equal vm-digest-send-type "rfc1153")
1140 (vm-rfc1153-encapsulate-messages
1141 mlist vm-rfc1153-digest-headers
1142 vm-rfc1153-digest-discard-header-regexp))
1143 ((equal vm-digest-send-type nil)
1145 (vm-no-frills-encapsulate-message
1146 (car mlist) vm-forwarded-headers
1147 vm-unforwarded-header-regexp)
1148 (setq mlist (cdr mlist)))))
1153 (let ((b (current-buffer)))
1154 (set-buffer mail-buffer)
1156 (vm-mime-attach-object b "multipart/digest"
1157 (list (concat "boundary=\""
1158 boundary "\"")) nil t)
1159 (add-hook 'kill-buffer-hook
1161 (list 'if (list 'eq mail-buffer '(current-buffer))
1162 (list 'kill-buffer b))))))
1165 (message "Building digest preamble...")
1168 (set-buffer mail-buffer)
1171 (let ((vm-summary-uninteresting-senders nil))
1172 (insert (vm-summary-sprintf vm-digest-preamble-format
1174 (if vm-digest-center-preamble
1179 (setq mp (cdr mp)))))
1180 (mail-position-on-field "To")
1181 (message "Building %s digest... done" vm-digest-send-type)))
1182 (run-hooks 'vm-send-digest-hook)
1183 (run-hooks 'vm-mail-mode-hook))
1186 (defun vm-send-rfc934-digest (&optional preamble)
1187 "Like vm-send-digest but always sends an RFC 934 digest."
1189 (let ((vm-digest-send-type "rfc934"))
1190 (vm-send-digest preamble)))
1193 (defun vm-send-rfc1153-digest (&optional preamble)
1194 "Like vm-send-digest but always sends an RFC 1153 digest."
1196 (let ((vm-digest-send-type "rfc1153"))
1197 (vm-send-digest preamble)))
1200 (defun vm-send-mime-digest (&optional preamble)
1201 "Like vm-send-digest but always sends an MIME (multipart/digest) digest."
1203 (let ((vm-digest-send-type "mime"))
1204 (vm-send-digest preamble)))
1207 (defun vm-continue-composing-message (&optional not-picky)
1208 "Find and select the most recently used mail composition buffer.
1209 If the selected buffer is already a Mail mode buffer then it is
1210 buried before beginning the search. Non Mail mode buffers and
1211 unmodified Mail buffers are skipped. Prefix arg means unmodified
1212 Mail mode buffers are not skipped. If no suitable buffer is
1213 found, the current buffer remains selected."
1215 (if (eq major-mode 'mail-mode)
1216 (vm-bury-buffer (current-buffer)))
1217 (let ((b (vm-find-composition-buffer not-picky)))
1218 (if (not (or (null b) (eq b (current-buffer))))
1220 ;; avoid having the window configuration code choose a
1221 ;; different composition buffer.
1222 (vm-unbury-buffer b)
1224 (if (and vm-mutable-frames vm-frame-per-composition
1225 (vm-multiple-frames-possible-p)
1226 ;; only pop up a frame if there's an undisplay
1227 ;; hook in place to make the frame go away.
1228 vm-undisplay-buffer-hook)
1229 (let ((w (vm-get-buffer-window b)))
1231 (vm-goto-new-frame 'composition)
1233 (and vm-warp-mouse-to-new-frame
1234 (vm-warp-mouse-to-frame-maybe (vm-window-frame w))))
1235 ;; need to do this here too, since XEmacs has per
1236 ;; frame buffer lists.
1237 (vm-unbury-buffer b)
1238 (vm-set-hooks-for-frame-deletion)))
1239 (vm-display b t '(vm-continue-composing-message)
1240 '(vm-continue-composing-message composing-message)))
1241 (message "No composition buffers found"))))
1244 (defun vm-mail-to-mailto-url (url)
1245 (vm-session-initialization)
1246 (vm-check-for-killed-folder)
1247 (vm-select-folder-buffer-if-possible)
1248 (vm-check-for-killed-summary)
1249 (let ((list (vm-parse url "^mailto:\\([^?]+\\)\\??\\|\\([^&]+\\)&?"
1251 to subject in-reply-to cc references newsgroups body
1252 tem header value header-list)
1254 to (vm-url-decode-string to)
1257 (setq tem (vm-parse (car list) "\\([^=]+\\)=?"))
1258 (if (null (nth 1 tem))
1260 (setq header (downcase (vm-url-decode-string (car tem)))
1261 value (vm-url-decode-string (nth 1 tem)))
1262 (if (member header '("subject" "in-reply-to" "cc"
1263 "references" "newsgroups" "body"))
1264 ;; set the variable let-bound above
1265 (set (intern header) value)
1266 ;; we'll insert the header later
1267 (setq header-list (cons header (cons value header-list)))))
1268 (setq list (cdr list)))
1269 (vm-mail-internal nil to subject in-reply-to cc references newsgroups)
1271 (goto-char (point-min))
1273 (insert (car header-list) ": ")
1274 (capitalize-region (point) (save-excursion (beginning-of-line) (point)))
1275 (insert (nth 1 header-list) "\n")
1276 (setq header-list (nthcdr 2 header-list)))
1280 (save-excursion (insert (vm-url-decode-string body) "\n"))
1281 ;; CRLF to LF for line breaks in the body
1282 (while (search-forward "\r\n" nil t)
1283 (replace-match "\n"))))
1284 (run-hooks 'vm-mail-hook)
1285 (run-hooks 'vm-mail-mode-hook)))
1287 ;; to quiet the v19 byte compiler
1288 (defvar mail-mode-map)
1289 (defvar mail-aliases)
1290 (defvar mail-default-reply-to)
1291 (defvar mail-signature-file)
1292 (defvar mail-personal-alias-file)
1294 (defun vm-drop-buffer-name-chars (buffer-name)
1295 "Replace chars matching `vm-drop-buffer-name-chars' by an \"_\"."
1296 (let ((r vm-drop-buffer-name-chars))
1297 (if (eq r t) (setq r "[^\x0-\x80]"))
1298 (if (and buffer-name r)
1299 (vm-replace-in-string buffer-name r "_" t)
1303 (defun vm-mail-internal
1304 (&optional buffer-name to subject in-reply-to cc references newsgroups)
1305 "Create a message buffer and set it up according to args.
1306 Fills in the headers as given by the arguments.
1307 Binds the `vm-mail-mode-map' and hooks"
1308 (let ((folder-buffer nil))
1309 (if (memq major-mode '(vm-mode vm-virtual-mode))
1310 (setq folder-buffer (current-buffer)))
1311 (setq buffer-name (if buffer-name
1312 (vm-decode-mime-encoded-words-in-string buffer-name)
1314 (setq buffer-name (vm-drop-buffer-name-chars buffer-name))
1315 (set-buffer (generate-new-buffer buffer-name))
1316 ;; FSF Emacs: try to prevent write-region (called to handle FCC) from
1317 ;; asking the user to choose a safe coding system.
1318 (if (and vm-fsfemacs-mule-p (fboundp 'set-buffer-file-coding-system))
1319 (set-buffer-file-coding-system 'raw-text))
1320 ;; avoid trying to write auto-save files in potentially
1321 ;; unwritable directories.
1322 (setq default-directory (or vm-folder-directory (expand-file-name "~/")))
1323 (auto-save-mode (if auto-save-default 1 -1))
1325 ;; TM infests mail mode, uninfest it if VM's MIME stuff is in
1327 (if vm-send-using-mime
1328 (vm-mail-mode-remove-tm-hooks))
1329 (use-local-map vm-mail-mode-map)
1330 ;; make mail-mode-map the parent of this vm-mail-mode-map, if we can.
1332 (if (not vm-mail-mode-map-parented)
1333 (cond ((fboundp 'set-keymap-parents)
1334 (set-keymap-parents vm-mail-mode-map (list mail-mode-map))
1335 (setq vm-mail-mode-map-parented t))
1336 ((consp mail-mode-map)
1337 (nconc vm-mail-mode-map mail-mode-map)
1338 (setq vm-mail-mode-map-parented t))))
1339 (setq vm-mail-buffer folder-buffer
1340 mode-popup-menu (and vm-use-menus
1341 (vm-menu-support-possible-p)
1342 (vm-menu-mode-menu)))
1343 (and vm-use-menus (vm-menu-support-possible-p)
1344 (vm-menu-install-mail-mode-menu))
1345 (if (fboundp 'mail-aliases-setup) ; use mail-abbrevs.el if present
1346 (mail-aliases-setup)
1347 (if (eq mail-aliases t)
1349 (setq mail-aliases nil)
1350 (if (file-exists-p (or mail-personal-alias-file "~/.mailrc"))
1351 (build-mail-aliases)))))
1352 (if (stringp vm-mail-header-from)
1353 (insert "From: " vm-mail-header-from "\n"))
1354 (setq to (if to (vm-decode-mime-encoded-words-in-string to))
1355 subject (if subject (vm-decode-mime-encoded-words-in-string subject))
1356 cc (if cc (vm-decode-mime-encoded-words-in-string cc)))
1357 (insert "To: " (or to "") "\n")
1358 (and cc (insert "Cc: " cc "\n"))
1359 (insert "Subject: " (or subject "") "\n")
1360 (and newsgroups (insert "Newsgroups: " newsgroups "\n"))
1361 (and in-reply-to (insert "In-Reply-To: " in-reply-to "\n"))
1362 (and references (insert "References: " references "\n"))
1363 (insert "X-Mailer: VM " (vm-version) " under ")
1364 (cond ((boundp 'emacs-version)
1365 (insert emacs-version))
1367 (insert "Unknown Emacs")))
1368 (if (functionp 'emacsw32-version)
1369 (insert " [" (emacsw32-version) "]"))
1370 (if (boundp 'system-configuration)
1371 (insert " (" system-configuration ")"))
1373 ;; REPLYTO environmental variable support
1374 ;; note that in FSF Emacs v19.29 we would initialize if the
1375 ;; value was t. nil is the trigger value used now.
1376 (and (eq mail-default-reply-to nil)
1377 (setq mail-default-reply-to (getenv "REPLYTO")))
1378 (if mail-default-reply-to
1379 (insert "Reply-To: " mail-default-reply-to "\n"))
1382 (cond ((and vm-xemacs-p (fboundp 'user-mail-address))
1383 (user-mail-address))
1384 ((and (boundp 'user-mail-address)
1385 (stringp user-mail-address))
1387 (t (user-login-name)))
1389 (if mail-archive-file-name
1390 (insert "FCC: " mail-archive-file-name "\n"))
1391 (if mail-default-headers
1392 (insert mail-default-headers))
1393 (if (not (= (preceding-char) ?\n))
1395 (insert mail-header-separator "\n")
1399 (narrow-to-region (point) (point))
1400 (cond ((stringp mail-signature)
1401 (insert mail-signature))
1402 ((eq mail-signature t)
1403 (insert-file-contents (or (and (boundp 'mail-signature-file)
1404 (stringp mail-signature-file)
1405 mail-signature-file)
1408 (let ((str (eval mail-signature)))
1411 (goto-char (point-min))
1412 (if (looking-at "\n*-- \n")
1415 (goto-char (point-max)))))
1416 ;; move this buffer to the head of the buffer list so window
1417 ;; config stuff will select it as the composition buffer.
1418 (vm-unbury-buffer (current-buffer))
1419 ;; make a new frame if the user wants it.
1420 (if (and vm-mutable-frames vm-frame-per-composition
1421 (vm-multiple-frames-possible-p))
1423 (vm-goto-new-frame 'composition)
1424 (vm-set-hooks-for-frame-deletion)))
1425 ;; now do window configuration
1426 (vm-display (current-buffer) t
1429 vm-mail-other-window
1431 vm-reply-other-frame
1432 vm-reply-include-text
1433 vm-reply-include-text-other-frame
1435 vm-followup-other-frame
1436 vm-followup-include-text
1437 vm-followup-include-text-other-frame
1439 vm-send-digest-other-frame
1440 vm-send-rfc934-digest
1441 vm-send-rfc934-digest-other-frame
1442 vm-send-rfc1153-digest
1443 vm-send-rfc1153-digest-other-frame
1445 vm-send-mime-digest-other-frame
1447 vm-forward-message-other-frame
1448 vm-forward-message-all-headers
1449 vm-forward-message-all-headers-other-frame
1451 vm-resend-message-other-frame
1452 vm-resend-bounced-message
1453 vm-resend-bounced-message-other-frame)
1454 (list this-command 'composing-message))
1456 (mail-position-on-field "To"))
1457 (cond ((and vm-xemacs-p
1458 (fboundp 'start-itimer)
1459 (null (get-itimer "vm-rename-mail"))
1460 (start-itimer "vm-rename-mail"
1461 'vm-update-composition-buffer-name
1463 ((and (fboundp 'run-with-idle-timer)
1464 (null vm-update-composition-buffer-name-timer))
1465 (setq vm-update-composition-buffer-name-timer
1466 (run-with-idle-timer 1.5 t 'vm-update-composition-buffer-name))))
1467 (run-hooks 'mail-setup-hook)))
1470 (defun vm-reply-other-frame (count)
1471 "Like vm-reply, but run in a newly created frame."
1473 (if (vm-multiple-frames-possible-p)
1474 (vm-goto-new-frame 'composition))
1475 (let ((vm-frame-per-composition nil)
1476 (vm-search-other-frames nil))
1478 (if (vm-multiple-frames-possible-p)
1479 (vm-set-hooks-for-frame-deletion)))
1482 (defun vm-reply-include-text-other-frame (count)
1483 "Like vm-reply-include-text, but run in a newly created frame."
1485 (if (vm-multiple-frames-possible-p)
1486 (vm-goto-new-frame 'composition))
1487 (let ((vm-frame-per-composition nil)
1488 (vm-search-other-frames nil))
1489 (vm-reply-include-text count))
1490 (if (vm-multiple-frames-possible-p)
1491 (vm-set-hooks-for-frame-deletion)))
1494 (defun vm-followup-other-frame (count)
1495 "Like vm-followup, but run in a newly created frame."
1497 (if (vm-multiple-frames-possible-p)
1498 (vm-goto-new-frame 'composition))
1499 (let ((vm-frame-per-composition nil)
1500 (vm-search-other-frames nil))
1501 (vm-followup count))
1502 (if (vm-multiple-frames-possible-p)
1503 (vm-set-hooks-for-frame-deletion)))
1506 (defun vm-followup-include-text-other-frame (count)
1507 "Like vm-followup-include-text, but run in a newly created frame."
1509 (if (vm-multiple-frames-possible-p)
1510 (vm-goto-new-frame 'composition))
1511 (let ((vm-frame-per-composition nil)
1512 (vm-search-other-frames nil))
1513 (vm-followup-include-text count))
1514 (if (vm-multiple-frames-possible-p)
1515 (vm-set-hooks-for-frame-deletion)))
1518 (defun vm-forward-message-all-headers-other-frame ()
1519 "Like vm-forward-message-all-headers, but run in a newly created frame."
1521 (if (vm-multiple-frames-possible-p)
1522 (vm-goto-new-frame 'composition))
1523 (let ((vm-frame-per-composition nil)
1524 (vm-search-other-frames nil))
1525 (vm-forward-message-all-headers))
1526 (if (vm-multiple-frames-possible-p)
1527 (vm-set-hooks-for-frame-deletion)))
1530 (defun vm-forward-message-other-frame ()
1531 "Like vm-forward-message, but run in a newly created frame."
1533 (if (vm-multiple-frames-possible-p)
1534 (vm-goto-new-frame 'composition))
1535 (let ((vm-frame-per-composition nil)
1536 (vm-search-other-frames nil))
1537 (vm-forward-message))
1538 (if (vm-multiple-frames-possible-p)
1539 (vm-set-hooks-for-frame-deletion)))
1542 (defun vm-resend-message-other-frame ()
1543 "Like vm-resend-message, but run in a newly created frame."
1545 (if (vm-multiple-frames-possible-p)
1546 (vm-goto-new-frame 'composition))
1547 (let ((vm-frame-per-composition nil)
1548 (vm-search-other-frames nil))
1549 (vm-resend-message))
1550 (if (vm-multiple-frames-possible-p)
1551 (vm-set-hooks-for-frame-deletion)))
1554 (defun vm-resend-bounced-message-other-frame ()
1555 "Like vm-resend-bounced-message, but run in a newly created frame."
1557 (if (vm-multiple-frames-possible-p)
1558 (vm-goto-new-frame 'composition))
1559 (let ((vm-frame-per-composition nil)
1560 (vm-search-other-frames nil))
1561 (vm-resend-bounced-message))
1562 (if (vm-multiple-frames-possible-p)
1563 (vm-set-hooks-for-frame-deletion)))
1566 (defun vm-send-digest-other-frame (&optional prefix)
1567 "Like vm-send-digest, but run in a newly created frame."
1569 (if (vm-multiple-frames-possible-p)
1570 (vm-goto-new-frame 'composition))
1571 (let ((vm-frame-per-composition nil)
1572 (vm-search-other-frames nil))
1573 (vm-send-digest prefix))
1574 (if (vm-multiple-frames-possible-p)
1575 (vm-set-hooks-for-frame-deletion)))
1578 (defun vm-send-rfc934-digest-other-frame (&optional prefix)
1579 "Like vm-send-rfc934-digest, but run in a newly created frame."
1581 (if (vm-multiple-frames-possible-p)
1582 (vm-goto-new-frame 'composition))
1583 (let ((vm-frame-per-composition nil)
1584 (vm-search-other-frames nil))
1585 (vm-send-rfc934-digest prefix))
1586 (if (vm-multiple-frames-possible-p)
1587 (vm-set-hooks-for-frame-deletion)))
1590 (defun vm-send-rfc1153-digest-other-frame (&optional prefix)
1591 "Like vm-send-rfc1153-digest, but run in a newly created frame."
1593 (if (vm-multiple-frames-possible-p)
1594 (vm-goto-new-frame 'composition))
1595 (let ((vm-frame-per-composition nil)
1596 (vm-search-other-frames nil))
1597 (vm-send-rfc1153-digest prefix))
1598 (if (vm-multiple-frames-possible-p)
1599 (vm-set-hooks-for-frame-deletion)))
1602 (defun vm-send-mime-digest-other-frame (&optional prefix)
1603 "Like vm-send-mime-digest, but run in a newly created frame."
1605 (if (vm-multiple-frames-possible-p)
1606 (vm-goto-new-frame 'composition))
1607 (let ((vm-frame-per-composition nil)
1608 (vm-search-other-frames nil))
1609 (vm-send-mime-digest prefix))
1610 (if (vm-multiple-frames-possible-p)
1611 (vm-set-hooks-for-frame-deletion)))
1613 (defvar enriched-mode)
1616 (defun vm-preview-composition ()
1617 "Show how the current composition buffer might be displayed
1618 in a MIME-aware mail reader. VM copies and encodes the current
1619 mail composition buffer and displays it as a mail folder.
1620 Type `q' to quit this temp folder and return to composing your
1623 (if (not (eq major-mode 'mail-mode))
1624 (error "Command must be used in a VM Mail mode buffer."))
1625 (let ((temp-buffer nil)
1626 (mail-buffer (current-buffer))
1627 (enriched (and (boundp 'enriched-mode) enriched-mode))
1631 (setq temp-buffer (generate-new-buffer "composition preview"))
1632 (set-buffer temp-buffer)
1633 ;; so vm-mime-xxxx-encode-composition won't complain
1634 (setq major-mode 'mail-mode)
1635 (set (make-local-variable 'enriched-mode) enriched)
1636 (vm-insert-region-from-buffer mail-buffer)
1637 (goto-char (point-min))
1638 (or (vm-mail-mode-get-header-contents "From")
1639 (insert "From: " (user-login-name) "\n"))
1640 (or (vm-mail-mode-get-header-contents "Message-ID")
1641 (insert (format "Message-ID: <fake.%d.%d@fake.fake>\n"
1642 (random 1000000) (random 1000000))))
1643 (or (vm-mail-mode-get-header-contents "Date")
1645 (format-time-string "%a, %d %b %Y %H%M%S %Z"
1648 (and vm-send-using-mime
1649 (null (vm-mail-mode-get-header-contents "MIME-Version:"))
1650 (vm-mime-encode-composition))
1651 (vm-remove-mail-mode-header-separator)
1652 (vm-munge-message-separators 'mmdf (point-min) (point-max))
1653 (goto-char (point-min))
1654 (insert (vm-leading-message-separator 'mmdf))
1655 (goto-char (point-max))
1656 (if (not (eq (preceding-char) ?\n))
1658 (insert (vm-trailing-message-separator 'mmdf))
1659 (set-buffer-modified-p nil)
1660 ;; point of no return, don't kill it if the user quits
1661 (setq temp-buffer nil)
1662 (let ((vm-auto-decode-mime-messages t)
1663 (vm-auto-displayed-mime-content-types t))
1664 (vm-save-buffer-excursion
1665 (vm-goto-new-folder-frame-maybe 'folder)
1668 (substitute-command-keys
1669 "Type \\[vm-quit] to continue composing your message"))
1670 ;; temp buffer, don't offer to save it.
1671 (setq buffer-offer-save nil)
1672 (vm-display (or vm-presentation-buffer (current-buffer)) t
1673 (list this-command) '(vm-mode startup)))
1674 (and temp-buffer (kill-buffer temp-buffer)))))
1676 (defun vm-update-composition-buffer-name ()
1677 (if (and (eq major-mode 'mail-mode)
1678 (save-match-data (string-match "^\\(mail\\|reply\\) to "
1680 (let ((to (mail-fetch-field "To"))
1681 (cc (mail-fetch-field "Cc"))
1682 (curbufname (buffer-name))
1686 (cond (vm-reply-list (setq fmt "reply to %s%s"))
1687 (t (setq fmt "mail to %s%s")))
1688 (setq to (vm-parse-addresses to)
1689 cc (vm-parse-addresses cc))
1691 (and (car to) (car cc)))
1692 (setq ellipsis ", ..."))
1693 (setq newbufname (or (car to) (car cc) "foo (?)")
1694 newbufname (funcall vm-chop-full-name-function newbufname)
1695 newbufname (or (car newbufname) (car (cdr newbufname)))
1696 newbufname (format fmt newbufname ellipsis))
1697 (if (equal newbufname curbufname)
1699 (setq newbufname (vm-drop-buffer-name-chars newbufname))
1700 (rename-buffer newbufname t)))))
1703 (defun vm-mail-mode-remove-tm-hooks ()
1704 (remove-hook 'mail-setup-hook 'turn-on-mime-edit)
1705 (remove-hook 'mail-setup-hook 'mime/decode-message-header)
1706 (remove-hook 'mail-setup-hook 'mime/editor-mode)
1707 (remove-hook 'mail-send-hook 'mime-edit-maybe-translate)
1708 (remove-hook 'mail-send-hook 'mime-editor/maybe-translate))
1712 ;;; vm-reply.el ends here