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