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