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