Fixed last change.
[elisp/wanderlust.git] / wl / wl-message.el
1 ;;; wl-message.el -- Message displaying modules for Wanderlust.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7
8 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
9
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)
13 ;; any later version.
14 ;;
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.
19 ;;
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.
24 ;;
25
26 ;;; Commentary:
27 ;; 
28
29 ;;; Code:
30 ;; 
31
32 (require 'wl-vars)
33 (require 'wl-highlight)
34
35 (eval-when-compile
36   (if wl-use-semi
37       (progn
38         (require 'wl-mime)
39         (require 'mime-view)
40         (require 'mmelmo-imap4))
41     (require 'tm-wl))
42   (defalias-maybe 'event-window 'ignore)
43   (defalias-maybe 'posn-window 'ignore)
44   (defalias-maybe 'event-start 'ignore)
45   (defalias-maybe 'mime-open-entity 'ignore))
46
47 (defvar wl-original-buf-name "*Message*")
48 (defvar wl-message-buf-name "Message")
49 (defvar wl-message-buffer-cur-summary-buffer nil)
50 (defvar wl-message-buffer-cur-folder nil)
51 (defvar wl-message-buffer-cur-number nil)
52
53 (defvar wl-original-buffer-cur-folder nil)
54 (defvar wl-original-buffer-cur-number nil)
55 (defvar wl-original-buffer-cur-msgdb  nil)
56
57 (defvar mmelmo-imap4-skipped-parts)
58
59 (make-variable-buffer-local 'wl-message-buffer-cur-folder)
60 (make-variable-buffer-local 'wl-message-buffer-cur-number)
61
62 (defvar wl-fixed-window-configuration nil)
63
64 (defun wl-message-buffer-window ()
65   (let* ((mes-buf (concat "^" (default-value 'wl-message-buf-name)))
66          (start-win (selected-window))
67          (cur-win start-win))
68     (catch 'found
69       (while (progn
70                (setq cur-win (next-window cur-win))
71                (if (string-match mes-buf (buffer-name (window-buffer cur-win)))
72                    (throw 'found cur-win))
73                (not (eq cur-win start-win)))))))
74
75 (defun wl-select-buffer (buffer)
76   (let ((gbw (or (get-buffer-window buffer)
77                  (wl-message-buffer-window)))
78         (sum (car wl-message-window-size))
79         (mes (cdr wl-message-window-size))
80         whi)
81     (when (and gbw
82                (not (eq (save-excursion (set-buffer (window-buffer gbw))
83                                         wl-message-buffer-cur-summary-buffer)
84                         (current-buffer))))
85       (delete-window gbw)
86       (run-hooks 'wl-message-window-deleted-hook)
87       (setq gbw nil))
88     (if gbw
89         (select-window gbw)
90 ;;;   (if (or (null mes)
91 ;;;           wl-stay-folder-window)
92 ;;;       (delete-other-windows))
93       (when wl-fixed-window-configuration
94         (delete-other-windows)
95         (and wl-stay-folder-window
96              (wl-summary-toggle-disp-folder)))
97       (setq whi (1- (window-height)))
98       (if mes
99           (progn
100             (let ((total (+ sum mes)))
101               (setq sum (max window-min-height (/ (* whi sum) total)))
102               (setq mes (max window-min-height (/ (* whi mes) total))))
103             (if (< whi (+ sum mes))
104                 (enlarge-window (- (+ sum mes) whi)))))
105       (split-window (get-buffer-window (current-buffer)) sum)
106       (other-window 1))
107     (switch-to-buffer buffer)))
108
109 ;;
110 ;; called by wl-summary-mode buffer
111 ;;
112 (defvar wl-message-func-called-hook nil)
113
114 (defun wl-message-scroll-down (amount)
115   (let ((view-message-buffer (get-buffer-create wl-message-buf-name))
116         (cur-buf (current-buffer)))
117     (wl-select-buffer view-message-buffer)
118     (if (bobp)
119         ()
120       (scroll-down))
121     (select-window (get-buffer-window cur-buf))))
122
123 (defun wl-message-scroll-up (amount)
124   (let ((view-message-buffer (get-buffer-create wl-message-buf-name))
125         (cur-buf (current-buffer)))
126     (wl-select-buffer view-message-buffer)
127     (save-excursion
128       (save-restriction
129         (widen)
130         (forward-page 1)
131         (if (pos-visible-in-window-p (point))
132             (wl-message-narrow-to-page 1)))) ; Go to next page.
133     (if (eobp)
134         ()
135       (scroll-up))
136     (select-window (get-buffer-window cur-buf))))
137   
138 (defun wl-message-follow-current-entity (buffer)
139   "Follow to current message."
140   (wl-draft-reply (wl-message-get-original-buffer)
141                   nil wl-message-buffer-cur-summary-buffer) ; reply to all
142   (let ((mail-reply-buffer buffer))
143     (wl-draft-yank-from-mail-reply-buffer nil)))
144
145 (defun wl-message-original-mode ()
146   (setq major-mode 'wl-message-original-mode)
147   (setq mode-name "Original")
148   (setq buffer-read-only t)
149   (if (fboundp 'set-buffer-file-coding-system)
150       (set-buffer-file-coding-system wl-cs-noconv)))
151
152 (defun wl-message-mode ()
153   (interactive)
154   (setq major-mode 'wl-message-mode)
155   (setq buffer-read-only t)
156   (setq mode-name "Message"))
157
158 (defun wl-message-get-buffer-create ()
159   (let ((buf-name wl-message-buf-name))
160     (or (get-buffer buf-name)
161         (save-excursion
162           (set-buffer (get-buffer-create buf-name))
163           (wl-message-mode)
164           (run-hooks 'wl-message-buffer-created-hook)
165           (get-buffer buf-name)))))
166
167 (defun wl-message-original-get-buffer-create ()
168   (or (get-buffer wl-original-buf-name)
169       (save-excursion
170         (set-buffer (get-buffer-create wl-original-buf-name))
171         (wl-message-original-mode)
172         (get-buffer wl-original-buf-name))))
173   
174 (defun wl-message-exit ()
175   (interactive)
176   (let (summary-buf summary-win)
177     (if (setq summary-buf wl-message-buffer-cur-summary-buffer)
178         (if (setq summary-win (get-buffer-window summary-buf))
179             (select-window summary-win)
180           (switch-to-buffer summary-buf)
181           (wl-select-buffer wl-message-buf-name)
182           (select-window (get-buffer-window summary-buf))))
183     (run-hooks 'wl-message-exit-hook)))
184
185 (defvar wl-message-mode-map nil)
186 (if wl-message-mode-map
187     ()
188   (setq wl-message-mode-map (make-sparse-keymap))
189   (define-key wl-message-mode-map "q" 'wl-message-exit)
190   (define-key wl-message-mode-map "n" 'wl-message-exit)
191   (define-key wl-message-mode-map "p" 'wl-message-exit))
192
193 (defun wl-message-decode (outbuf inbuf flag)
194   (cond
195    ((eq flag 'all-header)
196     (save-excursion
197       (set-buffer inbuf)
198       (let ((buffer-read-only nil))
199         (decode-mime-charset-region (point-min)
200                                     (save-excursion
201                                       (goto-char (point-min))
202                                       (re-search-forward "^$" nil t)
203                                       (point))
204                                     wl-mime-charset)))
205     (wl-message-decode-with-all-header outbuf inbuf))
206    ((eq flag 'no-mime)
207     (save-excursion
208       (set-buffer inbuf)
209       (let ((buffer-read-only nil))
210         (save-excursion
211           (set-buffer outbuf)
212           (elmo-set-buffer-multibyte nil))
213         (copy-to-buffer outbuf (point-min) (point-max))
214         (set-buffer outbuf)
215         (use-local-map wl-message-mode-map)
216         (elmo-set-buffer-multibyte default-enable-multibyte-characters)
217 ;;;     (decode-mime-charset-region (point-min) (point-max) wl-mime-charset)
218         ;; we can call decode-coding-region() directly, because multibyte flag is t.
219         (decode-coding-region (point-min) (point-max) wl-cs-autoconv)
220         (wl-highlight-message (point-min)
221                               (save-excursion
222                                 (goto-char (point-min))
223                                 (re-search-forward "^$" nil t)) nil))))
224    (t                                   ; normal
225     (save-excursion
226       (set-buffer inbuf)
227       (let ((buffer-read-only nil))
228         (decode-mime-charset-region (point-min)
229                                     (save-excursion
230                                       (goto-char (point-min))
231                                       (re-search-forward "^$" nil t)
232                                       (point))
233                                     wl-mime-charset)))
234     (wl-message-decode-mode outbuf inbuf))))
235
236 (defun wl-message-prev-page (&optional lines)
237   "Scroll down this message.  Returns non-nil if top of message."
238   (interactive)
239   (let ((cur-buf (current-buffer))
240         (view-message-buffer (get-buffer-create wl-message-buf-name))
241         ret-val)
242     (wl-select-buffer view-message-buffer)
243     (move-to-window-line 0)
244     (if (and wl-break-pages
245              (bobp)
246              (not (save-restriction (widen) (bobp))))
247         (progn
248           (wl-message-narrow-to-page -1)
249           (goto-char (point-max))
250           (recenter -1))
251       (if (not (bobp))
252           (scroll-down lines)
253         (setq ret-val t)))
254     (select-window (get-buffer-window cur-buf))
255     ret-val))
256
257 (static-if (fboundp 'luna-make-entity)
258     (defsubst wl-message-make-mime-entity (backend number backend folder msgdb)
259       (luna-make-entity (mm-expand-class-name 'elmo)
260                         :location (get-buffer-create
261                                    (concat mmelmo-entity-buffer-name "0"))
262                         :imap (eq backend 'elmo-imap4)
263                         :folder folder
264                         :number number
265                         :msgdb msgdb :size 0))
266   (defsubst wl-message-make-mime-entity (backend number backend folder msgdb)
267     (mime-open-entity backend (list folder number msgdb nil))))
268
269 (defun wl-message-next-page (&optional lines)
270   "Scroll up this message.  Returns non-nil if bottom of message."
271   (interactive)
272   (let ((cur-buf (current-buffer))
273         (view-message-buffer (get-buffer-create wl-message-buf-name))
274         ret-val)
275     (wl-select-buffer view-message-buffer)
276     (move-to-window-line -1)
277     (if (save-excursion
278           (end-of-line)
279           (and (pos-visible-in-window-p)
280                (eobp)))
281         (if (or (null wl-break-pages)
282                 (save-excursion
283                   (save-restriction
284                     (widen) (forward-line) (eobp))))
285             (setq ret-val t)
286           (wl-message-narrow-to-page 1)
287           (setq ret-val nil))
288       (condition-case ()
289           (static-if (boundp 'window-pixel-scroll-increment)
290               ;; XEmacs 21.2.20 and later.
291               (let (window-pixel-scroll-increment)
292                 (scroll-up lines))
293             (scroll-up lines))
294         (end-of-buffer
295          (goto-char (point-max))))
296       (setq ret-val nil))
297     (select-window (get-buffer-window cur-buf))
298     ret-val
299     ))
300
301 (defun wl-message-narrow-to-page (&optional arg)
302   (interactive "P")
303   (setq arg (if arg (prefix-numeric-value arg) 0))
304   (save-excursion
305     (condition-case ()
306         (forward-page -1)               ; Beginning of current page.
307       (beginning-of-buffer
308        (goto-char (point-min))))
309     (forward-char 1)  ; for compatibility with emacs-19.28 and emacs-19.29
310     (widen)
311     (cond
312      ((> arg 0) (forward-page arg))
313      ((< arg 0) (forward-page (1- arg))))
314     (forward-page)
315     (if wl-break-pages
316         (narrow-to-region (point)
317                           (progn
318                             (forward-page -1)
319                             (if (and (eolp) (not (bobp)))
320                                 (forward-line))
321                             (point)))) ))
322
323 (defun wl-message-toggle-disp-summary ()
324   (interactive)
325   (let ((summary-buf (get-buffer wl-message-buffer-cur-summary-buffer))
326         summary-win)
327     (if (and summary-buf
328              (buffer-live-p summary-buf))
329         (if (setq summary-win (get-buffer-window summary-buf))
330             (delete-window summary-win)
331           (switch-to-buffer summary-buf)
332           (wl-select-buffer wl-message-buf-name))
333       (wl-summary-goto-folder-subr wl-message-buffer-cur-folder 'no-sync
334                                    nil nil t)
335                                         ; no summary-buf
336       (let ((sum-buf (current-buffer)))
337         (wl-select-buffer wl-message-buf-name)
338         (setq wl-message-buffer-cur-summary-buffer sum-buf)))))
339
340 (defun wl-message-normal-get-original-buffer ()
341   (let ((ret-val (get-buffer wl-original-buf-name)))
342     (if (not ret-val)
343         (save-excursion
344           (set-buffer (setq ret-val
345                             (get-buffer-create wl-original-buf-name)))
346           (wl-message-original-mode)))
347     ret-val))
348
349
350 (if wl-use-semi
351     (defalias 'wl-message-get-original-buffer
352       'mmelmo-get-original-buffer)
353   (defalias 'wl-message-get-original-buffer
354     'wl-message-normal-get-original-buffer))
355
356 (defvar wl-message-redisplay-func 'wl-normal-message-redisplay)
357 (defvar wl-message-cache-used nil) ;whether cache is used or not.
358
359 (defun wl-message-redisplay (folder number flag msgdb &optional force-reload)
360   (let ((default-mime-charset wl-mime-charset)
361         (buffer-read-only nil))
362     (setq wl-message-cache-used nil)
363     (if wl-message-redisplay-func
364         (funcall wl-message-redisplay-func
365                  folder number flag msgdb force-reload))))
366
367 ;; nil means don't fetch all.
368 (defun wl-message-decide-backend (folder number message-id size)
369   (let ((dont-do-that (and
370                        (not (setq wl-message-cache-used
371                                   (or
372                                    (elmo-buffer-cache-hit
373                                     (list folder number message-id))
374                                    (elmo-cache-exists-p message-id
375                                                         folder number))))
376                        (integerp size)
377                        (not (elmo-local-file-p folder number))
378                        wl-fetch-confirm-threshold
379                        (>= size wl-fetch-confirm-threshold)
380                        (not (y-or-n-p
381                              (format "Fetch entire message? (%dbytes)"
382                                      size))))))
383     (message "")
384     (cond ((and dont-do-that
385                 (eq (elmo-folder-number-get-type folder number) 'imap4)
386                 (not (and (elmo-use-cache-p folder number)
387                           (elmo-cache-exists-p message-id folder number))))
388            'elmo-imap4)
389           (t (if (not dont-do-that) 'elmo)))))
390
391 (defmacro wl-message-original-buffer-folder ()
392   wl-original-buffer-cur-folder)
393
394 (defmacro wl-message-original-buffer-number ()
395   wl-original-buffer-cur-number)
396
397 (defun wl-message-set-original-buffer-information (folder number)
398   (when (or (not (string= folder (or wl-original-buffer-cur-folder "")))
399             (not (eq number (or wl-original-buffer-cur-number 0))))
400     (setq wl-original-buffer-cur-folder folder)
401     (setq wl-original-buffer-cur-number number)))
402
403 ;; Works on FLIM-1.9.0/SEMI-1.8.2 or later (maybe).
404 (defun wl-mmelmo-message-redisplay (folder number flag msgdb
405                                            &optional force-reload)
406   (let* ((cur-buf (current-buffer))
407          (view-message-buffer (wl-message-get-buffer-create))
408          (message-id (cdr (assq number
409                                 (elmo-msgdb-get-number-alist msgdb))))
410          (size (elmo-msgdb-overview-entity-get-size
411                 (elmo-msgdb-overview-get-entity number msgdb)))
412          (backend (wl-message-decide-backend folder number message-id size))
413          cur-entity ret-val header-end real-fld-num summary-win)
414     (require 'mmelmo)
415     (wl-select-buffer view-message-buffer)
416     (set-buffer view-message-buffer)
417     (unwind-protect
418         (progn
419           (setq wl-message-buffer-cur-summary-buffer cur-buf)
420           (setq wl-message-buffer-cur-folder folder)
421           (setq wl-message-buffer-cur-number number)
422           (setq buffer-read-only nil)
423           (erase-buffer)
424           (if backend
425               (let (mime-display-header-hook ;; bind to nil...
426                     (wl-message-ignored-field-list
427                      (if (eq flag 'all-header)
428                          nil
429                        wl-message-ignored-field-list))
430                     (mmelmo-force-reload force-reload)
431                     (mmelmo-imap4-threshold wl-fetch-confirm-threshold))
432                 (setq real-fld-num (elmo-get-real-folder-number
433                                     folder number))
434                 (setq cur-entity
435                       (wl-message-make-mime-entity
436                        backend
437                        (if (eq backend 'elmo-imap4)
438                            (cdr real-fld-num)
439                          number)
440                        backend
441                        (if (eq backend 'elmo-imap4)
442                            (car real-fld-num)
443                          folder)
444                        msgdb))
445                 (setq mmelmo-imap4-skipped-parts nil)
446                 ;; mime-display-message sets buffer-read-only variable as t.
447                 ;; which makes buffer read-only status confused...
448                 (mime-display-message cur-entity view-message-buffer
449                                       nil nil 'mmelmo-original-mode)
450                 (if mmelmo-imap4-skipped-parts
451                     (progn
452                       (message "Skipped fetching of %s."
453                                (mapconcat
454                                 (lambda (x)
455                                   (format "[%s]" x))
456                                 mmelmo-imap4-skipped-parts ","))))
457                 (if (and (eq backend 'elmo-imap4)
458                          (null mmelmo-imap4-skipped-parts))
459                     (message "No required part was skipped."))
460                 (setq ret-val (not (eq backend 'elmo-imap4))))
461             (message "Skipped fetching.")
462             (setq ret-val nil)))
463       (setq buffer-read-only nil)
464       (wl-message-set-original-buffer-information folder number)
465       (wl-message-overload-functions)
466       ;; highlight body
467       (when wl-highlight-body-too
468         (wl-highlight-body))
469       (condition-case ()
470           (wl-message-narrow-to-page)
471         (error nil));; ignore errors.
472       (setq mode-line-buffer-identification
473             (format "Wanderlust: << %s / %s >>"
474                     (if (memq 'modeline wl-use-folder-petname)
475                         (wl-folder-get-petname folder)
476                       folder) number))
477       (goto-char (point-min))
478       (unwind-protect
479           (save-excursion
480             (run-hooks 'wl-message-redisplay-hook))
481         ;; go back to summary mode
482         (set-buffer-modified-p nil)
483         (setq buffer-read-only t)
484         (set-buffer cur-buf)
485         (setq summary-win (get-buffer-window cur-buf))
486         (if (window-live-p summary-win)
487             (select-window summary-win))))
488     ret-val
489     ))
490
491 (defun wl-normal-message-redisplay (folder number flag msgdb
492                                            &optional force-reload)
493   (interactive)
494   (let* ((cur-buf (current-buffer))
495          (original-message-buffer (wl-message-get-original-buffer))
496          (view-message-buffer (wl-message-get-buffer-create))
497          (message-id (cdr (assq number
498                                 (elmo-msgdb-get-number-alist msgdb))))
499          (size (elmo-msgdb-overview-entity-get-size
500                 (elmo-msgdb-overview-get-entity number msgdb)))
501          header-end ret-val summary-win)
502     (wl-select-buffer view-message-buffer)
503     (unwind-protect
504         (progn
505           (setq wl-message-buffer-cur-summary-buffer cur-buf)
506           (setq wl-message-buffer-cur-folder folder)
507           (setq wl-message-buffer-cur-number number)
508           (setq buffer-read-only nil)
509           (erase-buffer)
510           (if (or (eq (elmo-folder-number-get-type folder number) 'localdir)
511                   (not (and (not 
512                              (setq wl-message-cache-used
513                                   (or
514                                    (elmo-buffer-cache-hit
515                                     (list folder number message-id))
516                                    (elmo-cache-exists-p message-id
517                                                         folder number))))
518                             (integerp size)
519                             wl-fetch-confirm-threshold
520                             (>= size wl-fetch-confirm-threshold)
521                             (not (y-or-n-p
522                                   (format "Fetch entire message? (%dbytes)"
523                                           size))))))
524               (progn
525                 (save-excursion
526                   (set-buffer original-message-buffer)
527                   (let ((buffer-read-only nil))
528                     (elmo-read-msg-with-buffer-cache
529                      folder number original-message-buffer msgdb force-reload)))
530                 ;; decode MIME message.
531                 (wl-message-decode
532                  view-message-buffer
533                  original-message-buffer flag)
534                 (setq ret-val t))
535             (save-excursion
536               (set-buffer view-message-buffer)
537               (insert "\n\n"))))
538       (setq buffer-read-only nil)
539       (wl-message-set-original-buffer-information folder number)
540       (wl-message-overload-functions)
541       ;; highlight body
542       (and wl-highlight-body-too (wl-highlight-body))
543       (condition-case ()
544           (wl-message-narrow-to-page)
545         (error nil)) ; ignore errors.
546       (setq mode-line-buffer-identification
547             (format "Wanderlust: << %s / %s >>"
548                     (if (memq 'modeline wl-use-folder-petname)
549                         (wl-folder-get-petname folder)
550                       folder)
551                     number))
552       (goto-char (point-min))
553       (unwind-protect
554           (run-hooks 'wl-message-redisplay-hook)
555         ;; go back to summary mode
556         (set-buffer-modified-p nil)
557         (setq buffer-read-only t)
558         (set-buffer cur-buf)
559         (setq summary-win (get-buffer-window cur-buf))
560         (if (window-live-p summary-win)
561             (select-window summary-win)))
562       ret-val
563       )))
564
565 (defvar wl-message-button-map (make-sparse-keymap))
566
567 (defun wl-message-add-button (from to function &optional data)
568   "Create a button between FROM and TO with callback FUNCTION and DATA."
569   (add-text-properties
570    from to
571    (nconc (list 'wl-message-button-callback function)
572           (if data
573               (list 'wl-message-button-data data))))
574   (let ((ov (make-overlay from to)))
575     (overlay-put ov 'mouse-face 'highlight)
576     (overlay-put ov 'local-map wl-message-button-map)
577     (overlay-put ov 'evaporate t)))
578
579 (defun wl-message-button-dispatcher (event)
580   "Select the button under point."
581   (interactive "@e")
582   (mouse-set-point event)
583   (let ((callback (get-text-property (point) 'wl-message-button-callback))
584         (data (get-text-property (point) 'wl-message-button-data)))
585     (if callback
586         (funcall callback data)
587       (wl-message-button-dispatcher-internal event))))
588
589 (defun wl-message-button-refer-article (data)
590   "Read article specified by Message-ID DATA at point."
591   (switch-to-buffer-other-window
592    wl-message-buffer-cur-summary-buffer)
593   (if (wl-summary-jump-to-msg-by-message-id data)
594       (wl-summary-redisplay)))
595
596 (defun wl-message-refer-article-or-url (e)
597   "Read article specified by message-id around point.
598 If failed, attempt to execute button-dispatcher."
599   (interactive "e")
600   (let ((window (get-buffer-window (current-buffer)))
601         mouse-window point beg end msg-id)
602     (unwind-protect
603         (progn
604           (mouse-set-point e)
605           (setq mouse-window (get-buffer-window (current-buffer)))
606           (setq point (point))
607           (setq beg (save-excursion (beginning-of-line) (point)))
608           (setq end (save-excursion (end-of-line) (point)))
609           (search-forward ">" end t)      ;Move point to end of "<....>".
610           (if (and (re-search-backward "\\(<[^<> \t\n]+@[^<> \t\n]+>\\)"
611                                        beg t)
612                    (not (string-match "mailto:"
613                                       (setq msg-id (wl-match-buffer 1)))))
614               (progn
615                 (goto-char point)
616                 (switch-to-buffer-other-window
617                  wl-message-buffer-cur-summary-buffer)
618                 (if (wl-summary-jump-to-msg-by-message-id msg-id)
619                     (wl-summary-redisplay)))
620             (wl-message-button-dispatcher-internal e)))
621       (if (eq mouse-window (get-buffer-window (current-buffer)))
622           (select-window window)))))
623
624 (defun wl-message-uu-substring (buf outbuf &optional first last)
625   (save-excursion
626     (set-buffer buf)
627     (search-forward "\n\n")
628     (let ((sp (point))
629           ep filename case-fold-search)
630       (catch 'done
631         (if first
632             (progn
633               (if (re-search-forward "^begin[ \t]+[0-9]+[ \t]+\\([^ ].*\\)" nil t)
634                   (setq filename (buffer-substring (match-beginning 1)(match-end 1)))
635                 (throw 'done nil)))
636           (re-search-forward "^M.*$" nil t)) ; uuencoded string
637         (beginning-of-line)
638         (setq sp (point))
639         (goto-char (point-max))
640         (if last
641             (re-search-backward "^end" sp t)
642           (re-search-backward "^M.*$" sp t)) ; uuencoded string
643         (forward-line 1)
644         (setq ep (point))
645         (set-buffer outbuf)
646         (goto-char (point-max))
647         (insert-buffer-substring buf sp ep)
648         (set-buffer buf)
649         filename))))
650
651 (require 'product)
652 (product-provide (provide 'wl-message) (require 'wl-version))
653
654 ;;; wl-message.el ends here