2 ;;; tm-vm.el --- tm-MUA for VM
4 ;;; Copyright (C) 1995 Free Software Foundation, Inc.
6 ;;; Author: MASUTANI Yasuhiro <masutani@me.es.osaka-u.ac.jp>
7 ;;; Kenji Wakamiya <wkenji@flab.fujitsu.co.jp>
8 ;;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
9 ;;; Shuhei KOBAYASHI <shuhei@cmpt01.phys.tohoku.ac.jp>
10 ;;; Oscar Figueiredo <figueire@lspsun2.epfl.ch>
11 ;;; modified by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
13 ;;; Keywords: news, MIME, multimedia, multilingual, encoded-word
15 ;;; This file is part of tm (Tools for MIME).
17 ;;; Plese insert (require 'tm-vm) in your ~/.vm or ~/.emacs file.
23 (defconst tm-vm/RCS-ID
24 "$Id: tm-vm.el,v 7.18 1995/11/20 02:48:34 morioka Exp $")
25 (defconst tm-vm/version (get-version-string tm-vm/RCS-ID))
27 (define-key vm-mode-map "Z" 'tm-vm/view-message)
28 (define-key vm-mode-map "T" 'tm-vm/decode-message-header)
29 (define-key vm-mode-map "\et" 'tm-vm/toggle-preview-mode)
32 ;;; @ for MIME encoded-words
35 (defvar tm-vm/use-tm-patch nil
36 "Does not decode encoded-words in summary buffer if it is t.
37 If you use tiny-mime patch for VM (by RIKITAKE Kenji
38 <kenji@reseau.toyonaka.osaka.jp>), please set it t [tm-vm.el]")
40 (or tm-vm/use-tm-patch
43 (defvar tm-vm/chop-full-name-function 'tm-vm/default-chop-full-name)
44 (setq vm-chop-full-name-function tm-vm/chop-full-name-function)
46 (defun tm-vm/default-chop-full-name (address)
47 (let* ((ret (vm-default-chop-full-name address))
50 (if (stringp full-name)
51 (cons (mime-eword/decode-string full-name)
56 (or (fboundp 'tm:vm-su-subject)
57 (fset 'tm:vm-su-subject (symbol-function 'vm-su-subject))
59 (defun vm-su-subject (m)
60 (mime-eword/decode-string (tm:vm-su-subject m))
65 (defun tm-vm/decode-message-header (&optional count)
66 "Decode MIME header of current message through tiny-mime.
67 Numeric prefix argument COUNT means to decode the current message plus
68 the next COUNT-1 messages. A negative COUNT means decode the current
69 message and the previous COUNT-1 messages.
70 When invoked on marked messages (via vm-next-command-uses-marks),
71 all marked messages are affected, other messages are ignored."
73 (or count (setq count 1))
74 (vm-follow-summary-cursor)
75 (vm-select-folder-buffer)
76 (vm-check-for-killed-summary)
77 (vm-error-if-folder-empty)
78 (vm-error-if-folder-read-only)
79 (let ((mlist (vm-select-marked-or-prefixed-messages count))
85 (setq realm (vm-real-message-of (car mlist)))
86 ;; Go to real folder of this message.
87 ;; But maybe this message is already real message...
88 (set-buffer (vm-buffer-of realm))
89 (let ((buffer-read-only nil))
91 (narrow-to-region (vm-headers-of realm) (vm-text-of realm))
92 (mime/decode-message-header))
93 (let ((vm-message-pointer (list realm))
95 (vm-discard-cached-data))
96 ;; Mark each virtual and real message for later summary
98 (setq vlist (cons realm (vm-virtual-messages-of realm)))
100 (vm-mark-for-summary-update (car vlist))
101 ;; Remember virtual and real folders related this message,
102 ;; for later display update.
103 (or (memq (vm-buffer-of (car vlist)) vbufs)
104 (setq vbufs (cons (vm-buffer-of (car vlist)) vbufs)))
105 (setq vlist (cdr vlist)))
106 (if (eq vm-flush-interval t)
107 (vm-stuff-virtual-attributes realm)
108 (vm-set-modflag-of realm t)))
109 (setq mlist (cdr mlist)))
110 ;; Update mail-buffers and summaries.
112 (set-buffer (car vbufs))
113 (vm-preview-current-message)
114 (setq vbufs (cdr vbufs))))))
117 ;;; @ automatic MIME preview
120 (defvar tm-vm/automatic-mime-preview t
121 "If non-nil, show MIME processed article.")
123 (defun tm-vm/preview-current-message ()
124 ;;; suggested by Simon Rowe <smr@robots.oxford.ac.uk>
125 ;;; (cf. [tm-eng:163])
126 ;; Selecting a new mail message, but we're already displaying a mime
127 ;; on in the window, make sure that the mail buffer is displayed.
128 (if (get-buffer-window "*MIME-out*")
129 (delete-window (get-buffer-window (get-buffer "*MIME-out*")))
131 (if (and tm-vm/automatic-mime-preview
132 ;; fixed by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
133 ;; 1995/11/17 (cf.[tm-ja:1120])
134 (display-buffer (current-buffer))
135 (let* ((mp (car vm-message-pointer))
136 (ct (vm-get-header-contents mp "Content-Type:"))
137 (cte (vm-get-header-contents
138 mp "Content-Transfer-Encoding:"))
140 ;; Check if this message actually is a mime, or just a text
141 ;; one sent by someone using PINE or similar.
143 (not (and (string= (car (mime/parse-Content-Type ct))
145 (member cte '("7bit" "8bit" "binary"))
148 (let ((win (selected-window)))
149 (let ((pwin (and mime::article/preview-buffer
150 (get-buffer mime::article/preview-buffer)
151 (get-buffer-window mime::article/preview-buffer))))
155 (vm-select-folder-buffer)
156 (vm-display (current-buffer) t
157 '(tm-vm/preview-current-message
158 vm-preview-current-message)
159 (list this-command 'reading-message))
161 (run-hooks 'tm-vm/vm-select-message-hook)
162 (vm-display (current-buffer) t
163 '(tm-vm/preview-current-message
164 vm-preview-current-message)
165 (list this-command 'reading-message))
167 (vm-display-buffer (current-buffer))
168 ;; (vm-display (current-buffer) t
169 ;; '(tm-vm/preview-current-message
170 ;; vm-preview-current-message)
171 ;; '(vm-summarize reading-message))
173 ;; fixed by Oscar Figueiredo <figueire@lspsun2.epfl.ch>
175 (if (and mime::article/preview-buffer
176 (get-buffer mime::article/preview-buffer))
177 (kill-buffer mime::article/preview-buffer))
178 (if tm-vm/automatic-mime-preview
179 (let (buffer-read-only)
180 (mime/decode-message-header)
181 (run-hooks 'tm-vm/vm-select-message-hook)
185 (add-hook 'vm-select-message-hook 'tm-vm/preview-current-message)
186 (add-hook 'vm-visit-folder-hook 'tm-vm/preview-current-message)
188 ;; fixed by Oscar Figueiredo <figueire@lspsun2.epfl.ch>
189 ;; 1995/11/14 (cf.[tm-eng:162])
190 (defun tm-vm/scroll-forward ()
192 (if (not tm-vm/automatic-mime-preview)
193 ;; fixed by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
194 ;; 1995/11/17 (cf.[tm-ja:1119])
196 (setq this-command 'vm-scroll-forward)
198 (let* ((summary-buffer (or vm-summary-buffer
199 (and (eq major-mode 'vm-summary-mode)
201 (summary-win (get-buffer-window summary-buffer))
202 (mail-buffer (save-excursion
203 (set-buffer summary-buffer)
205 (mail-win (get-buffer-window mail-buffer))
206 (preview-buf (save-excursion
207 (set-buffer mail-buffer)
208 mime::article/preview-buffer))
209 (preview-win (and preview-buf (get-buffer-window preview-buf)))
213 (select-window preview-win)
214 (if (pos-visible-in-window-p (point-max) preview-win)
216 (switch-to-buffer mail-buffer)
217 (goto-char (point-max))
218 (select-window summary-win))
220 (switch-to-buffer mail-buffer)
221 (select-window summary-win))))
222 ;; fixed by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
223 ;; 1995/11/17 (cf.[tm-ja:1119])
224 (setq this-command 'vm-scroll-forward)
227 (set-buffer summary-buffer)
228 (setq mail-win (get-buffer-window vm-mail-buffer)))
229 ;; fixed by Oscar Figueiredo <figueire@lspsun2.epfl.ch>
232 mime::article/preview-buffer
233 (get-buffer mime::article/preview-buffer))
235 (select-window mail-win)
236 (switch-to-buffer mime::article/preview-buffer)
237 (select-window summary-win)))
240 (defun tm-vm/scroll-backward ()
242 (if (not tm-vm/automatic-mime-preview)
243 ;; fixed by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
244 ;; 1995/11/17 (cf.[tm-ja:1119])
246 (setq this-command 'vm-scroll-backward)
247 (vm-scroll-backward nil))
248 (let* ((summary-buffer (or vm-summary-buffer
249 (and (eq major-mode 'vm-summary-mode)
251 (summary-win (get-buffer-window summary-buffer))
252 (mail-buffer (save-excursion
253 (set-buffer summary-buffer)
255 (mail-win (get-buffer-window mail-buffer))
256 (preview-buf (save-excursion
257 (set-buffer mail-buffer)
258 mime::article/preview-buffer))
259 (preview-win (and preview-buf (get-buffer-window preview-buf)))
263 (select-window preview-win)
264 (if (pos-visible-in-window-p (point-min) preview-win)
266 (switch-to-buffer mail-buffer)
267 (goto-char (point-min))
268 (select-window summary-win))
270 (switch-to-buffer mail-buffer)
271 (select-window summary-win))))
272 ;; fixed by SHIONO Jun'ichi <jun@case.nm.fujitsu.co.jp>
273 ;; 1995/11/17 (cf.[tm-ja:1119])
274 (setq this-command 'vm-scroll-backward)
275 (vm-scroll-backward nil)
277 (set-buffer summary-buffer)
278 (setq mail-win (get-buffer-window vm-mail-buffer)))
280 mime::article/preview-buffer
281 (get-buffer mime::article/preview-buffer))
283 (select-window mail-win)
284 (goto-char (point-max))
285 (switch-to-buffer mime::article/preview-buffer)
286 (select-window summary-win)))
289 ;; 1995/11/16 by Oscar Figueiredo <figueire@lspsun2.epfl.ch>
290 (defun tm-vm/expunge-folder ()
292 (let* ((summary-buf (or (and (eq major-mode 'vm-summary-mode)
295 (preview-buf (save-excursion
296 (set-buffer (save-excursion
297 (set-buffer summary-buf)
299 mime::article/preview-buffer))
300 (preview-win (and preview-buf
301 (get-buffer-window preview-buf)))
302 (win (selected-window)))
307 (set-buffer summary-buf)
308 (set-buffer vm-mail-buffer)
309 (if (eq (point-min) (point-max))
310 (kill-buffer preview-buf))))
313 ;; fixed by Oscar Figueiredo <figueire@lspsun2.epfl.ch>
314 ;; 1995/11/14 (cf. [tm-eng:162])
318 (set-buffer vm-mail-buffer)
319 (if (and mime::article/preview-buffer
320 (get-buffer mime::article/preview-buffer))
321 (kill-buffer mime::article/preview-buffer)))
325 (substitute-key-definition 'vm-scroll-forward
326 'tm-vm/scroll-forward vm-mode-map)
327 (substitute-key-definition 'vm-scroll-backward
328 'tm-vm/scroll-backward vm-mode-map)
329 (substitute-key-definition 'vm-expunge-folder
330 'tm-vm/expunge-folder vm-mode-map)
331 (substitute-key-definition 'vm-quit
332 'tm-vm/quit vm-mode-map)
336 (defun tm-vm/toggle-preview-mode ()
338 (if tm-vm/automatic-mime-preview
340 (setq tm-vm/automatic-mime-preview nil)
341 (vm-select-folder-buffer)
342 (vm-display (current-buffer) t
343 '(tm-vm/toggle-preview-mode)
344 '(tm-vm/toggle-preview-mode reading-message))
346 (setq tm-vm/automatic-mime-preview t)
347 (let ((win (selected-window)))
348 (vm-select-folder-buffer)
349 (save-window-excursion
350 (let* ((mp (car vm-message-pointer))
351 (ct (vm-get-header-contents mp "Content-Type:"))
352 (cte (vm-get-header-contents mp "Content-Transfer-Encoding:"))
354 (mime/viewer-mode nil (mime/parse-Content-Type (or ct "")) cte)
356 (vm-display mime::article/preview-buffer t
357 '(tm-vm/toggle-preview-mode)
358 '(tm-vm/toggle-preview-mode reading-message))
367 (defun tm-vm/quit-view-message ()
368 "Quit MIME-viewer and go back to VM.
369 This function is called by `mime-viewer/quit' command via
370 `mime-viewer/quitting-method-alist'."
371 (mime-viewer/kill-buffer)
372 (if (get-buffer mime/output-buffer-name)
373 (bury-buffer mime/output-buffer-name))
374 (vm-select-folder-buffer)
375 (vm-display (current-buffer) t '(mime-viewer/quit mime-viewer/up-content)
376 '(mime-viewer/quit reading-message)))
378 (defun tm-vm/view-message ()
379 "Decode and view MIME encoded message, under VM."
381 (vm-follow-summary-cursor)
382 (vm-select-folder-buffer)
383 (vm-check-for-killed-summary)
384 (vm-error-if-folder-empty)
385 (vm-display (current-buffer) t '(tm-vm/view-message)
386 '(tm-vm/view-mesage reading-message))
387 (let* ((mp (car vm-message-pointer))
388 (ct (vm-get-header-contents mp "Content-Type:"))
389 (cte (vm-get-header-contents mp "Content-Transfer-Encoding:"))
390 (exposed (= (point-min) (vm-start-of mp))))
393 ;; vm-widen-page hides exposed header if pages are delimited.
394 ;; So, here we expose it again.
396 (narrow-to-region (vm-start-of mp) (point-max)))
397 (select-window (vm-get-buffer-window (current-buffer)))
398 (mime/viewer-mode nil
399 (mime/parse-Content-Type (or ct ""))
403 (set-alist 'mime-viewer/quitting-method-alist
405 'tm-vm/quit-view-message)
407 (set-alist 'mime-viewer/quitting-method-alist
409 'tm-vm/quit-view-message)
419 (set-atype 'mime/content-decoding-condition
420 '((type . "message/partial")
421 (method . mime-article/grab-message/partials)
422 (major-mode . vm-mode)
423 (summary-buffer-exp . vm-summary-buffer)
425 (set-alist 'tm-partial/preview-article-method-alist
437 ;; 1995/11/9 by Shuhei KOBAYASHI <shuhei@cmpt01.phys.tohoku.ac.jp>
438 ;; (cf. [tm ML:1075])
439 (defun tm-vm/insert-message (&optional message)
441 (let* (mail-yank-hooks
442 (mail-citation-hook '(mime-editor/inserted-message-filter))
443 (mail-reply-buffer vm-mail-buffer)
446 (call-interactively 'vm-yank-message)
447 (vm-yank-message message))
451 ;;; @@ for multipart/digest
454 (defun tm-vm/enclose-messages (mlist)
455 "Enclose the messages in MLIST as multipart/digest.
456 The resulting digest is inserted at point in the current buffer.
458 MLIST should be a list of message structs (real or virtual).
459 These are the messages that will be enclosed."
461 (let ((digest (consp (cdr mlist)))
464 (narrow-to-region (point) (point))
466 (setq m (vm-real-message-of (car mlist)))
467 (mime-editor/insert-tag "message" "rfc822")
468 (tm-vm/insert-message m)
469 (goto-char (point-max))
470 (setq mlist (cdr mlist)))
472 (mime-editor/enclose-digest-region (point-min) (point-max)))
475 (defun tm-vm/forward-message ()
476 "Forward the current message to one or more recipients.
477 You will be placed in a Mail mode buffer as you would with a
478 reply, but you must fill in the To: header and perhaps the
479 Subject: header manually."
481 (if (not (equal vm-forwarding-digest-type "rfc1521"))
483 (vm-follow-summary-cursor)
484 (vm-select-folder-buffer)
485 (vm-check-for-killed-summary)
486 (vm-error-if-folder-empty)
487 (if (eq last-command 'vm-next-command-uses-marks)
488 (let ((vm-digest-send-type vm-forwarding-digest-type))
489 (setq this-command 'vm-next-command-uses-marks)
490 (command-execute 'tm-vm/send-digest))
491 (let ((dir default-directory)
492 (mp vm-message-pointer))
496 (format "forward of %s's note re: %s"
497 (vm-su-full-name (car vm-message-pointer))
498 (vm-su-subject (car vm-message-pointer)))
500 (and vm-forwarding-subject-format
501 (let ((vm-summary-uninteresting-senders nil))
502 (vm-sprintf 'vm-forwarding-subject-format (car mp)))))
503 (make-local-variable 'vm-forward-list)
504 (setq vm-system-state 'forwarding
505 vm-forward-list (list (car mp))
506 default-directory dir)
507 (goto-char (point-min))
509 (concat "^" (regexp-quote mail-header-separator) "\n") nil 0)
510 (tm-vm/enclose-messages vm-forward-list)
511 (mail-position-on-field "To"))
512 ;; (run-hooks 'tm-vm/forward-message-hook) ; Is it necessary?
513 (run-hooks 'vm-mail-mode-hook)))))
515 (defun tm-vm/send-digest (&optional prefix)
516 "Send a digest of all messages in the current folder to recipients.
517 The type of the digest is specified by the variable vm-digest-send-type.
518 You will be placed in a Mail mode buffer as is usual with replies, but you
519 must fill in the To: and Subject: headers manually.
521 If invoked on marked messages (via vm-next-command-uses-marks),
522 only marked messages will be put into the digest."
524 (if (not (equal vm-digest-send-type "rfc1521"))
525 (vm-send-digest prefix)
526 (vm-select-folder-buffer)
527 (vm-check-for-killed-summary)
528 (vm-error-if-folder-empty)
529 (let ((dir default-directory)
530 (mp vm-message-pointer)
531 (mlist (if (eq last-command 'vm-next-command-uses-marks)
532 (vm-select-marked-or-prefixed-messages 0)
537 (vm-mail-internal (format "digest from %s" (buffer-name)))
538 (setq vm-system-state 'forwarding
539 vm-forward-list mlist
540 default-directory dir)
541 (goto-char (point-min))
542 (re-search-forward (concat "^" (regexp-quote mail-header-separator)
544 (goto-char (match-end 0))
547 (vm-unsaved-message "Building %s digest..." vm-digest-send-type)
548 (tm-vm/enclose-messages mlist)
553 (mime-editor/insert-tag "text" "plain")
554 (vm-unsaved-message "Building digest preamble...")
556 (let ((vm-summary-uninteresting-senders nil))
557 (insert (vm-sprintf 'vm-digest-preamble-format (car mp)) "\n"))
558 (if vm-digest-center-preamble
563 (setq mp (cdr mp)))))
564 (mail-position-on-field "To")
565 (message "Building %s digest... done" vm-digest-send-type)))
566 ;; (run-hooks 'tm-vm/send-digest-hook) ; Is it necessary?
567 (run-hooks 'vm-mail-mode-hook)))
573 (substitute-key-definition 'vm-forward-message
574 'tm-vm/forward-message vm-mode-map)
575 (substitute-key-definition 'vm-send-digest
576 'tm-vm/send-digest vm-mode-map)
582 (set-alist 'mime-editor/message-inserter-alist
583 'mail-mode (function tm-vm/insert-message))
590 ;;(remove-hook 'mail-mode-hook 'mime/editor-mode)
591 ;;(add-hook 'vm-mail-mode-hook 'mime/editor-mode)
592 (setq vm-forwarding-digest-type "rfc1521")
593 (setq vm-digest-send-type "rfc1521")
604 (or (fboundp 'tm:bbdb/vm-update-record)
605 (fset 'tm:bbdb/vm-update-record
606 (symbol-function 'bbdb/vm-update-record))
608 (defun bbdb/vm-update-record (&optional offer-to-create)
609 (vm-select-folder-buffer)
610 (let ((vm-mail-buffer
611 (if (and mime::article/preview-buffer
612 (get-buffer mime::article/preview-buffer))
613 mime::article/preview-buffer
616 (bbdb/vm-update-record-recursive
617 (boundp 'bbdb/vm-update-record-recursive))
618 bbdb/vm-update-record-recursive ret)
619 (let ((bbdb/vm-update-record-answer
620 (if (boundp 'bbdb/vm-update-record-answer)
621 (setq bbdb/vm-update-record-answer
622 (or bbdb/vm-update-record-answer
623 (tm:bbdb/vm-update-record)
625 (setq ret (tm:bbdb/vm-update-record))
627 (or bbdb/vm-update-record-answer ret)
629 (defun tm-vm/bbdb-update-record (&optional offer-to-create)
630 (let ((vm-mail-buffer (current-buffer)))
631 (tm:bbdb/vm-update-record offer-to-create)
633 (remove-hook 'vm-select-message-hook 'bbdb/vm-update-record)
634 (remove-hook 'vm-show-message-hook 'bbdb/vm-update-record)
635 (add-hook 'tm-vm/select-message-hook 'tm-vm/update-record)