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