0df8510d445de14a0795d669818621ba9d06a4cd
[elisp/wanderlust.git] / wl / wl-summary.el
1 ;;; wl-summary.el --- Summary mode for Wanderlust.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
5 ;; Copyright (C) 1999,2000      TSUMURA Tomoaki <tsumura@kuis.kyoto-u.ac.jp>
6 ;; Copyright (C) 1999,2000      Kenichi OKADA <okada@opaopa.org>
7
8 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
9 ;;      Masahiro MURATA <muse@ba2.so-net.ne.jp>
10 ;;      TSUMURA Tomoaki <tsumura@kuis.kyoto-u.ac.jp>
11 ;;      Kenichi OKADA <okada@opaopa.org>
12 ;; Keywords: mail, net news
13
14 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
15
16 ;; This program is free software; you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; any later version.
20 ;;
21 ;; This program is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 ;; GNU General Public License for more details.
25 ;;
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
28 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
29 ;; Boston, MA 02111-1307, USA.
30 ;;
31
32 ;;; Commentary:
33 ;;
34
35 ;;; Code:
36 ;;
37
38 (require 'elmo)
39 (require 'elmo-multi)
40 (require 'wl-message)
41 (require 'wl-vars)
42 (require 'wl-highlight)
43 (require 'wl-refile)
44 (require 'wl-util)
45 (condition-case nil (require 'timezone) (error nil))
46 (condition-case nil (require 'easymenu) (error nil))
47 (require 'elmo-date)
48 (condition-case nil (require 'ps-print) (error nil))
49
50 (eval-when-compile
51   (require 'cl)
52   (condition-case () (require 'timer) (error nil))
53   (defalias-maybe 'ps-print-buffer-with-faces 'ignore)
54   (defalias-maybe 'elmo-database-msgid-put 'ignore)
55   (defalias-maybe 'elmo-database-close 'ignore)
56   (defalias-maybe 'elmo-database-msgid-get 'ignore)
57   (defalias-maybe 'run-with-idle-timer 'ignore)
58   (defalias-maybe 'ps-print-preprint 'ignore))
59
60 (defvar dragdrop-drop-functions)
61 (defvar scrollbar-height)
62 (defvar mail-reply-buffer)
63
64 (defvar wl-summary-buffer-name "Summary")
65 (defvar wl-summary-mode-map nil)
66 (defvar wl-current-summary-buffer nil)
67
68 (defvar wl-summary-buffer-elmo-folder nil)
69
70 (defmacro wl-summary-buffer-folder-name ()
71   (` (and wl-summary-buffer-elmo-folder
72           (elmo-folder-name-internal wl-summary-buffer-elmo-folder))))
73
74 (defmacro wl-summary-buffer-msgdb ()
75   (` (and wl-summary-buffer-elmo-folder
76           (elmo-folder-msgdb wl-summary-buffer-elmo-folder))))
77
78 (defvar wl-summary-buffer-disp-msg    nil)
79 (defvar wl-summary-buffer-disp-folder nil)
80 (defvar wl-summary-buffer-refile-list nil)
81 (defvar wl-summary-buffer-delete-list nil)
82 (defvar wl-summary-buffer-last-displayed-msg nil)
83 (defvar wl-summary-buffer-current-msg nil)
84 (defvar wl-summary-buffer-unread-count 0)
85 (defvar wl-summary-buffer-new-count    0)
86 (defvar wl-summary-buffer-mime-charset  nil)
87 (defvar wl-summary-buffer-weekday-name-lang  nil)
88 (defvar wl-summary-buffer-thread-indent-set-alist  nil)
89 (defvar wl-summary-buffer-view 'thread)
90 (defvar wl-summary-buffer-message-modified nil)
91 (defvar wl-summary-buffer-mark-modified nil)
92 (defvar wl-summary-buffer-thread-modified nil)
93
94 (defvar wl-summary-buffer-number-column nil)
95 (defvar wl-summary-buffer-temp-mark-column nil)
96 (defvar wl-summary-buffer-persistent-mark-column nil)
97
98 (defvar wl-summary-buffer-persistent nil)
99 (defvar wl-summary-buffer-thread-nodes nil)
100 (defvar wl-summary-buffer-target-mark-list nil)
101 (defvar wl-summary-buffer-copy-list nil)
102 (defvar wl-summary-buffer-prev-refile-destination nil)
103 (defvar wl-summary-buffer-prev-copy-destination nil)
104 (defvar wl-summary-buffer-saved-message nil)
105 (defvar wl-summary-buffer-prev-folder-function nil)
106 (defvar wl-summary-buffer-next-folder-function nil)
107 (defvar wl-summary-buffer-exit-function nil)
108 (defvar wl-summary-buffer-next-message-function nil)
109 (defvar wl-summary-buffer-number-list nil)
110 (defvar wl-summary-buffer-msgdb nil)
111 (defvar wl-summary-buffer-folder-name nil)
112 (defvar wl-summary-buffer-line-formatter nil)
113 (defvar wl-summary-buffer-line-format nil)
114 (defvar wl-summary-buffer-mode-line-formatter nil)
115 (defvar wl-summary-buffer-mode-line nil)
116
117 (defvar wl-thread-indent-level-internal nil)
118 (defvar wl-thread-have-younger-brother-str-internal nil)
119 (defvar wl-thread-youngest-child-str-internal nil)
120 (defvar wl-thread-vertical-str-internal nil)
121 (defvar wl-thread-horizontal-str-internal nil)
122 (defvar wl-thread-space-str-internal nil)
123 (defvar wl-summary-last-visited-folder nil)
124 (defvar wl-read-folder-hist nil)
125 (defvar wl-summary-scored nil)
126 (defvar wl-crosspost-alist-modified nil)
127 (defvar wl-summary-alike-hashtb nil)
128 (defvar wl-summary-search-buf-name " *wl-search-subject*")
129 (defvar wl-summary-delayed-update nil)
130 (defvar wl-summary-search-buf-folder-name nil)
131
132 (defvar wl-summary-get-petname-function 'wl-address-get-petname-1)
133
134 (defvar wl-summary-shell-command-last "")
135
136 (defvar wl-ps-preprint-hook nil)
137 (defvar wl-ps-print-hook nil)
138
139 (make-variable-buffer-local 'wl-summary-buffer-elmo-folder)
140 (make-variable-buffer-local 'wl-summary-search-buf-folder-name)
141 (make-variable-buffer-local 'wl-summary-buffer-disp-msg)
142 (make-variable-buffer-local 'wl-summary-buffer-disp-folder)
143 (make-variable-buffer-local 'wl-summary-buffer-refile-list)
144 (make-variable-buffer-local 'wl-summary-buffer-copy-list)
145 (make-variable-buffer-local 'wl-summary-buffer-target-mark-list)
146 (make-variable-buffer-local 'wl-summary-buffer-delete-list)
147 (make-variable-buffer-local 'wl-summary-buffer-last-displayed-msg)
148 (make-variable-buffer-local 'wl-summary-buffer-unread-count)
149 (make-variable-buffer-local 'wl-summary-buffer-new-count)
150 (make-variable-buffer-local 'wl-summary-buffer-mime-charset)
151 (make-variable-buffer-local 'wl-summary-buffer-weekday-name-lang)
152 (make-variable-buffer-local 'wl-summary-buffer-thread-indent-set)
153 (make-variable-buffer-local 'wl-summary-buffer-view)
154 (make-variable-buffer-local 'wl-summary-buffer-message-modified)
155 (make-variable-buffer-local 'wl-summary-buffer-mark-modified)
156 (make-variable-buffer-local 'wl-summary-buffer-thread-modified)
157 (make-variable-buffer-local 'wl-summary-buffer-number-column)
158 (make-variable-buffer-local 'wl-summary-buffer-temp-mark-column)
159 (make-variable-buffer-local 'wl-summary-buffer-persistent-mark-column)
160 (make-variable-buffer-local 'wl-summary-buffer-persistent)
161 (make-variable-buffer-local 'wl-summary-buffer-thread-nodes)
162 (make-variable-buffer-local 'wl-summary-buffer-prev-refile-destination)
163 (make-variable-buffer-local 'wl-summary-buffer-saved-message)
164 (make-variable-buffer-local 'wl-summary-scored)
165 (make-variable-buffer-local 'wl-summary-default-score)
166 (make-variable-buffer-local 'wl-summary-move-direction-downward)
167 (make-variable-buffer-local 'wl-summary-important-above)
168 (make-variable-buffer-local 'wl-summary-target-above)
169 (make-variable-buffer-local 'wl-summary-mark-below)
170 (make-variable-buffer-local 'wl-summary-expunge-below)
171 (make-variable-buffer-local 'wl-thread-indent-level-internal)
172 (make-variable-buffer-local 'wl-thread-have-younger-brother-str-internal)
173 (make-variable-buffer-local 'wl-thread-youngest-child-str-internal)
174 (make-variable-buffer-local 'wl-thread-vertical-str-internal)
175 (make-variable-buffer-local 'wl-thread-horizontal-str-internal)
176 (make-variable-buffer-local 'wl-thread-space-str-internal)
177 (make-variable-buffer-local 'wl-summary-buffer-prev-folder-function)
178 (make-variable-buffer-local 'wl-summary-buffer-next-folder-function)
179 (make-variable-buffer-local 'wl-summary-buffer-exit-function)
180 (make-variable-buffer-local 'wl-summary-buffer-next-message-function)
181 (make-variable-buffer-local 'wl-summary-buffer-number-list)
182 (make-variable-buffer-local 'wl-summary-buffer-msgdb)
183 (make-variable-buffer-local 'wl-summary-buffer-folder-name)
184 (make-variable-buffer-local 'wl-summary-buffer-line-formatter)
185 (make-variable-buffer-local 'wl-summary-buffer-line-format)
186 (make-variable-buffer-local 'wl-summary-buffer-mode-line-formatter)
187 (make-variable-buffer-local 'wl-summary-buffer-mode-line)
188
189 (defvar wl-datevec)
190 (defvar wl-thr-indent-string)
191 (defvar wl-thr-children-number)
192 (defvar wl-thr-linked)
193 (defvar wl-message-entity)
194 (defvar wl-parent-message-entity)
195 (defvar wl-temp-mark)
196 (defvar wl-persistent-mark)
197
198 ;; internal functions (dummy)
199 (unless (fboundp 'wl-summary-append-message-func-internal)
200   (defun wl-summary-append-message-func-internal (entity msgdb update
201                                                          &optional force-insert)))
202
203 (defmacro wl-summary-sticky-buffer-name (name)
204   (` (concat wl-summary-buffer-name ":" (, name))))
205
206 (defun wl-summary-default-subject (subject-string)
207   (if (string-match "^[ \t]*\\[[^:]+[,: ][0-9]+\\][ \t]*" subject-string)
208       (substring subject-string (match-end 0))
209     subject-string))
210
211 (defun wl-summary-default-from (from)
212   (let (retval tos ng)
213     (unless
214         (and (eq major-mode 'wl-summary-mode)
215              (stringp wl-summary-showto-folder-regexp)
216              (string-match wl-summary-showto-folder-regexp
217                            (wl-summary-buffer-folder-name))
218              (wl-address-user-mail-address-p from)
219              (cond
220               ((and (setq tos (elmo-msgdb-overview-entity-get-to
221                                wl-message-entity))
222                     (not (string= "" tos)))
223                (setq retval
224                      (concat "To:"
225                              (mapconcat
226                               (function
227                                (lambda (to)
228                                  (eword-decode-string
229                                   (if wl-use-petname
230                                       (or
231                                        (funcall
232                                         wl-summary-get-petname-function to)
233                                        (car
234                                         (std11-extract-address-components to))
235                                        to)
236                                     to))))
237                               (wl-parse-addresses tos)
238                               ","))))
239               ((setq ng (elmo-msgdb-overview-entity-get-extra-field
240                          wl-message-entity "newsgroups"))
241                (setq retval (concat "Ng:" ng)))))
242       (if wl-use-petname
243           (setq retval (or (funcall wl-summary-get-petname-function from)
244                            (car (std11-extract-address-components from))
245                            from))
246         (setq retval from)))
247     retval))
248
249 (defun wl-summary-simple-from (string)
250   (if wl-use-petname
251       (or (funcall wl-summary-get-petname-function string)
252           (car (std11-extract-address-components string))
253           string)
254     string))
255
256 (defvar wl-summary-mode-menu-spec
257   '("Summary"
258     ["Read" wl-summary-read t]
259     ["Prev page" wl-summary-prev-page t]
260     ["Next page" wl-summary-next-page t]
261     ["Top"       wl-summary-display-top t]
262     ["Bottom"    wl-summary-display-bottom t]
263     ["Prev"      wl-summary-prev t]
264     ["Next"      wl-summary-next t]
265     ["Up"        wl-summary-up t]
266     ["Down"      wl-summary-down t]
267     ["Parent message" wl-summary-jump-to-parent-message t]
268     "----"
269     ["Sync"            wl-summary-sync t]
270     ["Execute"         wl-summary-exec t]
271     ["Go to other folder" wl-summary-goto-folder t]
272     ["Pick" wl-summary-pick t]
273     ["Mark as read all" wl-summary-mark-as-read-all t]
274     ["Unmark all"      wl-summary-unmark-all t]
275     ["Toggle display message" wl-summary-toggle-disp-msg t]
276     ["Display folder" wl-summary-toggle-disp-folder t]
277     ["Toggle threading" wl-summary-toggle-thread t]
278     ["Stick" wl-summary-stick t]
279     ("Sort"
280      ["By Number" wl-summary-sort-by-number t]
281      ["By Date" wl-summary-sort-by-date t]
282      ["By From" wl-summary-sort-by-from t]
283      ["By Subject" wl-summary-sort-by-subject t])
284     "----"
285     ("Message Operation"
286      ["Mark as read"    wl-summary-mark-as-read t]
287      ["Mark as important" wl-summary-mark-as-important t]
288      ["Mark as unread"   wl-summary-mark-as-unread t]
289      ["Set delete mark" wl-summary-delete t]
290      ["Set refile mark" wl-summary-refile t]
291      ["Set copy mark"   wl-summary-copy t]
292      ["Prefetch"        wl-summary-prefetch t]
293      ["Set target mark" wl-summary-target-mark t]
294      ["Unmark"          wl-summary-unmark t]
295      ["Save"            wl-summary-save t]
296      ["Cancel posted news" wl-summary-cancel-message t]
297      ["Supersedes message" wl-summary-supersedes-message t]
298      ["Resend bounced mail" wl-summary-resend-bounced-mail t]
299      ["Resend message" wl-summary-resend-message t]
300      ["Enter the message" wl-summary-jump-to-current-message t]
301      ["Pipe message" wl-summary-pipe-message t]
302      ["Print message" wl-summary-print-message t])
303     ("Thread Operation"
304      ["Open or Close" wl-thread-open-close (eq wl-summary-buffer-view 'thread)]
305      ["Open all"     wl-thread-open-all (eq wl-summary-buffer-view 'thread)]
306      ["Close all"    wl-thread-close-all (eq wl-summary-buffer-view 'thread)]
307      ["Mark as read" wl-thread-mark-as-read (eq wl-summary-buffer-view 'thread)]
308      ["Mark as important"       wl-thread-mark-as-important (eq wl-summary-buffer-view 'thread)]
309      ["Mark as unread"          wl-thread-mark-as-unread (eq wl-summary-buffer-view 'thread)]
310      ["Set delete mark"  wl-thread-delete (eq wl-summary-buffer-view 'thread)]
311      ["Set refile mark"  wl-thread-refile (eq wl-summary-buffer-view 'thread)]
312      ["Set copy mark"    wl-thread-copy (eq wl-summary-buffer-view 'thread)]
313      ["Prefetch"     wl-thread-prefetch (eq wl-summary-buffer-view 'thread)]
314      ["Set target mark"        wl-thread-target-mark (eq wl-summary-buffer-view 'thread)]
315      ["Unmark"      wl-thread-unmark (eq wl-summary-buffer-view 'thread)]
316      ["Save"            wl-thread-save (eq wl-summary-buffer-view 'thread)]
317      ["Execute"      wl-thread-exec (eq wl-summary-buffer-view 'thread)])
318     ("Region Operation"
319      ["Mark as read" wl-summary-mark-as-read-region t]
320      ["Mark as important" wl-summary-mark-as-important-region t]
321      ["Mark as unread" wl-summary-mark-as-unread-region t]
322      ["Set delete mark" wl-summary-delete-region t]
323      ["Set refile mark" wl-summary-refile-region t]
324      ["Set copy mark" wl-summary-copy-region t]
325      ["Prefetch" wl-summary-prefetch-region t]
326      ["Set target mark" wl-summary-target-mark-region t]
327      ["Unmark" wl-summary-unmark-region t]
328      ["Save" wl-summary-save-region t]
329      ["Execute" wl-summary-exec-region t])
330     ("Mark Operation"
331      ["Mark as read" wl-summary-target-mark-mark-as-read t]
332      ["Mark as important" wl-summary-target-mark-mark-as-important t]
333      ["Mark as unread" wl-summary-target-mark-mark-as-unread t]
334      ["Set delete mark" wl-summary-target-mark-delete t]
335      ["Set refile mark" wl-summary-target-mark-refile t]
336      ["Set copy mark" wl-summary-target-mark-copy t]
337      ["Prefetch" wl-summary-target-mark-prefetch t]
338      ["Save" wl-summary-target-mark-save t]
339      ["Reply with citation" wl-summary-target-mark-reply-with-citation t]
340      ["Forward" wl-summary-target-mark-forward t]
341      ["uudecode" wl-summary-target-mark-uudecode t])
342     ("Score Operation"
343      ["Switch current score file" wl-score-change-score-file t]
344      ["Edit current score file" wl-score-edit-current-scores t]
345      ["Edit score file" wl-score-edit-file t]
346      ["Set mark below" wl-score-set-mark-below t]
347      ["Set expunge below" wl-score-set-expunge-below t]
348      ["Rescore buffer" wl-summary-rescore t]
349      ["Increase score" wl-summary-increase-score t]
350      ["Lower score" wl-summary-lower-score t])
351     "----"
352     ("Writing Messages"
353      ["Write a message" wl-summary-write t]
354      ["Write for current folder" wl-summary-write-current-folder t]
355      ["Reply" wl-summary-reply t]
356      ["Reply with citation" wl-summary-reply-with-citation t]
357      ["Forward" wl-summary-forward t])
358     "----"
359     ["Toggle Plug Status" wl-toggle-plugged t]
360     ["Change Plug Status" wl-plugged-change t]
361     "----"
362     ["Exit Current Folder" wl-summary-exit t]))
363
364 (if wl-on-xemacs
365     (defun wl-summary-setup-mouse ()
366       (define-key wl-summary-mode-map 'button4 'wl-summary-prev)
367       (define-key wl-summary-mode-map 'button5 'wl-summary-next)
368       (define-key wl-summary-mode-map [(shift button4)]
369         'wl-summary-up)
370       (define-key wl-summary-mode-map [(shift button5)]
371         'wl-summary-down)
372       (define-key wl-summary-mode-map 'button2 'wl-summary-click))
373   (defun wl-summary-setup-mouse ()
374     (define-key wl-summary-mode-map [mouse-4] 'wl-summary-prev)
375     (define-key wl-summary-mode-map [mouse-5] 'wl-summary-next)
376     (define-key wl-summary-mode-map [S-mouse-4] 'wl-summary-up)
377     (define-key wl-summary-mode-map [S-mouse-5] 'wl-summary-down)
378     (define-key wl-summary-mode-map [mouse-2] 'wl-summary-click)))
379
380 (if wl-summary-mode-map
381     ()
382   (setq wl-summary-mode-map (make-sparse-keymap))
383   (define-key wl-summary-mode-map " "    'wl-summary-read)
384   (define-key wl-summary-mode-map "."    'wl-summary-redisplay)
385   (define-key wl-summary-mode-map "<"    'wl-summary-display-top)
386   (define-key wl-summary-mode-map ">"    'wl-summary-display-bottom)
387   (define-key wl-summary-mode-map "\177" 'wl-summary-prev-page)
388   (define-key wl-summary-mode-map [backspace] 'wl-summary-prev-page)
389   (define-key wl-summary-mode-map "\r"   'wl-summary-next-line-content)
390   (define-key wl-summary-mode-map "\C-m" 'wl-summary-next-line-content)
391   (define-key wl-summary-mode-map "/"    'wl-thread-open-close)
392   (define-key wl-summary-mode-map "["    'wl-thread-open-all)
393   (define-key wl-summary-mode-map "]"    'wl-thread-close-all)
394   (define-key wl-summary-mode-map "-"    'wl-summary-prev-line-content)
395   (define-key wl-summary-mode-map "\e\r" 'wl-summary-prev-line-content)
396   (define-key wl-summary-mode-map "g"    'wl-summary-goto-folder)
397   (define-key wl-summary-mode-map "G"    'wl-summary-goto-folder-sticky)
398   (define-key wl-summary-mode-map "c"    'wl-summary-mark-as-read-all)
399 ;  (define-key wl-summary-mode-map "D"    'wl-summary-drop-unsync)
400
401   (define-key wl-summary-mode-map "a"    'wl-summary-reply)
402   (define-key wl-summary-mode-map "A"    'wl-summary-reply-with-citation)
403   (define-key wl-summary-mode-map "C"    'wl-summary-cancel-message)
404   (define-key wl-summary-mode-map "E"    'wl-summary-reedit)
405   (define-key wl-summary-mode-map "\eE"  'wl-summary-resend-bounced-mail)
406   (define-key wl-summary-mode-map "f"    'wl-summary-forward)
407   (define-key wl-summary-mode-map "$"    'wl-summary-mark-as-important)
408   (define-key wl-summary-mode-map "@"    'wl-summary-edit-addresses)
409
410   (define-key wl-summary-mode-map "y"    'wl-summary-save)
411   (define-key wl-summary-mode-map "n"    'wl-summary-next)
412   (define-key wl-summary-mode-map "p"    'wl-summary-prev)
413   (define-key wl-summary-mode-map "N"    'wl-summary-down)
414   (define-key wl-summary-mode-map "P"    'wl-summary-up)
415 ;;;(define-key wl-summary-mode-map "w"    'wl-draft)
416   (define-key wl-summary-mode-map "w"    'wl-summary-write)
417   (define-key wl-summary-mode-map "W"    'wl-summary-write-current-folder)
418 ;;;(define-key wl-summary-mode-map "e"     'wl-draft-open-file)
419   (define-key wl-summary-mode-map "e"     'wl-summary-save)
420   (define-key wl-summary-mode-map "\C-c\C-o" 'wl-jump-to-draft-buffer)
421   (define-key wl-summary-mode-map "\C-c\C-a" 'wl-addrmgr)
422   (define-key wl-summary-mode-map "\C-c\C-p" 'wl-summary-previous-buffer)
423   (define-key wl-summary-mode-map "\C-c\C-n" 'wl-summary-next-buffer)
424   (define-key wl-summary-mode-map "H"    'wl-summary-redisplay-all-header)
425   (define-key wl-summary-mode-map "M"    'wl-summary-redisplay-no-mime)
426   (define-key wl-summary-mode-map "B"    'wl-summary-burst)
427   (define-key wl-summary-mode-map "Z"    'wl-status-update)
428   (define-key wl-summary-mode-map "#"    'wl-summary-print-message)
429   (define-key wl-summary-mode-map "|"    'wl-summary-pipe-message)
430   (define-key wl-summary-mode-map "z"    'wl-summary-suspend)
431   (define-key wl-summary-mode-map "q"    'wl-summary-exit)
432   (define-key wl-summary-mode-map "Q"    'wl-summary-force-exit)
433
434   (define-key wl-summary-mode-map "j"    'wl-summary-jump-to-current-message)
435   (define-key wl-summary-mode-map "J"    'wl-thread-jump-to-msg)
436   (define-key wl-summary-mode-map "I"    'wl-summary-incorporate)
437   (define-key wl-summary-mode-map "\M-j" 'wl-summary-jump-to-msg-by-message-id)
438   (define-key wl-summary-mode-map "^"    'wl-summary-jump-to-parent-message)
439   (define-key wl-summary-mode-map "!"    'wl-summary-mark-as-unread)
440
441   (define-key wl-summary-mode-map "s"    'wl-summary-sync)
442   (define-key wl-summary-mode-map "S"    'wl-summary-sort)
443   (define-key wl-summary-mode-map "\M-s"    'wl-summary-stick)
444   (define-key wl-summary-mode-map "T"    'wl-summary-toggle-thread)
445
446   (define-key wl-summary-mode-map "l"    'wl-summary-toggle-disp-folder)
447   (define-key wl-summary-mode-map "v"    'wl-summary-toggle-disp-msg)
448   (define-key wl-summary-mode-map "V"    'wl-summary-virtual)
449
450   (define-key wl-summary-mode-map "\C-i"  'wl-summary-goto-last-displayed-msg)
451   (define-key wl-summary-mode-map "?"    'wl-summary-pick)
452   (define-key wl-summary-mode-map "\ee"  'wl-summary-expire)
453
454   ;; copy & paste.
455   (define-key wl-summary-mode-map "\ew"  'wl-summary-save-current-message)
456   (define-key wl-summary-mode-map "\C-y"  'wl-summary-yank-saved-message)
457
458   ;; line commands
459   (define-key wl-summary-mode-map "R"    'wl-summary-mark-as-read)
460   (define-key wl-summary-mode-map "i"    'wl-summary-prefetch)
461   (define-key wl-summary-mode-map "x"    'wl-summary-exec)
462   (define-key wl-summary-mode-map "*"    'wl-summary-target-mark)
463   (define-key wl-summary-mode-map "o"    'wl-summary-refile)
464   (define-key wl-summary-mode-map "O"    'wl-summary-copy)
465   (define-key wl-summary-mode-map "\M-o" 'wl-summary-refile-prev-destination)
466 ;  (define-key wl-summary-mode-map "\M-O" 'wl-summary-copy-prev-destination)
467   (define-key wl-summary-mode-map "\C-o" 'wl-summary-auto-refile)
468   (define-key wl-summary-mode-map "d"    'wl-summary-delete)
469   (define-key wl-summary-mode-map "u"    'wl-summary-unmark)
470   (define-key wl-summary-mode-map "U"    'wl-summary-unmark-all)
471
472   ;; thread commands
473   (define-key wl-summary-mode-map "t"   (make-sparse-keymap))
474   (define-key wl-summary-mode-map "tR" 'wl-thread-mark-as-read)
475   (define-key wl-summary-mode-map "ti" 'wl-thread-prefetch)
476   (define-key wl-summary-mode-map "tx" 'wl-thread-exec)
477   (define-key wl-summary-mode-map "t*" 'wl-thread-target-mark)
478   (define-key wl-summary-mode-map "to" 'wl-thread-refile)
479   (define-key wl-summary-mode-map "tO" 'wl-thread-copy)
480   (define-key wl-summary-mode-map "td" 'wl-thread-delete)
481   (define-key wl-summary-mode-map "tu" 'wl-thread-unmark)
482   (define-key wl-summary-mode-map "t!" 'wl-thread-mark-as-unread)
483   (define-key wl-summary-mode-map "t$" 'wl-thread-mark-as-important)
484   (define-key wl-summary-mode-map "ty" 'wl-thread-save)
485   (define-key wl-summary-mode-map "ts" 'wl-thread-set-parent)
486
487   ;; target-mark commands
488   (define-key wl-summary-mode-map "m"     (make-sparse-keymap))
489   (define-key wl-summary-mode-map "mi"   'wl-summary-target-mark-prefetch)
490   (define-key wl-summary-mode-map "mR"   'wl-summary-target-mark-mark-as-read)
491   (define-key wl-summary-mode-map "mo"   'wl-summary-target-mark-refile)
492   (define-key wl-summary-mode-map "mO"   'wl-summary-target-mark-copy)
493   (define-key wl-summary-mode-map "md"   'wl-summary-target-mark-delete)
494   (define-key wl-summary-mode-map "my"   'wl-summary-target-mark-save)
495   (define-key wl-summary-mode-map "m!"   'wl-summary-target-mark-mark-as-unread)
496   (define-key wl-summary-mode-map "m$"   'wl-summary-target-mark-mark-as-important)
497   (define-key wl-summary-mode-map "mu"   'wl-summary-delete-all-temp-marks)
498   (define-key wl-summary-mode-map "mU"   'wl-summary-target-mark-uudecode)
499   (define-key wl-summary-mode-map "ma"   'wl-summary-target-mark-all)
500   (define-key wl-summary-mode-map "mt"   'wl-summary-target-mark-thread)
501   (define-key wl-summary-mode-map "mA"   'wl-summary-target-mark-reply-with-citation)
502   (define-key wl-summary-mode-map "mf"   'wl-summary-target-mark-forward)
503   (define-key wl-summary-mode-map "m?"   'wl-summary-target-mark-pick)
504   (define-key wl-summary-mode-map "m#"   'wl-summary-target-mark-print)
505   (define-key wl-summary-mode-map "m|"   'wl-summary-target-mark-pipe)
506
507   ;; region commands
508   (define-key wl-summary-mode-map "r"    (make-sparse-keymap))
509   (define-key wl-summary-mode-map "rR"   'wl-summary-mark-as-read-region)
510   (define-key wl-summary-mode-map "ri"   'wl-summary-prefetch-region)
511   (define-key wl-summary-mode-map "rx"   'wl-summary-exec-region)
512   (define-key wl-summary-mode-map "mr"   'wl-summary-target-mark-region)
513   (define-key wl-summary-mode-map "r*"   'wl-summary-target-mark-region)
514   (define-key wl-summary-mode-map "ro"   'wl-summary-refile-region)
515   (define-key wl-summary-mode-map "rO"   'wl-summary-copy-region)
516   (define-key wl-summary-mode-map "rd"   'wl-summary-delete-region)
517   (define-key wl-summary-mode-map "ru"   'wl-summary-unmark-region)
518   (define-key wl-summary-mode-map "r!"   'wl-summary-mark-as-unread-region)
519   (define-key wl-summary-mode-map "r$"   'wl-summary-mark-as-important-region)
520   (define-key wl-summary-mode-map "ry"   'wl-summary-save-region)
521
522   ;; score commands
523   (define-key wl-summary-mode-map "K"    'wl-summary-increase-score)
524   (define-key wl-summary-mode-map "L"    'wl-summary-lower-score)
525   (define-key wl-summary-mode-map "h"    (make-sparse-keymap))
526   (define-key wl-summary-mode-map "hR"   'wl-summary-rescore)
527   (define-key wl-summary-mode-map "hc"   'wl-score-change-score-file)
528   (define-key wl-summary-mode-map "he"   'wl-score-edit-current-scores)
529   (define-key wl-summary-mode-map "hf"   'wl-score-edit-file)
530   (define-key wl-summary-mode-map "hF"   'wl-score-flush-cache)
531   (define-key wl-summary-mode-map "hm"   'wl-score-set-mark-below)
532   (define-key wl-summary-mode-map "hx"   'wl-score-set-expunge-below)
533
534   (define-key wl-summary-mode-map "\M-t" 'wl-toggle-plugged)
535   (define-key wl-summary-mode-map "\C-t" 'wl-plugged-change)
536   ;;
537   (define-key wl-summary-mode-map "\C-x\C-s" 'wl-summary-save-status)
538   (wl-summary-setup-mouse)
539   (easy-menu-define
540    wl-summary-mode-menu
541    wl-summary-mode-map
542    "Menu used in Summary mode."
543    wl-summary-mode-menu-spec))
544
545 (defun wl-status-update ()
546   (interactive)
547   (wl-address-init))
548
549 (defun wl-summary-display-top ()
550   (interactive)
551   (goto-char (point-min))
552   (if wl-summary-buffer-disp-msg
553       (wl-summary-redisplay)))
554
555 (defun wl-summary-display-bottom ()
556   (interactive)
557   (goto-char (point-max))
558   (forward-line -1)
559   (if wl-summary-buffer-disp-msg
560       (wl-summary-redisplay)))
561
562 (defun wl-summary-count-unread ()
563   (let ((pair
564          (elmo-msgdb-count-marks (wl-summary-buffer-msgdb)
565                                  wl-summary-new-mark
566                                  (list wl-summary-unread-uncached-mark
567                                        wl-summary-unread-cached-mark))))
568     (if (eq major-mode 'wl-summary-mode)
569         (setq wl-summary-buffer-new-count (car pair)
570               wl-summary-buffer-unread-count (cdr pair)))
571     pair))
572
573 (defun wl-summary-message-string (&optional use-cache)
574   "Return full body string of current message.
575 If optional USE-CACHE is non-nil, use cache if exists."
576   (let ((number (wl-summary-message-number))
577         (folder wl-summary-buffer-elmo-folder))
578     (if (null number)
579         (message "No message.")
580       (elmo-set-work-buf
581        (elmo-message-fetch folder
582                            number
583                            (elmo-make-fetch-strategy
584                             'entire
585                             use-cache ; use cache
586                             nil ; save cache (should `t'?)
587                             (and
588                              use-cache
589                              (elmo-file-cache-get-path
590                               (elmo-message-field folder number 'message-id))))
591                            nil
592                            (current-buffer)
593                            'unread)
594        (buffer-string)))))
595
596 (defun wl-summary-reedit (&optional arg)
597   "Re-edit current message.
598 If ARG is non-nil, Supersedes message"
599   (interactive "P")
600   (if arg
601       (wl-summary-supersedes-message)
602     (if (string= (wl-summary-buffer-folder-name) wl-draft-folder)
603         (if (wl-summary-message-number)
604             (progn
605               (wl-draft-reedit (wl-summary-message-number))
606               (if (wl-message-news-p)
607                   (mail-position-on-field "Newsgroups")
608                 (mail-position-on-field "To"))
609               (delete-other-windows)))
610       (wl-draft-edit-string (wl-summary-message-string)))))
611
612 (defun wl-summary-resend-bounced-mail ()
613   "Re-mail the current message.
614 This only makes sense if the current message is a bounce message which
615 contains some mail you have written but has been bounced back to
616 you."
617   (interactive)
618   (save-excursion
619     (wl-summary-set-message-buffer-or-redisplay)
620     (set-buffer (wl-message-get-original-buffer))
621     (goto-char (point-min))
622     (let ((case-fold-search nil))
623       (cond
624        ((and
625          (re-search-forward
626           (concat "^\\($\\|[Cc]ontent-[Tt]ype:[ \t]+multipart/\\(report\\|mixed\\)\\)") nil t)
627          (not (bolp))
628          (re-search-forward "boundary=\"\\([^\"]+\\)\"" nil t))
629         (let ((boundary (buffer-substring (match-beginning 1) (match-end 1)))
630               start)
631           (cond
632            ((and (setq start (re-search-forward
633                               (concat "^--" boundary "\n"
634                                       "\\([Cc]ontent-[Dd]escription:.*\n\\)?"
635                                       "[Cc]ontent-[Tt]ype:[ \t]+"
636                                       "\\(message/rfc822\\|text/rfc822-headers\\)\n"
637                                       "\\(.+\n\\)*\n") nil t))
638                  (re-search-forward
639                   (concat "\n\\(--" boundary "\\)--\n") nil t))
640             (wl-draft-edit-string (buffer-substring start (match-beginning 1))))
641            (t
642             (message "Seems no message/rfc822 part.")))))
643        ((let ((case-fold-search t))
644           (re-search-forward wl-rejected-letter-start nil t))
645         (skip-chars-forward " \t\n")
646         (wl-draft-edit-string (buffer-substring (point) (point-max))))
647        (t
648         (message "Does not appear to be a rejected letter."))))))
649
650 (defun wl-summary-resend-message (address)
651   "Resend the current message to ADDRESS."
652   (interactive "sResend message to: ")
653   (if (or (null address) (string-match "^[ \t]*$" address))
654       (message "No address specified.")
655     (message "Resending message to %s..." address)
656     (save-excursion
657       (let ((original (wl-summary-get-original-buffer)))
658         ;; We first set up a normal mail buffer.
659         (set-buffer (get-buffer-create " *wl-draft-resend*"))
660         (buffer-disable-undo (current-buffer))
661         (erase-buffer)
662         (setq wl-sent-message-via nil)
663         ;; Insert our usual headers.
664         (wl-draft-insert-from-field)
665         (wl-draft-insert-date-field)
666         (insert "to: " address "\n")
667         (goto-char (point-min))
668         ;; Rename them all to "Resent-*".
669         (while (re-search-forward "^[A-Za-z]" nil t)
670           (forward-char -1)
671           (insert "Resent-"))
672         (widen)
673         (forward-line)
674         (delete-region (point) (point-max))
675         (let ((beg  (point)))
676           ;; Insert the message to be resent.
677           (insert-buffer-substring original)
678           (goto-char (point-min))
679           (search-forward "\n\n")
680           (forward-char -1)
681           (save-restriction
682             (narrow-to-region beg (point))
683             (wl-draft-delete-fields wl-ignored-resent-headers)
684             (goto-char (point-max)))
685           (insert mail-header-separator)
686           ;; Rename all old ("Previous-")Resent headers.
687           (while (re-search-backward "^\\(Previous-\\)*Resent-" beg t)
688             (beginning-of-line)
689             (insert "Previous-"))
690           ;; Quote any "From " lines at the beginning.
691           (goto-char beg)
692           (when (looking-at "From ")
693             (replace-match "X-From-Line: ")))
694         ;; Send it.
695         (wl-draft-dispatch-message)
696         (kill-buffer (current-buffer)))
697       (message "Resending message to %s...done" address))))
698
699 (defun wl-summary-detect-mark-position ()
700   (let ((column wl-summary-buffer-number-column)
701         (formatter wl-summary-buffer-line-formatter)
702         (dummy-temp (char-to-string 200))
703         (dummy-persistent (char-to-string 201))
704         temp persistent)
705     (with-temp-buffer
706       (setq wl-summary-buffer-number-column column
707             wl-summary-buffer-line-formatter formatter)
708       (insert
709        (wl-summary-create-line
710         (elmo-msgdb-make-entity
711          :number 10000
712          :from "foo"
713          :subject "bar"
714          :size 100)
715         nil
716         dummy-temp
717         dummy-persistent))
718       (goto-char (point-min))
719       (setq temp (save-excursion
720                    (search-forward dummy-temp nil t)
721                    (current-column))
722             persistent (save-excursion
723                          (search-forward dummy-persistent nil t)
724                          (current-column))))
725     (setq wl-summary-buffer-temp-mark-column temp
726           wl-summary-buffer-persistent-mark-column persistent)))
727
728 (defun wl-summary-buffer-set-folder (folder)
729   (if (stringp folder)
730       (setq folder (wl-folder-get-elmo-folder folder)))
731   (setq wl-summary-buffer-elmo-folder folder)
732   (make-local-variable 'wl-message-buffer)
733   (setq wl-summary-buffer-mime-charset (or (wl-get-assoc-list-value
734                                             wl-folder-mime-charset-alist
735                                             (elmo-folder-name-internal folder))
736                                            wl-mime-charset))
737   (setq wl-summary-buffer-weekday-name-lang
738         (or (wl-get-assoc-list-value
739              wl-folder-weekday-name-lang-alist
740              (elmo-folder-name-internal folder))
741             wl-summary-weekday-name-lang))
742   (setq wl-summary-buffer-thread-indent-set
743         (wl-get-assoc-list-value
744          wl-folder-thread-indent-set-alist
745          (elmo-folder-name-internal folder)))
746   (setq wl-summary-buffer-number-column
747         (or (wl-get-assoc-list-value wl-summary-number-column-alist
748                                      (wl-summary-buffer-folder-name))
749             wl-summary-default-number-column))
750   (wl-line-formatter-setup
751    wl-summary-buffer-line-formatter
752    (setq wl-summary-buffer-line-format
753          (or (wl-get-assoc-list-value
754               wl-folder-summary-line-format-alist
755               (elmo-folder-name-internal folder))
756              wl-summary-line-format))
757    wl-summary-line-format-spec-alist)
758   (wl-line-formatter-setup
759    wl-summary-buffer-mode-line-formatter
760    wl-summary-mode-line-format
761    wl-summary-mode-line-format-spec-alist)
762   (wl-summary-detect-mark-position)
763   (setq wl-summary-buffer-persistent
764         (wl-folder-persistent-p (elmo-folder-name-internal folder)))
765   (elmo-folder-set-persistent-internal folder wl-summary-buffer-persistent)
766   ;; process duplicates.
767   (elmo-folder-set-process-duplicates-internal
768    folder (cdr (elmo-string-matched-assoc
769                 (elmo-folder-name-internal folder)
770                 wl-folder-process-duplicates-alist)))
771   (setq
772    wl-thread-indent-level-internal
773    (or (nth 0 wl-summary-buffer-thread-indent-set)
774        wl-thread-indent-level)
775    wl-thread-have-younger-brother-str-internal
776    (or (nth 1 wl-summary-buffer-thread-indent-set)
777        wl-thread-have-younger-brother-str)
778    wl-thread-youngest-child-str-internal
779    (or (nth 2 wl-summary-buffer-thread-indent-set)
780        wl-thread-youngest-child-str)
781    wl-thread-vertical-str-internal
782    (or (nth 3 wl-summary-buffer-thread-indent-set)
783        wl-thread-vertical-str)
784    wl-thread-horizontal-str-internal
785    (or (nth 4 wl-summary-buffer-thread-indent-set)
786        wl-thread-horizontal-str)
787    wl-thread-space-str-internal
788    (or (nth 5 wl-summary-buffer-thread-indent-set)
789        wl-thread-space-str))
790   (setq wl-thread-indent-regexp
791         (concat
792          (regexp-quote wl-thread-have-younger-brother-str-internal) "\\|"
793          (regexp-quote wl-thread-youngest-child-str-internal) "\\|"
794          (regexp-quote wl-thread-vertical-str-internal) "\\|"
795          (regexp-quote wl-thread-horizontal-str-internal) "\\|"
796          (regexp-quote wl-thread-space-str-internal)))
797   (run-hooks 'wl-summary-buffer-set-folder-hook))
798
799 (defun wl-summary-mode ()
800   "Major mode for reading threaded messages.
801 See Info under Wanderlust for full documentation.
802
803 Special commands:
804 \\{wl-summary-mode-map}
805
806 Entering Folder mode calls the value of `wl-summary-mode-hook'."
807   (interactive)
808   (unless (interactive-p) (kill-all-local-variables))
809   (setq major-mode 'wl-summary-mode)
810   (setq mode-name "Summary")
811   (use-local-map wl-summary-mode-map)
812 ;;;(setq default-directory (or wl-tmp-dir (expand-file-name "~/")))
813   (setq buffer-read-only t)
814   (setq truncate-lines t)
815 ;;;(make-local-variable 'tab-width)
816 ;;;(setq tab-width 1)
817   (buffer-disable-undo (current-buffer))
818   (setq selective-display t
819         selective-display-ellipses nil)
820   (wl-mode-line-buffer-identification '(wl-summary-buffer-mode-line))
821   (easy-menu-add wl-summary-mode-menu)
822   (when wl-summary-lazy-highlight
823     (if wl-on-xemacs 
824         (progn
825           (make-local-variable 'pre-idle-hook)
826           (add-hook 'pre-idle-hook 'wl-highlight-summary-window))
827       (make-local-variable 'window-scroll-functions)
828       (add-hook 'window-scroll-functions 'wl-highlight-summary-window)))
829   ;; This hook may contain the function `wl-setup-summary' for reasons
830   ;; of system internal to accord facilities for the Emacs variants.
831   (run-hooks 'wl-summary-mode-hook))
832
833 (defun wl-summary-overview-entity-compare-by-date (x y)
834   "Compare entity X and Y by date."
835   (condition-case nil
836       (string<
837        (timezone-make-date-sortable
838         (elmo-msgdb-overview-entity-get-date x))
839        (timezone-make-date-sortable
840         (elmo-msgdb-overview-entity-get-date y)))
841     (error))) ;; ignore error.
842
843 (defun wl-summary-overview-entity-compare-by-number (x y)
844    "Compare entity X and Y by number."
845   (<
846    (elmo-msgdb-overview-entity-get-number x)
847    (elmo-msgdb-overview-entity-get-number y)))
848
849 (defun wl-summary-overview-entity-compare-by-from (x y)
850   "Compare entity X and Y by from."
851   (string<
852    (wl-address-header-extract-address
853     (or (elmo-msgdb-overview-entity-get-from-no-decode x)
854         wl-summary-no-from-message))
855    (wl-address-header-extract-address
856     (or (elmo-msgdb-overview-entity-get-from-no-decode y)
857         wl-summary-no-from-message))))
858
859 (defun wl-summary-overview-entity-compare-by-subject (x y)
860   "Compare entity X and Y by subject."
861   (string< (elmo-msgdb-overview-entity-get-subject-no-decode x)
862            (elmo-msgdb-overview-entity-get-subject-no-decode y)))
863
864 (defun wl-summary-sort-by-date ()
865   (interactive)
866   (wl-summary-rescan "date"))
867 (defun wl-summary-sort-by-number ()
868   (interactive)
869   (wl-summary-rescan "number"))
870 (defun wl-summary-sort-by-subject ()
871   (interactive)
872   (wl-summary-rescan "subject"))
873 (defun wl-summary-sort-by-from ()
874   (interactive)
875   (wl-summary-rescan "from"))
876
877 (defun wl-summary-rescan (&optional sort-by)
878   "Rescan current folder without updating."
879   (interactive)
880   (let* ((cur-buf (current-buffer))
881          (msgdb (wl-summary-buffer-msgdb))
882          (overview (elmo-msgdb-get-overview msgdb))
883          (number-alist (elmo-msgdb-get-number-alist msgdb))
884          (elmo-mime-charset wl-summary-buffer-mime-charset)
885          i percent num
886          gc-message entity
887          curp
888          (inhibit-read-only t)
889          (buffer-read-only nil)
890          expunged)
891     (fset 'wl-summary-append-message-func-internal
892           (wl-summary-get-append-message-func))
893     (erase-buffer)
894     (message "Re-scanning...")
895     (setq i 0)
896     (setq num (length overview))
897     (when sort-by
898       (message "Sorting by %s..." sort-by)
899       (setq overview
900             (sort overview
901                   (intern (format "wl-summary-overview-entity-compare-by-%s"
902                                   sort-by))))
903       (message "Sorting by %s...done" sort-by)
904       (elmo-msgdb-set-overview (wl-summary-buffer-msgdb)
905                                overview))
906     (setq curp overview)
907     (set-buffer cur-buf)
908     (setq wl-thread-entity-hashtb (elmo-make-hash (* (length overview) 2)))
909     (setq wl-thread-entity-list nil)
910     (setq wl-thread-entities nil)
911     (setq wl-summary-buffer-number-list nil)
912     (setq wl-summary-buffer-target-mark-list nil)
913     (setq wl-summary-buffer-refile-list nil)
914     (setq wl-summary-buffer-delete-list nil)
915     (setq wl-summary-delayed-update nil)
916     (elmo-kill-buffer wl-summary-search-buf-name)
917     (while curp
918       (setq entity (car curp))
919       (wl-summary-append-message-func-internal entity msgdb nil)
920       (setq curp (cdr curp))
921       (when (> num elmo-display-progress-threshold)
922         (setq i (+ i 1))
923         (if (or (zerop (% i 5)) (= i num))
924             (elmo-display-progress
925              'wl-summary-rescan "Constructing summary structure..."
926              (/ (* i 100) num)))))
927     (when wl-summary-delayed-update
928       (while wl-summary-delayed-update
929         (message "Parent (%d) of message %d is no entity"
930                  (caar wl-summary-delayed-update)
931                  (elmo-msgdb-overview-entity-get-number
932                   (cdar wl-summary-delayed-update)))
933         (wl-summary-append-message-func-internal
934          (cdar wl-summary-delayed-update) msgdb nil t)
935         (setq wl-summary-delayed-update (cdr wl-summary-delayed-update))))
936     (message "Constructing summary structure...done")
937     (set-buffer cur-buf)
938     (if (eq wl-summary-buffer-view 'thread)
939         (progn
940           (message "Inserting thread...")
941           (wl-thread-insert-top)
942           (message "Inserting thread...done"))
943       (wl-summary-make-number-list))
944     (when wl-use-scoring
945       (setq wl-summary-scored nil)
946       (wl-summary-score-headers nil msgdb
947                                 (wl-summary-rescore-msgs number-alist)
948                                 t)
949       (when (and wl-summary-scored
950                  (setq expunged (wl-summary-score-update-all-lines)))
951         (message "%d message(s) are expunged by scoring." (length expunged))))
952     (wl-summary-set-message-modified)
953     (wl-summary-count-unread)
954     (wl-summary-update-modeline)
955     (goto-char (point-max))
956     (forward-line -1)
957     (set-buffer-modified-p nil)))
958
959 (defun wl-summary-next-folder-or-exit (&optional next-entity upward)
960   (if (and next-entity
961            wl-auto-select-next)
962       (let (retval)
963         (wl-summary-toggle-disp-msg 'off)
964         (unwind-protect
965             (setq retval
966                   (wl-summary-goto-folder-subr next-entity
967                                                'force-update
968                                                nil
969                                                nil ; not sticky
970                                                t   ; interactive!
971                                                ))
972           (wl-folder-set-current-entity-id (wl-folder-get-entity-id next-entity))
973           (if (and (eq retval 'more-next)
974                    (memq wl-auto-select-next '(unread skip-no-unread))
975                    (memq this-command wl-summary-next-no-unread-command))
976               (if upward
977                   (wl-summary-up
978                    t (eq wl-auto-select-next 'skip-no-unread))
979                 (goto-char (point-max))
980                 (forward-line -1)
981                 (wl-summary-down
982                  t (eq wl-auto-select-next 'skip-no-unread))))))
983     (wl-summary-exit)))
984
985 (defun wl-summary-entity-info-msg (entity finfo)
986   (or (and entity
987            (concat
988             (elmo-replace-in-string
989              (if (memq 'ask-folder wl-use-folder-petname)
990                  (wl-folder-get-petname entity)
991                entity)
992              "%" "%%")
993             (if (null (car finfo))
994                 " (? new/? unread)"
995               (format
996                " (%d new/%d unread)"
997                (nth 0 finfo)
998                (+ (nth 0 finfo)
999                   (nth 1 finfo))))))
1000       "folder mode"))
1001
1002 (defun wl-summary-set-message-modified ()
1003   (elmo-folder-set-message-modified-internal
1004    wl-summary-buffer-elmo-folder t)
1005   (setq wl-summary-buffer-message-modified t))
1006 (defun wl-summary-message-modified-p ()
1007   wl-summary-buffer-message-modified)
1008 (defun wl-summary-set-mark-modified ()
1009   (elmo-folder-set-mark-modified-internal
1010    wl-summary-buffer-elmo-folder t)
1011   (setq wl-summary-buffer-mark-modified t))
1012 (defun wl-summary-mark-modified-p ()
1013   wl-summary-buffer-mark-modified)
1014 (defun wl-summary-set-thread-modified ()
1015   (setq wl-summary-buffer-thread-modified t))
1016 (defun wl-summary-thread-modified-p ()
1017   wl-summary-buffer-thread-modified)
1018
1019 (defsubst wl-summary-cleanup-temp-marks (&optional sticky)
1020   (if (or wl-summary-buffer-refile-list
1021           wl-summary-buffer-copy-list
1022           wl-summary-buffer-delete-list)
1023       (if (y-or-n-p "Marks remain to be executed.  Execute them? ")
1024           (progn
1025             (wl-summary-exec)
1026             (if (or wl-summary-buffer-refile-list
1027                     wl-summary-buffer-copy-list
1028                     wl-summary-buffer-delete-list)
1029                 (error "Some execution was failed")))
1030         ;; delete temp-marks
1031         (message "")
1032         (wl-summary-delete-all-refile-marks)
1033         (wl-summary-delete-all-copy-marks)
1034         (wl-summary-delete-all-delete-marks)))
1035   (if wl-summary-buffer-target-mark-list
1036       (progn
1037         (wl-summary-delete-all-target-marks)
1038         (setq wl-summary-buffer-target-mark-list nil)))
1039   (wl-summary-delete-all-temp-marks-on-buffer sticky)
1040   (setq wl-summary-scored nil))
1041
1042 ;; a subroutine for wl-summary-exit/wl-save-status
1043 ;; Note that folder is not commited here.
1044 (defun wl-summary-save-view ()
1045   ;; already in summary buffer.
1046   (when wl-summary-buffer-persistent
1047     ;; save the current summary buffer view.
1048     (if (and wl-summary-cache-use
1049              (or (wl-summary-message-modified-p)
1050                  (wl-summary-mark-modified-p)
1051                  (wl-summary-thread-modified-p)))
1052         (wl-summary-save-view-cache))))
1053
1054 (defun wl-summary-save-status ()
1055   "Save summary view and msgdb."
1056   (interactive)
1057   (if (interactive-p) (message "Saving summary status..."))
1058   (wl-summary-save-view)
1059   (elmo-folder-commit wl-summary-buffer-elmo-folder)
1060   (elmo-folder-check wl-summary-buffer-elmo-folder)
1061   (if wl-use-scoring (wl-score-save))
1062   (if (interactive-p) (message "Saving summary status...done.")))
1063
1064 (defun wl-summary-force-exit ()
1065   "Exit current summary.  Buffer is deleted even the buffer is sticky."
1066   (interactive)
1067   (wl-summary-exit 'force-exit))
1068
1069 (defun wl-summary-exit (&optional force-exit)
1070   "Exit current summary.  if FORCE-EXIT, exits even the summary is sticky."
1071   (interactive "P")
1072   (let ((summary-buf (current-buffer))
1073         (sticky (wl-summary-sticky-p))
1074         summary-win
1075         message-buf message-win
1076         folder-buf folder-win)
1077     (run-hooks 'wl-summary-exit-pre-hook)
1078     (if wl-summary-buffer-exit-function
1079         (funcall wl-summary-buffer-exit-function)
1080       (if (or force-exit (not sticky))
1081           (wl-summary-cleanup-temp-marks sticky))
1082       (unwind-protect
1083           ;; save summary status
1084           (progn
1085             (wl-summary-save-view)
1086             (if (or force-exit (not sticky))
1087                 (elmo-folder-close wl-summary-buffer-elmo-folder)
1088               (elmo-folder-commit wl-summary-buffer-elmo-folder)
1089               (elmo-folder-check wl-summary-buffer-elmo-folder))
1090             (if wl-use-scoring (wl-score-save)))
1091         ;; for sticky summary
1092         (wl-delete-all-overlays)
1093         (setq wl-summary-buffer-disp-msg nil)
1094         (elmo-kill-buffer wl-summary-search-buf-name)
1095         ;; delete message window if displayed.
1096         (if (and wl-message-buffer (get-buffer-window wl-message-buffer))
1097             (delete-window (get-buffer-window wl-message-buffer)))
1098         (if (and wl-summary-use-frame
1099                  (> (length (visible-frame-list)) 1))
1100             (delete-frame))
1101         (if (setq folder-buf (get-buffer wl-folder-buffer-name))
1102             (if wl-summary-use-frame
1103                 (let (select-frame)
1104                   (save-selected-window
1105                     (dolist (frame (visible-frame-list))
1106                       (select-frame frame)
1107                       (if (get-buffer-window folder-buf)
1108                           (setq select-frame frame))))
1109                   (if select-frame
1110                       (select-frame select-frame)
1111                     (switch-to-buffer folder-buf)))
1112               (if (setq folder-win (get-buffer-window folder-buf))
1113                   ;; folder win is already displayed.
1114                   (select-window folder-win)
1115                 ;; folder win is not displayed.
1116                 (switch-to-buffer folder-buf)))
1117           ;; currently no folder buffer
1118           (wl-folder))
1119         (and wl-folder-move-cur-folder
1120              wl-folder-buffer-cur-point
1121              (goto-char wl-folder-buffer-cur-point))
1122         (setq wl-folder-buffer-cur-path nil)
1123         (setq wl-folder-buffer-cur-entity-id nil)
1124         (wl-delete-all-overlays)
1125         (if wl-summary-exit-next-move
1126             (wl-folder-next-unsync t)
1127           (beginning-of-line))
1128         (if (setq summary-win (get-buffer-window summary-buf))
1129             (delete-window summary-win))
1130         (if (or force-exit
1131                 (not sticky))
1132             (progn
1133               (set-buffer summary-buf)
1134               (kill-buffer summary-buf)))
1135         (run-hooks 'wl-summary-exit-hook)))))
1136
1137 (defun wl-summary-suspend ()
1138   (interactive)
1139   (wl-summary-exit)
1140   (wl-folder-suspend))
1141
1142 (defun wl-summary-sync-force-update (&optional unset-cursor no-check)
1143   (interactive)
1144   (wl-summary-sync-update unset-cursor nil no-check))
1145
1146 (defsubst wl-summary-sync-all-init ()
1147   (wl-summary-cleanup-temp-marks)
1148   (erase-buffer)
1149   (wl-summary-set-message-modified)
1150   (wl-summary-set-mark-modified)
1151   (setq wl-thread-entity-hashtb (elmo-make-hash
1152                                  (* (length (elmo-msgdb-get-number-alist
1153                                              (wl-summary-buffer-msgdb))) 2)))
1154   (setq wl-thread-entity-list nil)
1155   (setq wl-thread-entities nil)
1156   (setq wl-summary-buffer-number-list nil)
1157   (setq wl-summary-buffer-target-mark-list nil)
1158   (setq wl-summary-buffer-refile-list nil)
1159   (setq wl-summary-buffer-copy-list nil)
1160   (setq wl-summary-buffer-delete-list nil))
1161
1162 (defun wl-summary-sync (&optional unset-cursor force-range)
1163   (interactive)
1164   (let* ((folder wl-summary-buffer-elmo-folder)
1165          (inhibit-read-only t)
1166          (buffer-read-only nil)
1167          (msgdb-dir (elmo-folder-msgdb-path folder))
1168          (range (or force-range (wl-summary-input-range
1169                                  (elmo-folder-name-internal folder)))))
1170     (cond ((string= range "rescan")
1171            (let ((msg (wl-summary-message-number)))
1172              (wl-summary-rescan)
1173              (and msg (wl-summary-jump-to-msg msg))))
1174           ((string= range "rescan-noscore")
1175            (let ((msg (wl-summary-message-number))
1176                  wl-use-scoring)
1177              (wl-summary-rescan)
1178              (and msg (wl-summary-jump-to-msg msg))))
1179           ((string= range "cache-status")
1180            (let ((msg (wl-summary-message-number)))
1181              (wl-summary-resume-cache-status)
1182              (and msg (wl-summary-jump-to-msg msg))))
1183           ((or (string-match "last:" range)
1184                (string-match "first:" range))
1185            (wl-summary-goto-folder-subr (concat "/" range "/"
1186                                                 (elmo-folder-name-internal
1187                                                  folder))
1188             'force-update nil nil t))
1189           (t
1190            (wl-summary-sync-update unset-cursor
1191                                    (cond ((string= range "all") 'all)
1192                                          ((string= range "all-visible")
1193                                           'visible-only)))))))
1194
1195 (defvar wl-summary-edit-addresses-candidate-fields
1196   ;; First element becomes default.
1197   '("from" "to" "cc"))
1198
1199 (defun wl-summary-edit-addresses-collect-candidate-fields (mime-charset)
1200   (let ((fields wl-summary-edit-addresses-candidate-fields)
1201         body candidates components)
1202     (while fields
1203       (setq body
1204             (mapconcat 'identity (elmo-multiple-field-body (car fields))
1205                        ","))
1206       (setq body (wl-parse-addresses body))
1207       (if body (setq candidates (append candidates body)))
1208       (setq fields (cdr fields)))
1209     (setq candidates (elmo-uniq-list candidates))
1210     (elmo-set-work-buf
1211      (elmo-set-buffer-multibyte default-enable-multibyte-characters)
1212      (mapcar (function
1213               (lambda (x)
1214                 (setq components (std11-extract-address-components x))
1215                 (cons (nth 1 components)
1216                       (and (car components)
1217                            (eword-decode-string
1218                             (decode-mime-charset-string
1219                              (car components)
1220                              mime-charset))))))
1221              candidates))))
1222
1223 (defun wl-summary-edit-addresses-subr (the-email name-in-addr)
1224   ;; returns nil if there's no change.
1225   (if (elmo-get-hash-val (downcase the-email) wl-address-petname-hash)
1226       (let (char)
1227         (message "'%s' already exists. (e)dit/(d)elete/(c)ancel?"
1228                  the-email)
1229         (while (not (or (eq (setq char (read-char)) ?\r)
1230                         (eq char ?\n)
1231                         (eq char ? )
1232                         (eq char ?e)
1233                         (eq char ?c)
1234                         (eq char ?d)))
1235           (message
1236            "Please answer `e' or `d' or `c'. (e)dit/(d)elete/(c)ancel?"))
1237         (cond
1238          ((or (eq char ?e)
1239               (eq char ?\n)
1240               (eq char ?\r)
1241               (eq char ? ))
1242           ;; Change Addresses
1243           (wl-address-add-or-change
1244            the-email
1245            (wl-address-header-extract-realname
1246             (cdr (assoc
1247                   (let ((completion-ignore-case t) comp)
1248                     (setq comp
1249                           (try-completion the-email wl-address-completion-list))
1250                     (if (equal comp t) the-email comp))
1251                   wl-address-completion-list))))
1252           "edited")
1253          ((eq char ?d)
1254           ;; Delete Addresses
1255           (if (y-or-n-p (format "Delete '%s'? "
1256                                 the-email))
1257               (progn
1258                 (wl-address-delete the-email)
1259                 "deleted")
1260             (message "")
1261             nil))
1262          (t (message "")
1263             nil)))
1264     ;; Add Petname
1265     (wl-address-add-or-change the-email name-in-addr)
1266     "added"))
1267
1268 (defun wl-summary-edit-addresses (&optional addr-str)
1269   "Edit address book interactively.
1270 Optional argument ADDR-STR is used as a target address if specified."
1271   (interactive (if current-prefix-arg
1272                    (list (read-from-minibuffer "Target address: "))))
1273   (if (null (wl-summary-message-number))
1274       (message "No message.")
1275     (save-excursion
1276       (let* ((charset wl-summary-buffer-mime-charset)
1277              (candidates
1278               (with-current-buffer (wl-summary-get-original-buffer)
1279                 (wl-summary-edit-addresses-collect-candidate-fields
1280                  charset)))
1281              address pair result)
1282         (if addr-str
1283             (setq address addr-str)
1284           (when candidates
1285             (setq address (car (car candidates)))
1286             (setq address
1287                   (completing-read
1288                    (format "Target address (%s): " address)
1289                    (mapcar
1290                     (function (lambda (x) (cons (car x) (car x))))
1291                     candidates)
1292                    nil nil nil nil address))))
1293         (when address
1294           (setq pair (assoc address candidates))
1295           (unless pair
1296             (setq pair (cons address nil)))
1297           (when (setq result (wl-summary-edit-addresses-subr (car pair) (cdr pair)))
1298             ;; update alias
1299             (wl-status-update)
1300             (setq address (assoc (car pair) wl-address-list))
1301             (if address
1302                 (message "%s, %s, <%s> is %s."
1303                          (nth 2 address)
1304                          (nth 1 address)
1305                          (nth 0 address)
1306                          result)))
1307 ;;; i'd like to update summary-buffer, but...
1308 ;;;     (wl-summary-rescan)
1309           (run-hooks 'wl-summary-edit-addresses-hook))))))
1310
1311 (defun wl-summary-incorporate (&optional arg)
1312   "Check and prefetch all uncached messages.
1313 If ARG is non-nil, checking is omitted."
1314   (interactive "P")
1315   (unless arg
1316     (save-excursion
1317       (wl-summary-sync-force-update)))
1318   (wl-summary-prefetch-region (point-min) (point-max)
1319                               wl-summary-incorporate-marks))
1320
1321 (defun wl-summary-prefetch-msg (number &optional arg)
1322   "Returns status-mark. if skipped, returns nil."
1323   ;; prefetching procedure.
1324   (save-excursion
1325     (let* ((msgdb (wl-summary-buffer-msgdb))
1326            (number-alist (elmo-msgdb-get-number-alist msgdb))
1327            (message-id (cdr (assq number number-alist)))
1328            (ov (elmo-msgdb-overview-get-entity message-id msgdb))
1329            (entity ov)
1330            (size (elmo-msgdb-overview-entity-get-size ov))
1331            (inhibit-read-only t)
1332            (buffer-read-only nil)
1333            (file-cached (elmo-file-cache-exists-p message-id))
1334            (force-read (and size
1335                             (or (and (null wl-prefetch-confirm) arg)
1336                                 (null wl-prefetch-threshold)
1337                                 (< size wl-prefetch-threshold))))
1338            mark new-mark)
1339       (unwind-protect
1340           (progn
1341             (when (and (or arg (not file-cached))
1342                        size (not force-read) wl-prefetch-confirm)
1343               (setq force-read
1344                     (save-restriction
1345                       (widen)
1346                       (y-or-n-p
1347                        (format
1348                         "Message from %s has %d bytes.  Prefetch it? "
1349                         (concat
1350                          "[ "
1351                          (save-match-data
1352                            (wl-set-string-width
1353                             17
1354                             (funcall wl-summary-from-function
1355                              (eword-decode-string
1356                               (elmo-delete-char
1357                                ?\"
1358                                (or
1359                                 (elmo-msgdb-overview-entity-get-from ov)
1360                                 "??")))))) " ]")
1361                         size))))
1362               (message ""))             ; flush.
1363             (setq mark (elmo-msgdb-get-mark msgdb number))
1364             (if force-read
1365                 (save-excursion
1366                   (save-match-data
1367                     ;; online
1368                     (if (or arg (not file-cached))
1369                         (elmo-message-encache
1370                          wl-summary-buffer-elmo-folder
1371                          number))
1372                     (setq new-mark
1373                           (cond
1374                            ((string= mark
1375                                      wl-summary-unread-uncached-mark)
1376                             wl-summary-unread-cached-mark)
1377                            ((string= mark wl-summary-new-mark)
1378                             (setq wl-summary-buffer-new-count
1379                                   (- wl-summary-buffer-new-count 1))
1380                             (setq wl-summary-buffer-unread-count
1381                                   (+ wl-summary-buffer-unread-count 1))
1382                             wl-summary-unread-cached-mark)
1383                            ((string= mark wl-summary-read-uncached-mark)
1384                             nil)
1385                            (t mark)))
1386                     (elmo-msgdb-set-mark msgdb number new-mark)
1387                     (or new-mark (setq new-mark " "))
1388                     (wl-summary-set-mark-modified)
1389                     (wl-summary-update-modeline)
1390                     (wl-folder-update-unread
1391                      (wl-summary-buffer-folder-name)
1392                      (+ wl-summary-buffer-unread-count
1393                         wl-summary-buffer-new-count)))
1394                   new-mark)))))))
1395
1396 ;;(defvar wl-summary-message-uncached-marks
1397 ;;  (list wl-summary-new-mark
1398 ;;      wl-summary-unread-uncached-mark
1399 ;;      wl-summary-read-uncached-mark))
1400
1401 (defun wl-summary-prefetch-region (beg end &optional prefetch-marks)
1402   (interactive "r")
1403   (let ((count 0)
1404         targets
1405         mark length
1406         entity msg
1407         start-pos pos)
1408     (save-excursion
1409       (setq start-pos (point))
1410       (save-restriction
1411         (narrow-to-region beg end)
1412         ;; collect prefetch targets.
1413         (message "Collecting marks...")
1414         (goto-char (point-min))
1415         (while (not (eobp))
1416           (setq mark (wl-summary-persistent-mark)
1417                 msg (wl-summary-message-number))
1418           (if (or (and (null prefetch-marks)
1419                        msg
1420                        (null (elmo-file-cache-exists-p
1421                               (elmo-message-field
1422                                wl-summary-buffer-elmo-folder
1423                                msg
1424                                'message-id))))
1425                   (member mark prefetch-marks))
1426               (setq targets (nconc targets (list msg))))
1427           (setq entity (wl-thread-get-entity msg))
1428           (if (or (not (eq wl-summary-buffer-view 'thread))
1429                   (wl-thread-entity-get-opened entity))
1430               (); opened. no hidden children.
1431             (setq targets (nconc
1432                            targets
1433                            (wl-thread-get-children-msgs-uncached
1434                             msg prefetch-marks))))
1435           (forward-line 1))
1436         (setq length (length targets))
1437         (message "Prefetching...")
1438         (while targets
1439           (setq mark (if (not (wl-thread-entity-parent-invisible-p
1440                                (wl-thread-get-entity (car targets))))
1441                          (progn
1442                            (wl-summary-jump-to-msg (car targets))
1443                            (wl-summary-prefetch))
1444                        (wl-summary-prefetch-msg (car targets))))
1445           (if (if prefetch-marks
1446                   (string= mark wl-summary-unread-cached-mark)
1447                 (or (string= mark wl-summary-unread-cached-mark)
1448                     (string= mark " ")))
1449               (message "Prefetching... %d/%d message(s)"
1450                        (setq count (+ 1 count)) length))
1451           ;; redisplay!
1452           (save-excursion
1453             (setq pos (point))
1454             (goto-char start-pos)
1455             (if (pos-visible-in-window-p pos)
1456                 (save-restriction
1457                   (widen)
1458                   (sit-for 0))))
1459           (setq targets (cdr targets)))
1460         (message "Prefetched %d/%d message(s)" count length)
1461         (cons count length)))))
1462
1463 (defun wl-summary-prefetch (&optional arg)
1464   "Prefetch current message."
1465   (interactive "P")
1466   (save-excursion
1467     (let ((inhibit-read-only t)
1468           (buffer-read-only nil)
1469           (mark (wl-summary-persistent-mark)))
1470       (setq mark (wl-summary-prefetch-msg (wl-summary-message-number) arg))
1471       (when mark
1472         (delete-backward-char 1)
1473         (insert mark)
1474         (if wl-summary-highlight
1475             (wl-highlight-summary-current-line)))
1476       (set-buffer-modified-p nil)
1477       mark)))
1478
1479 (defun wl-summary-delete-marks-on-buffer (marks)
1480   (while marks
1481     (wl-summary-unmark (pop marks))))
1482
1483 (defun wl-summary-delete-copy-marks-on-buffer (copies)
1484   (wl-summary-delete-marks-on-buffer copies))
1485
1486 (defun wl-summary-delete-all-refile-marks ()
1487   (let ((marks wl-summary-buffer-refile-list))
1488     (while marks
1489       (wl-summary-unmark (car (pop marks))))))
1490
1491 (defun wl-summary-delete-all-copy-marks ()
1492   (let ((marks wl-summary-buffer-copy-list))
1493     (while marks
1494       (wl-summary-unmark (car (pop marks))))))
1495
1496 (defun wl-summary-delete-all-delete-marks ()
1497   (wl-summary-delete-marks-on-buffer wl-summary-buffer-delete-list))
1498
1499 (defun wl-summary-delete-all-target-marks ()
1500   (wl-summary-delete-marks-on-buffer wl-summary-buffer-target-mark-list))
1501
1502 (defun wl-summary-delete-all-temp-marks-on-buffer (&optional sticky)
1503   ;; for summary view cache saving.
1504   (save-excursion
1505     (goto-char (point-min))
1506     (let ((inhibit-read-only t)
1507           (buffer-read-only nil))
1508        (while (not (eobp))
1509         (unless (string= (wl-summary-temp-mark) " ")
1510           (delete-backward-char 1)
1511           (insert " "))
1512         (forward-line 1)))))
1513
1514 (defun wl-summary-mark-as-read-region (beg end)
1515   (interactive "r")
1516   (save-excursion
1517     (save-restriction
1518       (narrow-to-region beg end)
1519       (goto-char (point-min))
1520       (if (eq wl-summary-buffer-view 'thread)
1521           (progn
1522             (while (not (eobp))
1523               (let* ((number (wl-summary-message-number))
1524                      (entity (wl-thread-get-entity number))
1525                      children)
1526                 (if (wl-thread-entity-get-opened entity)
1527                     ;; opened...mark line.
1528                     (wl-summary-mark-as-read number)
1529                   ;; closed
1530                   (wl-summary-mark-as-read number) ; mark itself.
1531                   (setq children (wl-thread-get-children-msgs number))
1532                   (while children
1533                     (wl-summary-mark-as-read (car children))
1534                     (setq children (cdr children))))
1535                 (forward-line 1))))
1536         (while (not (eobp))
1537           (wl-summary-mark-as-read (wl-summary-message-number))
1538           (forward-line 1)))))
1539   (wl-summary-count-unread)
1540   (wl-summary-update-modeline))
1541
1542 (defun wl-summary-mark-as-unread-region (beg end)
1543   (interactive "r")
1544   (save-excursion
1545     (save-restriction
1546       (narrow-to-region beg end)
1547 ;;; use narrowing.
1548 ;;;      (save-excursion (goto-char end)
1549 ;;;                   (end-of-line) (point)))
1550       (goto-char (point-min))
1551       (if (eq wl-summary-buffer-view 'thread)
1552           (progn
1553             (while (not (eobp))
1554               (let* ((number (wl-summary-message-number))
1555                      (entity (wl-thread-get-entity number))
1556                      children)
1557                 (if (wl-thread-entity-get-opened entity)
1558                     ;; opened...mark line.
1559                     ;; Crossposts are not processed
1560                     (wl-summary-mark-as-unread)
1561                   ;; closed
1562                   (wl-summary-mark-as-unread) ; mark itself.
1563                   (setq children
1564                         (delq number (wl-thread-get-children-msgs number)))
1565                   (while children
1566                     (wl-summary-mark-as-unread (car children))
1567                     (setq children (cdr children))))
1568                 (forward-line 1))))
1569         (while (not (eobp))
1570           (wl-summary-mark-as-unread)
1571           (forward-line 1)))))
1572   (wl-summary-count-unread)
1573   (wl-summary-update-modeline))
1574
1575 (defun wl-summary-mark-as-important-region (beg end)
1576   (interactive "r")
1577   (save-excursion
1578     (save-restriction
1579       (narrow-to-region beg end);(save-excursion (goto-char end)
1580                                         ;    (end-of-line) (point)))
1581       (goto-char (point-min))
1582       (if (eq wl-summary-buffer-view 'thread)
1583           (progn
1584             (while (not (eobp))
1585               (let* ((number (wl-summary-message-number))
1586                      (entity (wl-thread-get-entity number))
1587                      children)
1588                 (if (wl-thread-entity-get-opened entity)
1589                     ;; opened...mark line.
1590                     ;; Crossposts are not processed
1591                     (wl-summary-mark-as-important)
1592                   ;; closed
1593                   (wl-summary-mark-as-important) ; mark itself.
1594                   (setq children
1595                         (delq number (wl-thread-get-children-msgs number)))
1596                   (while children
1597                     (wl-thread-msg-mark-as-important (car children))
1598                     (setq children (cdr children))))
1599                 (forward-line 1))))
1600         (while (not (eobp))
1601           (wl-summary-mark-as-important)
1602           (forward-line 1)))))
1603   (wl-summary-count-unread)
1604   (wl-summary-update-modeline))
1605
1606 (defun wl-summary-mark-as-read-all ()
1607   (interactive)
1608   (if (or (not (interactive-p))
1609           (y-or-n-p "Mark all messages as read? "))
1610       (let* ((folder wl-summary-buffer-elmo-folder)
1611              (cur-buf (current-buffer))
1612              (msgdb (wl-summary-buffer-msgdb))
1613              (inhibit-read-only t)
1614              (buffer-read-only nil)
1615              (case-fold-search nil)
1616              msg mark)
1617         (message "Setting all msgs as read...")
1618         (elmo-folder-mark-as-read folder
1619                                   (elmo-folder-list-unreads
1620                                    folder
1621                                    (list wl-summary-unread-cached-mark
1622                                          wl-summary-unread-uncached-mark
1623                                          wl-summary-new-mark)))
1624         (save-excursion
1625           (goto-char (point-min))
1626           (while (not (eobp))
1627             (setq msg (wl-summary-message-number))
1628             (setq mark (wl-summary-persistent-mark))
1629             (when (and (not (string= mark " "))
1630                        (not (string= mark wl-summary-important-mark))
1631                        (not (string= mark wl-summary-read-uncached-mark)))
1632               (delete-backward-char 1)
1633               (if (or (not (elmo-message-use-cache-p folder msg))
1634                       (string= mark wl-summary-unread-cached-mark))
1635                   (progn
1636                     (insert " ")
1637                     (elmo-msgdb-set-mark msgdb msg nil))
1638                 ;; New mark and unread-uncached mark
1639                 (insert wl-summary-read-uncached-mark)
1640                 (elmo-msgdb-set-mark
1641                  msgdb msg wl-summary-read-uncached-mark))
1642               (if wl-summary-highlight
1643                   (wl-highlight-summary-current-line nil nil t)))
1644             (forward-line 1)))
1645         (elmo-folder-replace-marks
1646          folder
1647          (list (cons wl-summary-unread-cached-mark
1648                      nil)
1649                (cons wl-summary-unread-uncached-mark
1650                      wl-summary-read-uncached-mark)
1651                (cons wl-summary-new-mark
1652                      wl-summary-read-uncached-mark)))
1653         (wl-summary-set-mark-modified)
1654         (wl-folder-update-unread (wl-summary-buffer-folder-name) 0)
1655         (setq wl-summary-buffer-unread-count 0)
1656         (setq wl-summary-buffer-new-count    0)
1657         (wl-summary-update-modeline)
1658         (message "Setting all msgs as read...done")
1659         (set-buffer-modified-p nil))))
1660
1661 (defun wl-summary-delete-cache ()
1662   "Delete cache of current message."
1663   (interactive)
1664   (save-excursion
1665     (let* ((inhibit-read-only t)
1666            (buffer-read-only nil)
1667            (folder wl-summary-buffer-elmo-folder)
1668            (msgdb (wl-summary-buffer-msgdb))
1669            (number-alist (elmo-msgdb-get-number-alist msgdb))
1670            (case-fold-search nil)
1671            mark number unread new-mark)
1672       (setq mark (wl-summary-persistent-mark))
1673       (cond
1674        ((or (string= mark wl-summary-new-mark)
1675             (string= mark wl-summary-unread-uncached-mark)
1676             (string= mark wl-summary-important-mark))
1677         ;; noop
1678         )
1679        ((string= mark wl-summary-unread-cached-mark)
1680         (setq new-mark wl-summary-unread-uncached-mark))
1681        (t
1682         (setq new-mark wl-summary-read-uncached-mark)))
1683       (when new-mark
1684         (setq number (wl-summary-message-number))
1685         (delete-backward-char 1)
1686         (insert new-mark)
1687         (elmo-file-cache-delete
1688          (elmo-file-cache-get-path
1689           (elmo-message-field wl-summary-buffer-elmo-folder
1690                               number
1691                               'message-id)))
1692         (elmo-msgdb-set-mark msgdb number new-mark)
1693         (wl-summary-set-mark-modified)
1694         (if wl-summary-highlight
1695             (wl-highlight-summary-current-line nil nil t))
1696         (set-buffer-modified-p nil)))))
1697
1698 (defun wl-summary-resume-cache-status ()
1699   "Resume the cache status of all messages in the current folder."
1700   (interactive)
1701   (let* ((folder wl-summary-buffer-elmo-folder)
1702          (cur-buf (current-buffer))
1703          (msgdb (wl-summary-buffer-msgdb))
1704          (number-alist (elmo-msgdb-get-number-alist msgdb))
1705          (inhibit-read-only t)
1706          (buffer-read-only nil)
1707          (case-fold-search nil)
1708          msg mark msgid set-mark)
1709     (message "Resuming cache status...")
1710     (save-excursion
1711       (goto-char (point-min))
1712       (while (not (eobp))
1713         (setq msg (wl-summary-message-number))
1714         (setq mark (wl-summary-persistent-mark))
1715         (setq msgid (elmo-msgdb-get-field msgdb msg 'message-id))
1716         (setq set-mark nil)
1717         (if (elmo-file-cache-exists-p msgid)
1718             (if (or
1719                  (string= mark wl-summary-unread-uncached-mark) ; U -> !
1720                  (string= mark wl-summary-new-mark)             ; N -> !
1721                  )
1722                 (setq set-mark wl-summary-unread-cached-mark)
1723               (if (string= mark wl-summary-read-uncached-mark)  ; u -> ' '
1724                   (setq set-mark " ")))
1725           (if (string= mark " ")
1726               (setq set-mark wl-summary-read-uncached-mark)     ;' ' -> u
1727             (if (string= mark wl-summary-unread-cached-mark)
1728                 (setq set-mark wl-summary-unread-uncached-mark) ; !  -> U
1729               )))
1730         (when set-mark
1731           (delete-backward-char 1)
1732           (insert set-mark)
1733           (elmo-msgdb-set-mark msgdb msg
1734                                (if (string= set-mark " ") nil set-mark))
1735           (if wl-summary-highlight
1736               (wl-highlight-summary-current-line)))
1737         (forward-line 1))
1738       (wl-summary-set-mark-modified)
1739       (wl-summary-count-unread)
1740       (wl-summary-update-modeline)
1741       (message "Resuming cache status...done")
1742       (set-buffer-modified-p nil))))
1743
1744 (defun wl-summary-delete-messages-on-buffer (msgs &optional deleting-info)
1745   (interactive)
1746   (save-excursion
1747     (let ((inhibit-read-only t)
1748           (buffer-read-only nil)
1749           (msgs2 msgs)
1750           (len (length msgs))
1751           (i 0)
1752           update-list)
1753       (elmo-kill-buffer wl-summary-search-buf-name)
1754       (while msgs
1755         (if (eq wl-summary-buffer-view 'thread)
1756             (progn
1757               ;; don't use wl-append(nconc), because list is broken. ...why?
1758               (setq update-list
1759                     (append update-list
1760                             (wl-thread-delete-message (car msgs))))
1761               (setq update-list (delq (car msgs) update-list)))
1762           (goto-char (point-min))
1763           (if (wl-summary-jump-to-msg (car msgs))
1764               (progn
1765                 (delete-region (point-at-bol) (point-at-eol))
1766                 (delete-char 1) ; delete '\n'
1767                 (setq wl-summary-buffer-number-list
1768                       (delq (car msgs) wl-summary-buffer-number-list)))))
1769         (when (and deleting-info
1770                    (> len elmo-display-progress-threshold))
1771           (setq i (1+ i))
1772           (if (or (zerop (% i 5)) (= i len))
1773               (elmo-display-progress
1774                'wl-summary-delete-messages-on-buffer deleting-info
1775                (/ (* i 100) len))))
1776         (setq msgs (cdr msgs)))
1777       (when (eq wl-summary-buffer-view 'thread)
1778         (wl-thread-update-line-msgs (elmo-uniq-list update-list)
1779                                     (unless deleting-info 'no-msg))
1780         (wl-thread-cleanup-symbols msgs2))
1781       (wl-summary-count-unread)
1782       (wl-summary-update-modeline)
1783       (wl-folder-update-unread
1784        (wl-summary-buffer-folder-name)
1785        (+ wl-summary-buffer-unread-count wl-summary-buffer-new-count)))))
1786
1787 (defun wl-summary-replace-status-marks (before after)
1788   "Replace the status marks on buffer."
1789   (interactive)
1790   (save-excursion
1791     (goto-char (point-min))
1792     (let ((inhibit-read-only t)
1793           (buffer-read-only nil))
1794       (while (not (eobp))
1795         (when (string= (wl-summary-persistent-mark) before)
1796           (delete-backward-char 1)
1797           (insert after)
1798           (if wl-summary-highlight
1799               (wl-highlight-summary-current-line)))
1800         (forward-line 1)))))
1801
1802 (defun wl-summary-get-delete-folder (folder)
1803   (if (string= folder wl-trash-folder)
1804       'null
1805     (let* ((type (or (wl-get-assoc-list-value wl-delete-folder-alist folder)
1806                      'trash)))
1807       (cond ((stringp type)
1808              type)
1809             ((or (equal type 'remove) (equal type 'null))
1810              'null)
1811             (t;; (equal type 'trash)
1812              (let ((trash-folder (wl-folder-get-elmo-folder wl-trash-folder)))
1813                (unless (elmo-folder-exists-p trash-folder)
1814                  (if (y-or-n-p
1815                       (format "Trash Folder %s does not exist, create it? "
1816                               wl-trash-folder))
1817                      (elmo-folder-create trash-folder)
1818                    (error "Trash Folder is not created"))))
1819                wl-trash-folder)))))
1820
1821 (defun wl-summary-get-append-message-func ()
1822   (if (eq wl-summary-buffer-view 'thread)
1823       'wl-summary-insert-thread-entity
1824     'wl-summary-insert-sequential))
1825
1826 (defun wl-summary-sort ()
1827   (interactive)
1828   (let ((sort-by (let ((input-range-list '("number" "date" "subject" "from"))
1829                        (default "date")
1830                        in)
1831                    (setq in
1832                          (completing-read
1833                           (format "Sort by (%s): " default)
1834                           (mapcar
1835                            (function (lambda (x) (cons x x)))
1836                            input-range-list)))
1837                    (if (string= in "")
1838                        default
1839                      in))))
1840     (if (not (member sort-by '("number" "date" "subject" "from")))
1841         (error "Sort by %s is not implemented"  sort-by))
1842     (wl-summary-rescan sort-by)))
1843
1844 (defun wl-summary-sync-marks ()
1845   "Update marks in summary."
1846   (interactive)
1847   (let ((last-progress 0)
1848         (i 0)
1849         unread-marks importants unreads
1850         importants-in-db unreads-in-db diff diffs
1851         mes progress)
1852     ;; synchronize marks.
1853     (when (not (eq (elmo-folder-type-internal
1854                     wl-summary-buffer-elmo-folder)
1855                    'internal))
1856       (message "Updating marks...")
1857       (setq unread-marks (list wl-summary-unread-cached-mark
1858                                wl-summary-unread-uncached-mark
1859                                wl-summary-new-mark)
1860             importants-in-db (elmo-folder-list-messages-mark-match
1861                               wl-summary-buffer-elmo-folder
1862                               (regexp-quote wl-summary-important-mark))
1863             unreads-in-db (elmo-folder-list-messages-mark-match
1864                            wl-summary-buffer-elmo-folder
1865                            (wl-regexp-opt unread-marks))
1866             importants (elmo-folder-list-importants
1867                         wl-summary-buffer-elmo-folder
1868                         wl-summary-important-mark)
1869             unreads (elmo-folder-list-unreads
1870                      wl-summary-buffer-elmo-folder
1871                      unread-marks))
1872       (setq diff (elmo-list-diff importants importants-in-db))
1873       (setq diffs (cadr diff)) ; important-deletes
1874       (setq mes (format "Updated (-%d" (length diffs)))
1875       (while diffs
1876         (wl-summary-mark-as-important (car diffs)
1877                                       wl-summary-important-mark
1878                                       'no-server)
1879         (setq diffs (cdr diffs)))
1880       (setq diffs (car diff)) ; important-appends
1881       (setq mes (concat mes (format "/+%d) important," (length diffs))))
1882       (while diffs
1883         (wl-summary-mark-as-important (car diffs) " " 'no-server)
1884         (setq diffs (cdr diffs)))
1885       (setq diff (elmo-list-diff unreads unreads-in-db))
1886       (setq diffs (cadr diff))
1887       (setq mes (concat mes (format "(-%d" (length diffs))))
1888       (while diffs
1889         (wl-summary-mark-as-read (car diffs) 'no-folder)
1890         (setq diffs (cdr diffs)))
1891       (setq diffs (car diff)) ; unread-appends
1892       (setq mes (concat mes (format "/+%d) unread mark(s)." (length diffs))))
1893       (while diffs
1894         (wl-summary-mark-as-unread (car diffs) 'no-server 'no-modeline)
1895         (setq diffs (cdr diffs)))
1896       (if (interactive-p) (message mes)))))
1897
1898 (defun wl-summary-sync-update (&optional unset-cursor sync-all no-check)
1899   "Update the summary view to the newest folder status."
1900   (interactive)
1901   (let* ((folder wl-summary-buffer-elmo-folder)
1902          (case-fold-search nil)
1903          (elmo-mime-charset wl-summary-buffer-mime-charset)
1904          (inhibit-read-only t)
1905          (buffer-read-only nil)
1906          gc-message
1907          overview number-alist
1908          curp num i new-msgdb
1909          append-list delete-list crossed
1910          update-thread update-top-list
1911          expunged mes sync-result entity)
1912     (unwind-protect
1913         (progn
1914           (unless wl-summary-buffer-elmo-folder
1915             (error "(Internal error) Folder is not set:%s" (buffer-name
1916                                                             (current-buffer))))
1917           (fset 'wl-summary-append-message-func-internal
1918                 (wl-summary-get-append-message-func))
1919           ;; Flush pending append operations (disconnected operation).
1920           ;;(setq seen-list
1921           ;;(wl-summary-flush-pending-append-operations seen-list))
1922           (goto-char (point-max))
1923           (wl-folder-confirm-existence folder (elmo-folder-plugged-p folder))
1924           (setq sync-result (elmo-folder-synchronize
1925                              folder
1926                              wl-summary-new-mark
1927                              wl-summary-unread-uncached-mark
1928                              wl-summary-unread-cached-mark
1929                              wl-summary-read-uncached-mark
1930                              wl-summary-important-mark
1931                              sync-all no-check))
1932           (setq new-msgdb (nth 0 sync-result))
1933           (setq delete-list (nth 1 sync-result))
1934           (setq crossed (nth 2 sync-result))
1935           (if sync-result
1936               (progn
1937                 ;; Setup sync-all
1938                 (if sync-all (wl-summary-sync-all-init))
1939 ;    (if (and has-nntp
1940 ;            (elmo-nntp-max-number-precedes-list-active-p))
1941         ;; XXX this does not work correctly in rare case.
1942 ;       (setq delete-list
1943 ;             (wl-summary-delete-canceled-msgs-from-list
1944 ;              delete-list
1945 ;              (wl-summary-buffer-msgdb))))
1946                 (when delete-list
1947                   (wl-summary-delete-messages-on-buffer delete-list "Deleting...")
1948                   (message "Deleting...done"))
1949                 (when new-msgdb
1950                   (wl-summary-replace-status-marks
1951                    wl-summary-new-mark
1952                    wl-summary-unread-uncached-mark))
1953                 (setq append-list (elmo-msgdb-get-overview new-msgdb))
1954                 (setq curp append-list)
1955                 (setq num (length curp))
1956                 (when append-list
1957                   (setq i 0)
1958
1959                   ;; set these value for append-message-func
1960                   (setq overview (elmo-msgdb-get-overview
1961                                   (elmo-folder-msgdb folder)))
1962                   (setq number-alist (elmo-msgdb-get-number-alist
1963                                       (elmo-folder-msgdb folder)))
1964
1965                   (setq wl-summary-delayed-update nil)
1966                   (elmo-kill-buffer wl-summary-search-buf-name)
1967                   (while curp
1968                     (setq entity (car curp))
1969                     (when (setq update-thread
1970                                 (wl-summary-append-message-func-internal
1971                                  entity (elmo-folder-msgdb folder)
1972                                  (not sync-all)))
1973                       (wl-append update-top-list update-thread))
1974                     (if elmo-use-database
1975                         (elmo-database-msgid-put
1976                          (car entity) (elmo-folder-name-internal folder)
1977                          (elmo-msgdb-overview-entity-get-number entity)))
1978                     (setq curp (cdr curp))
1979                     (when (> num elmo-display-progress-threshold)
1980                       (setq i (+ i 1))
1981                       (if (or (zerop (% i 5)) (= i num))
1982                           (elmo-display-progress
1983                            'wl-summary-sync-update "Updating thread..."
1984                            (/ (* i 100) num)))))
1985                   (when wl-summary-delayed-update
1986                     (while wl-summary-delayed-update
1987                       (message "Parent (%d) of message %d is no entity"
1988                                (caar wl-summary-delayed-update)
1989                                (elmo-msgdb-overview-entity-get-number
1990                                 (cdar wl-summary-delayed-update)))
1991                       (when (setq update-thread
1992                                   (wl-summary-append-message-func-internal
1993                                    (cdar wl-summary-delayed-update)
1994                                    (elmo-folder-msgdb folder)
1995                                    (not sync-all) t))
1996                         (wl-append update-top-list update-thread))
1997                       (setq wl-summary-delayed-update
1998                             (cdr wl-summary-delayed-update))))
1999                   (when (and (eq wl-summary-buffer-view 'thread)
2000                              update-top-list)
2001                     (wl-thread-update-indent-string-thread
2002                      (elmo-uniq-list update-top-list)))
2003                   (message "Updating thread...done"))
2004                 (unless (eq wl-summary-buffer-view 'thread)
2005                   (wl-summary-make-number-list))
2006                 (wl-summary-set-message-modified)
2007                 (wl-summary-set-mark-modified)
2008                 (when (and sync-all (eq wl-summary-buffer-view 'thread))
2009                   (elmo-kill-buffer wl-summary-search-buf-name)
2010                   (message "Inserting thread...")
2011                   (setq wl-thread-entity-cur 0)
2012                   (wl-thread-insert-top)
2013                   (message "Inserting thread...done"))
2014                 (if elmo-use-database
2015                     (elmo-database-close))
2016                 (run-hooks 'wl-summary-sync-updated-hook)
2017                 (setq mes
2018                       (if (and (eq (length delete-list) 0)
2019                                (eq num 0))
2020                           (format
2021                            "No updates for \"%s\"" (elmo-folder-name-internal
2022                                                     folder))
2023                         (format "Updated (-%d/+%d) message(s)"
2024                                 (length delete-list) num))))
2025             (setq mes "Quit updating.")))
2026       ;; synchronize marks.
2027       (if (and wl-summary-auto-sync-marks sync-result)
2028           (wl-summary-sync-marks))
2029       ;; scoring
2030       (when wl-use-scoring
2031         (setq wl-summary-scored nil)
2032         (wl-summary-score-headers nil (wl-summary-buffer-msgdb)
2033                                   (and sync-all
2034                                        (wl-summary-rescore-msgs number-alist))
2035                                   sync-all)
2036         (when (and wl-summary-scored
2037                    (setq expunged (wl-summary-score-update-all-lines)))
2038           (setq mes (concat mes
2039                             (format " (%d expunged)"
2040                                     (length expunged))))))
2041       (if (and crossed (> crossed 0))
2042           (setq mes
2043                 (if mes
2044                     (concat mes
2045                             (format " (%d crosspost)" crossed))
2046                   (format "%d crosspost message(s)" crossed)))
2047         (and mes (setq mes (concat mes "."))))
2048       ;; Update Folder mode
2049       (wl-folder-set-folder-updated
2050        (elmo-folder-name-internal folder)
2051        (list 0
2052              (let ((pair (wl-summary-count-unread)))
2053                (+ (car pair) (cdr pair)))
2054              (elmo-folder-messages folder)))
2055       (wl-summary-update-modeline)
2056       ;;
2057       (unless unset-cursor
2058         (goto-char (point-min))
2059         (if (not (wl-summary-cursor-down t))
2060             (progn
2061               (goto-char (point-max))
2062               (forward-line -1))
2063           (if (and wl-summary-highlight
2064                    (not (get-text-property (point) 'face)))
2065               (save-excursion
2066                 (forward-line (- 0
2067                                  (or
2068                                   wl-summary-partial-highlight-above-lines
2069                                   wl-summary-highlight-partial-threshold)))
2070                 (wl-highlight-summary (point) (point-max))))))
2071       (setq wl-summary-buffer-msgdb (elmo-folder-msgdb folder))
2072       (wl-delete-all-overlays)
2073       (set-buffer-modified-p nil)
2074       (if mes (message "%s" mes)))))
2075
2076 (defun wl-summary-set-score-mark (mark)
2077   (save-excursion
2078     (beginning-of-line)
2079     (let ((inhibit-read-only t)
2080           (buffer-read-only nil)
2081           msg-num
2082           cur-mark)
2083       (setq msg-num (wl-summary-message-number))
2084       (setq cur-mark (wl-summary-temp-mark))
2085       (when (member cur-mark (list " "
2086                                    wl-summary-score-below-mark
2087                                    wl-summary-score-over-mark))
2088         (delete-backward-char 1)
2089         (insert mark)
2090         (if wl-summary-highlight
2091             (wl-highlight-summary-current-line nil nil t))
2092         (set-buffer-modified-p nil)))))
2093
2094 (defun wl-summary-get-score-mark (msg-num)
2095   (let ((score (cdr (assq msg-num wl-summary-scored))))
2096     (if score
2097         (cond ((< score wl-summary-default-score)
2098                "-")
2099               ((> score wl-summary-default-score)
2100                "+")))))
2101
2102 (defun wl-summary-update-modeline ()
2103   (setq wl-summary-buffer-mode-line
2104         (funcall wl-summary-buffer-mode-line-formatter)))
2105
2106 (defun wl-summary-jump-to-msg (&optional number)
2107   (interactive)
2108   (let ((num (or number
2109                  (string-to-int
2110                   (read-from-minibuffer "Jump to Message(No.): ")))))
2111     (setq num (int-to-string num))
2112     (beginning-of-line)
2113     (if (or (and (re-search-forward (concat "\r" num "[^0-9]") nil t)
2114                  (progn (backward-char 1) t))
2115             (re-search-backward (concat "\r" num "[^0-9]") nil t))
2116         (progn (beginning-of-line) t)
2117       nil)))
2118
2119 (defun wl-summary-highlight-msgs (msgs)
2120   (save-excursion
2121     (let ((len (length msgs))
2122           i)
2123       (message "Hilighting...")
2124       (setq i 0)
2125       (while msgs
2126         (if (wl-summary-jump-to-msg (car msgs))
2127             (wl-highlight-summary-current-line))
2128         (setq msgs (cdr msgs))
2129         (when (> len elmo-display-progress-threshold)
2130           (setq i (+ i 1))
2131           (if (or (zerop (% i 5)) (= i len))
2132               (elmo-display-progress
2133                'wl-summary-highlight-msgs "Highlighting..."
2134                (/ (* i 100) len)))))
2135       (message "Highlighting...done"))))
2136
2137 (defun wl-summary-message-number ()
2138   (save-excursion
2139     (beginning-of-line)
2140     (if (or (re-search-forward "\r\\(-?[0-9]+\\)" (point-at-eol) t)
2141             (re-search-forward "^ *\\(-?[0-9]+\\)" (point-at-eol) t))
2142         (string-to-int (wl-match-buffer 1))
2143       nil)))
2144
2145 (defun wl-summary-delete-all-msgs ()
2146   (interactive)
2147   (let ((cur-buf (current-buffer))
2148         (dels (elmo-folder-list-messages wl-summary-buffer-elmo-folder)))
2149     (set-buffer cur-buf)
2150     (if (null dels)
2151         (message "No message to delete.")
2152       (if (y-or-n-p (format "%s has %d message(s).  Delete all? "
2153                             (wl-summary-buffer-folder-name)
2154                             (length dels)))
2155           (progn
2156             (message "Deleting...")
2157             (elmo-folder-delete-messages
2158              wl-summary-buffer-elmo-folder dels)
2159             (elmo-msgdb-delete-msgs (wl-summary-buffer-msgdb)
2160                                     dels)
2161 ;;;         (elmo-msgdb-save (wl-summary-buffer-folder-name) nil)
2162             (wl-summary-set-message-modified)
2163             (wl-summary-set-mark-modified)
2164             (wl-folder-set-folder-updated (wl-summary-buffer-folder-name)
2165                                           (list 0 0 0))
2166 ;;; for thread.
2167 ;;;         (setq wl-thread-top-entity '(nil t nil nil))
2168             (setq wl-summary-buffer-unread-count 0)
2169             (setq wl-summary-buffer-new-count    0)
2170             (wl-summary-update-modeline)
2171             (set-buffer cur-buf)
2172             (let ((inhibit-read-only t)
2173                   (buffer-read-only nil))
2174               (erase-buffer))
2175 ;;;         (if wl-summary-cache-use (wl-summary-save-view-cache))
2176             (message "Deleting...done")
2177             t)
2178         nil))))
2179
2180 (defun wl-summary-toggle-thread (&optional arg)
2181   "Toggle thread status (T)hread and (S)equential.
2182 If ARG, without confirm."
2183   (interactive "P")
2184   (when (or arg
2185             (y-or-n-p (format "Toggle threading? (y=%s): "
2186                               (if (eq wl-summary-buffer-view 'thread)
2187                                   "\"off\"" "\"on\""))))
2188     (if (eq wl-summary-buffer-view 'thread)
2189         (setq wl-summary-buffer-view 'sequence)
2190       (setq wl-summary-buffer-view 'thread))
2191     (wl-summary-update-modeline)
2192     (force-mode-line-update)
2193     (wl-summary-rescan)))
2194
2195 (defun wl-summary-load-file-object (filename)
2196   "Load lisp object from dir."
2197   (save-excursion
2198     (let ((tmp-buffer (get-buffer-create " *wl-summary-load-file-object*"))
2199           insert-file-contents-pre-hook   ; To avoid autoconv-xmas...
2200           insert-file-contents-post-hook
2201           ret-val)
2202       (if (not (file-readable-p filename))
2203           ()
2204         (set-buffer tmp-buffer)
2205         (as-binary-input-file (insert-file-contents filename))
2206         (setq ret-val
2207               (condition-case nil
2208                   (read (current-buffer))
2209                 (error (error "Reading failed")))))
2210       (kill-buffer tmp-buffer)
2211       ret-val)))
2212
2213 (defun wl-summary-goto-folder (&optional arg)
2214   (interactive "P")
2215   (wl-summary-goto-folder-subr nil nil nil nil t nil arg))
2216
2217 (defun wl-summary-goto-folder-sticky ()
2218   (interactive)
2219   (wl-summary-goto-folder-subr nil nil nil t t))
2220
2221 (defun wl-summary-goto-last-visited-folder ()
2222   (interactive)
2223   (let ((entity
2224          (wl-folder-search-entity-by-name wl-summary-last-visited-folder
2225                                           wl-folder-entity
2226                                           'folder)))
2227     (if entity (wl-folder-set-current-entity-id
2228                 (wl-folder-get-entity-id entity))))
2229   (wl-summary-goto-folder-subr wl-summary-last-visited-folder nil nil nil t))
2230
2231 (defun wl-summary-sticky-p (&optional folder)
2232   (if folder
2233       (get-buffer (wl-summary-sticky-buffer-name
2234                    (elmo-folder-name-internal folder)))
2235     (not (string= wl-summary-buffer-name (buffer-name)))))
2236
2237 (defun wl-summary-always-sticky-folder-p (folder)
2238   (or (eq t wl-summary-always-sticky-folder-list)
2239       (wl-string-match-member
2240        (elmo-folder-name-internal folder)
2241        wl-summary-always-sticky-folder-list)))
2242
2243 (defun wl-summary-stick (&optional force)
2244   "Make current summary buffer sticky."
2245   (interactive "P")
2246   (if (wl-summary-sticky-p)
2247       (message "Current summary buffer is already sticky.")
2248     (when (or force (y-or-n-p "Stick current summary buffer? "))
2249       (wl-summary-toggle-disp-msg 'off)
2250       (wl-summary-switch-to-clone-buffer
2251        (wl-summary-sticky-buffer-name
2252         (wl-summary-buffer-folder-name)))
2253 ;;; ???hang up
2254 ;;;   (rename-buffer (wl-summary-sticky-buffer-name
2255 ;;;                   (wl-summary-buffer-folder-name))))
2256       (message "Folder `%s' is now sticky." (wl-summary-buffer-folder-name)))))
2257
2258 (defun wl-summary-switch-to-clone-buffer (buffer-name)
2259   (let ((cur-buf (current-buffer))
2260         (msg (wl-summary-message-number))
2261         (buf (get-buffer-create buffer-name))
2262         (folder wl-summary-buffer-elmo-folder)
2263         (copy-variables
2264          (append '(wl-summary-buffer-view
2265                    wl-summary-buffer-refile-list
2266                    wl-summary-buffer-delete-list
2267                    wl-summary-buffer-copy-list
2268                    wl-summary-buffer-target-mark-list
2269                    wl-summary-buffer-elmo-folder
2270                    wl-summary-buffer-number-column
2271                    wl-summary-buffer-temp-mark-column
2272                    wl-summary-buffer-persistent-mark-column
2273                    wl-summary-buffer-message-modified
2274                    wl-summary-buffer-mark-modified
2275                    wl-summary-buffer-thread-modified
2276                    wl-summary-buffer-number-list
2277                    wl-summary-buffer-msgdb
2278                    wl-summary-buffer-folder-name
2279                    wl-summary-buffer-line-formatter)
2280                  (and (eq wl-summary-buffer-view 'thread)
2281                       '(wl-thread-entity-hashtb
2282                         wl-thread-entities
2283                         wl-thread-entity-list))
2284                  (and wl-use-scoring
2285                       '(wl-summary-scored
2286                         wl-summary-default-score
2287                         wl-summary-important-above
2288                         wl-summary-target-above
2289                         wl-summary-mark-below
2290                         wl-summary-expunge-below))
2291                  (and (featurep 'wl-score)
2292                       '(wl-current-score-file
2293                         wl-score-alist)))))
2294     (set-buffer buf)
2295     (wl-summary-mode)
2296     (wl-summary-buffer-set-folder folder)
2297     (let ((buffer-read-only nil))
2298       (insert-buffer cur-buf))
2299     (set-buffer-modified-p nil)
2300     (while copy-variables
2301       (set (car copy-variables)
2302            (save-excursion
2303              (set-buffer cur-buf)
2304              (symbol-value (car copy-variables))))
2305       (setq copy-variables (cdr copy-variables)))
2306     (switch-to-buffer buf)
2307     (kill-buffer cur-buf)
2308     (wl-summary-count-unread)
2309     (wl-summary-update-modeline)
2310     (if msg
2311         (if (eq wl-summary-buffer-view 'thread)
2312             (wl-thread-jump-to-msg msg)
2313           (wl-summary-jump-to-msg msg))
2314       (goto-char (point-max))
2315       (beginning-of-line))))
2316
2317 (defun wl-summary-get-buffer (folder)
2318   (or (and folder
2319            (get-buffer (wl-summary-sticky-buffer-name folder)))
2320       (get-buffer wl-summary-buffer-name)))
2321
2322 (defun wl-summary-get-buffer-create (name &optional force-sticky)
2323   (if force-sticky
2324       (get-buffer-create
2325        (wl-summary-sticky-buffer-name name))
2326     (or (get-buffer (wl-summary-sticky-buffer-name name))
2327         (get-buffer-create wl-summary-buffer-name))))
2328
2329 (defun wl-summary-make-number-list ()
2330   (setq wl-summary-buffer-number-list
2331         (mapcar
2332          (lambda (x) (elmo-msgdb-overview-entity-get-number x))
2333          (elmo-msgdb-get-overview (wl-summary-buffer-msgdb)))))
2334
2335 (defun wl-summary-auto-select-msg-p (unread-msg)
2336   (and unread-msg
2337        (not (string=
2338              (elmo-msgdb-get-mark
2339               (wl-summary-buffer-msgdb)
2340               unread-msg)
2341              wl-summary-important-mark))))
2342
2343 (defsubst wl-summary-open-folder (folder)
2344   ;; Select folder
2345   (let ((elmo-mime-charset wl-summary-buffer-mime-charset))
2346     (unwind-protect
2347         (elmo-folder-open folder 'load-msgdb)
2348       ;; For compatibility
2349       (setq wl-summary-buffer-msgdb (elmo-folder-msgdb folder))
2350       (setq wl-summary-buffer-folder-name (elmo-folder-name-internal
2351                                            folder)))))
2352
2353 (defun wl-summary-goto-folder-subr (&optional name scan-type other-window
2354                                               sticky interactive scoring
2355                                               force-exit)
2356   "Display target folder on summary."
2357   (interactive)
2358   (let* ((keep-cursor (memq this-command
2359                             wl-summary-keep-cursor-command))
2360          (name (or name (wl-summary-read-folder wl-default-folder)))
2361          (cur-fld wl-summary-buffer-elmo-folder)
2362          folder buf mes hilit reuse-buf
2363          retval entity)
2364     (if (string= name "")
2365         (setq name wl-default-folder))
2366     (setq folder (wl-folder-get-elmo-folder name))
2367     (when (and (not (string=
2368                      (and cur-fld (elmo-folder-name-internal cur-fld))
2369                      (elmo-folder-name-internal folder))) ; folder is moved.
2370                (eq major-mode 'wl-summary-mode)) ; called in summary.
2371       (setq wl-summary-last-visited-folder (wl-summary-buffer-folder-name))
2372       (run-hooks 'wl-summary-exit-pre-hook)
2373       (if (or force-exit (not (wl-summary-sticky-p)))
2374           (wl-summary-cleanup-temp-marks (wl-summary-sticky-p)))
2375       (wl-summary-save-view)
2376       (elmo-folder-commit wl-summary-buffer-elmo-folder)
2377       (if (and (wl-summary-sticky-p) force-exit)
2378           (kill-buffer (current-buffer))))
2379     (setq buf (wl-summary-get-buffer-create (elmo-folder-name-internal folder)
2380                                             sticky))
2381     (setq reuse-buf
2382           (save-excursion
2383             (set-buffer buf)
2384             (string= (elmo-folder-name-internal folder)
2385                      (wl-summary-buffer-folder-name))))
2386     (unwind-protect
2387         (if reuse-buf
2388             (if interactive
2389                 (switch-to-buffer buf)
2390               (set-buffer buf))
2391           (if other-window
2392               (delete-other-windows))
2393           (set-buffer buf)
2394           (unless (eq major-mode 'wl-summary-mode)
2395             (wl-summary-mode))
2396           (wl-summary-buffer-set-folder folder)
2397           (setq wl-summary-buffer-disp-msg nil)
2398           (setq wl-summary-buffer-last-displayed-msg nil)
2399           (setq wl-summary-buffer-current-msg nil)
2400           (let ((case-fold-search nil)
2401                 (inhibit-read-only t)
2402                 (buffer-read-only nil))
2403             (erase-buffer)
2404             ;; Resume summary view
2405             (if wl-summary-cache-use
2406                 (let* ((dir (elmo-folder-msgdb-path folder))
2407                        (cache (expand-file-name wl-summary-cache-file dir))
2408                        (view (expand-file-name wl-summary-view-file dir)))
2409                   (when (file-exists-p cache)
2410                     (insert-file-contents-as-binary cache)
2411                     (elmo-set-buffer-multibyte
2412                      default-enable-multibyte-characters)
2413                     (decode-mime-charset-region
2414                      (point-min)(point-max)
2415                      wl-summary-buffer-mime-charset 'LF))
2416                   (when (file-exists-p view)
2417                     (setq wl-summary-buffer-view
2418                           (wl-summary-load-file-object view)))
2419                   (wl-thread-resume-entity folder)
2420                   (wl-summary-open-folder folder))
2421               (setq wl-summary-buffer-view
2422                     (wl-summary-load-file-object
2423                      (expand-file-name wl-summary-view-file
2424                                        (elmo-folder-msgdb-path folder))))
2425               (wl-summary-open-folder folder)
2426               (wl-summary-rescan))
2427             (wl-summary-count-unread)
2428             (wl-summary-update-modeline)))
2429       (unless (eq wl-summary-buffer-view 'thread)
2430         (wl-summary-make-number-list))
2431       (when (and wl-summary-cache-use
2432                  (or (and wl-summary-check-line-format
2433                           (wl-summary-line-format-changed-p))
2434                      (wl-summary-view-old-p)))
2435         (wl-summary-rescan))
2436       (wl-summary-toggle-disp-msg (if wl-summary-buffer-disp-msg 'on 'off))
2437       (unless (and reuse-buf keep-cursor)
2438         ;(setq hilit wl-summary-highlight)
2439         (unwind-protect
2440             (let ((wl-summary-highlight (if reuse-buf wl-summary-highlight))
2441                   (wl-use-scoring
2442                    (if (or scoring interactive) wl-use-scoring)))
2443               (if (and (not scan-type)
2444                        interactive
2445                        (not wl-ask-range))
2446                   (setq scan-type (wl-summary-get-sync-range folder)))
2447               (cond
2448                ((eq scan-type nil)
2449                 (wl-summary-sync 'unset-cursor))
2450                ((eq scan-type 'all)
2451                 (wl-summary-sync 'unset-cursor "all"))
2452                ((eq scan-type 'no-sync))
2453                ((or (eq scan-type 'force-update)
2454                     (eq scan-type 'update))
2455                 (setq mes (wl-summary-sync-force-update
2456                            'unset-cursor 'no-check)))))
2457           (if interactive
2458               (switch-to-buffer buf)
2459             (set-buffer buf))
2460           ;; stick always-sticky-folder
2461           (when (wl-summary-always-sticky-folder-p folder)
2462             (or (wl-summary-sticky-p) (wl-summary-stick t)))
2463           (run-hooks 'wl-summary-prepared-pre-hook)
2464           (set-buffer-modified-p nil)
2465           (goto-char (point-min))
2466           (if (wl-summary-cursor-down t)
2467               (let ((unreadp (wl-summary-next-message
2468                               (wl-summary-message-number)
2469                               'down t)))
2470                 (cond ((and wl-auto-select-first
2471                             (wl-summary-auto-select-msg-p unreadp))
2472                        ;; wl-auto-select-first is non-nil and
2473                        ;; unreadp is non-nil but not important
2474                        (setq retval 'disp-msg))
2475                       ((and wl-auto-prefetch-first
2476                             (wl-summary-auto-select-msg-p unreadp))
2477                        ;; wl-auto-select-first is non-nil and
2478                        ;; unreadp is non-nil but not important
2479                        (setq retval 'prefetch-msg))
2480                       ((not (wl-summary-auto-select-msg-p unreadp))
2481                        ;; unreadp is nil or important
2482                        (setq retval 'more-next))))
2483             (goto-char (point-max))
2484             (if (elmo-folder-plugged-p folder)
2485                 (forward-line -1)
2486               (wl-summary-prev))
2487             (setq retval 'more-next))
2488           ;(setq wl-summary-highlight hilit)
2489           (if (and wl-summary-highlight
2490                    (not wl-summary-lazy-highlight)
2491                    (not reuse-buf))
2492               (if (and wl-summary-highlight-partial-threshold
2493                        (> (count-lines (point-min) (point-max))
2494                           wl-summary-highlight-partial-threshold))
2495                   (save-excursion
2496                     (forward-line (-
2497                                    0
2498                                    (or
2499                                     wl-summary-partial-highlight-above-lines
2500                                     wl-summary-highlight-partial-threshold)))
2501                     (wl-highlight-summary (point) (point-max)))
2502                 (wl-highlight-summary (point-min) (point-max))))
2503           (if (eq retval 'disp-msg)
2504               (wl-summary-redisplay))
2505           (if (eq retval 'prefetch-msg)
2506               (wl-message-buffer-prefetch
2507                folder
2508                (wl-summary-message-number)
2509                wl-message-buffer-prefetch-depth
2510                (current-buffer)
2511                wl-summary-buffer-mime-charset))
2512           (if mes (message "%s" mes))
2513           (if (and interactive wl-summary-recenter)
2514               (recenter (/ (- (window-height) 2) 2))))))
2515     ;; set current entity-id
2516     (if (and (not folder)
2517              (setq entity
2518                    (wl-folder-search-entity-by-name (elmo-folder-name-internal
2519                                                      folder)
2520                                                     wl-folder-entity
2521                                                     'folder)))
2522         ;; entity-id is unknown.
2523         (wl-folder-set-current-entity-id
2524          (wl-folder-get-entity-id entity)))
2525     (when (and wl-summary-lazy-highlight
2526                wl-on-xemacs)
2527       (sit-for 0))
2528     (unwind-protect
2529         (run-hooks 'wl-summary-prepared-hook)
2530       (set-buffer-modified-p nil))
2531     retval))
2532
2533 (defun wl-summary-goto-previous-message-beginning ()
2534   (end-of-line)
2535   (re-search-backward "\r\\(-?[0-9]+\\)" nil t)
2536   (beginning-of-line))
2537
2538 (defun wl-summary-goto-top-of-current-thread ()
2539   (wl-summary-jump-to-msg
2540    (wl-thread-entity-get-number
2541     (wl-thread-entity-get-top-entity (wl-thread-get-entity
2542                                       (wl-summary-message-number))))))
2543
2544 (defun wl-summary-goto-bottom-of-sub-thread (&optional depth)
2545   (interactive)
2546   (let ((depth (or depth
2547                    (wl-thread-get-depth-of-current-line))))
2548     (forward-line 1)
2549     (while (and (not (eobp))
2550                 (>= (wl-thread-get-depth-of-current-line)
2551                     depth))
2552       (forward-line 1))
2553     (beginning-of-line)))
2554
2555 (defun wl-summary-insert-line (line)
2556   "Insert LINE in the Summary."
2557   (if wl-use-highlight-mouse-line
2558       ;; remove 'mouse-face of current line.
2559       (put-text-property
2560        (save-excursion (beginning-of-line)(point))
2561        (save-excursion (end-of-line)(point))
2562        'mouse-face nil))
2563   (insert line "\n")
2564   (if wl-use-highlight-mouse-line
2565       ;; remove 'mouse-face of current line.
2566       (put-text-property
2567        (save-excursion (beginning-of-line)(point))
2568        (save-excursion (end-of-line)(point))
2569        'mouse-face nil))
2570   (ignore-errors
2571     (run-hooks 'wl-summary-line-inserted-hook)))
2572
2573 (defun wl-summary-insert-sequential (entity msgdb &rest args)
2574   (let ((inhibit-read-only t)
2575         buffer-read-only)
2576     (goto-char (point-max))
2577     (wl-summary-insert-line
2578      (wl-summary-create-line entity nil nil
2579                              (elmo-msgdb-get-mark
2580                               msgdb
2581                               (elmo-msgdb-overview-entity-get-number
2582                                entity))))))
2583
2584 (defun wl-summary-default-subject-filter (subject)
2585   (let ((case-fold-search t))
2586     (setq subject (elmo-replace-in-string subject "[ \t]*\\(re\\|was\\)[:>]" ""))
2587     (setq subject (elmo-replace-in-string subject "[ \t]" ""))
2588     (elmo-replace-in-string subject "^\\[.*\\]" "")))
2589
2590 (defun wl-summary-subject-equal (subject1 subject2)
2591   (string= (funcall wl-summary-subject-filter-function subject1)
2592            (funcall wl-summary-subject-filter-function subject2)))
2593
2594 (defmacro wl-summary-put-alike (alike)
2595   (` (elmo-set-hash-val (format "#%d" (wl-count-lines))
2596                         (, alike)
2597                         wl-summary-alike-hashtb)))
2598
2599 (defmacro wl-summary-get-alike ()
2600   (` (elmo-get-hash-val (format "#%d" (wl-count-lines))
2601                         wl-summary-alike-hashtb)))
2602
2603 (defun wl-summary-insert-headers (overview func mime-decode)
2604   (message "Creating subject cache...")
2605   (let (ov this last alike)
2606     (buffer-disable-undo (current-buffer))
2607     (make-local-variable 'wl-summary-alike-hashtb)
2608     (setq wl-summary-alike-hashtb (elmo-make-hash (* (length overview) 2)))
2609     (when mime-decode
2610       (elmo-set-buffer-multibyte default-enable-multibyte-characters))
2611     (while (setq ov (pop overview))
2612       (setq this (funcall func ov))
2613       (and this (setq this (std11-unfold-string this)))
2614       (if (equal last this)
2615           (wl-append alike (list ov))
2616         (when last
2617           (wl-summary-put-alike alike)
2618           (insert last ?\n))
2619         (setq alike (list ov)
2620               last this)))
2621     (when last
2622       (wl-summary-put-alike alike)
2623       (insert last ?\n))
2624     (when mime-decode
2625       (decode-mime-charset-region (point-min) (point-max)
2626                                   elmo-mime-charset)
2627       (when (eq mime-decode 'mime)
2628         (eword-decode-region (point-min) (point-max))))
2629     (message "Creating subject cache...done")
2630     (run-hooks 'wl-summary-insert-headers-hook)))
2631
2632 (defun wl-summary-search-by-subject (entity overview)
2633   (let ((summary-buf (current-buffer))
2634         (buf (get-buffer-create wl-summary-search-buf-name))
2635         (folder-name (wl-summary-buffer-folder-name))
2636         match founds found-entity)
2637     (with-current-buffer buf
2638       (let ((case-fold-search t))
2639         (when (or (not (string= wl-summary-search-buf-folder-name folder-name))
2640                   (zerop (buffer-size)))
2641           (setq wl-summary-search-buf-folder-name folder-name)
2642           (wl-summary-insert-headers
2643            overview
2644            (function
2645             (lambda (x)
2646               (funcall wl-summary-subject-filter-function
2647                (elmo-msgdb-overview-entity-get-subject-no-decode x))))
2648            t))
2649         (setq match (funcall wl-summary-subject-filter-function
2650                              (elmo-msgdb-overview-entity-get-subject entity)))
2651         (if (string= match "")
2652             (setq match "\n"))
2653         (goto-char (point-min))
2654         (while (and (not founds)
2655                     (not (= (point) (point-max)))
2656                     (search-forward match nil t))
2657           ;; check exactly match
2658           (when (and (eolp)
2659                      (= (point-at-bol)
2660                         (match-beginning 0)))
2661             (setq found-entity (wl-summary-get-alike))
2662             (if (and found-entity
2663                      ;; Is founded entity myself or children?
2664                      (not (string=
2665                            (elmo-msgdb-overview-entity-get-id entity)
2666                            (elmo-msgdb-overview-entity-get-id
2667                             (car found-entity))))
2668                      (with-current-buffer summary-buf
2669                        (not (wl-thread-descendant-p
2670                              (elmo-msgdb-overview-entity-get-number entity)
2671                              (elmo-msgdb-overview-entity-get-number
2672                               (car found-entity))))))
2673                 ;; return matching entity
2674                 (setq founds found-entity))))
2675         (if founds
2676             (car founds))))))
2677
2678 (defun wl-summary-insert-thread-entity (entity msgdb update
2679                                                &optional force-insert)
2680   (let* ((overview (elmo-msgdb-get-overview msgdb))
2681          this-id
2682          parent-entity
2683          parent-number
2684          (case-fold-search t)
2685          cur number overview2 cur-entity linked retval delayed-entity
2686          update-list entity-stack)
2687     (while entity
2688       (setq this-id (elmo-msgdb-overview-entity-get-id entity)
2689             parent-entity
2690             (elmo-msgdb-get-parent-entity entity msgdb)
2691             parent-number (elmo-msgdb-overview-entity-get-number
2692                            parent-entity))
2693       (setq number (elmo-msgdb-overview-entity-get-number entity))
2694       ;; If thread loop detected, set parent as nil.
2695       (setq cur entity)
2696       (while cur
2697         (if (eq number (elmo-msgdb-overview-entity-get-number
2698                         (setq cur
2699                               (elmo-msgdb-get-parent-entity cur msgdb))))
2700             (setq parent-number nil
2701                   cur nil)))
2702       (if (and parent-number
2703                (not (wl-thread-get-entity parent-number))
2704                (not force-insert))
2705           ;; parent exists in overview, but not in wl-thread-entities
2706           (progn
2707             (wl-append wl-summary-delayed-update
2708                        (list (cons parent-number entity)))
2709             (setq entity nil)) ;; exit loop
2710         ;; Search parent by subject.
2711         (when (and (null parent-number)
2712                    wl-summary-search-parent-by-subject-regexp
2713                    (string-match
2714                     wl-summary-search-parent-by-subject-regexp
2715                     (elmo-msgdb-overview-entity-get-subject entity)))
2716           (let ((found (wl-summary-search-by-subject entity overview)))
2717             (when (and found
2718                        (not (member found wl-summary-delayed-update)))
2719               (setq parent-entity found)
2720               (setq parent-number
2721                     (elmo-msgdb-overview-entity-get-number parent-entity))
2722               (setq linked t))))
2723         ;; If subject is change, divide thread.
2724         (if (and parent-number
2725                  wl-summary-divide-thread-when-subject-changed
2726                  (not (wl-summary-subject-equal
2727                        (or (elmo-msgdb-overview-entity-get-subject
2728                             entity) "")
2729                        (or (elmo-msgdb-overview-entity-get-subject
2730                             parent-entity) ""))))
2731             (setq parent-number nil))
2732         (setq retval
2733               (wl-thread-insert-message entity
2734                                         number parent-number update linked))
2735         (and retval
2736              (wl-append update-list (list retval)))
2737         (setq entity nil) ; exit loop
2738         (while (setq delayed-entity (assq number wl-summary-delayed-update))
2739           (setq wl-summary-delayed-update
2740                 (delq delayed-entity wl-summary-delayed-update))
2741           ;; update delayed message
2742           (wl-append entity-stack (list (cdr delayed-entity)))))
2743       (if (and (not entity)
2744                entity-stack)
2745           (setq entity (pop entity-stack))))
2746     update-list))
2747
2748 (defun wl-summary-update-thread (entity
2749                                  thr-entity
2750                                  parent-entity)
2751   (let* ((this-id (elmo-msgdb-overview-entity-get-id entity))
2752          (overview-entity entity)
2753          (parent-id (elmo-msgdb-overview-entity-get-id parent-entity))
2754          (number (elmo-msgdb-overview-entity-get-number entity))
2755          (parent-number (elmo-msgdb-overview-entity-get-number parent-entity)))
2756     (cond
2757      ((or (not parent-id)
2758           (string= this-id parent-id))
2759       (goto-char (point-max))
2760       (beginning-of-line))
2761      ;; parent already exists in buffer.
2762      ((wl-summary-jump-to-msg parent-number)
2763       (wl-thread-goto-bottom-of-sub-thread)))
2764     (let ((inhibit-read-only t)
2765           (buffer-read-only nil))
2766       (wl-summary-insert-line
2767        (wl-summary-create-line
2768         entity
2769         parent-entity
2770         nil
2771         (elmo-msgdb-get-mark (wl-summary-buffer-msgdb) number)
2772         (wl-thread-maybe-get-children-num number)
2773         (wl-thread-make-indent-string thr-entity)
2774         (wl-thread-entity-get-linked thr-entity))))))
2775
2776 (defun wl-summary-mark-as-unread (&optional number
2777                                             no-server-update
2778                                             no-modeline-update)
2779   (interactive)
2780   (save-excursion
2781     (let* (eol
2782           (inhibit-read-only t)
2783           (buffer-read-only nil)
2784           (folder wl-summary-buffer-elmo-folder)
2785           (msgdb (wl-summary-buffer-msgdb))
2786 ;;;       (number-alist (elmo-msgdb-get-number-alist msgdb))
2787           new-mark visible mark cur-mark)
2788       (if number
2789           (progn
2790             (setq visible (wl-summary-jump-to-msg number))
2791             (unless (setq mark (elmo-msgdb-get-mark msgdb number))
2792               (setq mark " ")))
2793         ;; interactive
2794         (setq visible t))
2795       (when visible
2796         (if (null (wl-summary-message-number))
2797             (message "No message.")
2798           (end-of-line)
2799           (setq eol (point))
2800           (wl-summary-goto-previous-message-beginning)))
2801       (if (or (and (not visible)
2802                    ;; already exists in msgdb.
2803                    (elmo-msgdb-overview-get-entity number msgdb))
2804               (progn
2805                 ;; visible.
2806                 (setq cur-mark (wl-summary-persistent-mark))
2807                 (or (string= cur-mark " ")
2808                     (string= cur-mark wl-summary-read-uncached-mark))))
2809           (progn
2810             (setq number (or number (wl-summary-message-number)))
2811             (setq mark (or mark cur-mark))
2812             (save-match-data
2813               (setq new-mark (if (string= mark
2814                                           wl-summary-read-uncached-mark)
2815                                  wl-summary-unread-uncached-mark
2816                                (if (elmo-message-use-cache-p folder number)
2817                                    wl-summary-unread-mark
2818                                  wl-summary-unread-uncached-mark))))
2819             ;; server side mark
2820             (unless no-server-update
2821               (save-match-data
2822                 (unless (elmo-folder-unmark-read folder (list number))
2823                   (error "Setting mark failed"))))
2824             (when visible
2825               (delete-backward-char 1)
2826               (insert new-mark))
2827             (elmo-msgdb-set-mark msgdb number new-mark)
2828             (unless no-modeline-update
2829               (setq wl-summary-buffer-unread-count
2830                     (+ 1 wl-summary-buffer-unread-count))
2831               (wl-summary-update-modeline)
2832               (wl-folder-update-unread
2833                (wl-summary-buffer-folder-name)
2834                (+ wl-summary-buffer-unread-count
2835                   wl-summary-buffer-new-count)))
2836             (wl-summary-set-mark-modified)
2837             (if (and visible wl-summary-highlight)
2838                 (wl-highlight-summary-current-line))))))
2839   (set-buffer-modified-p nil))
2840
2841 (defun wl-summary-delete (&optional number)
2842   "Mark a delete mark 'D'.
2843 If optional argument NUMBER is specified, mark message specified by NUMBER."
2844   (interactive)
2845   (let* ((buffer-num (wl-summary-message-number))
2846          (msg-num (or number buffer-num))
2847          mark)
2848     (catch 'done
2849       (when (null msg-num)
2850         (if (interactive-p)
2851             (message "No message."))
2852         (throw 'done nil))
2853       (when (setq mark (wl-summary-get-mark msg-num))
2854         (when (wl-summary-reserve-temp-mark-p mark)
2855           (if (interactive-p)
2856               (error "Already marked as `%s'" mark))
2857           (throw 'done nil))
2858         (wl-summary-unmark msg-num))
2859       (if (or (interactive-p)
2860               (eq number buffer-num))
2861           (wl-summary-mark-line "D"))
2862       (setq wl-summary-buffer-delete-list
2863             (cons msg-num wl-summary-buffer-delete-list))
2864       (if (interactive-p)
2865           (if (eq wl-summary-move-direction-downward nil)
2866               (wl-summary-prev)
2867             (wl-summary-next)))
2868       msg-num)))
2869
2870 (defun wl-summary-remove-destination ()
2871   (save-excursion
2872     (let ((inhibit-read-only t)
2873           (buffer-read-only nil)
2874           (buf (current-buffer))
2875           sol eol rs re)
2876       (beginning-of-line)
2877       (setq sol (point))
2878       (search-forward "\r")
2879       (forward-char -1)
2880       (setq eol (point))
2881       (setq rs (next-single-property-change sol 'wl-summary-destination
2882                                             buf eol))
2883       (setq re (next-single-property-change rs 'wl-summary-destination
2884                                             buf eol))
2885       (put-text-property rs re 'wl-summary-destination nil)
2886       (put-text-property rs re 'invisible nil)
2887       (goto-char re)
2888       (delete-char (- eol re)))))
2889
2890 (defun wl-summary-check-mark (msg mark)
2891   (let ((check-func (cond ((string= mark "o")
2892                            'wl-summary-msg-marked-as-refiled)
2893                           ((string= mark "O")
2894                            'wl-summary-msg-marked-as-copied)
2895                           ((string= mark "D")
2896                            'wl-summary-msg-marked-as-deleted)
2897                           ((string= mark "*")
2898                            'wl-summary-msg-marked-as-target))))
2899     (if check-func
2900         (funcall check-func msg))))
2901
2902 (defun wl-summary-mark-collect (mark &optional begin end)
2903   (save-excursion
2904     (save-restriction
2905       (let (msglist)
2906         (narrow-to-region (or begin (point-min))
2907                           (or end (point-max)))
2908         (goto-char (point-min))
2909         ;; for thread...
2910         (if (eq wl-summary-buffer-view 'thread)
2911             (progn
2912               (while (not (eobp))
2913                 (let* ((number (wl-summary-message-number))
2914                        (entity (wl-thread-get-entity number))
2915                        result)
2916                   ;; opened...only myself is checked.
2917                   (if (wl-summary-check-mark number mark)
2918                       (wl-append msglist (list number)))
2919                   (unless (wl-thread-entity-get-opened entity)
2920                     ;; closed...children is also checked.
2921                     (if (setq result (wl-thread-get-children-msgs-with-mark
2922                                       number
2923                                       mark))
2924                         (wl-append msglist result)))
2925                   (forward-line 1)))
2926               (elmo-uniq-list msglist))
2927           (while (not (eobp))
2928             (when (string= (wl-summary-temp-mark) mark)
2929               (setq msglist (cons (wl-summary-message-number) msglist)))
2930             (forward-line 1)))))))
2931
2932 (defun wl-summary-exec ()
2933   (interactive)
2934   (wl-summary-exec-subr (mapcar 'car wl-summary-buffer-refile-list)
2935                         (reverse wl-summary-buffer-delete-list)
2936                         (mapcar 'car wl-summary-buffer-copy-list)))
2937
2938 (defun wl-summary-exec-region (beg end)
2939   (interactive "r")
2940   (message "Collecting marks ...")
2941   (save-excursion
2942     (goto-char beg)
2943     (beginning-of-line)
2944     (setq beg (point))
2945     (goto-char (1- end))
2946     (forward-line)
2947     (setq end (point))
2948     (wl-summary-exec-subr (wl-summary-mark-collect "o" beg end)
2949                           (wl-summary-mark-collect "D" beg end)
2950                           (wl-summary-mark-collect "O" beg end))))
2951
2952 (defun wl-summary-exec-subr (moves dels copies)
2953   (if (not (or moves dels copies))
2954       (message "No marks")
2955     (save-excursion
2956       (let ((del-fld (wl-summary-get-delete-folder
2957                       (wl-summary-buffer-folder-name)))
2958             (start (point))
2959             (unread-marks (list wl-summary-unread-cached-mark
2960                                 wl-summary-unread-uncached-mark
2961                                 wl-summary-new-mark))
2962             (refiles (append moves dels))
2963             (refile-failures 0)
2964             (copy-failures 0)
2965             (copy-len (length copies))
2966             refile-len
2967             dst-msgs                    ; loop counter
2968             result)
2969         (message "Executing ...")
2970         (while dels
2971           (when (not (assq (car dels) wl-summary-buffer-refile-list))
2972             (wl-append wl-summary-buffer-refile-list
2973                        (list (cons (car dels) del-fld)))
2974             (setq wl-summary-buffer-delete-list
2975                   (delete (car dels) wl-summary-buffer-delete-list)))
2976           (setq dels (cdr dels)))
2977         ;; begin refile...
2978         (setq refile-len (length refiles))
2979         (setq dst-msgs
2980               (wl-inverse-alist refiles wl-summary-buffer-refile-list))
2981         (goto-char start)               ; avoid moving cursor to
2982                                         ; the bottom line.
2983         (when (> refile-len elmo-display-progress-threshold)
2984           (elmo-progress-set 'elmo-folder-move-messages
2985                              refile-len "Moving messages..."))
2986         (while dst-msgs
2987           (setq result nil)
2988           (condition-case nil
2989               (setq result (elmo-folder-move-messages
2990                             wl-summary-buffer-elmo-folder
2991                             (cdr (car dst-msgs))
2992                             (if (eq 'null (car (car dst-msgs)))
2993                                 'null
2994                               (wl-folder-get-elmo-folder
2995                                (car (car dst-msgs))))
2996                             (wl-summary-buffer-msgdb)
2997                             (not (null (cdr dst-msgs)))
2998                             nil ; no-delete
2999                             nil ; same-number
3000                             unread-marks
3001                             t))
3002             (error nil))
3003           (if result                    ; succeeded.
3004               (progn
3005                 ;; update buffer.
3006                 (wl-summary-delete-messages-on-buffer (cdr (car dst-msgs)))
3007                 ;; update refile-alist.
3008                 (setq wl-summary-buffer-refile-list
3009                       (wl-delete-associations (cdr (car dst-msgs))
3010                                               wl-summary-buffer-refile-list)))
3011             (setq refile-failures
3012                   (+ refile-failures (length (cdr (car dst-msgs))))))
3013           (setq dst-msgs (cdr dst-msgs)))
3014         (elmo-progress-clear 'elmo-folder-move-messages)
3015         ;; end refile
3016         ;; begin cOpy...
3017         (setq dst-msgs (wl-inverse-alist copies wl-summary-buffer-copy-list))
3018         (when (> copy-len elmo-display-progress-threshold)
3019           (elmo-progress-set 'elmo-folder-move-messages
3020                              copy-len "Copying messages..."))
3021         (while dst-msgs
3022           (setq result nil)
3023           (condition-case nil
3024               (setq result (elmo-folder-move-messages
3025                             wl-summary-buffer-elmo-folder
3026                             (cdr (car dst-msgs))
3027                             (wl-folder-get-elmo-folder
3028                              (car (car dst-msgs)))
3029                             (wl-summary-buffer-msgdb)
3030                             (not (null (cdr dst-msgs)))
3031                             t ; t is no-delete (copy)
3032                             nil ; same number
3033                             unread-marks
3034                             t))
3035             (error nil))
3036           (if result                    ; succeeded.
3037               (progn
3038                 ;; update buffer.
3039                 (wl-summary-delete-copy-marks-on-buffer (cdr (car dst-msgs)))
3040                 ;; update copy-alist
3041                 (setq wl-summary-buffer-copy-list
3042                       (wl-delete-associations (cdr (car dst-msgs))
3043                                               wl-summary-buffer-copy-list)))
3044             (setq copy-failures
3045                   (+ copy-failures (length (cdr (car dst-msgs))))))
3046           (setq dst-msgs (cdr dst-msgs)))
3047         ;; Hide progress bar.
3048         (elmo-progress-clear 'elmo-folder-move-messages)
3049         ;; end cOpy
3050         (wl-summary-folder-info-update)
3051         (wl-summary-set-message-modified)
3052         (wl-summary-set-mark-modified)
3053         (run-hooks 'wl-summary-exec-hook)
3054         (unless (and wl-message-buffer
3055                      (eq (wl-summary-message-number)
3056                          (with-current-buffer wl-message-buffer
3057                            wl-message-buffer-cur-number)))
3058           (wl-summary-toggle-disp-msg 'off))
3059         (set-buffer-modified-p nil)
3060         (message (concat "Executing ... done"
3061                          (if (> refile-failures 0)
3062                              (format " (%d refiling failed)" refile-failures)
3063                            "")
3064                          (if (> copy-failures 0)
3065                              (format " (%d copying failed)" copy-failures)
3066                            "")
3067                          "."))))))
3068
3069 (defun wl-summary-read-folder (default &optional purpose ignore-error
3070                                 no-create init)
3071   (let ((fld (completing-read
3072               (format "Folder name %s(%s): " (or purpose "")
3073                       default)
3074               (or wl-folder-completion-function
3075                   (if (memq 'read-folder wl-use-folder-petname)
3076                       (wl-folder-get-entity-with-petname)
3077                     wl-folder-entity-hashtb))
3078               nil nil (or init wl-default-spec)
3079               'wl-read-folder-hist)))
3080     (if (or (string= fld wl-default-spec)
3081             (string= fld ""))
3082         (setq fld default))
3083     (setq fld (elmo-string (wl-folder-get-realname fld)))
3084     (if (string-match "\n" fld)
3085         (error "Not supported folder name: %s" fld))
3086     (unless no-create
3087       (if ignore-error
3088           (condition-case nil
3089               (wl-folder-confirm-existence
3090                (wl-folder-get-elmo-folder
3091                 fld))
3092             (error))
3093         (wl-folder-confirm-existence (wl-folder-get-elmo-folder
3094                                       fld))))
3095     fld))
3096
3097 (defun wl-summary-print-destination (msg-num folder)
3098   "Print refile destination on line."
3099   (wl-summary-remove-destination)
3100   (let ((inhibit-read-only t)
3101         (folder (copy-sequence folder))
3102         (buffer-read-only nil)
3103         len rs re c)
3104     (setq len (string-width folder))
3105     (if (< len 1) ()
3106       ;;(end-of-line)
3107       (beginning-of-line)
3108       (search-forward "\r")
3109       (forward-char -1)
3110       (setq re (point))
3111       (setq c 0)
3112       (while (< c len)
3113         (forward-char -1)
3114         (setq c (+ c (char-width (following-char)))))
3115       (and (> c len) (setq folder (concat " " folder)))
3116       (setq rs (point))
3117       (put-text-property rs re 'invisible t)
3118       (put-text-property rs re 'wl-summary-destination t)
3119       (goto-char re)
3120       (wl-highlight-refile-destination-string folder)
3121       (insert folder)
3122       (set-buffer-modified-p nil))))
3123
3124 (defsubst wl-summary-get-mark (number)
3125   "Return a temporal mark of message specified by NUMBER."
3126   (or (and (memq number wl-summary-buffer-delete-list) "D")
3127       (and (assq number wl-summary-buffer-copy-list) "O")
3128       (and (assq number wl-summary-buffer-refile-list) "o")
3129       (and (memq number wl-summary-buffer-target-mark-list) "*")))
3130
3131 (defsubst wl-summary-reserve-temp-mark-p (mark)
3132   "Return t if temporal MARK should be reserved."
3133   (member mark wl-summary-reserve-mark-list))
3134
3135 (defun wl-summary-refile (&optional dst number)
3136   "Put refile mark on current line message.
3137 If optional argument DST is specified, put mark without asking
3138 destination folder.
3139 If optional argument NUMBER is specified, mark message specified by NUMBER.
3140
3141 If folder is read-only, message should be copied.
3142 See `wl-refile-policy-alist' for more details."
3143   (interactive)
3144   (let ((policy (wl-get-assoc-list-value wl-refile-policy-alist
3145                                          (wl-summary-buffer-folder-name))))
3146     (cond ((eq policy 'copy)
3147            (if (interactive-p)
3148                (call-interactively 'wl-summary-copy)
3149              (wl-summary-copy dst number)))
3150           (t
3151            (wl-summary-refile-subr 'refile (interactive-p) dst number)))))
3152
3153 (defun wl-summary-copy (&optional dst number)
3154   "Put copy mark on current line message.
3155 If optional argument DST is specified, put mark without asking
3156 destination folder.
3157 If optional argument NUMBER is specified, mark message specified by NUMBER."
3158   (interactive)
3159   (wl-summary-refile-subr 'copy (interactive-p) dst number))
3160
3161 (defun wl-summary-refile-subr (copy-or-refile interactive &optional dst number)
3162   (let* ((buffer-num (wl-summary-message-number))
3163          (msg-num (or number buffer-num))
3164          (msgid (and msg-num
3165                      (elmo-message-field wl-summary-buffer-elmo-folder
3166                                          msg-num 'message-id)))
3167          (entity (and msg-num
3168                       (elmo-msgdb-overview-get-entity
3169                        msg-num (wl-summary-buffer-msgdb))))
3170          (variable
3171           (intern (format "wl-summary-buffer-%s-list" copy-or-refile)))
3172          folder mark already tmp-folder)
3173     (catch 'done
3174       (when (null entity)
3175         ;; msgdb is empty?
3176         (if interactive
3177             (message "Cannot refile."))
3178         (throw 'done nil))
3179       (when (null msg-num)
3180         (if interactive
3181             (message "No message."))
3182         (throw 'done nil))
3183       (when (setq mark (wl-summary-get-mark msg-num))
3184         (when (wl-summary-reserve-temp-mark-p mark)
3185           (if interactive
3186               (error "Already marked as `%s'" mark))
3187           (throw 'done nil)))
3188       (setq folder (and msg-num
3189                         (or dst (wl-summary-read-folder
3190                                  (or (wl-refile-guess entity) wl-trash-folder)
3191                                  (format "for %s" copy-or-refile)))))
3192       ;; Cache folder hack by okada@opaopa.org
3193       (if (and (eq (elmo-folder-type-internal
3194                     (wl-folder-get-elmo-folder
3195                      (wl-folder-get-realname folder))) 'cache)
3196                (not (string= folder
3197                              (setq tmp-folder
3198                                    (concat "'cache/"
3199                                            (elmo-cache-get-path-subr
3200                                             (elmo-msgid-to-cache msgid)))))))
3201           (progn
3202             (setq folder tmp-folder)
3203             (message "Force refile to %s." folder)))
3204       (if (string= folder (wl-summary-buffer-folder-name))
3205           (error "Same folder"))
3206       (if (or (not (elmo-folder-writable-p (wl-folder-get-elmo-folder folder)))
3207               (string= folder wl-queue-folder)
3208               (string= folder wl-draft-folder))
3209           (error "Don't %s messages to %s" copy-or-refile folder))
3210       ;; learn for refile.
3211       (if (eq copy-or-refile 'refile)
3212           (wl-refile-learn entity folder))
3213       (wl-summary-unmark msg-num)
3214       (set variable (append
3215                      (symbol-value variable)
3216                      (list (cons msg-num folder))))
3217       (when (or interactive
3218                 (eq number buffer-num))
3219         (wl-summary-mark-line (if (eq copy-or-refile 'refile)
3220                                   "o" "O"))
3221         ;; print refile destination
3222         (wl-summary-print-destination msg-num folder))
3223       (if interactive
3224           (if (eq wl-summary-move-direction-downward nil)
3225               (wl-summary-prev)
3226             (wl-summary-next)))
3227       (run-hooks (intern (format "wl-summary-%s-hook" copy-or-refile)))
3228       (setq wl-summary-buffer-prev-refile-destination folder)
3229       msg-num)))
3230
3231 (defun wl-summary-refile-prev-destination ()
3232   "Refile message to previously refiled destination."
3233   (interactive)
3234   (wl-summary-refile wl-summary-buffer-prev-refile-destination
3235                      (wl-summary-message-number))
3236   (if (eq wl-summary-move-direction-downward nil)
3237       (wl-summary-prev)
3238     (wl-summary-next)))
3239
3240 (defun wl-summary-copy-prev-destination ()
3241   "Refile message to previously refiled destination."
3242   (interactive)
3243   (wl-summary-copy wl-summary-buffer-prev-copy-destination
3244                    (wl-summary-message-number))
3245   (if (eq wl-summary-move-direction-downward nil)
3246       (wl-summary-prev)
3247     (wl-summary-next)))
3248
3249 (defsubst wl-summary-no-auto-refile-message-p (msg)
3250   (member (elmo-msgdb-get-mark (wl-summary-buffer-msgdb) msg)
3251           wl-summary-auto-refile-skip-marks))
3252
3253 (defun wl-summary-auto-refile (&optional open-all)
3254   "Set refile mark automatically according to 'wl-refile-guess-by-rule'."
3255   (interactive "P")
3256   (message "Marking...")
3257   (save-excursion
3258     (if (and (eq wl-summary-buffer-view 'thread)
3259              open-all)
3260         (wl-thread-open-all))
3261     (let* ((spec (wl-summary-buffer-folder-name))
3262            checked-dsts
3263            (count 0)
3264            number dst thr-entity)
3265       (goto-line 1)
3266       (while (not (eobp))
3267         (setq number (wl-summary-message-number))
3268         (dolist (number (cons number
3269                               (and (eq wl-summary-buffer-view 'thread)
3270                                    ;; process invisible children.
3271                                    (not (wl-thread-entity-get-opened
3272                                          (setq thr-entity
3273                                                (wl-thread-get-entity number))))
3274                                    (wl-thread-entity-get-descendant
3275                                     thr-entity))))
3276           (when (and (not (wl-summary-no-auto-refile-message-p
3277                            number))
3278                      (setq dst
3279                            (wl-folder-get-realname
3280                             (wl-refile-guess-by-rule
3281                              (elmo-msgdb-overview-get-entity
3282                               number (wl-summary-buffer-msgdb)))))
3283                      (not (equal dst spec))
3284                      (let ((pair (assoc dst checked-dsts))
3285                            ret)
3286                        (if pair
3287                            (cdr pair)
3288                          (setq ret
3289                                (condition-case nil
3290                                    (progn
3291                                      (wl-folder-confirm-existence
3292                                       (wl-folder-get-elmo-folder dst))
3293                                      t)
3294                                  (error)))
3295                          (setq checked-dsts (cons (cons dst ret) checked-dsts))
3296                          ret)))
3297             (if (wl-summary-refile dst number)
3298                 (incf count))
3299             (message "Marking...%d message(s)." count)))
3300         (forward-line))
3301       (if (eq count 0)
3302           (message "No message was marked.")
3303         (message "Marked %d message(s)." count)))))
3304
3305 (defun wl-summary-unmark (&optional number)
3306   "Unmark marks (temporary, refile, copy, delete)of current line.
3307 If optional argument NUMBER is specified, unmark message specified by NUMBER."
3308   (interactive)
3309   (save-excursion
3310     (beginning-of-line)
3311     (let ((inhibit-read-only t)
3312           (buffer-read-only nil)
3313           visible
3314           msg-num
3315           cur-mark
3316           score-mark)
3317       (if number
3318           (setq visible (wl-summary-jump-to-msg number))
3319         (setq visible t))
3320       ;; Delete mark on buffer.
3321       (when visible
3322         (setq cur-mark (wl-summary-temp-mark))
3323         (if (string= cur-mark " ")
3324             ()
3325           (delete-backward-char 1)
3326           (or number
3327               (setq number (wl-summary-message-number)))
3328           (if (setq score-mark (wl-summary-get-score-mark number))
3329               (insert score-mark)
3330             (insert " ")))
3331         (if (or (string= cur-mark "o")
3332                 (string= cur-mark "O"))
3333             (wl-summary-remove-destination))
3334         (if wl-summary-highlight
3335             (wl-highlight-summary-current-line nil nil score-mark))
3336         (set-buffer-modified-p nil))
3337       ;; Remove from temporal mark structure.
3338       (and number
3339            (wl-summary-delete-mark number)))))
3340
3341 (defun wl-summary-msg-marked-as-target (msg)
3342   (if (memq msg wl-summary-buffer-target-mark-list)
3343       t))
3344
3345 (defun wl-summary-msg-marked-as-copied (msg)
3346   (assq msg wl-summary-buffer-copy-list))
3347
3348 (defun wl-summary-msg-marked-as-deleted (msg)
3349   (if (memq msg wl-summary-buffer-delete-list)
3350       t))
3351
3352 (defun wl-summary-msg-marked-as-refiled (msg)
3353   (assq msg wl-summary-buffer-refile-list))
3354
3355 (defun wl-summary-target-mark (&optional number)
3356   "Put target mark '*' on current message.
3357 If optional argument NUMBER is specified, mark message specified by NUMBER."
3358   (interactive)
3359   (let* ((buffer-num (wl-summary-message-number))
3360          (msg-num (or number buffer-num))
3361          mark)
3362     (catch 'done
3363       (when (null msg-num)
3364         (if (interactive-p)
3365             (message "No message."))
3366         (throw 'done nil))
3367       (when (setq mark (wl-summary-get-mark msg-num))
3368         (when (wl-summary-reserve-temp-mark-p mark)
3369           (if (interactive-p)
3370               (error "Already marked as `%s'" mark))
3371           (throw 'done nil))
3372         (wl-summary-unmark msg-num))
3373       (if (or (interactive-p)
3374               (eq number buffer-num))
3375           (wl-summary-mark-line "*"))
3376       (setq wl-summary-buffer-target-mark-list
3377             (cons msg-num wl-summary-buffer-target-mark-list))
3378       (if (interactive-p)
3379           (if (eq wl-summary-move-direction-downward nil)
3380               (wl-summary-prev)
3381             (wl-summary-next)))
3382       msg-num)))
3383
3384
3385 (defun wl-summary-refile-region (beg end)
3386   "Put copy mark on messages in the region specified by BEG and END."
3387   (interactive "r")
3388   (wl-summary-refile-region-subr "refile" beg end))
3389
3390 (defun wl-summary-copy-region (beg end)
3391   "Put copy mark on messages in the region specified by BEG and END."
3392   (interactive "r")
3393   (wl-summary-refile-region-subr "copy" beg end))
3394
3395 (defun wl-summary-refile-region-subr (copy-or-refile beg end)
3396   (save-excursion
3397     (save-restriction
3398       (goto-char beg)
3399       ;; guess by first msg
3400       (let* ((msgid (cdr (assq (wl-summary-message-number)
3401                                (elmo-msgdb-get-number-alist
3402                                 (wl-summary-buffer-msgdb)))))
3403              (function (intern (format "wl-summary-%s" copy-or-refile)))
3404              (entity (assoc msgid (elmo-msgdb-get-overview
3405                                    (wl-summary-buffer-msgdb))))
3406              folder)
3407         (if entity
3408             (setq folder (wl-summary-read-folder (wl-refile-guess entity)
3409                                                  (format "for %s"
3410                                                          copy-or-refile))))
3411         (narrow-to-region beg end)
3412         (if (eq wl-summary-buffer-view 'thread)
3413             (progn
3414               (while (not (eobp))
3415                 (let* ((number (wl-summary-message-number))
3416                        (entity (wl-thread-get-entity number))
3417                        children)
3418                   (if (wl-thread-entity-get-opened entity)
3419                       ;; opened...refile line.
3420                       (funcall function folder number)
3421                     ;; closed
3422                     (setq children (wl-thread-get-children-msgs number))
3423                     (while children
3424                       (funcall function folder (pop children))))
3425                   (forward-line 1))))
3426           (while (not (eobp))
3427             (funcall function folder (wl-summary-message-number))
3428             (forward-line 1)))))))
3429
3430 (defun wl-summary-unmark-region (beg end)
3431   (interactive "r")
3432   (save-excursion
3433     (save-restriction
3434       (narrow-to-region beg end)
3435       (goto-char (point-min))
3436       (if (eq wl-summary-buffer-view 'thread)
3437           (progn
3438             (while (not (eobp))
3439               (let* ((number (wl-summary-message-number))
3440                      (entity (wl-thread-get-entity number)))
3441                 (if (wl-thread-entity-get-opened entity)
3442                     ;; opened...unmark line.
3443                     (wl-summary-unmark)
3444                   ;; closed
3445                   (wl-summary-delete-marks-on-buffer
3446                    (wl-thread-get-children-msgs number))))
3447               (forward-line 1)))
3448         (while (not (eobp))
3449           (wl-summary-unmark)
3450           (forward-line 1))))))
3451
3452 (defun wl-summary-mark-region-subr (function beg end)
3453   (save-excursion
3454     (save-restriction
3455       (narrow-to-region beg end)
3456       (goto-char (point-min))
3457       (if (eq wl-summary-buffer-view 'thread)
3458           (progn
3459             (while (not (eobp))
3460               (let* ((number (wl-summary-message-number))
3461                      (entity (wl-thread-get-entity number))
3462                      (wl-summary-move-direction-downward t)
3463                      children)
3464                 (if (wl-thread-entity-get-opened entity)
3465                     ;; opened...delete line.
3466                     (funcall function number)
3467                   ;; closed
3468                   (setq children (wl-thread-get-children-msgs number))
3469                   (while children
3470                     (funcall function (pop children))))
3471                 (forward-line 1))))
3472         (while (not (eobp))
3473           (funcall function (wl-summary-message-number))
3474           (forward-line 1))))))
3475
3476 (defun wl-summary-delete-region (beg end)
3477   (interactive "r")
3478   (wl-summary-mark-region-subr 'wl-summary-delete beg end))
3479
3480 (defun wl-summary-target-mark-region (beg end)
3481   (interactive "r")
3482   (wl-summary-mark-region-subr 'wl-summary-target-mark beg end))
3483
3484 (defun wl-summary-target-mark-all ()
3485   (interactive)
3486   (wl-summary-target-mark-region (point-min) (point-max))
3487   (setq wl-summary-buffer-target-mark-list
3488         (mapcar 'car
3489                 (elmo-msgdb-get-number-alist (wl-summary-buffer-msgdb)))))
3490
3491 (defun wl-summary-delete-all-mark (mark)
3492   (goto-char (point-min))
3493   (while (not (eobp))
3494     (when (string= (wl-summary-temp-mark) mark)
3495       (wl-summary-unmark))
3496     (forward-line 1))
3497   (cond ((string= mark "*")
3498          (setq wl-summary-buffer-target-mark-list nil))
3499         ((string= mark "D")
3500          (setq wl-summary-buffer-delete-list nil))
3501         ((string= mark "O")
3502          (setq wl-summary-buffer-copy-list nil))
3503         ((string= mark "o")
3504          (setq wl-summary-buffer-refile-list nil))))
3505
3506 (defun wl-summary-unmark-all ()
3507   "Unmark all according to what you input."
3508   (interactive)
3509   (let ((unmarks (string-to-char-list (read-from-minibuffer "Unmark: ")))
3510         cur-mark)
3511     (save-excursion
3512       (while unmarks
3513         (setq cur-mark (char-to-string (car unmarks)))
3514         (wl-summary-delete-all-mark cur-mark)
3515         (setq unmarks (cdr unmarks))))))
3516
3517 (defun wl-summary-target-mark-thread ()
3518   (interactive)
3519   (wl-thread-call-region-func 'wl-summary-target-mark-region t))
3520
3521 (defun wl-summary-target-mark-msgs (msgs)
3522   "Return the number of marked messages."
3523   (let ((i 0) num)
3524     (while msgs
3525       (if (eq wl-summary-buffer-view 'thread)
3526           (wl-thread-jump-to-msg (car msgs))
3527         (wl-summary-jump-to-msg (car msgs)))
3528       (setq num (wl-summary-message-number))
3529       (when (eq num (car msgs))
3530         (wl-summary-target-mark num)
3531         (setq i (1+ i)))
3532       (setq msgs (cdr msgs)))
3533     i))
3534
3535 (defun wl-summary-pick (&optional from-list delete-marks)
3536   (interactive)
3537   (save-excursion
3538     (let* ((condition (car (elmo-parse-search-condition
3539                             (elmo-read-search-condition
3540                              wl-summary-pick-field-default))))
3541            (result (elmo-folder-search wl-summary-buffer-elmo-folder
3542                                        condition
3543                                        from-list))
3544            num)
3545       (if delete-marks
3546           (let ((mlist wl-summary-buffer-target-mark-list))
3547             (while mlist
3548               (when (wl-summary-jump-to-msg (car mlist))
3549                 (wl-summary-unmark))
3550               (setq mlist (cdr mlist)))
3551             (setq wl-summary-buffer-target-mark-list nil)))
3552       (if (and result
3553                (setq num (wl-summary-target-mark-msgs result))
3554                (> num 0))
3555           (if (= num (length result))
3556               (message "%d message(s) are picked." num)
3557             (message "%d(%d) message(s) are picked." num
3558                      (- (length result) num)))
3559         (message "No message was picked.")))))
3560
3561 (defun wl-summary-unvirtual ()
3562   "Exit from current virtual folder."
3563   (interactive)
3564   (if (eq 'filter
3565           (elmo-folder-type-internal wl-summary-buffer-elmo-folder))
3566       (wl-summary-goto-folder-subr
3567        (elmo-folder-name-internal
3568         (elmo-filter-folder-target-internal
3569          wl-summary-buffer-elmo-folder))
3570        'update nil nil t)
3571     (error "This folder is not filtered")))
3572
3573 (defun wl-summary-virtual (&optional arg)
3574   "Goto virtual folder.
3575 If ARG, exit virtual folder."
3576   (interactive "P")
3577   (if arg
3578       (wl-summary-unvirtual)
3579     (wl-summary-goto-folder-subr (concat "/"
3580                                          (elmo-read-search-condition
3581                                           wl-summary-pick-field-default)
3582                                          "/"
3583                                          (wl-summary-buffer-folder-name))
3584                                  'update nil nil t)))
3585
3586 (defun wl-summary-delete-all-temp-marks (&optional no-msg)
3587   "Erase all temp marks from buffer."
3588   (interactive)
3589   (when (or wl-summary-buffer-target-mark-list
3590             wl-summary-buffer-delete-list
3591             wl-summary-buffer-refile-list
3592             wl-summary-buffer-copy-list)
3593     (save-excursion
3594       (goto-char (point-min))
3595       (unless no-msg
3596         (message "Unmarking..."))
3597       (while (not (eobp))
3598         (wl-summary-unmark)
3599         (forward-line 1))
3600       (unless no-msg
3601         (message "Unmarking...done"))
3602       (setq wl-summary-buffer-target-mark-list nil)
3603       (setq wl-summary-buffer-delete-list nil)
3604       (setq wl-summary-buffer-refile-list nil)
3605       (setq wl-summary-buffer-copy-list nil))))
3606
3607 (defun wl-summary-delete-mark (number)
3608   "Delete temporary mark of the message specified by NUMBER."
3609   (cond
3610    ((memq number wl-summary-buffer-target-mark-list)
3611     (setq wl-summary-buffer-target-mark-list
3612           (delq number wl-summary-buffer-target-mark-list)))
3613    ((memq number wl-summary-buffer-delete-list)
3614     (setq wl-summary-buffer-delete-list
3615           (delq number wl-summary-buffer-delete-list)))
3616    (t
3617     (let (pair)
3618       (cond
3619        ((setq pair (assq number wl-summary-buffer-copy-list))
3620         (setq wl-summary-buffer-copy-list
3621               (delq pair wl-summary-buffer-copy-list)))
3622        ((setq pair (assq number wl-summary-buffer-refile-list))
3623         (setq wl-summary-buffer-refile-list
3624               (delq pair wl-summary-buffer-refile-list))))))))
3625
3626 (defsubst wl-summary-temp-mark ()
3627   "Move to the temp-mark column and return mark string."
3628   (move-to-column wl-summary-buffer-temp-mark-column)
3629   (buffer-substring (- (point) 1) (point)))
3630
3631 (defsubst wl-summary-persistent-mark ()
3632   "Move to the persistent-mark column and return mark string."
3633   (move-to-column wl-summary-buffer-persistent-mark-column)
3634   (buffer-substring (- (point) 1) (point)))
3635
3636 (defun wl-summary-mark-line (mark)
3637   "Put MARK on current line.  Return message number."
3638   (save-excursion
3639     (beginning-of-line)
3640     (let ((inhibit-read-only t)
3641           (buffer-read-only nil))
3642       (wl-summary-temp-mark) ; mark
3643       (delete-backward-char 1)
3644       (insert mark)
3645       (if wl-summary-highlight
3646           (wl-highlight-summary-current-line nil nil t))
3647       (set-buffer-modified-p nil))))
3648
3649 (defun wl-summary-target-mark-delete ()
3650   (interactive)
3651   (save-excursion
3652     (goto-char (point-min))
3653     (let (number mlist)
3654       (while (not (eobp))
3655         (when (string= (wl-summary-temp-mark) "*")
3656           (let (wl-summary-buffer-disp-msg)
3657             (when (setq number (wl-summary-message-number))
3658               (wl-summary-delete number)
3659               (setq wl-summary-buffer-target-mark-list
3660                     (delq number wl-summary-buffer-target-mark-list)))))
3661         (forward-line 1))
3662       (setq mlist wl-summary-buffer-target-mark-list)
3663       (while mlist
3664         (wl-append wl-summary-buffer-delete-list (list (car mlist)))
3665         (setq wl-summary-buffer-target-mark-list
3666               (delq (car mlist) wl-summary-buffer-target-mark-list))
3667         (setq mlist (cdr mlist))))))
3668
3669 (defun wl-summary-target-mark-prefetch (&optional ignore-cache)
3670   (interactive "P")
3671   (save-excursion
3672     (let* ((mlist (nreverse wl-summary-buffer-target-mark-list))
3673            (inhibit-read-only t)
3674            (buffer-read-only nil)
3675            (count 0)
3676            (length (length mlist))
3677            (pos (point))
3678            skipped
3679            new-mark)
3680       (while mlist
3681         (setq new-mark (wl-summary-prefetch-msg (car mlist) ignore-cache))
3682         (if new-mark
3683             (progn
3684               (message "Prefetching... %d/%d message(s)"
3685                        (setq count (+ 1 count)) length)
3686               (when (wl-summary-jump-to-msg (car mlist))
3687                 (wl-summary-unmark)
3688                 (when new-mark
3689                   (wl-summary-persistent-mark) ; move
3690                   (delete-backward-char 1)
3691                   (insert new-mark)
3692                   (if wl-summary-highlight
3693                       (wl-highlight-summary-current-line))
3694                   (save-excursion
3695                     (goto-char pos)
3696                     (sit-for 0)))))
3697           (setq skipped (cons (car mlist) skipped)))
3698         (setq mlist (cdr mlist)))
3699       (setq wl-summary-buffer-target-mark-list skipped)
3700       (message "Prefetching... %d/%d message(s)." count length)
3701       (set-buffer-modified-p nil))))
3702
3703 (defun wl-summary-target-mark-refile-subr (copy-or-refile)
3704   (let ((variable
3705          (intern (format "wl-summary-buffer-%s-list" copy-or-refile)))
3706         (function
3707          (intern (format "wl-summary-%s" copy-or-refile)))
3708         (numlist wl-summary-buffer-number-list)
3709         regexp number msgid entity folder mlist)
3710     (save-excursion
3711       ;; guess by first mark
3712       (while numlist
3713         (if (memq (car numlist) wl-summary-buffer-target-mark-list)
3714             (setq number (car numlist)
3715                   numlist nil))
3716         (setq numlist (cdr numlist)))
3717       (when number
3718         (setq msgid (elmo-message-field wl-summary-buffer-elmo-folder
3719                                         number 'message-id)
3720               entity (elmo-msgdb-overview-get-entity
3721                       number (wl-summary-buffer-msgdb)))
3722         (if (null entity)
3723             (error "Cannot %s" copy-or-refile))
3724         (funcall function
3725                  (setq folder (wl-summary-read-folder
3726                                (wl-refile-guess entity)
3727                                (format "for %s" copy-or-refile)))
3728                  number)
3729         (goto-char (point-min))
3730         (while (not (eobp))
3731           (when (string= (wl-summary-temp-mark) "*")
3732             (let (wl-summary-buffer-disp-msg)
3733               (when (setq number (wl-summary-message-number))
3734                 (funcall function folder number)
3735                 (setq wl-summary-buffer-target-mark-list
3736                       (delq number wl-summary-buffer-target-mark-list)))))
3737           (forward-line 1))
3738         ;; process invisible messages.
3739         (setq mlist wl-summary-buffer-target-mark-list)
3740         (while mlist
3741           (set variable
3742                (append (symbol-value variable)
3743                        (list (cons (car mlist) folder))))
3744           (setq wl-summary-buffer-target-mark-list
3745                 (delq (car mlist) wl-summary-buffer-target-mark-list))
3746           (setq mlist (cdr mlist)))))))
3747
3748 (defun wl-summary-next-buffer ()
3749   "Switch to next summary buffer."
3750   (interactive)
3751   (let ((buffers (sort (wl-collect-summary)
3752                        (lambda (buffer1 buffer2)
3753                          (string-lessp (buffer-name buffer1)
3754                                        (buffer-name buffer2))))))
3755     (switch-to-buffer
3756      (or (cadr (memq (current-buffer) buffers))
3757          (car buffers)))))
3758
3759 (defun wl-summary-previous-buffer ()
3760   "Switch to previous summary buffer."
3761   (interactive)
3762   (let ((buffers (sort (wl-collect-summary)
3763                        (lambda (buffer1 buffer2)
3764                          (not (string-lessp (buffer-name buffer1)
3765                                             (buffer-name buffer2)))))))
3766     (switch-to-buffer
3767      (or (cadr (memq (current-buffer) buffers))
3768          (car buffers)))))
3769
3770 (defun wl-summary-target-mark-copy ()
3771   (interactive)
3772   (wl-summary-target-mark-refile-subr "copy"))
3773
3774 (defun wl-summary-target-mark-refile ()
3775   (interactive)
3776   (wl-summary-target-mark-refile-subr "refile"))
3777
3778 (defun wl-summary-target-mark-mark-as-read ()
3779   (interactive)
3780   (save-excursion
3781     (goto-char (point-min))
3782     (let ((inhibit-read-only t)
3783           (buffer-read-only nil)
3784           wl-summary-buffer-disp-msg
3785           number mlist)
3786       (while (not (eobp))
3787         (when (string= (wl-summary-temp-mark) "*")
3788           ;; delete target-mark from buffer.
3789           (delete-backward-char 1)
3790           (insert " ")
3791           (setq number (wl-summary-message-number))
3792           (wl-summary-mark-as-read number)
3793           (if wl-summary-highlight
3794               (wl-highlight-summary-current-line))
3795           (if number
3796               (setq wl-summary-buffer-target-mark-list
3797                     (delq number wl-summary-buffer-target-mark-list))))
3798         (forward-line 1))
3799       (setq mlist wl-summary-buffer-target-mark-list)
3800       (while mlist
3801         (wl-summary-mark-as-read (car mlist))
3802         (setq wl-summary-buffer-target-mark-list
3803               (delq (car mlist) wl-summary-buffer-target-mark-list))
3804         (setq mlist (cdr mlist)))
3805       (wl-summary-count-unread)
3806       (wl-summary-update-modeline))))
3807
3808 (defun wl-summary-target-mark-mark-as-unread ()
3809   (interactive)
3810   (save-excursion
3811     (goto-char (point-min))
3812     (let ((inhibit-read-only t)
3813           (buffer-read-only nil)
3814           wl-summary-buffer-disp-msg
3815           number mlist)
3816       (while (not (eobp))
3817         (when (string= (wl-summary-temp-mark) "*")
3818           (delete-backward-char 1)
3819           (insert " ")
3820           (setq number (wl-summary-mark-as-unread))
3821           (if wl-summary-highlight
3822               (wl-highlight-summary-current-line))
3823           (if number
3824               (setq wl-summary-buffer-target-mark-list
3825                     (delq number wl-summary-buffer-target-mark-list))))
3826         (forward-line 1))
3827       (setq mlist wl-summary-buffer-target-mark-list)
3828       (while mlist
3829         (wl-summary-mark-as-unread (car mlist))
3830 ;;;     (wl-thread-msg-mark-as-unread (car mlist))
3831         (setq wl-summary-buffer-target-mark-list
3832               (delq (car mlist) wl-summary-buffer-target-mark-list))
3833         (setq mlist (cdr mlist)))
3834       (wl-summary-count-unread)
3835       (wl-summary-update-modeline))))
3836
3837 (defun wl-summary-target-mark-mark-as-important ()
3838   (interactive)
3839   (save-excursion
3840     (goto-char (point-min))
3841     (let ((inhibit-read-only t)
3842           (buffer-read-only nil)
3843           wl-summary-buffer-disp-msg
3844           number mlist)
3845       (while (not (eobp))
3846         (when (string= (wl-summary-temp-mark) "*")
3847           ;; delete target-mark from buffer.
3848           (delete-backward-char 1)
3849           (insert " ")
3850           (setq number (wl-summary-mark-as-important))
3851           (if wl-summary-highlight
3852               (wl-highlight-summary-current-line))
3853           (if number
3854               (setq wl-summary-buffer-target-mark-list
3855                     (delq number wl-summary-buffer-target-mark-list))))
3856         (forward-line 1))
3857       (setq mlist wl-summary-buffer-target-mark-list)
3858       (while mlist
3859         (wl-summary-mark-as-important (car mlist))
3860         (wl-thread-msg-mark-as-important (car mlist))
3861         (setq wl-summary-buffer-target-mark-list
3862               (delq (car mlist) wl-summary-buffer-target-mark-list))
3863         (setq mlist (cdr mlist)))
3864       (wl-summary-count-unread)
3865       (wl-summary-update-modeline))))
3866
3867 (defun wl-summary-target-mark-save ()
3868   (interactive)
3869   (let ((wl-save-dir
3870          (wl-read-directory-name "Save to directory: "
3871                                  wl-temporary-file-directory))
3872         number)
3873     (if (null (file-exists-p wl-save-dir))
3874         (make-directory wl-save-dir))
3875     (while (setq number (car wl-summary-buffer-target-mark-list))
3876       (wl-thread-jump-to-msg number)
3877       (wl-summary-save t wl-save-dir)
3878       (wl-summary-unmark number))))
3879
3880 (defun wl-summary-target-mark-pick ()
3881   (interactive)
3882   (wl-summary-pick wl-summary-buffer-target-mark-list 'delete))
3883
3884 (defun wl-summary-mark-as-read (&optional number no-folder-mark)
3885   (interactive)
3886   (save-excursion
3887     (let ((buffer-read-only nil)
3888           (folder wl-summary-buffer-elmo-folder)
3889           (msgdb (wl-summary-buffer-msgdb))
3890           (case-fold-search nil)
3891           cur-mark mark stat visible uncached new-mark marked)
3892       (setq number (or number (wl-summary-message-number))
3893             visible (if number
3894                         (wl-summary-jump-to-msg number)
3895                       ;; interactive
3896                       t)
3897             mark (elmo-msgdb-get-mark msgdb number))
3898       (cond
3899        ((string= mark wl-summary-new-mark) ; N
3900         (setq stat 'new))
3901        ((string= mark wl-summary-unread-uncached-mark) ; U
3902         (setq stat 'unread))
3903        ((string= mark wl-summary-unread-cached-mark)  ; !
3904         (setq stat 'unread))
3905        ((string= mark wl-summary-read-uncached-mark)  ; u
3906         (setq stat 'read))
3907        (t
3908         ;; no need to mark server.
3909         (setq no-folder-mark t)))
3910       (setq new-mark
3911             (if (and (if (elmo-message-use-cache-p folder number)
3912                          (not (elmo-folder-local-p folder)))
3913                      (not (elmo-file-cache-exists-p
3914                            (elmo-message-field wl-summary-buffer-elmo-folder
3915                                                number 'message-id))))
3916                 wl-summary-read-uncached-mark
3917               nil))
3918       ;; folder mark.
3919       (unless no-folder-mark
3920         (setq marked (elmo-folder-mark-as-read folder (list number))))
3921       (when (or no-folder-mark marked)
3922         (cond ((eq stat 'unread)
3923                (setq wl-summary-buffer-unread-count
3924                      (1- wl-summary-buffer-unread-count)))
3925               ((eq stat 'new)
3926                (setq wl-summary-buffer-new-count
3927                      (1- wl-summary-buffer-new-count))))
3928         (wl-summary-update-modeline)
3929         (wl-folder-update-unread
3930          (wl-summary-buffer-folder-name)
3931          (+ wl-summary-buffer-unread-count
3932             wl-summary-buffer-new-count))
3933         (when stat
3934           ;; set mark on buffer
3935           (when visible
3936             (unless (string= (wl-summary-persistent-mark) new-mark)
3937               (delete-backward-char 1)
3938               (insert (or new-mark " "))))
3939           ;; set msgdb mark.
3940           (elmo-msgdb-set-mark msgdb number new-mark)
3941           (wl-summary-set-mark-modified))
3942         (if (and visible wl-summary-highlight)
3943             (wl-highlight-summary-current-line nil nil t)))
3944       (set-buffer-modified-p nil)
3945       (if stat
3946           (run-hooks 'wl-summary-unread-message-hook))
3947       number ;return value
3948       )))
3949
3950 (defun wl-summary-mark-as-important (&optional number
3951                                                mark
3952                                                no-server-update)
3953   (interactive)
3954   (if (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
3955           'internal)
3956       (error "Cannot process mark in this folder"))
3957   (save-excursion
3958     (let* (eol
3959           (inhibit-read-only t)
3960           (buffer-read-only nil)
3961           (folder wl-summary-buffer-elmo-folder)
3962           (msgdb (wl-summary-buffer-msgdb))
3963           (number-alist (elmo-msgdb-get-number-alist msgdb))
3964           message-id visible cur-mark)
3965       (if number
3966           (progn
3967             (setq visible (wl-summary-jump-to-msg number))
3968             (setq mark (or mark (elmo-msgdb-get-mark msgdb number))))
3969         (setq visible t))
3970       (when visible
3971         (if (null (setq number (wl-summary-message-number)))
3972             (progn
3973               (message "No message.")
3974               (setq visible nil))
3975           (end-of-line)
3976           (setq eol (point))
3977           (wl-summary-goto-previous-message-beginning)))
3978       (if (or (and (not visible)
3979                    ;; already exists in msgdb.
3980                    (elmo-msgdb-overview-get-entity number msgdb))
3981               (setq cur-mark (wl-summary-persistent-mark)))
3982           (progn
3983             (setq number (or number (wl-summary-message-number)))
3984             (setq mark (or mark cur-mark))
3985             (setq message-id (elmo-message-field
3986                               wl-summary-buffer-elmo-folder
3987                               number
3988                               'message-id))
3989             (if (string= mark wl-summary-important-mark)
3990                 (progn
3991                   ;; server side mark
3992                   (save-match-data
3993                     (unless no-server-update
3994                       (elmo-folder-unmark-important folder (list number))
3995                       (elmo-msgdb-global-mark-delete message-id))
3996                     ;; Remove cache if local folder.
3997                     (if (and (elmo-folder-local-p folder)
3998                              (not (eq 'mark
3999                                       (elmo-folder-type-internal folder))))
4000                         (elmo-file-cache-delete
4001                          (elmo-file-cache-get-path message-id))))
4002                   (when visible
4003                     (delete-backward-char 1)
4004                     (insert " "))
4005                   (elmo-msgdb-set-mark msgdb number nil))
4006               ;; server side mark
4007               (save-match-data
4008                 (unless no-server-update
4009                   (elmo-folder-mark-as-important folder (list number))))
4010               (when visible
4011                 (delete-backward-char 1)
4012                 (insert wl-summary-important-mark))
4013               (elmo-msgdb-set-mark msgdb number
4014                                    wl-summary-important-mark)
4015               (if (eq (elmo-file-cache-exists-p message-id) 'entire)
4016                   (elmo-folder-mark-as-read folder (list number))
4017                 ;; Force cache message.
4018                 (elmo-message-encache folder number 'read))
4019               (unless no-server-update
4020                 (elmo-msgdb-global-mark-set message-id
4021                                             wl-summary-important-mark)))
4022             (wl-summary-set-mark-modified)))
4023       (if (and visible wl-summary-highlight)
4024           (wl-highlight-summary-current-line nil nil t))))
4025   (set-buffer-modified-p nil)
4026   number)
4027
4028 ;;; Summary line.
4029 (defvar wl-summary-line-formatter nil)
4030
4031 (defun wl-summary-view-old-p ()
4032   "Return non-nil when summary view cache has old format."
4033   (save-excursion
4034     (goto-char (point-min))
4035     (and wl-summary-buffer-number-list
4036          (not (re-search-forward "\r-?[0-9]+" (point-at-eol) t)))))
4037
4038 (defun wl-summary-line-format-changed-p ()
4039   "Return non-nil when summary line format is changed."
4040   (not (string=
4041         wl-summary-buffer-line-format
4042         (or (elmo-object-load (expand-file-name 
4043                                wl-summary-line-format-file
4044                                (elmo-folder-msgdb-path
4045                                 wl-summary-buffer-elmo-folder))
4046                               wl-summary-buffer-mime-charset)
4047             wl-summary-buffer-line-format))))
4048
4049 (defun wl-summary-line-format-save ()
4050   "Save current summary line format."
4051   (elmo-object-save
4052    (expand-file-name wl-summary-line-format-file
4053                      (elmo-folder-msgdb-path
4054                       wl-summary-buffer-elmo-folder))
4055    wl-summary-buffer-line-format
4056    wl-summary-buffer-mime-charset))
4057
4058 (defun wl-summary-line-number ()
4059   (wl-set-string-width
4060    (- wl-summary-buffer-number-column)
4061    (number-to-string
4062     (elmo-msgdb-overview-entity-get-number wl-message-entity))))
4063
4064 (defun wl-summary-line-year ()
4065   (aref wl-datevec 0))
4066 (defun wl-summary-line-month ()
4067   (format "%02d" (aref wl-datevec 1)))
4068 (defun wl-summary-line-day ()
4069   (format "%02d" (aref wl-datevec 2)))
4070 (defun wl-summary-line-day-of-week ()
4071   (condition-case nil
4072       (elmo-date-get-week (aref wl-datevec 0)
4073                           (aref wl-datevec 1)
4074                           (aref wl-datevec 2))
4075     (error "??")))
4076 (defun wl-summary-line-hour ()
4077   (format "%02d" (aref wl-datevec 3)))
4078 (defun wl-summary-line-minute ()
4079   (format "%02d" (aref wl-datevec 4)))
4080
4081 (defun wl-summary-line-size ()
4082   (let ((size (elmo-msgdb-overview-entity-get-size wl-message-entity)))
4083     (if size
4084         (cond
4085          ((<= 1 (/ size 1048576))
4086           (format "%.0fM" (/ size 1048576.0)))
4087          ((<= 1 (/ size 1024))
4088           (format "%.0fK" (/ size 1024.0)))
4089          (t (format "%dB" size)))
4090       "")))
4091
4092 (defvar wl-summary-line-subject-minimum-length nil)
4093 (defun wl-summary-line-subject ()
4094   (let (no-parent subject parent-raw-subject parent-subject)
4095     (if (string= wl-thr-indent-string "")
4096         (setq no-parent t)) ; no parent
4097     (setq subject
4098           (elmo-delete-char ?\n
4099                             (or (elmo-msgdb-overview-entity-get-subject
4100                                  wl-message-entity)
4101                                 wl-summary-no-subject-message)))
4102     (setq parent-raw-subject
4103           (elmo-msgdb-overview-entity-get-subject wl-parent-message-entity))
4104     (setq parent-subject
4105           (if parent-raw-subject
4106               (elmo-delete-char ?\n parent-raw-subject)))
4107     (setq subject
4108           (if (or no-parent
4109                   (null parent-subject)
4110                   (not (wl-summary-subject-equal
4111                         subject parent-subject)))
4112               (funcall wl-summary-subject-function subject)
4113             ""))
4114     (when (and wl-summary-line-subject-minimum-length
4115                (< (string-width subject)
4116                   wl-summary-line-subject-minimum-length))
4117       (while (< (string-width subject)
4118                 wl-summary-line-subject-minimum-length)
4119         (setq subject (concat subject " "))))
4120     (if (and (not wl-summary-width)
4121              wl-summary-subject-length-limit)
4122         (truncate-string subject
4123                          wl-summary-subject-length-limit)
4124       subject)))
4125
4126 (defun wl-summary-line-from ()
4127   (elmo-delete-char ?\n
4128                     (funcall wl-summary-from-function
4129                              (elmo-msgdb-overview-entity-get-from
4130                               wl-message-entity))))
4131
4132 (defun wl-summary-line-list-info ()
4133   (let ((folder wl-summary-buffer-folder-name)
4134         (sequence) (ml-name) (ml-count) (subject-string))
4135     (setq sequence (elmo-msgdb-overview-entity-get-extra-field
4136                     wl-message-entity "x-sequence")
4137           ml-name (or (elmo-msgdb-overview-entity-get-extra-field
4138                        wl-message-entity "x-ml-name")
4139                       (and sequence
4140                            (car (split-string sequence " "))))
4141           ml-count (or (elmo-msgdb-overview-entity-get-extra-field
4142                         wl-message-entity "x-mail-count")
4143                        (elmo-msgdb-overview-entity-get-extra-field
4144                         wl-message-entity "x-ml-count")
4145                        (and sequence
4146                             (cadr (split-string sequence " "))))
4147           subject-string
4148           (elmo-delete-char ?\n
4149                             (or (elmo-msgdb-overview-entity-get-subject
4150                                  wl-message-entity)
4151                                 wl-summary-no-subject-message)))
4152     (if (string-match
4153          "^\\s(\\(\\S)+\\)[ :]\\([0-9]+\\)\\s)[ \t]*"
4154          subject-string)
4155         (progn
4156           (if (not ml-name) (setq ml-name (match-string 1 subject-string)))
4157           (if (not ml-count) (setq ml-count (match-string 2 subject-string)))))
4158     (condition-case nil
4159         (if (and ml-name ml-count)
4160             (format "(%s %05d)"
4161                     (car (split-string ml-name " "))
4162                     (string-to-int ml-count))
4163           "")
4164       (error ""))))
4165
4166 (defun wl-summary-line-list-count ()
4167   (let ((folder wl-summary-buffer-folder-name)
4168         (sequence) (ml-count) (subject-string))
4169     (setq sequence (elmo-msgdb-overview-entity-get-extra-field
4170                     wl-message-entity "x-sequence")
4171           ml-count (or (elmo-msgdb-overview-entity-get-extra-field
4172                         wl-message-entity "x-mail-count")
4173                        (elmo-msgdb-overview-entity-get-extra-field
4174                         wl-message-entity "x-ml-count")
4175                        (and sequence
4176                             (cadr (split-string sequence " ")))))
4177     (if ml-count
4178         (format "%d" (string-to-int ml-count))
4179       (setq subject-string
4180             (elmo-delete-char ?\n
4181                               (or (elmo-msgdb-overview-entity-get-subject
4182                                    wl-message-entity)
4183                                   "")))
4184       (if (string-match
4185            "^\\s(\\(\\S)+\\)[ :]\\([0-9]+\\)\\s)[ \t]*"
4186            subject-string)
4187           (match-string 2 subject-string)
4188         ""))))
4189
4190 (defun wl-summary-line-attached ()
4191   (let ((content-type (elmo-msgdb-overview-entity-get-extra-field
4192                        wl-message-entity "content-type")))
4193     (if (and content-type
4194              (string-match "multipart/mixed" content-type))
4195         "@"
4196       "")))
4197
4198 (defun wl-summary-create-line (wl-message-entity
4199                                wl-parent-message-entity
4200                                wl-temp-mark
4201                                wl-persistent-mark
4202                                &optional
4203                                wl-thr-children-number
4204                                wl-thr-indent-string
4205                                wl-thr-linked)
4206   "Create a summary line."
4207   (let ((wl-mime-charset wl-summary-buffer-mime-charset)
4208         (elmo-mime-charset wl-summary-buffer-mime-charset)
4209         (elmo-lang wl-summary-buffer-weekday-name-lang)
4210         (wl-datevec (or (ignore-errors (timezone-fix-time
4211                                         (elmo-msgdb-overview-entity-get-date 
4212                                          wl-message-entity)
4213                                         nil
4214                                         wl-summary-fix-timezone))
4215                         (make-vector 5 0)))
4216         (entity wl-message-entity) ; backward compatibility.
4217         line mark)
4218     (if (and wl-thr-indent-string
4219              wl-summary-indent-length-limit
4220              (< wl-summary-indent-length-limit
4221                 (string-width wl-thr-indent-string)))
4222         (setq wl-thr-indent-string (wl-set-string-width
4223                                     wl-summary-indent-length-limit
4224                                     wl-thr-indent-string)))
4225     (setq line (funcall wl-summary-buffer-line-formatter))
4226     (if wl-summary-width (setq line
4227                                (wl-set-string-width
4228                                 (- wl-summary-width 1) line nil
4229                                 'ignore-invalid)))
4230     (setq line (concat line
4231                        "\r"
4232                        (number-to-string
4233                         (elmo-msgdb-overview-entity-get-number 
4234                          wl-message-entity))))
4235     (if wl-summary-highlight
4236         (wl-highlight-summary-line-string line
4237                                           wl-persistent-mark
4238                                           wl-temp-mark
4239                                           wl-thr-indent-string))
4240     line))
4241
4242 (defsubst wl-summary-proc-wday (wday-str year month mday)
4243   (save-match-data
4244     (if (string-match "\\([A-Z][a-z][a-z]\\).*" wday-str)
4245         (wl-match-string 1 wday-str)
4246       (elmo-date-get-week year month mday))))
4247
4248 (defvar wl-summary-move-spec-plugged-alist
4249   (` ((new . ((t . nil)
4250               (p . (, wl-summary-new-mark))
4251               (p . (, (wl-regexp-opt
4252                        (list wl-summary-unread-uncached-mark
4253                              wl-summary-unread-cached-mark))))
4254               (p . (, (regexp-quote wl-summary-important-mark)))))
4255       (unread . ((t . nil)
4256                  (p . (, (wl-regexp-opt
4257                           (list wl-summary-new-mark
4258                                 wl-summary-unread-uncached-mark
4259                                 wl-summary-unread-cached-mark))))
4260                  (p . (, (regexp-quote wl-summary-important-mark))))))))
4261
4262 (defvar wl-summary-move-spec-unplugged-alist
4263   (` ((new . ((t . nil)
4264               (p . (, wl-summary-unread-cached-mark))
4265               (p . (, (regexp-quote wl-summary-important-mark)))))
4266       (unread . ((t . nil)
4267                  (p . (, wl-summary-unread-cached-mark))
4268                  (p . (, (regexp-quote wl-summary-important-mark))))))))
4269
4270 (defsubst wl-summary-next-message (num direction hereto)
4271   (if wl-summary-buffer-next-message-function
4272       (funcall wl-summary-buffer-next-message-function num direction hereto)
4273     (let ((cur-spec (cdr (assq wl-summary-move-order
4274                                (if (elmo-folder-plugged-p
4275                                     wl-summary-buffer-elmo-folder)
4276                                    wl-summary-move-spec-plugged-alist
4277                                  wl-summary-move-spec-unplugged-alist))))
4278           (nums (memq num (if (eq direction 'up)
4279                               (reverse wl-summary-buffer-number-list)
4280                             wl-summary-buffer-number-list)))
4281           marked-list nums2)
4282       (unless hereto (setq nums (cdr nums)))
4283       (setq nums2 nums)
4284       (if cur-spec
4285           (catch 'done
4286             (while cur-spec
4287               (setq nums nums2)
4288               (cond ((eq (car (car cur-spec)) 'p)
4289                      (if (setq marked-list
4290                                (elmo-folder-list-messages-mark-match
4291                                 wl-summary-buffer-elmo-folder
4292                                 (cdr (car cur-spec))))
4293                          (while nums
4294                            (if (memq (car nums) marked-list)
4295                                (throw 'done (car nums)))
4296                            (setq nums (cdr nums)))))
4297                     ((eq (car (car cur-spec)) 't)
4298                      (if wl-summary-buffer-target-mark-list
4299                          (while nums
4300                            (if (memq (car nums)
4301                                      wl-summary-buffer-target-mark-list)
4302                                (throw 'done (car nums)))
4303                            (setq nums (cdr nums))))))
4304               (setq cur-spec (cdr cur-spec))))
4305         (car nums)))))
4306
4307 (defsubst wl-summary-cursor-move (direction hereto)
4308   (when (and (eq direction 'up)
4309              (eobp))
4310     (forward-line -1)
4311     (setq hereto t))
4312   (let (num)
4313     (when (setq num (wl-summary-next-message (wl-summary-message-number)
4314                                              direction hereto))
4315       (if (numberp num)
4316           (wl-thread-jump-to-msg num))
4317       t)))
4318 ;;
4319 ;; Goto unread or important
4320 ;; returns t if next message exists in this folder.
4321 (defun wl-summary-cursor-down (&optional hereto)
4322   (interactive "P")
4323   (wl-summary-cursor-move 'down hereto))
4324
4325 (defun wl-summary-cursor-up (&optional hereto)
4326   (interactive "P")
4327   (wl-summary-cursor-move 'up hereto))
4328
4329 (defun wl-summary-save-view-cache ()
4330   (save-excursion
4331     (let* ((dir (elmo-folder-msgdb-path wl-summary-buffer-elmo-folder))
4332            (cache (expand-file-name wl-summary-cache-file dir))
4333            (view (expand-file-name wl-summary-view-file dir))
4334            (save-view wl-summary-buffer-view)
4335            (mark-list (copy-sequence wl-summary-buffer-target-mark-list))
4336            (refile-list (copy-sequence wl-summary-buffer-refile-list))
4337            (copy-list (copy-sequence wl-summary-buffer-copy-list))
4338            (delete-list (copy-sequence wl-summary-buffer-delete-list))
4339            (tmp-buffer (get-buffer-create " *wl-summary-save-view-cache*"))
4340            (temp-column wl-summary-buffer-temp-mark-column)
4341            (charset wl-summary-buffer-mime-charset))
4342       (if (file-directory-p dir)
4343           (); ok.
4344         (if (file-exists-p dir)
4345             (error "File %s already exists" dir)
4346           (elmo-make-directory dir)))
4347       (if (eq save-view 'thread)
4348           (wl-thread-save-entity dir))
4349       (when wl-summary-check-line-format
4350         (wl-summary-line-format-save))
4351       (unwind-protect
4352           (progn
4353             (when (file-writable-p cache)
4354               (copy-to-buffer tmp-buffer (point-min) (point-max))
4355               (with-current-buffer tmp-buffer
4356                 (widen)
4357                 (make-local-variable 'wl-summary-highlight)
4358                 (setq wl-summary-highlight nil
4359                       wl-summary-buffer-target-mark-list mark-list
4360                       wl-summary-buffer-refile-list refile-list
4361                       wl-summary-buffer-copy-list copy-list
4362                       wl-summary-buffer-delete-list delete-list
4363                       wl-summary-buffer-temp-mark-column temp-column)
4364                 (wl-summary-delete-all-temp-marks)
4365                 (encode-coding-region
4366                  (point-min) (point-max)
4367                  (or (mime-charset-to-coding-system charset 'LF)
4368                      ;; Mule 2 doesn't have `*ctext*unix'.
4369                      (mime-charset-to-coding-system charset)))
4370                 (write-region-as-binary (point-min)(point-max)
4371                                         cache nil 'no-msg)))
4372             (when (file-writable-p view) ; 'thread or 'sequence
4373               (save-excursion
4374                 (set-buffer tmp-buffer)
4375                 (erase-buffer)
4376                 (prin1 save-view tmp-buffer)
4377                 (princ "\n" tmp-buffer)
4378                 (write-region (point-min) (point-max) view nil 'no-msg))))
4379         ;; kill tmp buffer.
4380         (kill-buffer tmp-buffer)))))
4381
4382 (defsubst wl-summary-get-sync-range (folder)
4383   (intern (or (and
4384                (elmo-folder-plugged-p folder)
4385                (wl-get-assoc-list-value
4386                 wl-folder-sync-range-alist
4387                 (elmo-folder-name-internal folder)))
4388               wl-default-sync-range)))
4389
4390 ;; redefined for wl-summary-sync-update
4391 (defun wl-summary-input-range (folder)
4392   "returns update or all or rescan."
4393   ;; for the case when parts are expanded in the bottom of the folder
4394   (let ((input-range-list '("update" "all" "rescan" "first:" "last:"
4395                             "cache-status"
4396                             "no-sync" "rescan-noscore" "all-visible"))
4397         (default (or (wl-get-assoc-list-value
4398                       wl-folder-sync-range-alist
4399                       folder)
4400                      wl-default-sync-range))
4401         range)
4402     (setq range
4403           (completing-read (format "Range (%s): " default)
4404                            (mapcar
4405                             (function (lambda (x) (cons x x)))
4406                             input-range-list)))
4407     (if (string= range "")
4408         default
4409       range)))
4410
4411 (defun wl-summary-toggle-disp-folder (&optional arg)
4412   (interactive)
4413   (let ((cur-buf (current-buffer))
4414         (summary-win (get-buffer-window (current-buffer)))
4415         fld-buf fld-win)
4416     (cond
4417      ((eq arg 'on)
4418       (setq wl-summary-buffer-disp-folder t)
4419       ;; hide your folder window
4420       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4421           (if (setq fld-win (get-buffer-window fld-buf))
4422               (delete-window fld-win))))
4423      ((eq arg 'off)
4424       (setq wl-summary-buffer-disp-folder nil)
4425       ;; hide your wl-message window!
4426       (when (buffer-live-p wl-message-buffer)
4427         (wl-message-select-buffer wl-message-buffer)
4428         (delete-window))
4429       (select-window (get-buffer-window cur-buf))
4430       ;; display wl-folder window!!
4431       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4432           (if (setq fld-win (get-buffer-window fld-buf))
4433               ;; folder win is already displayed.
4434               (select-window fld-win)
4435             ;; folder win is not displayed.
4436             (switch-to-buffer fld-buf))
4437         ;; no folder buf
4438         (wl-folder))
4439       ;; temporarily delete summary-win.
4440       (if summary-win
4441           (delete-window summary-win))
4442       (split-window-horizontally wl-folder-window-width)
4443       (other-window 1)
4444       (switch-to-buffer cur-buf))
4445      (t
4446       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4447           (if (setq fld-win (get-buffer-window fld-buf))
4448               (setq wl-summary-buffer-disp-folder nil)
4449             (setq wl-summary-buffer-disp-folder t)))
4450       (if (not wl-summary-buffer-disp-folder)
4451           ;; hide message window
4452           (let ((mes-win (and wl-message-buffer
4453                               (get-buffer-window wl-message-buffer)))
4454                 (wl-stay-folder-window t))
4455             (if mes-win (delete-window mes-win))
4456             ;; hide your folder window
4457             (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4458                 (if (setq fld-win (get-buffer-window fld-buf))
4459                     (progn
4460                       (delete-window (get-buffer-window cur-buf))
4461                       (select-window fld-win)
4462                       (switch-to-buffer cur-buf))))
4463             (run-hooks 'wl-summary-toggle-disp-folder-off-hook)
4464             ;; resume message window.
4465             (when mes-win
4466               (wl-message-select-buffer wl-message-buffer)
4467               (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
4468               (select-window (get-buffer-window cur-buf))))
4469         ;; hide message window
4470         (let ((wl-stay-folder-window t)
4471               (mes-win (and wl-message-buffer
4472                             (get-buffer-window wl-message-buffer))))
4473           (if mes-win (delete-window mes-win))
4474           (select-window (get-buffer-window cur-buf))
4475           ;; display wl-folder window!!
4476           (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4477               (if (setq fld-win (get-buffer-window fld-buf))
4478                   ;; folder win is already displayed.
4479                   (select-window fld-win)
4480                 ;; folder win is not displayed...occupy all.
4481                 (switch-to-buffer fld-buf))
4482             ;; no folder buf
4483             (wl-folder))
4484           (split-window-horizontally wl-folder-window-width)
4485           (other-window 1)
4486           (switch-to-buffer cur-buf)
4487           ;; resume message window.
4488           (run-hooks 'wl-summary-toggle-disp-folder-on-hook)
4489           (when mes-win
4490             (wl-message-select-buffer wl-message-buffer)
4491             (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
4492             (select-window (get-buffer-window cur-buf))))))))
4493   (run-hooks 'wl-summary-toggle-disp-folder-hook))
4494
4495 (defun wl-summary-toggle-disp-msg (&optional arg)
4496   (interactive)
4497   (let ((cur-buf (current-buffer))
4498         fld-buf fld-win
4499         summary-win)
4500     (cond
4501      ((eq arg 'on)
4502       (setq wl-summary-buffer-disp-msg t)
4503       (save-excursion
4504         ;; hide your folder window
4505         (if (and (not wl-stay-folder-window)
4506                  (setq fld-buf (get-buffer wl-folder-buffer-name)))
4507             (if (setq fld-win (get-buffer-window fld-buf))
4508                 (unless (one-window-p fld-win)
4509                   (delete-window fld-win))))))
4510      ((eq arg 'off)
4511       (wl-delete-all-overlays)
4512       (setq wl-summary-buffer-disp-msg nil)
4513       (save-excursion
4514         (when (buffer-live-p wl-message-buffer)
4515           (wl-message-select-buffer wl-message-buffer)
4516           (delete-window)
4517           (and (get-buffer-window cur-buf)
4518                (select-window (get-buffer-window cur-buf))))
4519         (run-hooks 'wl-summary-toggle-disp-off-hook)))
4520      (t
4521       (if (and wl-message-buffer
4522                (get-buffer-window wl-message-buffer)) ; already displayed
4523           (setq wl-summary-buffer-disp-msg nil)
4524         (setq wl-summary-buffer-disp-msg t))
4525       (if wl-summary-buffer-disp-msg
4526           (progn
4527             (wl-summary-redisplay)
4528 ;;; hide your folder window
4529 ;;;         (setq fld-buf (get-buffer wl-folder-buffer-name))
4530 ;;;         (if (setq fld-win (get-buffer-window fld-buf))
4531 ;;;             (delete-window fld-win)))
4532             (run-hooks 'wl-summary-toggle-disp-on-hook))
4533         (wl-delete-all-overlays)
4534         (save-excursion
4535           (wl-message-select-buffer wl-message-buffer)
4536           (delete-window)
4537           (select-window (get-buffer-window cur-buf))
4538           (run-hooks 'wl-summary-toggle-disp-off-hook))
4539 ;;;     (switch-to-buffer cur-buf)
4540         )))))
4541
4542 (defun wl-summary-next-line-content ()
4543   "Show next line of the message."
4544   (interactive)
4545   (let ((cur-buf (current-buffer)))
4546     (wl-summary-toggle-disp-msg 'on)
4547     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4548       (set-buffer cur-buf)
4549       (wl-message-next-page 1))))
4550
4551 (defun wl-summary-prev-line-content ()
4552   (interactive)
4553   (let ((cur-buf (current-buffer)))
4554     (wl-summary-toggle-disp-msg 'on)
4555     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4556       (set-buffer cur-buf)
4557       (wl-message-prev-page 1))))
4558
4559 (defun wl-summary-next-page ()
4560   (interactive)
4561   (let ((cur-buf (current-buffer)))
4562     (wl-summary-toggle-disp-msg 'on)
4563     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4564       (set-buffer cur-buf)
4565       (wl-message-next-page))))
4566
4567 (defun wl-summary-prev-page ()
4568   (interactive)
4569   (let ((cur-buf (current-buffer)))
4570     (wl-summary-toggle-disp-msg 'on)
4571     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4572       (set-buffer cur-buf)
4573       (wl-message-prev-page))))
4574
4575 (defsubst wl-summary-no-mime-p (folder)
4576   (wl-string-match-member (elmo-folder-name-internal folder)
4577                           wl-summary-no-mime-folder-list))
4578
4579 (defun wl-summary-set-message-buffer-or-redisplay (&rest args)
4580   "Set message buffer.
4581 If message is not displayed yet, display it.
4582 Return t if message exists."
4583   (let ((folder wl-summary-buffer-elmo-folder)
4584         (number (wl-summary-message-number))
4585         cur-folder cur-number message-last-pos)
4586     (when (buffer-live-p wl-message-buffer)
4587       (save-window-excursion
4588         (wl-message-select-buffer wl-message-buffer)
4589         (setq cur-folder wl-message-buffer-cur-folder)
4590         (setq cur-number wl-message-buffer-cur-number)))
4591     (if (and (string= (elmo-folder-name-internal folder) (or cur-folder ""))
4592              (eq number (or cur-number 0)))
4593         (progn
4594           (set-buffer wl-message-buffer)
4595           t)
4596       (if (wl-summary-no-mime-p folder)
4597           (wl-summary-redisplay-no-mime-internal folder number)
4598         (wl-summary-redisplay-internal folder number))
4599       (when (buffer-live-p wl-message-buffer)
4600         (set-buffer wl-message-buffer))
4601       nil)))
4602
4603 (defun wl-summary-target-mark-forward (&optional arg)
4604   (interactive "P")
4605   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
4606         (summary-buf (current-buffer))
4607         (wl-draft-forward t)
4608         start-point
4609         draft-buf)
4610     (wl-summary-jump-to-msg (car mlist))
4611     (wl-summary-forward t)
4612     (setq start-point (point))
4613     (setq draft-buf (current-buffer))
4614     (setq mlist (cdr mlist))
4615     (save-window-excursion
4616       (when mlist
4617         (while mlist
4618           (set-buffer summary-buf)
4619           (wl-summary-jump-to-msg (car mlist))
4620           (wl-summary-redisplay)
4621           (set-buffer draft-buf)
4622           (goto-char (point-max))
4623           (wl-draft-insert-message)
4624           (setq mlist (cdr mlist)))
4625         (wl-draft-body-goto-top)
4626         (wl-draft-enclose-digest-region (point) (point-max)))
4627       (goto-char start-point)
4628       (save-excursion
4629         (set-buffer summary-buf)
4630         (wl-summary-delete-all-temp-marks)))
4631     (run-hooks 'wl-mail-setup-hook)))
4632
4633 (defun wl-summary-target-mark-reply-with-citation (&optional arg)
4634   (interactive "P")
4635   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
4636         (summary-buf (current-buffer))
4637         change-major-mode-hook
4638         start-point
4639         draft-buf)
4640     (wl-summary-jump-to-msg (car mlist))
4641     (wl-summary-reply arg t)
4642     (goto-char (point-max))
4643     (setq start-point (point-marker))
4644     (setq draft-buf (current-buffer))
4645     (save-window-excursion
4646       (while mlist
4647         (set-buffer summary-buf)
4648         (delete-other-windows)
4649         (wl-summary-jump-to-msg (car mlist))
4650         (wl-summary-redisplay)
4651         (set-buffer draft-buf)
4652         (goto-char (point-max))
4653         (wl-draft-yank-original)
4654         (setq mlist (cdr mlist)))
4655       (goto-char start-point)
4656       (save-excursion
4657         (set-buffer summary-buf)
4658         (wl-summary-delete-all-temp-marks)))
4659     (run-hooks 'wl-mail-setup-hook)))
4660
4661 (defun wl-summary-reply-with-citation (&optional arg)
4662   (interactive "P")
4663   (when (wl-summary-reply arg t)
4664     (goto-char (point-max))
4665     (wl-draft-yank-original)
4666     (run-hooks 'wl-mail-setup-hook)))
4667
4668 (defun wl-summary-jump-to-msg-by-message-id (&optional id)
4669   (interactive)
4670   (let* ((original (wl-summary-message-number))
4671          (msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
4672          (number-alist (elmo-msgdb-get-number-alist (wl-summary-buffer-msgdb)))
4673          msg otherfld schar
4674          (errmsg
4675           (format "No message with id \"%s\" in the folder." msgid)))
4676     (if (setq msg (car (rassoc msgid number-alist)))
4677 ;;;     (wl-summary-jump-to-msg-internal
4678 ;;;      (wl-summary-buffer-folder-name) msg 'no-sync)
4679         (progn
4680           (wl-thread-jump-to-msg msg)
4681           t)
4682       ;; for XEmacs!
4683       (if (and elmo-use-database
4684                (setq errmsg
4685                      (format
4686                       "No message with id \"%s\" in the database." msgid))
4687                (setq otherfld (elmo-database-msgid-get msgid)))
4688           (if (cdr (wl-summary-jump-to-msg-internal
4689                     (car otherfld) (nth 1 otherfld) 'no-sync))
4690               t ; succeed.
4691             ;; Back to original.
4692             (wl-summary-jump-to-msg-internal
4693              (wl-summary-buffer-folder-name) original 'no-sync))
4694         (cond ((eq wl-summary-search-via-nntp 'confirm)
4695                (require 'elmo-nntp)
4696                (message "Search message in nntp server \"%s\" <y/n/s(elect)>?"
4697                         elmo-nntp-default-server)
4698                (setq schar (read-char))
4699                (cond ((eq schar ?y)
4700                       (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
4701                      ((eq schar ?s)
4702                       (wl-summary-jump-to-msg-by-message-id-via-nntp
4703                        msgid
4704                        (read-from-minibuffer "NNTP Server: ")))
4705                      (t
4706                       (message errmsg)
4707                       nil)))
4708               (wl-summary-search-via-nntp
4709                (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
4710               (t
4711                (message errmsg)
4712                nil))))))
4713
4714 (defun wl-summary-jump-to-msg-by-message-id-via-nntp (&optional id server-spec)
4715   (interactive)
4716   (let* ((msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
4717          newsgroups folder ret
4718          user server port type spec)
4719     (if server-spec
4720         (if (string-match "^-" server-spec)
4721             (setq spec (wl-folder-get-elmo-folder server-spec)
4722                   user (elmo-net-folder-user-internal spec)
4723                   server (elmo-net-folder-server-internal spec)
4724                   port (elmo-net-folder-port-internal spec)
4725                   type (elmo-net-folder-stream-type-internal spec))
4726           (setq server server-spec)))
4727     (when (setq ret (elmo-nntp-get-newsgroup-by-msgid
4728                      msgid
4729                      (or server elmo-nntp-default-server)
4730                      (or user elmo-nntp-default-user)
4731                      (or port elmo-nntp-default-port)
4732                      (or type elmo-nntp-default-stream-type)))
4733       (setq newsgroups (elmo-nntp-parse-newsgroups ret))
4734       (setq folder (concat "-" (car newsgroups)
4735                            (elmo-nntp-folder-postfix user server port type)))
4736       (catch 'found
4737         (while newsgroups
4738           (if (wl-folder-entity-exists-p (car newsgroups)
4739                                          wl-folder-newsgroups-hashtb)
4740               (throw 'found
4741                      (setq folder (concat "-" (car newsgroups)
4742                                           (elmo-nntp-folder-postfix
4743                                            user server port type)))))
4744           (setq newsgroups (cdr newsgroups)))))
4745     (if ret
4746         (wl-summary-jump-to-msg-internal folder nil 'update msgid)
4747       (message "No message id \"%s\" in nntp server \"%s\"."
4748                msgid (or server elmo-nntp-default-server))
4749       nil)))
4750
4751 (defun wl-summary-jump-to-msg-internal (folder msg scan-type &optional msgid)
4752   (let (wl-auto-select-first entity)
4753     (if (or (string= folder (wl-summary-buffer-folder-name))
4754             (y-or-n-p
4755              (format
4756               "Message was found in the folder \"%s\". Jump to it? "
4757               folder)))
4758         (progn
4759           (unwind-protect
4760               (wl-summary-goto-folder-subr
4761                folder scan-type nil nil t)
4762             (if msgid
4763                 (setq msg
4764                       (car (rassoc msgid
4765                                    (elmo-msgdb-get-number-alist
4766                                     (wl-summary-buffer-msgdb))))))
4767             (setq entity (wl-folder-search-entity-by-name folder
4768                                                           wl-folder-entity
4769                                                           'folder))
4770             (if entity
4771                 (wl-folder-set-current-entity-id
4772                  (wl-folder-get-entity-id entity))))
4773           (if (null msg)
4774               (message "Message was not found currently in this folder.")
4775             (setq msg (and (wl-thread-jump-to-msg msg) msg)))
4776           (cons folder msg)))))
4777
4778 (defun wl-summary-jump-to-parent-message (arg)
4779   (interactive "P")
4780   (let ((cur-buf (current-buffer))
4781         (number (wl-summary-message-number))
4782         (regexp "\\(<[^<>]*>\\)[ \t]*$")
4783         (i -1) ;; xxx
4784         msg-id msg-num ref-list ref irt)
4785     (if (null number)
4786         (message "No message.")
4787       (when (eq wl-summary-buffer-view 'thread)
4788         (cond ((and arg (not (numberp arg)))
4789                (setq msg-num
4790                      (wl-thread-entity-get-number
4791                       (wl-thread-entity-get-top-entity
4792                        (wl-thread-get-entity number)))))
4793               ((and arg (numberp arg))
4794                (setq i 0)
4795                (setq msg-num number)
4796                (while (< i arg)
4797                  (setq msg-num
4798                        (wl-thread-entity-get-number
4799                         (wl-thread-entity-get-parent-entity
4800                          (wl-thread-get-entity msg-num))))
4801                  (setq i (1+ i))))
4802               (t (setq msg-num
4803                        (wl-thread-entity-get-number
4804                         (wl-thread-entity-get-parent-entity
4805                          (wl-thread-get-entity number)))))))
4806       (when (null msg-num)
4807         (wl-summary-set-message-buffer-or-redisplay)
4808         (set-buffer (wl-message-get-original-buffer))
4809         (message "Searching parent message...")
4810         (setq ref (std11-field-body "References")
4811               irt (std11-field-body "In-Reply-To"))
4812         (cond
4813          ((and arg (not (numberp arg)) ref (not (string= ref ""))
4814                (string-match regexp ref))
4815           ;; The first message of the thread.
4816           (setq msg-id (wl-match-string 1 ref)))
4817          ;; "In-Reply-To:" has only one msg-id.
4818          ((and (null arg) irt (not (string= irt ""))
4819                (string-match regexp irt))
4820           (setq msg-id (wl-match-string 1 irt)))
4821          ((and (or (null arg) (numberp arg)) ref (not (string= ref ""))
4822                (string-match regexp ref))
4823           ;; "^" searching parent, "C-u 2 ^" looking for grandparent.
4824           (while (string-match regexp ref)
4825             (setq ref-list
4826                   (append (list
4827                            (wl-match-string 1 ref))
4828                           ref-list))
4829             (setq ref (substring ref (match-end 0)))
4830             (setq i (1+ i)))
4831           (setq msg-id
4832                 (if (null arg) (nth 0 ref-list) ;; previous
4833                   (if (<= arg i) (nth (1- arg) ref-list)
4834                     (nth i ref-list)))))))
4835       (set-buffer cur-buf)
4836       (cond ((and (null msg-id) (null msg-num))
4837              (message "No parent message!")
4838              nil)
4839             ((and msg-id (wl-summary-jump-to-msg-by-message-id msg-id))
4840              (wl-summary-redisplay)
4841              (message "Searching parent message...done")
4842              t)
4843             ((and msg-num (wl-summary-jump-to-msg msg-num))
4844              (wl-summary-redisplay)
4845              (message "Searching parent message...done")
4846              t)
4847             (t ; failed.
4848              (message "Parent message was not found.")
4849              nil)))))
4850
4851 (defun wl-summary-reply (&optional arg without-setup-hook)
4852   "Reply to current message. Default is \"wide\" reply.
4853 Reply to author if invoked with ARG."
4854   (interactive "P")
4855   (let ((folder wl-summary-buffer-elmo-folder)
4856         (number (wl-summary-message-number))
4857         (summary-buf (current-buffer))
4858         mes-buf)
4859     (when number
4860       (save-excursion
4861         (wl-summary-redisplay-internal folder number))
4862       (setq mes-buf wl-message-buffer)
4863       (wl-message-select-buffer wl-message-buffer)
4864       (set-buffer mes-buf)
4865       (goto-char (point-min))
4866       (unless wl-draft-use-frame
4867         (split-window-vertically)
4868         (other-window 1))
4869       (when (setq mes-buf (wl-message-get-original-buffer))
4870         (wl-draft-reply mes-buf arg summary-buf)
4871         (unless without-setup-hook
4872           (run-hooks 'wl-mail-setup-hook)))
4873       t)))
4874
4875 (defun wl-summary-write ()
4876   "Write a new draft from Summary."
4877   (interactive)
4878   (wl-draft (list (cons 'To ""))
4879             nil nil nil nil (wl-summary-buffer-folder-name))
4880   (run-hooks 'wl-mail-setup-hook)
4881   (mail-position-on-field "To"))
4882
4883 (defvar wl-summary-write-current-folder-functions
4884   '(wl-folder-get-newsgroups
4885     wl-folder-guess-mailing-list-by-refile-rule
4886     wl-folder-guess-mailing-list-by-folder-name)
4887   "Newsgroups or Mailing List address guess functions list.
4888 Call from `wl-summary-write-current-folder'.
4889 When guess function return nil, challenge next guess-function.")
4890
4891 (defun wl-summary-write-current-folder (&optional folder)
4892   "Write message to current FOLDER's newsgroup or mailing-list.
4893 Use function list is `wl-summary-write-current-folder-functions'."
4894   (interactive)
4895   ;; default FOLDER is current buffer folder
4896   (setq folder (or folder (wl-summary-buffer-folder-name)))
4897   (let ((func-list wl-summary-write-current-folder-functions)
4898         guess-list guess-func)
4899     (while func-list
4900       (setq guess-list (funcall (car func-list) folder))
4901       (if (null guess-list)
4902           (setq func-list (cdr func-list))
4903         (setq guess-func (car func-list))
4904         (setq func-list nil)))
4905     (if (null guess-func)
4906         (wl-summary-write)
4907       (unless (or (stringp (nth 0 guess-list))
4908                   (stringp (nth 1 guess-list))
4909                   (stringp (nth 2 guess-list)))
4910         (error "Invalid value return guess function `%s'"
4911                (symbol-name guess-func)))
4912       (wl-draft (list (cons 'To (nth 0 guess-list))
4913                       (cons 'Cc (nth 1 guess-list))
4914                       (cons 'Newsgroups (nth 2 guess-list)))
4915                 nil nil nil nil folder)
4916       (run-hooks 'wl-mail-setup-hook)
4917       (mail-position-on-field "Subject"))))
4918
4919 (defun wl-summary-forward (&optional without-setup-hook)
4920   ""
4921   (interactive)
4922   (let ((folder wl-summary-buffer-elmo-folder)
4923         (number (wl-summary-message-number))
4924         (summary-buf (current-buffer))
4925         (wl-draft-forward t)
4926         mes-buf
4927         entity subject num)
4928     (if (null number)
4929         (message "No message.")
4930       (if (and (elmo-message-use-cache-p folder number)
4931                (eq (elmo-file-cache-status
4932                     (elmo-file-cache-get
4933                      (elmo-message-field folder number 'message-id)))
4934                    'section))
4935           ;; Reload.
4936           (wl-summary-redisplay-internal nil nil 'force-reload)
4937         (wl-summary-redisplay-internal folder number))
4938       (setq mes-buf wl-message-buffer)
4939       (wl-message-select-buffer mes-buf)
4940       (unless wl-draft-use-frame
4941         (split-window-vertically)
4942         (other-window 1))
4943       ;; get original subject.
4944       (if summary-buf
4945           (save-excursion
4946             (set-buffer summary-buf)
4947             (setq subject
4948                   (or (elmo-message-field folder number 'subject) ""))))
4949       (set-buffer mes-buf)
4950       (wl-draft-forward subject summary-buf)
4951       (unless without-setup-hook
4952         (run-hooks 'wl-mail-setup-hook)))))
4953
4954 (defun wl-summary-click (e)
4955   (interactive "e")
4956   (mouse-set-point e)
4957   (wl-summary-read))
4958
4959 (defun wl-summary-read ()
4960   "Proceed reading message in the summary buffer."
4961   (interactive)
4962   (let ((cur-buf (current-buffer)))
4963     (wl-summary-toggle-disp-msg 'on)
4964     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4965       (set-buffer cur-buf)
4966       (if (wl-message-next-page)
4967           (wl-summary-down t)))))
4968
4969 (defsubst wl-summary-cursor-move-surface (downward interactive)
4970   (if wl-summary-move-direction-toggle
4971       (setq wl-summary-move-direction-downward downward))
4972   (let ((start (point))
4973         (skip-tmark-regexp (wl-regexp-opt wl-summary-skip-mark-list))
4974         (skip t)
4975         skip-pmark-regexp goto-next next-entity finfo)
4976     (if (elmo-folder-plugged-p wl-summary-buffer-elmo-folder)
4977         ()
4978       (setq skip-pmark-regexp
4979             (wl-regexp-opt (list " "
4980                                  wl-summary-unread-cached-mark
4981                                  wl-summary-important-mark))))
4982     (while (and skip
4983                 (not (if downward (eobp) (bobp))))
4984       (if downward
4985           (forward-line 1)
4986         (forward-line -1))
4987       (setq skip (or (string-match skip-tmark-regexp 
4988                                    (save-excursion
4989                                      (wl-summary-temp-mark)))
4990                      (and skip-pmark-regexp
4991                           (not (string-match
4992                                 skip-pmark-regexp
4993                                 (save-excursion
4994                                   (wl-summary-persistent-mark))))))))
4995
4996     (if (if downward (eobp) (and (bobp) skip)) (setq goto-next t))
4997     (if (or (eobp) (and (bobp) skip))
4998         (goto-char start))
4999
5000     (beginning-of-line)
5001
5002     (if (not goto-next)
5003         (if wl-summary-buffer-disp-msg
5004             (wl-summary-redisplay))
5005       (if interactive
5006           (if wl-summary-buffer-next-folder-function
5007               (funcall wl-summary-buffer-next-folder-function)
5008             (when wl-auto-select-next
5009               (setq next-entity
5010                     (if downward
5011                         (wl-summary-get-next-folder)
5012                       (wl-summary-get-prev-folder)))
5013               (if next-entity
5014                   (setq finfo (wl-folder-get-entity-info next-entity))))
5015             (wl-ask-folder
5016              '(lambda () (wl-summary-next-folder-or-exit next-entity))
5017              (format
5018               "No more messages. Type SPC to go to %s."
5019               (wl-summary-entity-info-msg next-entity finfo))))))))
5020
5021 (defun wl-summary-prev (&optional interactive)
5022   (interactive)
5023   (wl-summary-cursor-move-surface nil (or interactive (interactive-p))))
5024
5025 (defun wl-summary-next (&optional interactive)
5026   (interactive)
5027   (wl-summary-cursor-move-surface t (or interactive (interactive-p))))
5028
5029 (defun wl-summary-up (&optional interactive skip-no-unread)
5030   ""
5031   (interactive)
5032   (if wl-summary-move-direction-toggle
5033       (setq wl-summary-move-direction-downward nil))
5034   (if (wl-summary-cursor-up)
5035       (if wl-summary-buffer-disp-msg
5036           (wl-summary-redisplay))
5037     (if (or interactive
5038             (interactive-p))
5039         (if wl-summary-buffer-prev-folder-function
5040             (funcall wl-summary-buffer-prev-folder-function)
5041           (let (next-entity finfo)
5042             (when wl-auto-select-next
5043               (progn
5044                 (setq next-entity (wl-summary-get-prev-unread-folder))
5045                 (if next-entity
5046                     (setq finfo (wl-folder-get-entity-info next-entity)))))
5047             (if (and skip-no-unread
5048                      (eq wl-auto-select-next 'skip-no-unread))
5049                 (wl-summary-next-folder-or-exit next-entity t)
5050               (wl-ask-folder
5051                '(lambda () (wl-summary-next-folder-or-exit next-entity t))
5052                (format
5053                 "No more unread messages. Type SPC to go to %s."
5054                 (wl-summary-entity-info-msg next-entity finfo)))))))))
5055
5056 (defun wl-summary-get-prev-folder ()
5057   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5058         last-entity cur-id)
5059     (when folder-buf
5060       (setq cur-id (save-excursion (set-buffer folder-buf)
5061                                    wl-folder-buffer-cur-entity-id))
5062       (wl-folder-get-prev-folder cur-id))))
5063
5064 (defun wl-summary-get-next-folder ()
5065   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5066         cur-id)
5067     (when folder-buf
5068       (setq cur-id (save-excursion (set-buffer folder-buf)
5069                                    wl-folder-buffer-cur-entity-id))
5070       (wl-folder-get-next-folder cur-id))))
5071
5072 (defun wl-summary-get-next-unread-folder ()
5073   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5074         cur-id)
5075     (when folder-buf
5076       (setq cur-id (save-excursion (set-buffer folder-buf)
5077                                    wl-folder-buffer-cur-entity-id))
5078       (wl-folder-get-next-folder cur-id 'unread))))
5079
5080 (defun wl-summary-get-prev-unread-folder ()
5081   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5082         cur-id)
5083     (when folder-buf
5084       (setq cur-id (save-excursion (set-buffer folder-buf)
5085                                    wl-folder-buffer-cur-entity-id))
5086       (wl-folder-get-prev-folder cur-id 'unread))))
5087
5088 (defun wl-summary-down (&optional interactive skip-no-unread)
5089   (interactive)
5090   (if wl-summary-move-direction-toggle
5091       (setq wl-summary-move-direction-downward t))
5092   (if (wl-summary-cursor-down)
5093       (if wl-summary-buffer-disp-msg
5094           (wl-summary-redisplay))
5095     (if (or interactive
5096             (interactive-p))
5097         (if wl-summary-buffer-next-folder-function
5098             (funcall wl-summary-buffer-next-folder-function)
5099           (let (next-entity finfo)
5100             (when wl-auto-select-next
5101               (setq next-entity (wl-summary-get-next-unread-folder)))
5102             (if next-entity
5103                 (setq finfo (wl-folder-get-entity-info next-entity)))
5104             (if (and skip-no-unread
5105                      (eq wl-auto-select-next 'skip-no-unread))
5106                 (wl-summary-next-folder-or-exit next-entity)
5107               (wl-ask-folder
5108                '(lambda () (wl-summary-next-folder-or-exit next-entity))
5109                (format
5110                 "No more unread messages. Type SPC to go to %s."
5111                 (wl-summary-entity-info-msg next-entity finfo)))))))))
5112
5113 (defun wl-summary-goto-last-displayed-msg ()
5114   (interactive)
5115   (unless wl-summary-buffer-last-displayed-msg
5116     (setq wl-summary-buffer-last-displayed-msg
5117           wl-summary-buffer-current-msg))
5118   (if wl-summary-buffer-last-displayed-msg
5119       (progn
5120         (wl-summary-jump-to-msg wl-summary-buffer-last-displayed-msg)
5121         (if wl-summary-buffer-disp-msg
5122             (wl-summary-redisplay)))
5123     (message "No last message.")))
5124
5125 (defun wl-summary-redisplay (&optional arg)
5126   (interactive "P")
5127   (if (and (not arg)
5128            (wl-summary-no-mime-p wl-summary-buffer-elmo-folder))
5129       (wl-summary-redisplay-no-mime)
5130     (wl-summary-redisplay-internal nil nil arg)))
5131
5132 (defsubst wl-summary-redisplay-internal (&optional folder number force-reload)
5133   (interactive)
5134   (let* ((msgdb (wl-summary-buffer-msgdb))
5135          (folder (or folder wl-summary-buffer-elmo-folder))
5136          (num (or number (wl-summary-message-number)))
5137          (wl-mime-charset      wl-summary-buffer-mime-charset)
5138          (default-mime-charset wl-summary-buffer-mime-charset)
5139          fld-buf fld-win thr-entity)
5140     (if (and wl-thread-open-reading-thread
5141              (eq wl-summary-buffer-view 'thread)
5142              (not (wl-thread-entity-get-opened
5143                    (setq thr-entity (wl-thread-get-entity
5144                                      num))))
5145              (wl-thread-entity-get-children thr-entity))
5146         (wl-thread-force-open))
5147     (if num
5148         (progn
5149           (setq wl-summary-buffer-disp-msg t)
5150           (setq wl-summary-buffer-last-displayed-msg
5151                 wl-summary-buffer-current-msg)
5152           ;; hide folder window
5153           (if (and (not wl-stay-folder-window)
5154                    (setq fld-buf (get-buffer wl-folder-buffer-name)))
5155               (if (setq fld-win (get-buffer-window fld-buf))
5156                   (delete-window fld-win)))
5157           (setq wl-current-summary-buffer (current-buffer))
5158           (wl-summary-mark-as-read
5159            num
5160            ;; not fetched, then change server-mark.
5161            (if (wl-message-redisplay folder num 'mime
5162                                      (or force-reload
5163                                          (string= (elmo-folder-name-internal
5164                                                    folder)
5165                                                   wl-draft-folder)))
5166                nil
5167              ;; plugged, then leave server-mark.
5168              (if (and
5169                   (not
5170                    (elmo-folder-local-p
5171                     wl-summary-buffer-elmo-folder))
5172                   (elmo-folder-plugged-p
5173                    wl-summary-buffer-elmo-folder))
5174                  'leave)))
5175           (setq wl-summary-buffer-current-msg num)
5176           (when wl-summary-recenter
5177             (recenter (/ (- (window-height) 2) 2))
5178             (if (not wl-summary-indent-length-limit)
5179                 (wl-horizontal-recenter)))
5180           (wl-highlight-summary-displaying)
5181           (wl-message-buffer-prefetch-next folder num
5182                                            wl-message-buffer-prefetch-depth
5183                                            (current-buffer)
5184                                            wl-summary-buffer-mime-charset)
5185           (run-hooks 'wl-summary-redisplay-hook))
5186       (message "No message to display."))))
5187
5188 (defun wl-summary-redisplay-no-mime (&optional ask-coding)
5189   "Display message without MIME decoding.
5190 If ASK-CODING is non-nil, coding-system for the message is asked."
5191   (interactive "P")
5192   (let ((elmo-mime-display-as-is-coding-system
5193          (if ask-coding
5194              (or (read-coding-system "Coding system: ")
5195                  elmo-mime-display-as-is-coding-system)
5196            elmo-mime-display-as-is-coding-system)))
5197     (wl-summary-redisplay-no-mime-internal)))
5198
5199 (defun wl-summary-redisplay-no-mime-internal (&optional folder number)
5200   (let* ((fld (or folder wl-summary-buffer-elmo-folder))
5201          (num (or number (wl-summary-message-number)))
5202          wl-break-pages)
5203     (if num
5204         (progn
5205           (setq wl-summary-buffer-disp-msg t)
5206           (setq wl-summary-buffer-last-displayed-msg
5207                 wl-summary-buffer-current-msg)
5208           (setq wl-current-summary-buffer (current-buffer))
5209           (wl-message-redisplay fld num 'as-is
5210                                 (string= (elmo-folder-name-internal fld)
5211                                          wl-draft-folder))
5212           (wl-summary-mark-as-read num)
5213           (setq wl-summary-buffer-current-msg num)
5214           (when wl-summary-recenter
5215             (recenter (/ (- (window-height) 2) 2))
5216             (if (not wl-summary-indent-length-limit)
5217                 (wl-horizontal-recenter)))
5218           (wl-highlight-summary-displaying)
5219           (run-hooks 'wl-summary-redisplay-hook))
5220       (message "No message to display.")
5221       (wl-ask-folder 'wl-summary-exit
5222                      "No more messages. Type SPC to go to folder mode."))))
5223
5224 (defun wl-summary-redisplay-all-header (&optional folder number)
5225   (interactive)
5226   (let* ((fld (or folder wl-summary-buffer-elmo-folder))
5227          (num (or number (wl-summary-message-number)))
5228          (wl-mime-charset      wl-summary-buffer-mime-charset)
5229          (default-mime-charset wl-summary-buffer-mime-charset))
5230     (if num
5231         (progn
5232           (setq wl-summary-buffer-disp-msg t)
5233           (setq wl-summary-buffer-last-displayed-msg
5234                 wl-summary-buffer-current-msg)
5235           (setq wl-current-summary-buffer (current-buffer))
5236           (if (wl-message-redisplay fld num 'all-header
5237                                     (string= (elmo-folder-name-internal fld)
5238                                              wl-draft-folder))
5239               (wl-summary-mark-as-read num))
5240           (setq wl-summary-buffer-current-msg num)
5241           (when wl-summary-recenter
5242             (recenter (/ (- (window-height) 2) 2))
5243             (if (not wl-summary-indent-length-limit)
5244                 (wl-horizontal-recenter)))
5245           (wl-highlight-summary-displaying)
5246           (run-hooks 'wl-summary-redisplay-hook))
5247       (message "No message to display."))))
5248
5249 (defun wl-summary-jump-to-current-message ()
5250   "Jump into Message buffer."
5251   (interactive)
5252   (let (message-buf message-win)
5253     (if (setq message-buf wl-message-buffer)
5254         (if (setq message-win (get-buffer-window message-buf))
5255             (select-window message-win)
5256           (wl-message-select-buffer wl-message-buffer))
5257       (wl-summary-redisplay)
5258       (wl-message-select-buffer wl-message-buffer))))
5259
5260 (defun wl-summary-cancel-message ()
5261   "Cancel an article on news."
5262   (interactive)
5263   (if (null (wl-summary-message-number))
5264       (message "No message.")
5265     (let ((summary-buf (current-buffer))
5266           message-buf)
5267       (wl-summary-set-message-buffer-or-redisplay)
5268       (if (setq message-buf (wl-message-get-original-buffer))
5269           (set-buffer message-buf))
5270       (unless (wl-message-news-p)
5271         (set-buffer summary-buf)
5272         (if (and (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
5273                      'nntp)
5274                  (y-or-n-p "Cannot get Newsgroups. Fetch again? "))
5275             (progn
5276               (wl-summary-redisplay t)
5277               (wl-summary-supersedes-message))
5278           (error "This is not a news article; supersedes is impossible")))
5279       (when (yes-or-no-p "Do you really want to cancel this article? ")
5280         (let (from newsgroups message-id distribution buf)
5281           (save-excursion
5282             (setq from (std11-field-body "from")
5283                   newsgroups (std11-field-body "newsgroups")
5284                   message-id (std11-field-body "message-id")
5285                   distribution (std11-field-body "distribution"))
5286             ;; Make sure that this article was written by the user.
5287             (unless (wl-address-user-mail-address-p
5288                      (wl-address-header-extract-address
5289                       (car (wl-parse-addresses from))))
5290               (error "This article is not yours"))
5291             ;; Make control message.
5292             (setq buf (set-buffer (get-buffer-create " *message cancel*")))
5293             (setq wl-draft-buffer-cur-summary-buffer summary-buf)
5294             (buffer-disable-undo (current-buffer))
5295             (erase-buffer)
5296             (insert "Newsgroups: " newsgroups "\n"
5297                     "From: " (wl-address-header-extract-address
5298                               wl-from) "\n"
5299                               "Subject: cmsg cancel " message-id "\n"
5300                               "Control: cancel " message-id "\n"
5301                               (if distribution
5302                                   (concat "Distribution: " distribution "\n")
5303                                 "")
5304                               mail-header-separator "\n"
5305                               wl-summary-cancel-message)
5306             (message "Canceling your message...")
5307             (wl-draft-raw-send t t) ; kill when done, force-pre-hooks.
5308             (message "Canceling your message...done")))))))
5309
5310 (defun wl-summary-supersedes-message ()
5311   "Supersede current message."
5312   (interactive)
5313   (let ((summary-buf (current-buffer))
5314         message-buf from)
5315     (wl-summary-set-message-buffer-or-redisplay)
5316     (if (setq message-buf (wl-message-get-original-buffer))
5317         (set-buffer message-buf))
5318     (unless (wl-message-news-p)
5319       (set-buffer summary-buf)
5320       (if (and (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
5321                    'nntp)
5322                (y-or-n-p "Cannot get Newsgroups. Fetch again? "))
5323           (progn
5324             (wl-summary-redisplay t)
5325             (wl-summary-supersedes-message))
5326         (error "This is not a news article; supersedes is impossible")))
5327     (save-excursion
5328       (setq from (std11-field-body "from"))
5329       ;; Make sure that this article was written by the user.
5330       (unless (wl-address-user-mail-address-p
5331                (wl-address-header-extract-address
5332                 (car (wl-parse-addresses from))))
5333         (error "This article is not yours"))
5334       (let* ((message-id (std11-field-body "message-id"))
5335              (followup-to (std11-field-body "followup-to"))
5336              (mail-default-headers
5337               (concat mail-default-headers
5338                       "Supersedes: " message-id "\n"
5339                       (and followup-to
5340                            (concat "Followup-To: " followup-to "\n")))))
5341         (if message-buf (set-buffer message-buf))
5342         (wl-draft-edit-string (buffer-substring (point-min) (point-max)))))))
5343
5344 (defun wl-summary-save (&optional arg wl-save-dir)
5345   "Save current message to disk."
5346   (interactive)
5347   (let ((filename)
5348         (num (wl-summary-message-number)))
5349     (if (null wl-save-dir)
5350         (setq wl-save-dir wl-temporary-file-directory))
5351     (if num
5352         (save-excursion
5353           (setq filename (expand-file-name
5354                           (int-to-string num)
5355                           wl-save-dir))
5356           (if (null (and arg
5357                          (null (file-exists-p filename))))
5358               (setq filename
5359                     (read-file-name "Save to file: " filename)))
5360
5361           (wl-summary-set-message-buffer-or-redisplay)
5362           (set-buffer (wl-message-get-original-buffer))
5363           (if (and (null arg) (file-exists-p filename))
5364               (if (y-or-n-p "File already exists.  override it? ")
5365                   (write-region (point-min) (point-max) filename))
5366             (write-region (point-min) (point-max) filename)))
5367       (message "No message to save."))
5368     num))
5369
5370 (defun wl-summary-save-region (beg end)
5371   (interactive "r")
5372   (save-excursion
5373     (save-restriction
5374       (narrow-to-region beg end)
5375       (goto-char (point-min))
5376       (let ((wl-save-dir
5377              (wl-read-directory-name "Save to directory: "
5378                                      wl-temporary-file-directory)))
5379         (if (null (file-exists-p wl-save-dir))
5380             (make-directory wl-save-dir))
5381         (if (eq wl-summary-buffer-view 'thread)
5382             (progn
5383               (while (not (eobp))
5384                 (let* ((number (wl-summary-message-number))
5385                        (entity (wl-thread-get-entity number)))
5386                   (if (wl-thread-entity-get-opened entity)
5387                       (wl-summary-save t wl-save-dir)
5388                     ;; closed
5389                     (wl-summary-save t wl-save-dir))
5390                   (forward-line 1))))
5391           (while (not (eobp))
5392             (wl-summary-save t wl-save-dir)
5393             (forward-line 1)))))))
5394
5395 ;; mew-summary-pipe-message()
5396 (defun wl-summary-pipe-message (prefix command)
5397   "Send this message via pipe."
5398   (interactive (list current-prefix-arg nil))
5399   (if (null (wl-summary-message-number))
5400       (message "No message.")
5401     (setq command (read-string "Shell command on message: "
5402                                wl-summary-shell-command-last))
5403     (if (y-or-n-p "Send this message to pipe? ")
5404         (wl-summary-pipe-message-subr prefix command))))
5405
5406 (defun wl-summary-target-mark-pipe (prefix command)
5407   "Send each marked messages via pipe."
5408   (interactive (list current-prefix-arg nil))
5409   (if (null wl-summary-buffer-target-mark-list)
5410       (message "No marked message.")
5411     (setq command (read-string "Shell command on each marked message: "
5412                                wl-summary-shell-command-last))
5413     (when (y-or-n-p "Send each marked message to pipe? ")
5414       (while (car wl-summary-buffer-target-mark-list)
5415         (let ((num (car wl-summary-buffer-target-mark-list)))
5416           (wl-thread-jump-to-msg num)
5417           (wl-summary-pipe-message-subr prefix command)
5418           (wl-summary-unmark num))))))
5419
5420 (defun wl-summary-pipe-message-subr (prefix command)
5421   (save-excursion
5422     (wl-summary-set-message-buffer-or-redisplay)
5423     (set-buffer (wl-message-get-original-buffer))
5424     (if (string= command "")
5425         (setq command wl-summary-shell-command-last))
5426     (goto-char (point-min)) ; perhaps this line won't be necessary
5427     (if prefix
5428         (search-forward "\n\n"))
5429     (shell-command-on-region (point) (point-max) command nil)
5430     (setq wl-summary-shell-command-last command)))
5431
5432 (defun wl-summary-print-message (&optional arg)
5433   (interactive "P")
5434   (if (null (wl-summary-message-number))
5435       (message "No message.")
5436     (save-excursion
5437       (wl-summary-set-message-buffer-or-redisplay)
5438       (if (or (not (interactive-p))
5439               (y-or-n-p "Print ok? "))
5440           (progn
5441             (let ((buffer (generate-new-buffer " *print*")))
5442               (copy-to-buffer buffer (point-min) (point-max))
5443               (set-buffer buffer)
5444               (funcall wl-print-buffer-function)
5445               (kill-buffer buffer)))
5446         (message "")))))
5447
5448 (defun wl-summary-print-message-with-ps-print (&optional filename)
5449   "Print message via ps-print."
5450   (interactive)
5451   (if (null (wl-summary-message-number))
5452       (message "No message.")
5453     (setq filename (ps-print-preprint current-prefix-arg))
5454     (if (or (not (interactive-p))
5455             (y-or-n-p "Print ok? "))
5456         (let ((summary-buffer (current-buffer))
5457               wl-break-pages)
5458           (save-excursion
5459             (wl-summary-set-message-buffer-or-redisplay)
5460             ;; (wl-summary-redisplay-internal)
5461             (let* ((buffer (generate-new-buffer " *print*"))
5462                    (entity (progn
5463                              (set-buffer summary-buffer)
5464                              (assoc (cdr (assq
5465                                           (wl-summary-message-number)
5466                                           (elmo-msgdb-get-number-alist
5467                                            (wl-summary-buffer-msgdb))))
5468                                     (elmo-msgdb-get-overview
5469                                      (wl-summary-buffer-msgdb)))))
5470                    (wl-ps-subject
5471                     (and entity
5472                          (or (elmo-msgdb-overview-entity-get-subject entity)
5473                              "")))
5474                    (wl-ps-from
5475                     (and entity
5476                          (or (elmo-msgdb-overview-entity-get-from entity) "")))
5477                    (wl-ps-date
5478                     (and entity
5479                          (or (elmo-msgdb-overview-entity-get-date entity) ""))))
5480               (run-hooks 'wl-ps-preprint-hook)
5481               (set-buffer wl-message-buffer)
5482               (copy-to-buffer buffer (point-min) (point-max))
5483               (set-buffer buffer)
5484               (unwind-protect
5485                   (let ((ps-left-header
5486                          (list (concat "(" wl-ps-subject ")")
5487                                (concat "(" wl-ps-from ")")))
5488                         (ps-right-header
5489                          (list "/pagenumberstring load"
5490                                (concat "(" wl-ps-date ")"))))
5491                     (run-hooks 'wl-ps-print-hook)
5492                     (funcall wl-ps-print-buffer-function filename))
5493                 (kill-buffer buffer)))))
5494       (message ""))))
5495
5496 (if (featurep 'ps-print) ; ps-print is available.
5497     (fset 'wl-summary-print-message 'wl-summary-print-message-with-ps-print))
5498
5499 (defun wl-summary-target-mark-print ()
5500   (interactive)
5501   (if (null wl-summary-buffer-target-mark-list)
5502       (message "No marked message.")
5503     (when (y-or-n-p "Print all marked messages. OK? ")
5504       (while (car wl-summary-buffer-target-mark-list)
5505         (let ((num (car wl-summary-buffer-target-mark-list)))
5506           (wl-thread-jump-to-msg num)
5507           (wl-summary-print-message)
5508           (wl-summary-unmark num))))))
5509
5510 (defun wl-summary-folder-info-update ()
5511   (let ((folder (elmo-string (wl-summary-buffer-folder-name)))
5512         (num-db (elmo-msgdb-get-number-alist
5513                  (wl-summary-buffer-msgdb))))
5514     (wl-folder-set-folder-updated folder
5515                                   (list 0
5516                                         (+ wl-summary-buffer-unread-count
5517                                            wl-summary-buffer-new-count)
5518                                         (length num-db)))))
5519
5520 (defun wl-summary-get-original-buffer ()
5521   "Get original buffer for the current summary."
5522   (save-excursion
5523     (wl-summary-set-message-buffer-or-redisplay)
5524     (wl-message-get-original-buffer)))
5525
5526 (defun wl-summary-pack-number (&optional arg)
5527   (interactive "P")
5528   (elmo-folder-pack-numbers wl-summary-buffer-elmo-folder)
5529   (let (wl-use-scoring)
5530     (wl-summary-rescan)))
5531
5532 (defun wl-summary-target-mark-uudecode ()
5533   (interactive)
5534   (let ((mlist (reverse wl-summary-buffer-target-mark-list))
5535         (summary-buf (current-buffer))
5536         (tmp-buf (get-buffer-create "*WL UUENCODE*"))
5537         orig-buf i k filename rc errmsg)
5538     (setq i 1)
5539     (setq k (length mlist))
5540     (set-buffer tmp-buf)
5541     (erase-buffer)
5542     (save-window-excursion
5543       (while mlist
5544         (set-buffer summary-buf)
5545         (wl-summary-jump-to-msg (car mlist))
5546         (wl-summary-redisplay)
5547         (set-buffer (setq orig-buf (wl-summary-get-original-buffer)))
5548         (goto-char (point-min))
5549         (cond ((= i 1) ; first
5550                (if (setq filename (wl-message-uu-substring
5551                                    orig-buf tmp-buf t
5552                                    (= i k)))
5553                    nil
5554                  (error "Can't find begin line")))
5555               ((< i k)
5556                (wl-message-uu-substring orig-buf tmp-buf))
5557               (t ; last
5558                (wl-message-uu-substring orig-buf tmp-buf nil t)))
5559         (setq i (1+ i))
5560         (setq mlist (cdr mlist)))
5561       (set-buffer tmp-buf)
5562       (message "Exec %s..." wl-prog-uudecode)
5563       (unwind-protect
5564           (let ((decode-dir wl-temporary-file-directory))
5565             (if (not wl-prog-uudecode-no-stdout-option)
5566                 (setq filename (read-file-name "Save to file: "
5567                                                (expand-file-name
5568                                                 (elmo-safe-filename filename)
5569                                                 wl-temporary-file-directory)))
5570               (setq decode-dir
5571                     (wl-read-directory-name "Save to directory: "
5572                                             wl-temporary-file-directory))
5573               (setq filename (expand-file-name filename decode-dir)))
5574             (if (file-exists-p filename)
5575                 (or (yes-or-no-p (format "File %s exists. Save anyway? "
5576                                          filename))
5577                     (error "")))
5578             (elmo-bind-directory
5579              decode-dir
5580              (setq rc
5581                    (as-binary-process
5582                     (apply 'call-process-region (point-min) (point-max)
5583                            wl-prog-uudecode t (current-buffer) nil
5584                            wl-prog-uudecode-arg))))
5585             (when (not (= 0 rc))
5586               (setq errmsg (buffer-substring (point-min)(point-max)))
5587               (error "Uudecode error: %s" errmsg))
5588             (if (not wl-prog-uudecode-no-stdout-option)
5589                 (let (file-name-handler-alist) ;; void jka-compr
5590                   (as-binary-output-file
5591                    (write-region (point-min) (point-max)
5592                                  filename nil 'no-msg))))
5593             (save-excursion
5594               (set-buffer summary-buf)
5595               (wl-summary-delete-all-temp-marks))
5596             (if (file-exists-p filename)
5597                 (message "Saved as %s" filename)))
5598         (kill-buffer tmp-buf)))))
5599
5600 ;; Someday
5601 ;; (defun wl-summary-drop-unsync ()
5602 ;;   "Drop all unsync messages."
5603 ;;   (interactive)
5604 ;;   (if (elmo-folder-pipe-p (wl-summary-buffer-folder-name))
5605 ;;       (error "You cannot drop unsync messages in this folder"))
5606 ;;   (if (or (not (interactive-p))
5607 ;;        (y-or-n-p "Drop all unsync messages? "))
5608 ;;       (let* ((folder-list (elmo-folder-get-primitive-folder-list
5609 ;;                         (wl-summary-buffer-folder-name)))
5610 ;;           (is-multi (elmo-multi-p (wl-summary-buffer-folder-name)))
5611 ;;           (sum 0)
5612 ;;           (multi-num 0)
5613 ;;           pair)
5614 ;;      (message "Dropping...")
5615 ;;      (while folder-list
5616 ;;        (setq pair (elmo-folder-message-numbers (car folder-list)))
5617 ;;        (when is-multi ;; dirty hack...
5618 ;;          (incf multi-num)
5619 ;;          (setcar pair (+ (* multi-num elmo-multi-divide-number)
5620 ;;                          (car pair))))
5621 ;;        (elmo-msgdb-set-number-alist
5622 ;;         (wl-summary-buffer-msgdb)
5623 ;;         (nconc
5624 ;;          (elmo-msgdb-get-number-alist (wl-summary-buffer-msgdb))
5625 ;;          (list (cons (car pair) nil))))
5626 ;;        (setq sum (+ sum (cdr pair)))
5627 ;;        (setq folder-list (cdr folder-list)))
5628 ;;      (wl-summary-set-message-modified)
5629 ;;      (wl-folder-set-folder-updated (wl-summary-buffer-folder-name)
5630 ;;                                    (list 0
5631 ;;                                          (+ wl-summary-buffer-unread-count
5632 ;;                                             wl-summary-buffer-new-count)
5633 ;;                                          sum))
5634 ;;      (message "Dropping...done"))))
5635
5636 (defun wl-summary-default-get-next-msg (msg)
5637   (or (wl-summary-next-message msg
5638                                (if wl-summary-move-direction-downward 'down
5639                                  'up)
5640                                nil)
5641       (cadr (memq msg (if wl-summary-move-direction-downward
5642                           wl-summary-buffer-number-list
5643                         (reverse wl-summary-buffer-number-list))))))
5644
5645 (defun wl-summary-save-current-message ()
5646   "Save current message for `wl-summary-yank-saved-message'."
5647   (interactive)
5648   (let ((number (wl-summary-message-number)))
5649     (setq wl-summary-buffer-saved-message number)
5650     (and number (message "No: %s is saved." number))))
5651
5652 (defun wl-summary-yank-saved-message ()
5653   "Set current message as a parent of the saved message."
5654   (interactive)
5655   (if wl-summary-buffer-saved-message
5656       (let ((number (wl-summary-message-number)))
5657         (if (eq wl-summary-buffer-saved-message number)
5658             (message "Cannot set itself as a parent.")
5659           (save-excursion
5660             (wl-thread-jump-to-msg wl-summary-buffer-saved-message)
5661             (wl-thread-set-parent number)
5662             (wl-summary-set-thread-modified))
5663           (setq  wl-summary-buffer-saved-message nil)))
5664     (message "There's no saved message.")))
5665
5666 (require 'product)
5667 (product-provide (provide 'wl-summary) (require 'wl-version))
5668
5669 ;;; wl-summary.el ends here