comparison lisp/tm/tm-vm.el @ 4:b82b59fe008d r19-15b3

Import from CVS: tag r19-15b3
author cvs
date Mon, 13 Aug 2007 08:46:56 +0200
parents
children 4b173ad71786
comparison
equal deleted inserted replaced
3:30df88044ec6 4:b82b59fe008d
1 ;;; tm-vm.el --- tm-MUA (MIME Extension module) for VM
2
3 ;; Copyright (C) 1994,1995,1996 Free Software Foundation, Inc.
4
5 ;; Author: MASUTANI Yasuhiro <masutani@me.es.osaka-u.ac.jp>
6 ;; Kenji Wakamiya <wkenji@flab.fujitsu.co.jp>
7 ;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
8 ;; Shuhei KOBAYASHI <shuhei-k@jaist.ac.jp>
9 ;; Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch>
10 ;; Maintainer: Oscar Figueiredo <Oscar.Figueiredo@di.epfl.ch>
11 ;; Created: 1994/10/29
12 ;; Version: $Revision: 1.1.1.1 $
13 ;; Keywords: mail, MIME, multimedia, multilingual, encoded-word
14
15 ;; This file is part of tm (Tools for MIME).
16
17 ;; This program is free software; you can redistribute it and/or
18 ;; modify it under the terms of the GNU General Public License as
19 ;; published by the Free Software Foundation; either version 2, or (at
20 ;; your option) any later version.
21
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 ;; General Public License for more details.
26
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with GNU Emacs; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
30 ;; Boston, MA 02111-1307, USA.
31
32 ;;; Commentary:
33
34 ;; Plese insert `(require 'tm-vm)' in your ~/.vm file.
35
36 ;;; Code:
37
38 (require 'tm-view)
39 (require 'vm)
40 (eval-when-compile
41 (require 'ps-print))
42
43 (defconst tm-vm/RCS-ID
44 "$Id: tm-vm.el,v 1.1.1.1 1996/12/18 03:55:32 steve Exp $")
45 (defconst tm-vm/version (get-version-string tm-vm/RCS-ID))
46
47 (define-key vm-mode-map "Z" 'tm-vm/view-message)
48 (define-key vm-mode-map "T" 'tm-vm/decode-message-header)
49 (define-key vm-mode-map "\et" 'tm-vm/toggle-preview-mode)
50
51 (defvar tm-vm/use-original-url-button nil
52 "*If it is t, use original URL button instead of tm's.")
53
54 (defvar tm-vm-load-hook nil
55 "*List of functions called after tm-vm is loaded.")
56
57
58 ;;; @ for MIME encoded-words
59 ;;;
60
61 (defvar tm-vm/use-tm-patch nil
62 "Does not decode encoded-words in summary buffer if it is t.
63 If you use tiny-mime patch for VM (by RIKITAKE Kenji
64 <kenji@reseau.toyonaka.osaka.jp>), please set it t [tm-vm.el]")
65
66 (or tm-vm/use-tm-patch
67 (progn
68 ;;;
69 (defvar tm-vm/chop-full-name-function 'tm-vm/default-chop-full-name)
70 (setq vm-chop-full-name-function tm-vm/chop-full-name-function)
71
72 (defun tm-vm/default-chop-full-name (address)
73 (let* ((ret (vm-default-chop-full-name address))
74 (full-name (car ret))
75 )
76 (if (stringp full-name)
77 (cons (mime-eword/decode-string full-name)
78 (cdr ret))
79 ret)))
80
81 (require 'vm-summary)
82 (or (fboundp 'tm:vm-su-subject)
83 (fset 'tm:vm-su-subject (symbol-function 'vm-su-subject))
84 )
85 (defun vm-su-subject (m)
86 (mime-eword/decode-string (tm:vm-su-subject m))
87 )
88
89 (or (fboundp 'tm:vm-su-full-name)
90 (fset 'tm:vm-su-full-name (symbol-function 'vm-su-full-name))
91 )
92 (defun vm-su-full-name (m)
93 (mime-eword/decode-string (tm:vm-su-full-name m))
94 )
95
96 (or (fboundp 'tm:vm-su-to-names)
97 (fset 'tm:vm-su-to-names (symbol-function 'vm-su-to-names))
98 )
99 (defun vm-su-to-names (m)
100 (mime-eword/decode-string (tm:vm-su-to-names m))
101 )
102 ;;;
103 ))
104
105 (defun tm-vm/decode-message-header (&optional count)
106 "Decode MIME header of current message.
107 Numeric prefix argument COUNT means to decode the current message plus
108 the next COUNT-1 messages. A negative COUNT means decode the current
109 message and the previous COUNT-1 messages.
110 When invoked on marked messages (via vm-next-command-uses-marks),
111 all marked messages are affected, other messages are ignored."
112 (interactive "p")
113 (or count (setq count 1))
114 (vm-follow-summary-cursor)
115 (vm-select-folder-buffer)
116 (vm-check-for-killed-summary)
117 (vm-error-if-folder-empty)
118 (vm-error-if-folder-read-only)
119 (let ((mlist (vm-select-marked-or-prefixed-messages count))
120 (realm nil)
121 (vlist nil)
122 (vbufs nil))
123 (save-excursion
124 (while mlist
125 (setq realm (vm-real-message-of (car mlist)))
126 ;; Go to real folder of this message.
127 ;; But maybe this message is already real message...
128 (set-buffer (vm-buffer-of realm))
129 (let ((buffer-read-only nil))
130 (vm-save-restriction
131 (narrow-to-region (vm-headers-of realm) (vm-text-of realm))
132 (mime/decode-message-header))
133 (let ((vm-message-pointer (list realm))
134 (last-command nil))
135 (vm-discard-cached-data))
136 ;; Mark each virtual and real message for later summary
137 ;; update.
138 (setq vlist (cons realm (vm-virtual-messages-of realm)))
139 (while vlist
140 (vm-mark-for-summary-update (car vlist))
141 ;; Remember virtual and real folders related this message,
142 ;; for later display update.
143 (or (memq (vm-buffer-of (car vlist)) vbufs)
144 (setq vbufs (cons (vm-buffer-of (car vlist)) vbufs)))
145 (setq vlist (cdr vlist)))
146 (if (eq vm-flush-interval t)
147 (vm-stuff-virtual-attributes realm)
148 (vm-set-modflag-of realm t)))
149 (setq mlist (cdr mlist)))
150 ;; Update mail-buffers and summaries.
151 (while vbufs
152 (set-buffer (car vbufs))
153 (vm-preview-current-message)
154 (setq vbufs (cdr vbufs))))))
155
156
157 ;;; @ automatic MIME preview
158 ;;;
159
160 (defvar tm-vm/automatic-mime-preview t
161 "*If non-nil, automatically process and show MIME messages.")
162
163 (defvar tm-vm/strict-mime t
164 "*If nil, do MIME processing even if there is no MIME-Version field.")
165
166 (defvar tm-vm/select-message-hook nil
167 "*List of functions called every time a message is selected.
168 tm-vm uses `vm-select-message-hook', use this hook instead.")
169
170 (defvar tm-vm/system-state nil)
171
172 (setq mime-viewer/content-header-filter-alist
173 (append '((vm-mode . tm-vm/header-filter)
174 (vm-virtual-mode . tm-vm/header-filter))
175 mime-viewer/content-header-filter-alist))
176
177 (defun tm-vm/header-filter ()
178 "Filter headers in current buffer (assumed to be a message-like buffer)
179 according to vm-visible-headers and vm-invisible-header-regexp"
180 (goto-char (point-min))
181 (let ((visible-headers vm-visible-headers))
182 (if (or vm-use-lucid-highlighting
183 vm-display-xfaces)
184 (setq visible-headers (cons "X-Face:" vm-visible-headers)))
185 (vm-reorder-message-headers nil
186 visible-headers
187 vm-invisible-header-regexp)
188 (mime/decode-message-header)))
189
190 (defun tm-vm/system-state ()
191 (save-excursion
192 (if mime::preview/article-buffer
193 (set-buffer mime::preview/article-buffer)
194 (vm-select-folder-buffer))
195 tm-vm/system-state))
196
197 (defun tm-vm/sync-preview-buffer ()
198 "Ensure that the MIME preview buffer, if it exists actually corresponds to
199 the current message. If no MIME Preview buffer is needed, delete it. If no
200 MIME Preview buffer exists nothing is done."
201 ;; Current buffer should be message buffer when calling this function
202 (let* ((mbuf (current-buffer))
203 (pbuf (and mime::article/preview-buffer
204 (get-buffer mime::article/preview-buffer)))
205 (win (or (and pbuf (vm-get-buffer-window pbuf))
206 (vm-get-buffer-window mbuf)))
207 (frame (selected-frame)))
208 (if pbuf
209 ;; Go to the frame where pbuf or mbuf is (frame-per-composition t)
210 (save-excursion
211 (if win
212 (vm-select-frame (vm-window-frame win)))
213 ;; Rebuild MIME Preview buffer to ensure it corresponds to
214 ;; current message
215 (save-window-excursion
216 (save-selected-window
217 (save-excursion
218 (set-buffer mbuf)
219 (setq mime::article/preview-buffer nil)
220 (if pbuf (kill-buffer pbuf)))
221 (tm-vm/view-message)))
222 ;; Return to previous frame
223 (vm-select-frame frame)))))
224
225 (defun tm-vm/display-preview-buffer ()
226 (let* ((mbuf (current-buffer))
227 (mwin (vm-get-visible-buffer-window mbuf))
228 (pbuf (and mime::article/preview-buffer
229 (get-buffer mime::article/preview-buffer)))
230 (pwin (and pbuf (vm-get-visible-buffer-window pbuf))))
231 (if (and pbuf (tm-vm/system-state))
232 ;; display preview buffer
233 (cond
234 ((and mwin pwin)
235 (vm-undisplay-buffer mbuf)
236 (tm-vm/show-current-message))
237 ((and mwin (not pwin))
238 (set-window-buffer mwin pbuf)
239 (tm-vm/show-current-message))
240 (pwin
241 (tm-vm/show-current-message))
242 (t
243 ;; don't display if neither mwin nor pwin was displayed before.
244 ))
245 ;; display folder buffer
246 (cond
247 ((and mwin pwin)
248 (vm-undisplay-buffer pbuf))
249 ((and (not mwin) pwin)
250 (set-window-buffer pwin mbuf))
251 (mwin
252 ;; folder buffer is already displayed.
253 )
254 (t
255 ;; don't display if neither mwin nor pwin was displayed before.
256 )))
257 (set-buffer mbuf)))
258
259 (defun tm-vm/preview-current-message ()
260 "Preview current message if it has MIME contents and
261 tm-vm/automatic-mime-preview is non nil. Installed on
262 vm-visit-folder-hook and vm-select-message-hook."
263 ;; assumed current buffer is folder buffer.
264 (setq tm-vm/system-state nil)
265 (if (get-buffer mime/output-buffer-name)
266 (vm-undisplay-buffer mime/output-buffer-name))
267 (if (and vm-message-pointer tm-vm/automatic-mime-preview)
268 (if (or (not tm-vm/strict-mime)
269 (vm-get-header-contents (car vm-message-pointer)
270 "MIME-Version:"))
271 ;; do MIME processing.
272 (progn
273 ;; Consider message as shown => update its flags and store them
274 ;; in folder buffer before entering MIME viewer
275 (tm-vm/show-current-message)
276 (set (make-local-variable 'tm-vm/system-state) 'previewing)
277 (save-window-excursion
278 (vm-widen-page)
279 (goto-char (point-max))
280 (widen)
281 (narrow-to-region (point)
282 (save-excursion
283 (goto-char
284 (vm-start-of (car vm-message-pointer))
285 )
286 (forward-line)
287 (point)
288 ))
289
290 (mime/viewer-mode nil nil nil nil nil vm-mode-map)
291 ;; Highlight message (and display XFace if supported)
292 (if (or vm-highlighted-header-regexp
293 (and (vm-xemacs-p) vm-use-lucid-highlighting))
294 (vm-highlight-headers))
295 ;; Energize URLs and buttons
296 (if (and tm-vm/use-original-url-button
297 vm-use-menus (vm-menu-support-possible-p))
298 (progn
299 (vm-energize-urls)
300 (vm-energize-headers)))
301 (goto-char (point-min))
302 (narrow-to-region (point) (search-forward "\n\n" nil t))
303 ))
304 ;; don't do MIME processing. decode header only.
305 (let (buffer-read-only)
306 (mime/decode-message-header))
307 )
308 ;; don't preview; do nothing.
309 )
310 (tm-vm/display-preview-buffer)
311 (run-hooks 'tm-vm/select-message-hook))
312
313 (defun tm-vm/show-current-message ()
314 "Update current message display and summary. Remove 'unread' and 'new' flags. "
315 (if mime::preview/article-buffer
316 (set-buffer mime::preview/article-buffer)
317 (vm-select-folder-buffer))
318 (if mime::article/preview-buffer
319 (save-excursion
320 (set-buffer mime::article/preview-buffer)
321 (goto-char (point-min))
322 (widen)))
323 (if (or (and mime::article/preview-buffer
324 (vm-get-visible-buffer-window mime::article/preview-buffer))
325 (vm-get-visible-buffer-window (current-buffer)))
326 (progn
327 (setq tm-vm/system-state 'reading)
328 (if (vm-new-flag (car vm-message-pointer))
329 (vm-set-new-flag (car vm-message-pointer) nil))
330 (if (vm-unread-flag (car vm-message-pointer))
331 (vm-set-unread-flag (car vm-message-pointer) nil))
332 (vm-update-summary-and-mode-line)
333 (tm-vm/howl-if-eom))
334 (vm-update-summary-and-mode-line)))
335
336 (defun tm-vm/toggle-preview-mode ()
337 "Toggle automatic MIME preview on or off. In automatic MIME Preview mode
338 each newly selected article is MIME processed if it has MIME content without
339 need for an explicit request from the user. This behaviour is controlled by the
340 variable tm-vm/automatic-mime-preview."
341 (interactive)
342 (if tm-vm/automatic-mime-preview
343 (progn
344 (tm-vm/quit-view-message)
345 (setq tm-vm/automatic-mime-preview nil)
346 (message "Automatic MIME Preview is now disabled."))
347 ;; Enable Automatic MIME Preview
348 (tm-vm/view-message)
349 (setq tm-vm/automatic-mime-preview t)
350 (message "Automatic MIME Preview is now enabled.")
351 ))
352
353 (add-hook 'vm-select-message-hook 'tm-vm/preview-current-message)
354 (add-hook 'vm-visit-folder-hook 'tm-vm/preview-current-message)
355
356 ;;; tm-vm move commands
357 ;;;
358
359 (defmacro tm-vm/save-window-excursion (&rest forms)
360 (list 'let '((tm-vm/selected-window (selected-window)))
361 (list 'unwind-protect
362 (cons 'progn forms)
363 '(if (window-live-p tm-vm/selected-window)
364 (select-window tm-vm/selected-window)))))
365
366 ;;; based on vm-scroll-forward [vm-page.el]
367 (defun tm-vm/scroll-forward (&optional arg)
368 (interactive "P")
369 (let ((this-command 'vm-scroll-forward))
370 (if (not (tm-vm/system-state))
371 (progn
372 (vm-scroll-forward arg)
373 (tm-vm/display-preview-buffer))
374 (let* ((mp-changed (vm-follow-summary-cursor))
375 (mbuf (or (vm-select-folder-buffer) (current-buffer)))
376 (mwin (vm-get-buffer-window mbuf))
377 (pbuf (and mime::article/preview-buffer
378 (get-buffer mime::article/preview-buffer)))
379 (pwin (and pbuf (vm-get-buffer-window pbuf)))
380 (was-invisible (and (null mwin) (null pwin)))
381 )
382 ;; now current buffer is folder buffer.
383 (tm-vm/save-window-excursion
384 (if (or mp-changed was-invisible)
385 (vm-display mbuf t '(vm-scroll-forward vm-scroll-backward)
386 (list this-command 'reading-message)))
387 (tm-vm/display-preview-buffer)
388 (setq mwin (vm-get-buffer-window mbuf)
389 pwin (and pbuf (vm-get-buffer-window pbuf)))
390 (cond
391 ((or mp-changed was-invisible)
392 nil
393 )
394 ((null pbuf)
395 ;; preview buffer is killed.
396 (tm-vm/preview-current-message)
397 (vm-update-summary-and-mode-line))
398 ((eq (tm-vm/system-state) 'previewing)
399 (tm-vm/show-current-message))
400 (t
401 (select-window pwin)
402 (set-buffer pbuf)
403 (if (pos-visible-in-window-p (point-max) pwin)
404 (tm-vm/next-message)
405 ;; not end of message. scroll preview buffer only.
406 (scroll-up)
407 (tm-vm/howl-if-eom)
408 (set-buffer mbuf))
409 ))))
410 )))
411
412 ;;; based on vm-scroll-backward [vm-page.el]
413 (defun tm-vm/scroll-backward (&optional arg)
414 (interactive "P")
415 (let ((this-command 'vm-scroll-backward))
416 (if (not (tm-vm/system-state))
417 (vm-scroll-backward arg)
418 (let* ((mp-changed (vm-follow-summary-cursor))
419 (mbuf (or (vm-select-folder-buffer) (current-buffer)))
420 (mwin (vm-get-buffer-window mbuf))
421 (pbuf (and mime::article/preview-buffer
422 (get-buffer mime::article/preview-buffer)))
423 (pwin (and pbuf (vm-get-buffer-window pbuf)))
424 (was-invisible (and (null mwin) (null pwin)))
425 )
426 ;; now current buffer is folder buffer.
427 (if (or mp-changed was-invisible)
428 (vm-display mbuf t '(vm-scroll-forward vm-scroll-backward)
429 (list this-command 'reading-message)))
430 (tm-vm/save-window-excursion
431 (tm-vm/display-preview-buffer)
432 (setq mwin (vm-get-buffer-window mbuf)
433 pwin (and pbuf (vm-get-buffer-window pbuf)))
434 (cond
435 (was-invisible
436 nil
437 )
438 ((null pbuf)
439 ;; preview buffer is killed.
440 (tm-vm/preview-current-message)
441 (vm-update-summary-and-mode-line))
442 ((eq (tm-vm/system-state) 'previewing)
443 (tm-vm/show-current-message))
444 (t
445 (select-window pwin)
446 (set-buffer pbuf)
447 (if (pos-visible-in-window-p (point-min) pwin)
448 nil
449 ;; scroll preview buffer only.
450 (scroll-down)
451 (set-buffer mbuf))
452 ))))
453 )))
454
455 ;;; based on vm-beginning-of-message [vm-page.el]
456 (defun tm-vm/beginning-of-message ()
457 "Moves to the beginning of the current message."
458 (interactive)
459 (if (not (tm-vm/system-state))
460 (progn
461 (setq this-command 'vm-beginning-of-message)
462 (vm-beginning-of-message))
463 (vm-follow-summary-cursor)
464 (vm-select-folder-buffer)
465 (vm-check-for-killed-summary)
466 (vm-error-if-folder-empty)
467 (let ((mbuf (current-buffer))
468 (pbuf (and mime::article/preview-buffer
469 (get-buffer mime::article/preview-buffer))))
470 (if (null pbuf)
471 (progn
472 (tm-vm/preview-current-message)
473 (setq pbuf (get-buffer mime::article/preview-buffer))
474 ))
475 (vm-display mbuf t '(vm-beginning-of-message)
476 '(vm-beginning-of-message reading-message))
477 (tm-vm/display-preview-buffer)
478 (set-buffer pbuf)
479 (tm-vm/save-window-excursion
480 (select-window (vm-get-buffer-window pbuf))
481 (push-mark)
482 (goto-char (point-min))
483 ))))
484
485 ;;; based on vm-end-of-message [vm-page.el]
486 (defun tm-vm/end-of-message ()
487 "Moves to the end of the current message."
488 (interactive)
489 (if (not (tm-vm/system-state))
490 (progn
491 (setq this-command 'vm-end-of-message)
492 (vm-end-of-message))
493 (vm-follow-summary-cursor)
494 (vm-select-folder-buffer)
495 (vm-check-for-killed-summary)
496 (vm-error-if-folder-empty)
497 (let ((mbuf (current-buffer))
498 (pbuf (and mime::article/preview-buffer
499 (get-buffer mime::article/preview-buffer))))
500 (if (null pbuf)
501 (progn
502 (tm-vm/preview-current-message)
503 (setq pbuf (get-buffer mime::article/preview-buffer))
504 ))
505 (vm-display mbuf t '(vm-end-of-message)
506 '(vm-end-of-message reading-message))
507 (tm-vm/display-preview-buffer)
508 (set-buffer pbuf)
509 (tm-vm/save-window-excursion
510 (select-window (vm-get-buffer-window pbuf))
511 (push-mark)
512 (goto-char (point-max))
513 ))))
514
515 ;;; based on vm-howl-if-eom [vm-page.el]
516 (defun tm-vm/howl-if-eom ()
517 (let* ((pbuf (or mime::article/preview-buffer (current-buffer)))
518 (pwin (and (vm-get-visible-buffer-window pbuf))))
519 (and pwin
520 (save-excursion
521 (save-window-excursion
522 (condition-case ()
523 (let ((next-screen-context-lines 0))
524 (select-window pwin)
525 (save-excursion
526 (save-window-excursion
527 (let ((scroll-in-place-replace-original nil))
528 (scroll-up))))
529 nil)
530 (error t))))
531 (tm-vm/emit-eom-blurb)
532 )))
533
534 ;;; based on vm-emit-eom-blurb [vm-page.el]
535 (defun tm-vm/emit-eom-blurb ()
536 (save-excursion
537 (if mime::preview/article-buffer
538 (set-buffer mime::preview/article-buffer))
539 (vm-emit-eom-blurb)))
540
541 ;;; based on vm-quit [vm-folder.el]
542 (defun tm-vm/quit ()
543 "Quit VM saving the folder buffer and killing the MIME Preview buffer if any"
544 (interactive)
545 (save-excursion
546 (vm-select-folder-buffer)
547 (if (and mime::article/preview-buffer
548 (get-buffer mime::article/preview-buffer))
549 (kill-buffer mime::article/preview-buffer)))
550 (vm-quit))
551
552 (defun tm-vm/quit-no-change ()
553 "Quit VM without saving the folder buffer but killing the MIME Preview buffer
554 if any"
555 (interactive)
556 (save-excursion
557 (vm-select-folder-buffer)
558 (if (and mime::article/preview-buffer
559 (get-buffer mime::article/preview-buffer))
560 (kill-buffer mime::article/preview-buffer)))
561 (vm-quit-no-change))
562
563 ;;; based on vm-next-message [vm-motion.el]
564 (defun tm-vm/next-message ()
565 (set-buffer mime::preview/article-buffer)
566 (let ((this-command 'vm-next-message)
567 (owin (selected-window))
568 (vm-preview-lines nil)
569 )
570 (vm-next-message 1 nil t)
571 (if (window-live-p owin)
572 (select-window owin))))
573
574 ;;; based on vm-previous-message [vm-motion.el]
575 (defun tm-vm/previous-message ()
576 (set-buffer mime::preview/article-buffer)
577 (let ((this-command 'vm-previous-message)
578 (owin (selected-window))
579 (vm-preview-lines nil)
580 )
581 (vm-previous-message 1 nil t)
582 (if (window-live-p owin)
583 (select-window owin))))
584
585 (set-alist 'mime-viewer/over-to-previous-method-alist
586 'vm-mode 'tm-vm/previous-message)
587 (set-alist 'mime-viewer/over-to-next-method-alist
588 'vm-mode 'tm-vm/next-message)
589 (set-alist 'mime-viewer/over-to-previous-method-alist
590 'vm-virtual-mode 'tm-vm/previous-message)
591 (set-alist 'mime-viewer/over-to-next-method-alist
592 'vm-virtual-mode 'tm-vm/next-message)
593
594 ;;; @@ vm-yank-message
595 ;;;
596 ;; 1996/3/28 by Oscar Figueiredo <figueire@lspsun16.epfl.ch>
597
598 (require 'vm-reply)
599
600 (defvar tm-vm/yank:message-to-restore nil
601 "For internal use by tm-vm only.")
602
603 (defun vm-yank-message (&optional message)
604 "Yank message number N into the current buffer at point.
605 When called interactively N is always read from the minibuffer. When
606 called non-interactively the first argument is expected to be a
607 message struct.
608
609 This function originally provided by vm-reply has been patched for TM
610 in order to provide better citation of MIME messages : if a MIME
611 Preview buffer exists for the message then its contents are inserted
612 instead of the raw message.
613
614 This command is meant to be used in VM created Mail mode buffers; the
615 yanked message comes from the mail buffer containing the message you
616 are replying to, forwarding, or invoked VM's mail command from.
617
618 All message headers are yanked along with the text. Point is
619 left before the inserted text, the mark after. Any hook
620 functions bound to mail-citation-hook are run, after inserting
621 the text and setting point and mark. For backward compatibility,
622 if mail-citation-hook is set to nil, `mail-yank-hooks' is run
623 instead.
624
625 If mail-citation-hook and mail-yank-hooks are both nil, this
626 default action is taken: the yanked headers are trimmed as
627 specified by vm-included-text-headers and
628 vm-included-text-discard-header-regexp, and the value of
629 vm-included-text-prefix is prepended to every yanked line."
630 (interactive
631 (list
632 ;; What we really want for the first argument is a message struct,
633 ;; but if called interactively, we let the user type in a message
634 ;; number instead.
635 (let (mp default
636 (result 0)
637 prompt
638 (last-command last-command)
639 (this-command this-command))
640 (if (bufferp vm-mail-buffer)
641 (save-excursion
642 (vm-select-folder-buffer)
643 (setq default (and vm-message-pointer
644 (vm-number-of (car vm-message-pointer)))
645 prompt (if default
646 (format "Yank message number: (default %s) "
647 default)
648 "Yank message number: "))
649 (while (zerop result)
650 (setq result (read-string prompt))
651 (and (string= result "") default (setq result default))
652 (setq result (string-to-int result)))
653 (if (null (setq mp (nthcdr (1- result) vm-message-list)))
654 (error "No such message."))
655 (setq tm-vm/yank:message-to-restore (string-to-int default))
656 (save-selected-window
657 (vm-goto-message result))
658 (car mp))
659 nil))))
660 (if (null message)
661 (if mail-reply-buffer
662 (tm-vm/yank-content)
663 (error "This is not a VM Mail mode buffer."))
664 (if (null (buffer-name vm-mail-buffer))
665 (error "The folder buffer containing message %d has been killed."
666 (vm-number-of message)))
667 (vm-display nil nil '(vm-yank-message)
668 '(vm-yank-message composing-message))
669 (let ((b (current-buffer)) (start (point)) end)
670 (save-restriction
671 (widen)
672 (save-excursion
673 (set-buffer (vm-buffer-of message))
674 (let* ((mbuf (current-buffer))
675 pbuf)
676 (tm-vm/sync-preview-buffer)
677 (setq pbuf (and mime::article/preview-buffer
678 (get-buffer mime::article/preview-buffer)))
679 (if (and pbuf
680 (not (eq this-command 'tm-vm/forward-message)))
681 (if running-xemacs
682 (let ((tmp (generate-new-buffer "tm-vm/tmp")))
683 (set-buffer pbuf)
684 (append-to-buffer tmp (point-min) (point-max))
685 (set-buffer tmp)
686 (map-extents
687 '(lambda (ext maparg)
688 (set-extent-property ext 'begin-glyph nil)))
689 (append-to-buffer b (point-min) (point-max))
690 (setq end (vm-marker
691 (+ start (length (buffer-string))) b))
692 (kill-buffer tmp))
693 (set-buffer pbuf)
694 (append-to-buffer b (point-min) (point-max))
695 (setq end (vm-marker
696 (+ start (length (buffer-string))) b)))
697 (save-restriction
698 (setq message (vm-real-message-of message))
699 (set-buffer (vm-buffer-of message))
700 (widen)
701 (append-to-buffer
702 b (vm-headers-of message) (vm-text-end-of message))
703 (setq end
704 (vm-marker (+ start (- (vm-text-end-of message)
705 (vm-headers-of message))) b))))))
706 (push-mark end)
707 (cond (mail-citation-hook (run-hooks 'mail-citation-hook))
708 (mail-yank-hooks (run-hooks 'mail-yank-hooks))
709 (t (vm-mail-yank-default message)))
710 ))
711 (if tm-vm/yank:message-to-restore
712 (save-selected-window
713 (vm-goto-message tm-vm/yank:message-to-restore)
714 (setq tm-vm/yank:message-to-restore nil)))
715 ))
716
717
718 ;;; @ for tm-view
719 ;;;
720
721 ;;; based on vm-do-reply [vm-reply.el]
722 (defun tm-vm/do-reply (buf to-all include-text)
723 (save-excursion
724 (set-buffer buf)
725 (let ((dir default-directory)
726 to cc subject mp in-reply-to references newsgroups)
727 (cond ((setq to
728 (let ((reply-to (std11-field-body "Reply-To")))
729 (if (vm-ignored-reply-to reply-to)
730 nil
731 reply-to))))
732 ((setq to (std11-field-body "From")))
733 ;; (t (error "No From: or Reply-To: header in message"))
734 )
735 (if to-all
736 (setq cc (delq nil (cons cc (std11-field-bodies '("To" "Cc"))))
737 cc (mapconcat 'identity cc ","))
738 )
739 (setq subject (std11-field-body "Subject"))
740 (and subject vm-reply-subject-prefix
741 (let ((case-fold-search t))
742 (not
743 (equal
744 (string-match (regexp-quote vm-reply-subject-prefix)
745 subject)
746 0)))
747 (setq subject (concat vm-reply-subject-prefix subject)))
748 (setq in-reply-to (std11-field-body "Message-Id")
749 references (nconc
750 (std11-field-bodies '("References" "In-Reply-To"))
751 (list in-reply-to))
752 newsgroups (list (or (and to-all
753 (std11-field-body "Followup-To"))
754 (std11-field-body "Newsgroups"))))
755 (setq to (vm-parse-addresses to)
756 cc (vm-parse-addresses cc))
757 (if vm-reply-ignored-addresses
758 (setq to (vm-strip-ignored-addresses to)
759 cc (vm-strip-ignored-addresses cc)))
760 (setq to (vm-delete-duplicates to nil t))
761 (setq cc (vm-delete-duplicates
762 (append (vm-delete-duplicates cc nil t)
763 to (copy-sequence to))
764 t t))
765 (and to (setq to (mapconcat 'identity to ",\n ")))
766 (and cc (setq cc (mapconcat 'identity cc ",\n ")))
767 (and (null to) (setq to cc cc nil))
768 (setq references (delq nil references)
769 references (mapconcat 'identity references " ")
770 references (vm-parse references "[^<]*\\(<[^>]+>\\)")
771 references (vm-delete-duplicates references)
772 references (if references (mapconcat 'identity references "\n\t")))
773 (setq newsgroups (delq nil newsgroups)
774 newsgroups (mapconcat 'identity newsgroups ",")
775 newsgroups (vm-parse newsgroups "[ \t\f\r\n,]*\\([^ \t\f\r\n,]+\\)")
776 newsgroups (vm-delete-duplicates newsgroups)
777 newsgroups (if newsgroups (mapconcat 'identity newsgroups ",")))
778 (vm-mail-internal
779 (if to
780 (format "reply to %s%s"
781 (std11-full-name-string
782 (car (std11-parse-address-string to)))
783 (if cc ", ..." "")))
784 to subject in-reply-to cc references newsgroups)
785 (setq mail-reply-buffer buf
786 ;; vm-system-state 'replying
787 default-directory dir))
788 (if include-text
789 (save-excursion
790 (goto-char (point-min))
791 (let ((case-fold-search nil))
792 (re-search-forward
793 (concat "^" (regexp-quote mail-header-separator) "$") nil 0))
794 (forward-char 1)
795 (tm-vm/yank-content)))
796 (run-hooks 'vm-reply-hook)
797 (run-hooks 'vm-mail-mode-hook)
798 ))
799
800 (defun tm-vm/following-method (buf)
801 (tm-vm/do-reply buf 'to-all 'include-text)
802 )
803
804 (defun tm-vm/yank-content ()
805 (interactive)
806 (let ((this-command 'vm-yank-message))
807 (vm-display nil nil '(vm-yank-message)
808 '(vm-yank-message composing-message))
809 (save-restriction
810 (narrow-to-region (point)(point))
811 (insert-buffer mail-reply-buffer)
812 (goto-char (point-max))
813 (push-mark)
814 (goto-char (point-min)))
815 (cond (mail-citation-hook (run-hooks 'mail-citation-hook))
816 (mail-yank-hooks (run-hooks 'mail-yank-hooks))
817 (t (mail-indent-citation)))
818 ))
819
820 (set-alist 'mime-viewer/following-method-alist
821 'vm-mode
822 (function tm-vm/following-method))
823 (set-alist 'mime-viewer/following-method-alist
824 'vm-virtual-mode
825 (function tm-vm/following-method))
826
827
828 (defun tm-vm/quit-view-message ()
829 "Quit MIME-Viewer and go back to normal VM. MIME Preview buffer
830 is killed. This function is called by `mime-viewer/quit' command
831 via `mime-viewer/quitting-method-alist'."
832 (if (get-buffer mime/output-buffer-name)
833 (vm-undisplay-buffer mime/output-buffer-name))
834 (vm-select-folder-buffer)
835 (let* ((mbuf (current-buffer))
836 (pbuf (and mime::article/preview-buffer
837 (get-buffer mime::article/preview-buffer)))
838 (pwin (and pbuf (vm-get-visible-buffer-window pbuf))))
839 (kill-buffer pbuf)
840 (and pwin
841 (select-window pwin)
842 (switch-to-buffer mbuf)))
843 (setq tm-vm/system-state nil)
844 (vm-display (current-buffer) t (list this-command)
845 (list 'reading-message))
846 )
847
848 (defun tm-vm/view-message ()
849 "Decode and view a MIME encoded message under VM.
850 A MIME Preview buffer using mime/viewer-mode is created.
851 See mime/viewer-mode for more information"
852 (interactive)
853 (vm-follow-summary-cursor)
854 (vm-select-folder-buffer)
855 (vm-check-for-killed-summary)
856 (vm-error-if-folder-empty)
857 (vm-display (current-buffer) t '(tm-vm/view-message
858 tm-vm/toggle-preview-mode)
859 '(tm-vm/view-message reading-message))
860 (let ((tm-vm/automatic-mime-preview t))
861 (tm-vm/preview-current-message))
862 )
863
864 (set-alist 'mime-viewer/quitting-method-alist
865 'vm-mode
866 'tm-vm/quit-view-message)
867
868 (set-alist 'mime-viewer/quitting-method-alist
869 'vm-virtual-mode
870 'tm-vm/quit-view-message)
871
872
873 ;;; @ for tm-partial
874 ;;;
875
876 (call-after-loaded
877 'tm-partial
878 (function
879 (lambda ()
880 (set-atype 'mime/content-decoding-condition
881 '((type . "message/partial")
882 (method . mime-article/grab-message/partials)
883 (major-mode . vm-mode)
884 (summary-buffer-exp . vm-summary-buffer)
885 ))
886 (set-alist 'tm-partial/preview-article-method-alist
887 'vm-mode
888 (function
889 (lambda ()
890 (tm-vm/view-message)
891 )))
892 )))
893
894
895 ;;; @ for tm-edit
896 ;;;
897
898 ;;; @@ for multipart/digest
899 ;;;
900
901 (defvar tm-vm/forward-message-hook nil
902 "*List of functions called after a Mail mode buffer has been
903 created to forward a message in message/rfc822 type format.
904 If `vm-forwarding-digest-type' is \"rfc1521\", tm-vm runs this
905 hook instead of `vm-forward-message-hook'.")
906
907 (defvar tm-vm/send-digest-hook nil
908 "*List of functions called after a Mail mode buffer has been
909 created to send a digest in multipart/digest type format.
910 If `vm-digest-send-type' is \"rfc1521\", tm-vm runs this hook
911 instead of `vm-send-digest-hook'.")
912
913 (defun tm-vm/enclose-messages (mlist &optional preamble)
914 "Enclose the messages in MLIST as multipart/digest.
915 The resulting digest is inserted at point in the current buffer.
916
917 MLIST should be a list of message structs (real or virtual).
918 These are the messages that will be enclosed."
919 (if mlist
920 (let ((digest (consp (cdr mlist)))
921 (mp mlist)
922 m)
923 (save-restriction
924 (narrow-to-region (point) (point))
925 (while mlist
926 (setq m (vm-real-message-of (car mlist)))
927 (mime-editor/insert-tag "message" "rfc822")
928 (tm-mail/insert-message m)
929 (goto-char (point-max))
930 (setq mlist (cdr mlist)))
931 (if preamble
932 (progn
933 (goto-char (point-min))
934 (mime-editor/insert-tag "text" "plain")
935 (vm-unsaved-message "Building digest preamble...")
936 (while mp
937 (let ((vm-summary-uninteresting-senders nil))
938 (insert
939 (vm-sprintf 'vm-digest-preamble-format (car mp)) "\n"))
940 (if vm-digest-center-preamble
941 (progn
942 (forward-char -1)
943 (center-line)
944 (forward-char 1)))
945 (setq mp (cdr mp)))))
946 (if digest
947 (mime-editor/enclose-digest-region (point-min) (point-max)))
948 ))))
949
950 (defun tm-vm/forward-message ()
951 "Forward the current message to one or more recipients.
952 You will be placed in a Mail mode buffer as you would with a
953 reply, but you must fill in the To: header and perhaps the
954 Subject: header manually."
955 (interactive)
956 (if (not (equal vm-forwarding-digest-type "rfc1521"))
957 (vm-forward-message)
958 (if mime::preview/article-buffer
959 (set-buffer mime::preview/article-buffer))
960 (vm-follow-summary-cursor)
961 (vm-select-folder-buffer)
962 (vm-check-for-killed-summary)
963 (vm-error-if-folder-empty)
964 (if (eq last-command 'vm-next-command-uses-marks)
965 (let ((vm-digest-send-type vm-forwarding-digest-type))
966 (setq this-command 'vm-next-command-uses-marks)
967 (command-execute 'tm-vm/send-digest))
968 (let ((dir default-directory)
969 (mp vm-message-pointer))
970 (save-restriction
971 (widen)
972 (vm-mail-internal
973 (format "forward of %s's note re: %s"
974 (vm-su-full-name (car vm-message-pointer))
975 (vm-su-subject (car vm-message-pointer)))
976 nil
977 (and vm-forwarding-subject-format
978 (let ((vm-summary-uninteresting-senders nil))
979 (vm-sprintf 'vm-forwarding-subject-format (car mp)))))
980 (make-local-variable 'vm-forward-list)
981 (setq vm-system-state 'forwarding
982 vm-forward-list (list (car mp))
983 default-directory dir)
984 (goto-char (point-min))
985 (re-search-forward
986 (concat "^" (regexp-quote mail-header-separator) "\n") nil 0)
987 (tm-vm/enclose-messages vm-forward-list)
988 (mail-position-on-field "To"))
989 (run-hooks 'tm-vm/forward-message-hook)
990 (run-hooks 'vm-mail-mode-hook)))))
991
992 (defun tm-vm/send-digest (&optional arg)
993 "Send a digest of all messages in the current folder to recipients.
994 The type of the digest is specified by the variable vm-digest-send-type.
995 You will be placed in a Mail mode buffer as is usual with replies, but you
996 must fill in the To: and Subject: headers manually.
997
998 If invoked on marked messages (via vm-next-command-uses-marks),
999 only marked messages will be put into the digest."
1000 (interactive "P")
1001 (if (not (equal vm-digest-send-type "rfc1521"))
1002 (vm-send-digest arg)
1003 (vm-select-folder-buffer)
1004 (vm-check-for-killed-summary)
1005 (vm-error-if-folder-empty)
1006 (let ((dir default-directory)
1007 (vm-forward-list (if (eq last-command 'vm-next-command-uses-marks)
1008 (vm-select-marked-or-prefixed-messages 0)
1009 vm-message-list))
1010 start)
1011 (save-restriction
1012 (widen)
1013 (vm-mail-internal (format "digest from %s" (buffer-name)))
1014 (setq vm-system-state 'forwarding
1015 default-directory dir)
1016 (goto-char (point-min))
1017 (re-search-forward (concat "^" (regexp-quote mail-header-separator)
1018 "\n"))
1019 (goto-char (match-end 0))
1020 (vm-unsaved-message "Building %s digest..." vm-digest-send-type)
1021 (tm-vm/enclose-messages vm-forward-list arg)
1022 (mail-position-on-field "To")
1023 (message "Building %s digest... done" vm-digest-send-type)))
1024 (run-hooks 'tm-vm/send-digest-hook)
1025 (run-hooks 'vm-mail-mode-hook)))
1026
1027 (substitute-key-definition 'vm-forward-message
1028 'tm-vm/forward-message vm-mode-map)
1029 (substitute-key-definition 'vm-send-digest
1030 'tm-vm/send-digest vm-mode-map)
1031
1032
1033 ;;; @@ setting
1034 ;;;
1035
1036 (defvar tm-vm/use-xemacs-popup-menu t)
1037
1038 ;;; modified by Steven L. Baur <steve@miranova.com>
1039 ;;; 1995/12/6 (c.f. [tm-en:209])
1040 (defun mime-editor/attach-to-vm-mode-menu ()
1041 "Arrange to attach MIME editor's popup menu to VM's"
1042 (if (boundp 'vm-menu-mail-menu)
1043 (progn
1044 (setq vm-menu-mail-menu
1045 (append vm-menu-mail-menu
1046 (list "----"
1047 mime-editor/popup-menu-for-xemacs)))
1048 (remove-hook 'vm-mail-mode-hook 'mime-editor/attach-to-vm-mode-menu)
1049 )))
1050
1051 (call-after-loaded
1052 'tm-edit
1053 (function
1054 (lambda ()
1055 (autoload 'tm-mail/insert-message "tm-mail")
1056 (set-alist 'mime-editor/message-inserter-alist
1057 'mail-mode (function tm-mail/insert-message))
1058 (set-alist 'mime-editor/split-message-sender-alist
1059 'mail-mode (function
1060 (lambda ()
1061 (interactive)
1062 (sendmail-send-it)
1063 )))
1064 (if (and (string-match "XEmacs\\|Lucid" emacs-version)
1065 tm-vm/use-xemacs-popup-menu)
1066 (add-hook 'vm-mail-mode-hook 'mime-editor/attach-to-vm-mode-menu)
1067 )
1068 )))
1069
1070 (call-after-loaded
1071 'mime-setup
1072 (function
1073 (lambda ()
1074 (setq vm-forwarding-digest-type "rfc1521")
1075 (setq vm-digest-send-type "rfc1521")
1076 )))
1077
1078
1079 ;;; @ for BBDB
1080 ;;;
1081
1082 (call-after-loaded
1083 'bbdb
1084 (function
1085 (lambda ()
1086 (require 'bbdb-vm)
1087 (require 'tm-bbdb)
1088 (defun tm-bbdb/vm-update-record (&optional offer-to-create)
1089 (vm-select-folder-buffer)
1090 (if (and (tm-vm/system-state)
1091 mime::article/preview-buffer
1092 (get-buffer mime::article/preview-buffer))
1093 (let ((tm-bbdb/auto-create-p bbdb/mail-auto-create-p))
1094 (tm-bbdb/update-record offer-to-create))
1095 (or (bbdb/vm-update-record offer-to-create)
1096 (delete-windows-on (get-buffer "*BBDB*")))
1097 ))
1098 (remove-hook 'vm-select-message-hook 'bbdb/vm-update-record)
1099 (remove-hook 'vm-show-message-hook 'bbdb/vm-update-record)
1100 (add-hook 'tm-vm/select-message-hook 'tm-bbdb/vm-update-record)
1101 )))
1102
1103 ;;; @ for ps-print (Suggestted by Anders Stenman <stenman@isy.liu.se>)
1104 ;;;
1105
1106 (defvar tm-vm/use-ps-print (not (or running-mule-merged-emacs
1107 running-xemacs-with-mule))
1108 "*Use Postscript printing (ps-print) to print MIME messages.")
1109
1110 (if tm-vm/use-ps-print
1111 (progn
1112 (require 'ps-print)
1113 (add-hook 'vm-mode-hook 'tm-vm/ps-print-setup)
1114 (add-hook 'mime-viewer/define-keymap-hook 'tm-vm/ps-print-setup)
1115 (fset 'vm-toolbar-print-command 'tm-vm/print-message)))
1116
1117 (defun tm-vm/ps-print-setup ()
1118 "Set things up for printing MIME messages with ps-print. Set binding to
1119 the [Print Screen] key."
1120 (local-set-key (ps-prsc) 'tm-vm/print-message)
1121 (setq ps-header-lines 3)
1122 (setq ps-left-header
1123 (list 'ps-article-subject 'ps-article-author 'buffer-name)))
1124
1125 (defun tm-vm/print-message ()
1126 "Print current message with ps-print if it's a MIME message.
1127 Value of tm-vm/strict-mime is also taken into consideration."
1128 (interactive)
1129 (vm-follow-summary-cursor)
1130 (let* ((mbuf (or (vm-select-folder-buffer) (current-buffer)))
1131 pbuf)
1132 (tm-vm/sync-preview-buffer)
1133 (setq pbuf (and mime::article/preview-buffer
1134 (get-buffer mime::article/preview-buffer)))
1135 (if pbuf
1136 (save-excursion
1137 (set-buffer pbuf)
1138 (require 'ps-print)
1139 (ps-print-buffer-with-faces))
1140 (vm-print-message))))
1141
1142
1143 ;;; @ Substitute VM bindings and menus
1144 ;;;
1145
1146 (substitute-key-definition 'vm-scroll-forward
1147 'tm-vm/scroll-forward vm-mode-map)
1148 (substitute-key-definition 'vm-scroll-backward
1149 'tm-vm/scroll-backward vm-mode-map)
1150 (substitute-key-definition 'vm-beginning-of-message
1151 'tm-vm/beginning-of-message vm-mode-map)
1152 (substitute-key-definition 'vm-end-of-message
1153 'tm-vm/end-of-message vm-mode-map)
1154 (substitute-key-definition 'vm-forward-message
1155 'tm-vm/forward-message vm-mode-map)
1156 (substitute-key-definition 'vm-quit
1157 'tm-vm/quit vm-mode-map)
1158 (substitute-key-definition 'vm-quit-no-change
1159 'tm-vm/quit-no-change vm-mode-map)
1160
1161 ;; The following function should be modified and called on vm-menu-setup-hook
1162 ;; but VM 5.96 does not run that hook on XEmacs
1163 (require 'vm-menu)
1164 (if running-xemacs
1165 (condition-case nil
1166 (aset (car (find-menu-item vm-menu-dispose-menu '("Forward")))
1167 1
1168 'tm-vm/forward-message)
1169 (t nil)))
1170
1171 ;;; @ end
1172 ;;;
1173
1174 (provide 'tm-vm)
1175
1176 (run-hooks 'tm-vm-load-hook)
1177
1178 ;;; tm-vm.el ends here.
1179