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