1 ;;; wl-message.el --- Message displaying modules for Wanderlust.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
8 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
31 (eval-when-compile (require 'cl
))
32 (eval-when-compile (require 'static
))
35 (require 'wl-highlight
)
43 (defalias-maybe 'event-window
'ignore
)
44 (defalias-maybe 'posn-window
'ignore
)
45 (defalias-maybe 'event-start
'ignore
)
46 (defalias-maybe 'mime-open-entity
'ignore
)
47 (defalias-maybe 'itimer-function
'ignore
)
48 (defalias-maybe 'delete-itimer
'ignore
)
49 (defvar-maybe itimer-list
))
51 (defvar wl-message-buffer-prefetch-get-next-function
52 'wl-summary-default-get-next-msg
)
54 (defvar wl-message-buffer-prefetch-debug nil
)
56 (defvar wl-message-buffer nil
) ; message buffer.
58 (defvar wl-message-buffer-cur-folder nil
)
59 (defvar wl-message-buffer-cur-number nil
)
60 (defvar wl-message-buffer-cur-display-type nil
)
61 (defvar wl-message-buffer-cur-summary-buffer nil
)
62 (defvar wl-message-buffer-require-all-header nil
)
63 (defvar wl-message-buffer-original-buffer nil
) ; original buffer.
64 (defvar wl-message-buffer-mode-line-formatter nil
)
65 (defvar wl-message-buffer-flag-indicator nil
)
66 (defvar wl-message-buffer-mime-entity nil
)
68 (make-variable-buffer-local 'wl-message-buffer-cur-folder
)
69 (make-variable-buffer-local 'wl-message-buffer-cur-number
)
70 (make-variable-buffer-local 'wl-message-buffer-cur-display-type
)
71 (make-variable-buffer-local 'wl-message-buffer-cur-summary-buffer
)
72 (make-variable-buffer-local 'wl-message-buffer-require-all-header
)
73 (make-variable-buffer-local 'wl-message-buffer-original-buffer
)
74 (make-variable-buffer-local 'wl-message-buffer-mode-line-formatter
)
75 (make-variable-buffer-local 'wl-message-buffer-flag-indicator
)
76 (make-variable-buffer-local 'wl-message-buffer-mime-entity
)
78 (defvar wl-fixed-window-configuration nil
)
80 (defvar wl-message-buffer-cache-size
10) ; At least 1.
82 ;;; Message buffer cache.
84 (defvar wl-message-buffer-cache nil
85 "Message cache. (old ... new) order alist.
86 With association ((\"folder\" message \"message-id\") . cache-buffer).")
88 (defmacro wl-message-buffer-cache-buffer-get
(entry)
91 (defmacro wl-message-buffer-cache-folder-get
(entry)
94 (defmacro wl-message-buffer-cache-message-get
(entry)
97 (defmacro wl-message-buffer-cache-entry-make
(key buf
)
100 (defmacro wl-message-buffer-cache-hit
(key)
101 "Return value assosiated with key."
102 `(wl-message-buffer-cache-buffer-get
103 (assoc ,key wl-message-buffer-cache
)))
105 (defun wl-message-buffer-cache-sort (entry)
106 "Move ENTRY to the top of `wl-message-buffer-cache'."
107 (setq wl-message-buffer-cache
108 (cons entry
(delete entry wl-message-buffer-cache
))))
109 ; (let* ((pointer (cons nil wl-message-buffer-cache))
111 ; (while (cdr pointer)
112 ; (if (equal (car (cdr pointer)) entry)
113 ; (setcdr pointer (cdr (cdr pointer)))
114 ; (setq pointer (cdr pointer))))
115 ; (setcdr pointer (list entry))
116 ; (setq wl-message-buffer-cache (cdr top))))
118 (defconst wl-original-message-buffer-name
" *Original*")
120 (defun wl-original-message-mode ()
121 "A major mode for original message buffer."
122 (setq major-mode
'wl-original-message-mode
)
123 (setq buffer-read-only t
)
124 (set-buffer-multibyte nil
)
125 (setq mode-name
"Wanderlust original message"))
127 (defun wl-original-message-buffer-get (name)
128 "Get original message buffer for NAME.
129 If original message buffer already exists, it is re-used."
130 (let* ((name (concat wl-original-message-buffer-name name
))
131 (buffer (get-buffer name
)))
132 (unless (and buffer
(buffer-live-p buffer
))
133 (with-current-buffer (setq buffer
(get-buffer-create name
))
134 (wl-original-message-mode)))
137 (defun wl-message-buffer-create ()
138 "Create a new message buffer."
139 (let* ((buffer (generate-new-buffer wl-message-buffer-name
))
140 (name (buffer-name buffer
)))
141 (with-current-buffer buffer
142 (setq wl-message-buffer-original-buffer
143 (wl-original-message-buffer-get name
))
144 (when wl-message-use-header-narrowing
145 (wl-message-header-narrowing-setup))
146 (run-hooks 'wl-message-buffer-created-hook
))
149 (defun wl-message-buffer-cache-add (key)
150 "Add (KEY . buf) to the top of `wl-message-buffer-cache'.
151 Return its cache buffer."
152 (let ((len (length wl-message-buffer-cache
))
154 (if (< len wl-message-buffer-cache-size
)
155 (setq buf
(wl-message-buffer-create))
156 (let ((entry (nth (1- len
) wl-message-buffer-cache
)))
158 (setq buf
(wl-message-buffer-cache-buffer-get entry
)))
159 (setcdr (nthcdr (- len
2) wl-message-buffer-cache
) nil
)
160 (setq wl-message-buffer-cache
(delq entry wl-message-buffer-cache
))
161 (setq buf
(wl-message-buffer-create)))))
162 (setq wl-message-buffer-cache
163 (cons (wl-message-buffer-cache-entry-make key buf
)
164 wl-message-buffer-cache
))
167 (defun wl-message-buffer-cache-delete (&optional key
)
168 "Delete the most recent cache entry"
170 (setq wl-message-buffer-cache
171 (delq (assoc key wl-message-buffer-cache
)
172 wl-message-buffer-cache
))
173 (let ((buf (wl-message-buffer-cache-buffer-get
174 (car wl-message-buffer-cache
))))
175 (setq wl-message-buffer-cache
176 (nconc (cdr wl-message-buffer-cache
)
177 (list (wl-message-buffer-cache-entry-make nil buf
)))))))
179 (defun wl-message-buffer-cache-clean-up ()
180 "A function to flush all decoded messages in cache list."
182 (if (and (eq major-mode
'wl-summary-mode
)
184 (get-buffer-window wl-message-buffer
))
185 (delete-window (get-buffer-window wl-message-buffer
)))
186 (wl-kill-buffers (regexp-quote wl-message-buffer-name
))
187 (setq wl-message-buffer-cache nil
))
189 ;;; Message buffer handling from summary buffer.
191 (defun wl-message-buffer-window ()
192 "Get message buffer window if any."
193 (let* ((start-win (selected-window))
197 (setq cur-win
(next-window cur-win
))
198 (with-current-buffer (window-buffer cur-win
)
199 (if (or (eq major-mode
'wl-message-mode
)
200 (eq major-mode
'mime-view-mode
))
201 (throw 'found cur-win
)))
202 (not (eq cur-win start-win
)))))))
204 (defun wl-message-select-buffer (buffer)
205 "Select BUFFER as a message buffer."
206 (let ((window (get-buffer-window buffer
))
207 (sum (car wl-message-window-size
))
208 (mes (cdr wl-message-window-size
))
211 (not (eq (save-excursion (set-buffer (window-buffer window
))
212 wl-message-buffer-cur-summary-buffer
)
214 (delete-window window
)
215 (run-hooks 'wl-message-window-deleted-hook
)
218 (select-window window
)
219 (when wl-fixed-window-configuration
220 (delete-other-windows)
221 (and wl-stay-folder-window
222 (wl-summary-toggle-disp-folder)))
223 ;; There's no buffer window. Search for message window and snatch it.
224 (if (setq window
(wl-message-buffer-window))
225 (select-window window
)
226 (setq whi
(1- (window-height)))
229 (let ((total (+ sum mes
)))
230 (setq sum
(max window-min-height
(/ (* whi sum
) total
)))
231 (setq mes
(max window-min-height
(/ (* whi mes
) total
))))
232 (if (< whi
(+ sum mes
))
233 (enlarge-window (- (+ sum mes
) whi
)))))
234 (split-window (get-buffer-window (current-buffer)) sum
)
236 (switch-to-buffer buffer
)))
238 (defun wl-message-narrow-to-page (&optional arg
)
240 If ARG is specified, narrow to ARGth page."
242 (setq arg
(if arg
(prefix-numeric-value arg
) 0))
245 (forward-page -
1) ; Beginning of current page.
247 (goto-char (point-min))))
248 (forward-char 1) ; for compatibility with emacs-19.28 and emacs-19.29
251 ((> arg
0) (forward-page arg
))
252 ((< arg
0) (forward-page (1- arg
))))
255 (narrow-to-region (point)
258 (if (and (eolp) (not (bobp)))
262 (defun wl-message-prev-page (&optional lines
)
263 "Scroll down current message by LINES.
264 Returns non-nil if top of message."
267 (save-selected-window
268 (unless (eq major-mode
'mime-view-mode
)
269 (when (buffer-live-p wl-message-buffer
)
270 (wl-message-select-buffer wl-message-buffer
)))
271 (move-to-window-line 0)
272 (if (and wl-break-pages
274 (not (setq real-top
(save-restriction (widen) (bobp)))))
276 (wl-message-narrow-to-page -
1)
277 (goto-char (point-max))
281 (scroll-down (or lines wl-message-scroll-amount
))
285 (let ((f (assq (mime-preview-original-major-mode)
286 mime-preview-over-to-previous-method-alist
)))
287 (if f
(funcall (cdr f
))))))
290 (defun wl-message-next-page (&optional lines
)
291 "Scroll up current message by LINES.
292 Returns non-nil if bottom of message."
295 (save-selected-window
296 (unless (eq major-mode
'mime-view-mode
)
297 (when (buffer-live-p wl-message-buffer
)
298 (wl-message-select-buffer wl-message-buffer
)))
299 (move-to-window-line -
1)
302 (and (pos-visible-in-window-p)
304 (if (or (null wl-break-pages
)
307 (widen) (forward-line) (eobp))))
309 (wl-message-narrow-to-page 1)
312 (static-if (boundp 'window-pixel-scroll-increment
)
313 ;; XEmacs 21.2.20 and later.
314 (let (window-pixel-scroll-increment)
315 (scroll-up (or lines wl-message-scroll-amount
)))
316 (scroll-up (or lines wl-message-scroll-amount
)))
318 (goto-char (point-max))))
321 (let ((f (assq (mime-preview-original-major-mode)
322 mime-preview-over-to-next-method-alist
)))
323 (if f
(funcall (cdr f
))))))
327 (defun wl-message-follow-current-entity (buffer)
328 "Follow to current message."
329 (wl-draft-reply (wl-message-get-original-buffer)
330 nil wl-message-buffer-cur-summary-buffer
) ; reply to all
331 (let ((mail-reply-buffer buffer
))
332 (wl-draft-yank-from-mail-reply-buffer nil
)))
336 (defun wl-message-mode ()
337 "A major mode for message displaying."
339 (setq major-mode
'wl-message-mode
)
340 (setq buffer-read-only t
)
341 (setq mode-name
"Message"))
343 (defun wl-message-exit ()
344 "Move to summary buffer or mother buffer."
346 (let (summary-buf summary-win mother-buffer
)
347 (cond ((setq summary-buf wl-message-buffer-cur-summary-buffer
)
348 (unless (buffer-live-p summary-buf
)
349 (error "Summary buffer not found: %s"
350 wl-message-buffer-cur-folder
))
351 (if (setq summary-win
(get-buffer-window summary-buf
))
352 (select-window summary-win
)
353 (switch-to-buffer summary-buf
)
354 (wl-message-select-buffer wl-message-buffer
)
355 (select-window (get-buffer-window summary-buf
))))
356 ((setq mother-buffer mime-mother-buffer
)
357 (kill-buffer (current-buffer))
358 (when (buffer-live-p mother-buffer
)
359 (switch-to-buffer mother-buffer
))))
360 (run-hooks 'wl-message-exit-hook
)))
362 (defun wl-message-toggle-disp-summary ()
364 (let ((summary-buf (get-buffer wl-message-buffer-cur-summary-buffer
))
367 (buffer-live-p summary-buf
))
368 (if (setq summary-win
(get-buffer-window summary-buf
))
369 (delete-window summary-win
)
370 (switch-to-buffer summary-buf
)
371 (wl-message-select-buffer wl-message-buffer
))
372 (wl-summary-goto-folder-subr wl-message-buffer-cur-folder
'no-sync
375 (let ((sum-buf (current-buffer)))
376 (wl-message-select-buffer wl-message-buffer
)
377 (setq wl-message-buffer-cur-summary-buffer sum-buf
)))))
379 (defun wl-message-get-original-buffer ()
380 "Get original buffer for current message buffer."
381 (if (buffer-live-p wl-message-buffer-original-buffer
)
382 wl-message-buffer-original-buffer
383 (wl-original-message-buffer-get (buffer-name (current-buffer)))))
385 (defun wl-message-add-buttons-to-body (start end
)
388 (narrow-to-region start end
)
389 (let ((case-fold-search t
)
390 (alist wl-message-body-button-alist
)
393 (setq entry
(car alist
)
395 (goto-char (point-min))
396 (while (re-search-forward (car entry
) (+ (point) (nth 4 entry
)) t
)
397 (unless (get-text-property (point) 'keymap
)
398 (wl-message-add-button
399 (match-beginning (nth 1 entry
))
400 (match-end (nth 1 entry
))
402 (match-string (nth 3 entry
))))))))))
404 (defun wl-message-add-buttons-to-header (start end
)
407 (narrow-to-region start end
)
408 (let ((case-fold-search t
)
409 (alist wl-message-header-button-alist
)
412 (setq entry
(car alist
)
414 (goto-char (point-min))
415 (while (re-search-forward (car entry
) nil t
)
416 (setq start
(match-beginning 0)
417 end
(if (re-search-forward "^[^ \t]" nil t
)
421 (while (re-search-forward (nth 1 entry
) end t
)
422 (wl-message-add-button
423 (match-beginning (nth 2 entry
))
424 (match-end (nth 2 entry
))
425 (nth 3 entry
) (match-string (nth 4 entry
))))
426 (goto-char end
)))))))
428 ;; display-type object definition.
429 (defun wl-message-make-display-type (mime header
)
432 (setq symbol
(intern (format "%s-%s-header" mime header
)))
434 'wl-message-display-type
435 (list :mime mime
:header header
)))))
437 (defun wl-message-display-type-property (display-type prop
)
438 (plist-get (get display-type
'wl-message-display-type
) prop
))
440 (defun wl-message-mime-analysis-p (display-type &optional header-or-body
)
441 (let ((mode (wl-message-display-type-property display-type
:mime
)))
444 (memq mode
'(mime header-only
)))
448 (defun wl-message-display-all-header-p (display-type)
449 (eq (wl-message-display-type-property display-type
:header
) 'all
))
451 (defun wl-message-display-no-merge-p (display-type)
452 (eq (wl-message-display-type-property display-type
:mime
) 'no-merge
))
454 (defun wl-message-buffer-display-type (&optional message-buffer
)
456 (with-current-buffer message-buffer
457 wl-message-buffer-cur-display-type
)
458 wl-message-buffer-cur-display-type
))
460 (defun wl-message-flag-indicator (flags)
461 (let ((flags (elmo-get-global-flags flags
)))
468 (let ((indicator (capitalize (symbol-name flag
)))
470 (when (and (assq flag wl-summary-flag-alist
)
473 (format "wl-highlight-summary-%s-flag-face"
475 (put-text-property 0 (length indicator
) 'face face indicator
))
479 (> (length (memq (assq l wl-summary-flag-alist
)
480 wl-summary-flag-alist
))
481 (length (memq (assq r wl-summary-flag-alist
)
482 wl-summary-flag-alist
)))))
486 (defun wl-message-redisplay (folder number display-type
&optional force-reload
)
487 (let* ((default-mime-charset wl-mime-charset
)
488 (buffer-read-only nil
)
489 (summary-buf (current-buffer))
490 message-buf entity summary-win flags
)
491 (setq buffer-read-only nil
)
492 (setq wl-message-buffer
(wl-message-buffer-display
493 folder number display-type force-reload
))
494 (setq message-buf wl-message-buffer
)
495 (wl-message-select-buffer wl-message-buffer
)
497 (set-buffer message-buf
)
498 (wl-deactivate-region)
499 (make-local-variable 'truncate-partial-width-windows
)
500 (setq truncate-partial-width-windows nil
)
501 (setq truncate-lines wl-message-truncate-lines
)
502 (setq buffer-read-only nil
)
503 (setq wl-message-buffer-cur-summary-buffer summary-buf
)
504 (setq wl-message-buffer-cur-folder
(elmo-folder-name-internal folder
))
505 (setq wl-message-buffer-cur-number number
)
506 (setq wl-message-buffer-flag-indicator
507 (wl-message-flag-indicator (elmo-message-flags folder number
)))
508 (wl-line-formatter-setup
509 wl-message-buffer-mode-line-formatter
510 wl-message-mode-line-format
511 wl-message-mode-line-format-spec-alist
)
512 (setq mode-line-buffer-identification
513 (funcall wl-message-buffer-mode-line-formatter
))
515 ; (when wl-highlight-body-too
516 ; (wl-highlight-body))
517 (ignore-errors (wl-message-narrow-to-page))
518 (goto-char (point-min))
519 (when (re-search-forward "^$" nil t
)
520 (wl-message-add-buttons-to-header (point-min) (point))
521 (wl-message-add-buttons-to-body (point) (point-max)))
522 (when (and wl-message-use-header-narrowing
523 (not (wl-message-display-all-header-p display-type
)))
524 (wl-message-header-narrowing))
525 (goto-char (point-min))
526 (ignore-errors (run-hooks 'wl-message-redisplay-hook
))
527 ;; go back to summary mode
528 (set-buffer-modified-p nil
)
529 (setq buffer-read-only t
)
530 (set-buffer summary-buf
)
531 (setq summary-win
(get-buffer-window summary-buf
))
532 (if (window-live-p summary-win
)
533 (select-window summary-win
))))
535 ;; Use message buffer cache.
536 (defun wl-message-buffer-display (folder number display-type
537 &optional force-reload unread
)
538 (let* ((msg-id (ignore-errors
539 (elmo-message-field folder number
'message-id
)))
540 (fname (elmo-folder-name-internal folder
))
541 (hit (wl-message-buffer-cache-hit (list fname number msg-id
)))
544 (when (and hit
(not (buffer-live-p hit
)))
545 (wl-message-buffer-cache-delete (list fname number msg-id
))
549 ;; move hit to the top.
550 (wl-message-buffer-cache-sort
551 (wl-message-buffer-cache-entry-make (list fname number msg-id
) hit
))
552 (with-current-buffer hit
553 ;; Rewind to the top page
555 (goto-char (point-min))
556 (ignore-errors (wl-message-narrow-to-page))
557 (setq entity wl-message-buffer-mime-entity
)
558 (unless (eq wl-message-buffer-cur-display-type display-type
)
559 (setq redisplay t
))))
560 ;; delete tail and add new to the top.
561 (setq hit
(wl-message-buffer-cache-add (list fname number msg-id
)))
563 (when (or force-reload redisplay
)
565 (with-current-buffer hit
566 (when (or force-reload
568 (not (elmo-mime-entity-display-p
570 (if (wl-message-mime-analysis-p display-type
)
573 (if (wl-message-display-no-merge-p display-type
)
574 (elmo-mime-entity-reassembled-p entity
)
575 (elmo-mime-entity-fragment-p entity
)))
576 (setq entity
(elmo-message-mime-entity
579 (wl-message-get-original-buffer)
580 (and wl-message-auto-reassemble-message
/partial
581 (not (wl-message-display-no-merge-p
585 (not (wl-message-mime-analysis-p display-type
)))))
587 (error "Cannot display message %s/%s" fname number
))
588 (wl-message-display-internal entity display-type
))
590 (wl-message-buffer-cache-delete)
591 (error "Display message %s/%s is quitted" fname number
))
593 (wl-message-buffer-cache-delete)
594 (signal (car err
) (cdr err
))
595 nil
))) ;; will not be used
598 (defun wl-message-display-internal (entity display-type
)
599 (let ((default-mime-charset wl-mime-charset
)
600 (elmo-mime-charset wl-mime-charset
)
601 (wl-message-buffer-require-all-header
602 (wl-message-display-all-header-p display-type
)))
603 (if (wl-message-mime-analysis-p display-type
)
604 (elmo-mime-entity-display entity
606 'wl-original-message-mode
607 (wl-message-define-keymap))
608 (let* ((elmo-mime-display-header-analysis
609 (wl-message-mime-analysis-p display-type
'header
))
610 (wl-highlight-x-face-function
611 (and elmo-mime-display-header-analysis
612 wl-highlight-x-face-function
)))
613 (elmo-mime-entity-display-as-is entity
615 'wl-original-message-mode
616 (wl-message-define-keymap))
617 (let (buffer-read-only)
618 (wl-highlight-message (point-min) (point-max) t
))))
619 (setq wl-message-buffer-cur-display-type display-type
620 wl-message-buffer-mime-entity entity
)
621 (run-hooks 'wl-message-display-internal-hook
)
622 (setq buffer-read-only t
)))
624 (defun wl-message-buffer-prefetch-p (folder &optional number
)
625 (and (or (not number
)
626 (elmo-message-file-p folder number
)
627 (let ((size (elmo-message-field folder number
'size
)))
628 (not (and (integerp size
)
629 wl-message-buffer-prefetch-threshold
630 (>= size wl-message-buffer-prefetch-threshold
)))))
632 (elmo-folder-plugged-p folder
)
633 (elmo-file-cache-exists-p
634 (elmo-message-field folder number
'message-id
)))
636 ((eq wl-message-buffer-prefetch-folder-type-list t
)
638 ((and number wl-message-buffer-prefetch-folder-type-list
)
639 (memq (elmo-folder-type-internal
640 (elmo-message-folder folder number
))
641 wl-message-buffer-prefetch-folder-type-list
))
642 (wl-message-buffer-prefetch-folder-type-list
643 (let ((list wl-message-buffer-prefetch-folder-type-list
)
646 (while (setq type
(pop list
))
647 (if (elmo-folder-contains-type folder type
)
648 (throw 'done t
)))))))
650 ((consp wl-message-buffer-prefetch-folder-list
)
651 (wl-string-match-member (elmo-folder-name-internal folder
)
652 wl-message-buffer-prefetch-folder-list
))
653 (t wl-message-buffer-prefetch-folder-list
)))))
655 (defsubst wl-message-buffer-prefetch-clear-timer
()
656 ;;; cannot use for the bug of fsf-compat package (1.09).
657 ;;; (cancel-function-timers 'wl-message-buffer-prefetch-subr)
658 (if (fboundp 'run-with-idle-timer
)
659 (if (featurep 'xemacs
)
660 (let ((p itimer-list
))
662 (if (eq 'wl-message-buffer-prefetch-subr
663 (itimer-function (car p
)))
664 (delete-itimer (car p
)))
666 ;; FSF Emacs is correct
667 (cancel-function-timers 'wl-message-buffer-prefetch-subr
))))
669 (defsubst wl-message-buffer-prefetch-set-timer
(folder number count
671 (if (not (fboundp 'run-with-idle-timer
))
672 (when (sit-for wl-message-buffer-prefetch-idle-time
)
673 (wl-message-buffer-prefetch-subr
674 folder number count summary charset
))
676 wl-message-buffer-prefetch-idle-time
678 'wl-message-buffer-prefetch-subr
679 folder number count summary charset
)))
681 (defvar wl-message-buffer-prefetch-move-spec-alist nil
)
683 (defun wl-message-buffer-prefetch-get-next (folder number summary
)
684 (if (buffer-live-p summary
)
685 (with-current-buffer summary
686 (let ((wl-summary-move-spec-alist
687 (or wl-message-buffer-prefetch-move-spec-alist
688 wl-summary-move-spec-alist
))
690 (while (and (setq next
(funcall
691 wl-message-buffer-prefetch-get-next-function
693 (not (wl-message-buffer-prefetch-p folder next
))))
696 (defun wl-message-buffer-prefetch (folder number count
697 &optional summary charset
)
698 (let* ((summary (or summary
(get-buffer wl-summary-buffer-name
)))
700 (when (and (> count
0)
701 (wl-message-buffer-prefetch-p folder
))
702 (unless (wl-message-buffer-prefetch-p folder number
)
704 (wl-message-buffer-prefetch-get-next folder number summary
)))
706 (wl-message-buffer-prefetch-clear-timer)
707 (wl-message-buffer-prefetch-set-timer
708 folder num count summary charset
)))))
710 (defun wl-message-buffer-prefetch-next (folder number count
711 &optional summary charset
)
712 (let* ((summary (or summary
(get-buffer wl-summary-buffer-name
)))
714 (when (and (> count
0)
715 (wl-message-buffer-prefetch-p folder
))
716 (setq next
(wl-message-buffer-prefetch-get-next folder number summary
))
718 (wl-message-buffer-prefetch-clear-timer)
719 (wl-message-buffer-prefetch-set-timer
720 folder next count summary charset
)))))
722 (defun wl-message-buffer-prefetch-subr (folder number count summary charset
)
723 (if (buffer-live-p summary
)
724 (with-current-buffer summary
727 (>= (setq count
(- count
1)) 0)
728 (string= (elmo-folder-name-internal folder
)
729 (wl-summary-buffer-folder-name)))
730 (let* ((wl-mime-charset charset
)
731 (default-mime-charset charset
)
732 (message-id (elmo-message-field folder number
'message-id
))
733 (key (list (elmo-folder-name-internal folder
)
735 (hit (wl-message-buffer-cache-hit key
))
736 (display-type (wl-message-make-display-type
737 wl-summary-buffer-display-mime-mode
738 wl-summary-buffer-display-header-mode
))
739 time1 time2 sec micro
)
740 (when wl-message-buffer-prefetch-debug
741 (message "%d: count %d, hit %s" number count
(buffer-name hit
)))
742 (if (and hit
(buffer-live-p hit
))
744 (wl-message-buffer-cache-sort
745 (wl-message-buffer-cache-entry-make key hit
))
746 (wl-message-buffer-prefetch-subr
748 (wl-message-buffer-prefetch-get-next
749 folder number summary
)
750 count summary charset
))
752 (when wl-message-buffer-prefetch-debug
753 (setq time1
(current-time))
754 (message "Prefetching %d..." number
))
755 (wl-message-buffer-display folder number
756 display-type nil
'unread
)
757 (when (elmo-message-use-cache-p folder number
)
758 (elmo-message-set-cached folder number t
))
759 (when wl-message-buffer-prefetch-debug
760 (setq time2
(current-time))
761 (setq sec
(- (nth 1 time2
)(nth 1 time1
)))
762 (setq micro
(- (nth 2 time2
)(nth 2 time1
)))
763 (setq micro
(+ micro
(* 1000000 sec
)))
764 (message "Prefetching %d...done(%f msec)."
769 (wl-message-buffer-prefetch-set-timer
771 (wl-message-buffer-prefetch-get-next
772 folder number summary
)
773 count summary charset
)
778 (when wl-message-buffer-prefetch-debug
779 (message "Buffer Cached Messages: %s"
782 (if (numberp (nth 1 (car cache
)))
785 (elmo-folder-name-internal folder
))
788 (format "*%d" (nth 1 (car cache
))))
790 wl-message-buffer-cache
" "))) )))
792 (defvar wl-message-button-map
(make-sparse-keymap))
794 (defun wl-message-add-button (from to function
&optional data
)
795 "Create a button between FROM and TO with callback FUNCTION and DATA."
798 (nconc (list 'wl-message-button-callback function
)
800 (list 'wl-message-button-data data
))))
801 (let ((ov (make-overlay from to
)))
802 (overlay-put ov
'mouse-face
'highlight
)
803 (overlay-put ov
'local-map wl-message-button-map
)
804 (overlay-put ov
'evaporate t
)))
806 (defun wl-message-button-dispatcher (event)
807 "Select the button under point."
809 (mouse-set-point event
)
810 (let ((callback (get-text-property (point) 'wl-message-button-callback
))
811 (data (get-text-property (point) 'wl-message-button-data
)))
813 (funcall callback data
)
814 (wl-message-button-dispatcher-internal event
))))
816 (defun wl-message-button-refer-article (data)
817 "Read article specified by Message-ID DATA at point."
818 (switch-to-buffer-other-window
819 wl-message-buffer-cur-summary-buffer
)
820 (if (wl-summary-jump-to-msg-by-message-id data
)
821 (wl-summary-redisplay)))
823 (defun wl-message-uu-substring (buf outbuf
&optional first last
)
826 (search-forward "\n\n")
828 ep filename case-fold-search
)
832 (if (re-search-forward "^begin[ \t]+[0-9]+[ \t]+\\([^ ].*\\)" nil t
)
833 (setq filename
(buffer-substring (match-beginning 1)(match-end 1)))
835 (re-search-forward "^M.*$" nil t
)) ; uuencoded string
838 (goto-char (point-max))
840 (re-search-backward "^end" sp t
)
841 (re-search-backward "^M.*$" sp t
)) ; uuencoded string
845 (goto-char (point-max))
846 (insert-buffer-substring buf sp ep
)
850 ;;; Header narrowing courtesy of Hideyuki Shirai.
851 (defun wl-message-header-narrowing ()
853 (unless (eq this-command
'wl-summary-redisplay-all-header
)
856 (goto-char (point-min))
857 (if (re-search-forward "^$" nil t
)
859 (goto-char (point-max)))
860 (narrow-to-region (point-min) (point))
861 (let ((fields wl-message-header-narrowing-fields
))
863 (wl-message-header-narrowing-1 (concat "^" (car fields
) ":"))
864 (setq fields
(cdr fields
))))))))
866 (defvar wl-message-header-narrowing-map
(make-sparse-keymap))
867 (define-key wl-message-header-narrowing-map
[mouse-2
]
868 'wl-message-header-narrowing-again-at-mouse
)
870 (defvar wl-message-header-narrowing-widen-map
(make-sparse-keymap))
871 (define-key wl-message-header-narrowing-widen-map
[mouse-2
]
872 'wl-message-header-narrowing-widen-at-mouse
)
874 (defun wl-message-header-narrowing-again-at-mouse (event)
876 (save-window-excursion
878 (mouse-set-point event
)
879 (wl-message-header-narrowing))))
881 (defun wl-message-header-narrowing-1 (hregexp)
882 (let ((case-fold-search t
)
884 (goto-char (point-min))
885 (while (re-search-forward hregexp nil t
)
886 (setq start
(match-beginning 0))
888 (setq end
(progn (while (looking-at "^[ \t]") (forward-line))
890 (line-end-position)))
891 (if (<= (count-lines start end
) wl-message-header-narrowing-lines
)
894 (forward-line (1- wl-message-header-narrowing-lines
))
897 (unless (eq (get-char-property start
'invisible
)
898 'wl-message-header-narrowing
)
900 (let ((ovs (overlays-at start
))
902 (while (and ovs
(not (overlayp ov
)))
903 (if (overlay-get (car ovs
)
904 'wl-message-header-narrowing
)
906 (setq ovs
(cdr ovs
)))
908 (make-overlay start end
)))
909 (overlay-put ov
'wl-message-header-narrowing t
)
910 (overlay-put ov
'evaporate t
)
911 (overlay-put ov
'invisible
'wl-message-header-narrowing
)
912 (overlay-put ov
'after-string
913 wl-message-header-narrowing-string
))))))
915 (defun wl-message-header-narrowing-widen-at-mouse (event)
917 (save-selected-window
918 (select-window (posn-window (event-start event
)))
919 (let* ((win (selected-window))
920 (wpos (window-start win
))
921 (pos (mouse-set-point event
))
922 (ovs (overlays-in (1- pos
) (1+ pos
))) ;; Uum...
924 (while (and ovs
(not (overlayp ov
)))
925 (when (overlay-get (car ovs
) 'wl-message-header-narrowing
)
927 (setq ovs
(cdr ovs
)))
929 (overlay-put ov
'face
'wl-message-header-narrowing-face
)
930 (overlay-put ov
'local-map wl-message-header-narrowing-map
)
931 (overlay-put ov
'invisible nil
)
932 (overlay-put ov
'after-string nil
))
933 (set-window-start win wpos
))))
935 (defun wl-message-header-narrowing-setup ()
936 (when (boundp 'line-move-ignore-invisible
)
937 (set (make-local-variable 'line-move-ignore-invisible
) t
))
938 (set-text-properties 0 (length wl-message-header-narrowing-string
)
940 wl-message-header-narrowing-face
942 ,wl-message-header-narrowing-widen-map
)
943 wl-message-header-narrowing-string
))
945 (defun wl-message-header-narrowing-toggle ()
946 "Toggle header narrowing."
948 (when wl-message-use-header-narrowing
950 (goto-char (point-min))
951 (if (re-search-forward "^$" nil t
)
953 (goto-char (point-max)))
954 (let ((ovs (overlays-in (point-min) (point)))
956 (while (setq ov
(car ovs
))
957 (when (overlay-get ov
'wl-message-header-narrowing
)
958 (setq hn-ovs
(cons ov hn-ovs
)))
959 (setq ovs
(cdr ovs
)))
962 (delete-overlay (car hn-ovs
))
963 (setq hn-ovs
(cdr hn-ovs
)))
964 (wl-message-header-narrowing))))))
967 (product-provide (provide 'wl-message
) (require 'wl-version
))
969 ;;; wl-message.el ends here