Merged beta branch.
[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..."
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 t)
2221         (message "Deleting...done."))
2222       ;;(set-buffer cur-buf)
2223       ;; Change "New" marks to "Uncached Unread" marks.
2224       (wl-summary-set-status-marks mark-alist
2225                                    wl-summary-new-mark
2226                                    wl-summary-unread-uncached-mark)
2227       (wl-summary-set-status-marks-on-buffer
2228        wl-summary-new-mark
2229        wl-summary-unread-uncached-mark)
2230       ;; Confirm appended message number.
2231       (setq append-list (wl-summary-confirm-appends initial-append-list))
2232       (when (and elmo-use-killed-list
2233                  (not (eq (length initial-append-list)
2234                           (length append-list)))
2235                  (setq diff (elmo-list-diff initial-append-list append-list)))
2236         (elmo-msgdb-append-to-killed-list folder (car diff)))
2237       (setq num (length append-list))
2238       (if append-list
2239           (progn
2240             (setq i 0)
2241             (setq result (elmo-msgdb-create
2242                           folder
2243                           append-list
2244                           wl-summary-new-mark
2245                           wl-summary-unread-cached-mark ; !
2246                           wl-summary-read-uncached-mark ; u ;; XXXX
2247                           wl-summary-important-mark
2248                           seen-list))
2249             ;; delete duplicated messages.
2250             (when (elmo-folder-contains-multi folder)
2251               (setq crossed (elmo-multi-delete-crossposts
2252                              msgdb result))
2253               (setq result (cdr crossed))
2254               (setq crossed (car crossed)))
2255             (setq overview-append (car result))
2256             (setq msgdb (elmo-msgdb-append msgdb result t))
2257             ;; set these value for append-message-func
2258             (setq overview (elmo-msgdb-get-overview msgdb))
2259             (setq number-alist (elmo-msgdb-get-number-alist msgdb))
2260             (setq mark-alist (elmo-msgdb-get-mark-alist msgdb))
2261             ;; (setq location (elmo-msgdb-get-location msgdb))
2262             (setq curp overview-append)
2263             (setq num (length curp))
2264             (setq wl-summary-delayed-update nil)
2265             (elmo-kill-buffer wl-summary-search-buf-name)
2266             (while curp
2267               (setq entity (car curp))
2268               (when (setq update-thread
2269                           (wl-summary-append-message-func-internal
2270                            entity overview mark-alist
2271                            (not sync-all)))
2272                 (wl-append update-top-list update-thread))
2273               (if elmo-use-database
2274                   (elmo-database-msgid-put
2275                    (car entity) folder
2276                    (elmo-msgdb-overview-entity-get-number entity)))
2277               (setq curp (cdr curp))
2278               (when (> num elmo-display-progress-threshold)
2279                 (setq i (+ i 1))
2280                 (if (or (zerop (% i 5)) (= i num))
2281                     (elmo-display-progress
2282                      'wl-summary-sync-update3 "Updating thread..."
2283                      (/ (* i 100) num)))))
2284             (when wl-summary-delayed-update
2285               (while wl-summary-delayed-update
2286                 (message "Parent (%d) of message %d is no entity"
2287                          (caar wl-summary-delayed-update)
2288                          (elmo-msgdb-overview-entity-get-number
2289                           (cdar wl-summary-delayed-update)))
2290                 (when (setq update-thread
2291                             (wl-summary-append-message-func-internal
2292                              (cdar wl-summary-delayed-update)
2293                              overview mark-alist (not sync-all) t))
2294                   (wl-append update-top-list update-thread))
2295                 (setq wl-summary-delayed-update
2296                       (cdr wl-summary-delayed-update))))
2297             (when (and (eq wl-summary-buffer-view 'thread)
2298                        update-top-list)
2299               (wl-thread-update-indent-string-thread
2300                (elmo-uniq-list update-top-list)))
2301             (message "Updating thread...done.")
2302             ;;(set-buffer cur-buf)
2303             ))
2304       (wl-summary-set-message-modified)
2305       (wl-summary-set-mark-modified)
2306       (setq wl-summary-buffer-msgdb msgdb)
2307       (when (and sync-all (eq wl-summary-buffer-view 'thread))
2308         (elmo-kill-buffer wl-summary-search-buf-name)
2309         (message "Inserting thread...")
2310         (setq wl-thread-entity-cur 0)
2311         (wl-thread-insert-top)
2312         (message "Inserting thread...done."))
2313       (if elmo-use-database
2314           (elmo-database-close))
2315       (run-hooks 'wl-summary-sync-updated-hook)
2316       (setq ret-val (format "Updated (-%d/+%d) message(s)"
2317                             (length delete-list) num)))
2318     ;; synchronize marks.
2319     (if wl-summary-auto-sync-marks
2320         (wl-summary-sync-marks))
2321     ;; scoring
2322     (when wl-use-scoring
2323       (setq wl-summary-scored nil)
2324       (wl-summary-score-headers nil msgdb
2325                                 (and sync-all
2326                                      (wl-summary-rescore-msgs number-alist))
2327                                 sync-all)
2328       (when (and wl-summary-scored
2329                  (setq expunged (wl-summary-score-update-all-lines)))
2330         (setq ret-val (concat ret-val
2331                               (format " (%d expunged)"
2332                                       (length expunged))))))
2333     ;; crosspost
2334     (setq crossed2 (wl-summary-update-crosspost))
2335     (if (or crossed crossed2)
2336         (let ((crosses (+ (or crossed 0)
2337                           (or crossed2 0))))
2338           (setq ret-val
2339                 (if ret-val
2340                     (concat ret-val
2341                             (format " (%d crosspost)" crosses))
2342                   (format "%d crosspost message(s)" crosses))))
2343       (and ret-val
2344            (setq ret-val (concat ret-val "."))))
2345     ;; Update Folder mode
2346     (wl-folder-set-folder-updated folder (list 0
2347                                                (wl-summary-count-unread
2348                                                 (elmo-msgdb-get-mark-alist
2349                                                  msgdb))
2350                                                (length in-folder)))
2351     (wl-summary-update-modeline)
2352     (wl-summary-buffer-number-column-detect t)
2353     ;;
2354     (unless unset-cursor
2355       (goto-char (point-min))
2356       (if (not (wl-summary-cursor-down t))
2357           (progn
2358             (goto-char (point-max))
2359             (forward-line -1))
2360         (if (and wl-summary-highlight
2361                  (not (get-text-property (point) 'face)))
2362             (save-excursion
2363               (forward-line (- 0
2364                                (or
2365                                 wl-summary-partial-highlight-above-lines
2366                                 wl-summary-highlight-partial-threshold)))
2367               (wl-highlight-summary (point) (point-max))))))
2368     (wl-delete-all-overlays)
2369     (set-buffer-modified-p nil)
2370     ret-val))
2371
2372 (defun wl-summary-set-score-mark (mark)
2373   (save-excursion
2374     (beginning-of-line)
2375     (let ((inhibit-read-only t)
2376           (buffer-read-only nil)
2377           msg-num
2378           cur-mark)
2379       (when (looking-at "^ *\\([0-9]+\\)\\([^0-9]\\)")
2380         (setq msg-num  (string-to-int (wl-match-buffer 1)))
2381         (setq cur-mark (wl-match-buffer 2))
2382         (when (member cur-mark (list " "
2383                                      wl-summary-score-below-mark
2384                                      wl-summary-score-over-mark))
2385           (goto-char (match-end 1))
2386           (delete-region (match-beginning 2) (match-end 2))
2387           (insert mark)
2388           (if wl-summary-highlight
2389               (wl-highlight-summary-current-line nil nil t))
2390           (set-buffer-modified-p nil))))))
2391
2392 (defun wl-summary-get-score-mark (msg-num)
2393   (let ((score (cdr (assq msg-num wl-summary-scored))))
2394     (if score
2395         (cond ((< score wl-summary-default-score)
2396                "-")
2397               ((> score wl-summary-default-score)
2398                "+")))))
2399
2400 (defun wl-summary-update-modeline ()
2401   (setq wl-summary-buffer-unread-status
2402         (format " {%s}(%d new/%d unread)"
2403                 (if (eq wl-summary-buffer-view 'thread)
2404                     "T" "S")
2405                 wl-summary-buffer-new-count
2406                 (+ wl-summary-buffer-new-count
2407                    wl-summary-buffer-unread-count))))
2408
2409 (defsubst wl-summary-jump-to-msg (&optional number)
2410   (interactive)
2411   (let ((num (or number
2412                  (string-to-int
2413                   (read-from-minibuffer "Jump to Message(No.): ")))))
2414     (setq num (int-to-string num))
2415     (if (re-search-forward (concat "^[ \t]*" num "[^0-9]") nil t)
2416         (progn
2417           (beginning-of-line)
2418           t)
2419       (if (re-search-backward (concat "^[ \t]*" num "[^0-9]") nil t)
2420           (progn
2421             (beginning-of-line)
2422             t)
2423         nil))))
2424
2425 (defun wl-summary-highlight-msgs (msgs)
2426   (save-excursion
2427     (let ((len (length msgs))
2428           i)
2429       (message "Hilighting...")
2430       (setq i 0)
2431       (while msgs
2432         (if (wl-summary-jump-to-msg (car msgs))
2433             (wl-highlight-summary-current-line))
2434         (setq msgs (cdr msgs))
2435         (when (> len elmo-display-progress-threshold)
2436           (setq i (+ i 1))
2437           (if (or (zerop (% i 5)) (= i len))
2438               (elmo-display-progress
2439                'wl-summary-highlight-msgs "Highlighting..."
2440                (/ (* i 100) len)))))
2441       (message "Highlighting...done."))))
2442
2443 (defun wl-summary-message-number ()
2444   (save-excursion
2445     (beginning-of-line)
2446     (if (looking-at "^ *\\([0-9]+\\)")
2447         (string-to-int (wl-match-buffer 1))
2448       nil)))
2449
2450 (defun wl-summary-move (src dsts-msgs)
2451   (let* ((dsts (car dsts-msgs))         ; (+foo +bar)
2452 ;;       (msgs (cdr dsts-msgs))         ; (1 2 3)
2453 ;;       (msgdb wl-summary-buffer-msgdb)
2454 ;;       result)
2455          )
2456     (while dsts
2457       (setq dsts (cdr dsts)))))
2458
2459 (defun wl-summary-flush-pending-append-operations (&optional seen-list)
2460   "Execute append operations that are done while offline status."
2461   (when (and (elmo-folder-plugged-p wl-summary-buffer-folder-name)
2462              elmo-enable-disconnected-operation)
2463     (let* ((resumed-list (elmo-dop-append-list-load
2464                           wl-summary-buffer-folder-name t))
2465            (append-list (elmo-dop-append-list-load
2466                          wl-summary-buffer-folder-name))
2467            (appends (append resumed-list append-list))
2468            (number-alist (elmo-msgdb-get-number-alist wl-summary-buffer-msgdb))
2469            dels pair)
2470       (when appends
2471         (while appends
2472           (if (setq pair (rassoc (car appends) number-alist))
2473               (setq dels (append dels (list (car pair)))))
2474           (setq appends (cdr appends)))
2475         (when dels
2476           (setq seen-list
2477                 (elmo-msgdb-add-msgs-to-seen-list-subr
2478                  dels
2479                  wl-summary-buffer-msgdb
2480                  (concat wl-summary-important-mark
2481                          wl-summary-read-uncached-mark)
2482                  seen-list))
2483           (message "Resuming summary status...")
2484           (elmo-msgdb-delete-msgs wl-summary-buffer-folder-name
2485                                   dels wl-summary-buffer-msgdb t)
2486           (wl-summary-delete-messages-on-buffer dels)
2487           (message "Resuming summary status...done."))
2488         ;; delete resume-file
2489         (elmo-dop-append-list-save wl-summary-buffer-folder-name nil t)
2490         (when append-list
2491           (elmo-dop-flush-pending-append-operations
2492            wl-summary-buffer-folder-name append-list)))))
2493   seen-list)
2494
2495 (defun wl-summary-delete-all-msgs ()
2496   (interactive)
2497   (let ((cur-buf (current-buffer))
2498         (dels (elmo-list-folder wl-summary-buffer-folder-name)))
2499     (set-buffer cur-buf)
2500     (if (null dels)
2501         (message "No message to delete.")
2502       (if (y-or-n-p (format "%s has %d message(s). Delete all?"
2503                             wl-summary-buffer-folder-name
2504                             (length dels)))
2505           (progn
2506             (message "Deleting...")
2507             (elmo-delete-msgs wl-summary-buffer-folder-name dels
2508                               wl-summary-buffer-msgdb)
2509             (elmo-msgdb-delete-msgs wl-summary-buffer-folder-name
2510                                     dels wl-summary-buffer-msgdb)
2511             ;;(elmo-msgdb-save wl-summary-buffer-folder-name nil)
2512             (wl-summary-set-message-modified)
2513             (wl-summary-set-mark-modified)
2514             (wl-folder-set-folder-updated wl-summary-buffer-folder-name
2515                                           (list 0 0 0))
2516             ;; for thread.
2517             ;; (setq wl-thread-top-entity '(nil t nil nil))
2518             (setq wl-summary-buffer-unread-count 0)
2519             (setq wl-summary-buffer-new-count    0)
2520             (wl-summary-update-modeline)
2521             (set-buffer cur-buf)
2522             (let ((inhibit-read-only t)
2523                   (buffer-read-only nil))
2524               (erase-buffer))
2525             ;;    (if wl-summary-cache-use (wl-summary-save-view-cache))
2526             (message "Deleting...done.")
2527             t)
2528         nil))))
2529
2530 (defun wl-summary-toggle-thread (&optional arg)
2531   "Toggle thread status (T)hread and (S)equencial."
2532   (interactive "P")
2533   (when (or arg
2534             (y-or-n-p (format "Toggle threading? (y=%s): "
2535                               (if (eq wl-summary-buffer-view 'thread)
2536                                   "\"off\"" "\"on\""))))
2537     (if (eq wl-summary-buffer-view 'thread)
2538         (setq wl-summary-buffer-view 'sequence)
2539       (setq wl-summary-buffer-view 'thread))
2540     (wl-summary-update-modeline)
2541     (force-mode-line-update)
2542     (wl-summary-rescan)))
2543
2544 (defun wl-summary-load-file-object (filename)
2545   "Load lisp object from dir."
2546   (save-excursion
2547     (let ((tmp-buffer (get-buffer-create " *wl-summary-load-file-object*"))
2548           insert-file-contents-pre-hook   ; To avoid autoconv-xmas...
2549           insert-file-contents-post-hook
2550           ret-val)
2551       (if (not (file-readable-p filename))
2552           ()
2553         (set-buffer tmp-buffer)
2554         (as-binary-input-file (insert-file-contents filename))
2555         (setq ret-val
2556               (condition-case nil
2557                   (read (current-buffer))
2558                 (error (error "reading failed")))))
2559       (kill-buffer tmp-buffer)
2560       ret-val)))
2561
2562 (defun wl-summary-goto-folder (&optional arg)
2563   (interactive "P")
2564   (wl-summary-goto-folder-subr nil nil nil arg t))
2565
2566 (defun wl-summary-goto-last-visited-folder ()
2567   (interactive)
2568   (let ((entity
2569          (wl-folder-search-entity-by-name wl-summary-last-visited-folder
2570                                           wl-folder-entity
2571                                           'folder)))
2572     (if entity (wl-folder-set-current-entity-id
2573                 (wl-folder-get-entity-id entity))))
2574   (wl-summary-goto-folder-subr wl-summary-last-visited-folder nil nil nil t))
2575
2576 (defun wl-summary-sticky-p (&optional fld)
2577   (if fld
2578       (get-buffer (wl-summary-sticky-buffer-name fld))
2579     (not (string= wl-summary-buffer-name (buffer-name)))))
2580
2581 (defun wl-summary-always-sticky-folder-p (fld)
2582   (or (eq t wl-summary-always-sticky-folder-list)
2583       (wl-string-match-member fld wl-summary-always-sticky-folder-list)))
2584
2585 (defun wl-summary-stick (&optional force)
2586   "Make current summary buffer sticky."
2587   (interactive "P")
2588   (if (wl-summary-sticky-p)
2589       (message "Current summary buffer is already sticky.")
2590     (when (or force (y-or-n-p "Stick current summary buffer?"))
2591       (wl-summary-toggle-disp-msg 'off)
2592       (wl-summary-switch-to-clone-buffer
2593        (wl-summary-sticky-buffer-name
2594         wl-summary-buffer-folder-name))
2595 ;;; ???hang up
2596 ;      (rename-buffer (wl-summary-sticky-buffer-name
2597 ;                     wl-summary-buffer-folder-name)))
2598       (message "Folder `%s' is now sticky." wl-summary-buffer-folder-name))))
2599
2600 (defun wl-summary-switch-to-clone-buffer (buffer-name)
2601   (let ((cur-buf (current-buffer))
2602         (msg (wl-summary-message-number))
2603         (buf (get-buffer-create buffer-name))
2604         (folder wl-summary-buffer-folder-name)
2605         (copy-variables
2606          (append '(wl-summary-buffer-view
2607                    wl-summary-buffer-refile-list
2608                    wl-summary-buffer-delete-list
2609                    wl-summary-buffer-copy-list
2610                    wl-summary-buffer-target-mark-list
2611                    wl-summary-buffer-msgdb
2612                    wl-summary-buffer-number-column
2613                    wl-summary-buffer-number-regexp
2614                    wl-summary-buffer-message-modified
2615                    wl-summary-buffer-mark-modified
2616                    wl-summary-buffer-thread-modified)
2617                  (and (eq wl-summary-buffer-view 'thread)
2618                       '(wl-thread-entity-hashtb
2619                         wl-thread-entities
2620                         wl-thread-entity-list))
2621                  (and wl-use-scoring
2622                       '(wl-summary-scored
2623                         wl-summary-default-score
2624                         wl-summary-important-above
2625                         wl-summary-temp-above
2626                         wl-summary-mark-below
2627                         wl-summary-expunge-below))
2628                  (and (featurep 'wl-score)
2629                       '(wl-current-score-file
2630                         wl-score-alist)))))
2631     (set-buffer buf)
2632     (wl-summary-mode)
2633     (wl-summary-buffer-set-folder folder)
2634     (let ((buffer-read-only nil))
2635       (insert-buffer cur-buf))
2636     (set-buffer-modified-p nil)
2637     (while copy-variables
2638       (set (car copy-variables)
2639            (save-excursion
2640              (set-buffer cur-buf)
2641              (symbol-value (car copy-variables))))
2642       (setq copy-variables (cdr copy-variables)))
2643     (switch-to-buffer buf)
2644     (kill-buffer cur-buf)
2645     (wl-summary-count-unread
2646      (elmo-msgdb-get-mark-alist wl-summary-buffer-msgdb))
2647     (wl-summary-update-modeline)
2648     (if msg
2649         (if (eq wl-summary-buffer-view 'thread)
2650             (wl-thread-jump-to-msg msg)
2651           (wl-summary-jump-to-msg msg))
2652       (goto-char (point-max))
2653       (beginning-of-line))))
2654
2655 (defun wl-summary-get-buffer (folder)
2656   (or (and folder
2657            (get-buffer (wl-summary-sticky-buffer-name folder)))
2658       (get-buffer wl-summary-buffer-name)))
2659
2660 (defun wl-summary-get-buffer-create (folder &optional force-sticky)
2661   (if force-sticky
2662       (get-buffer-create
2663        (wl-summary-sticky-buffer-name folder))
2664     (or (get-buffer (wl-summary-sticky-buffer-name folder))
2665         (get-buffer-create wl-summary-buffer-name))))
2666
2667 (defun wl-summary-disp-msg (folder disp-msg)
2668   (let (disp mes-win)
2669     (if (and disp-msg
2670              wl-summary-buffer-disp-msg)
2671         (let ((view-message-buffer (get-buffer wl-message-buf-name))
2672               (number (wl-summary-message-number))
2673               cur-folder cur-number sel-win)
2674           (when view-message-buffer
2675             (save-excursion
2676               (set-buffer view-message-buffer)
2677               (setq cur-folder wl-message-buffer-cur-folder
2678                     cur-number wl-message-buffer-cur-number))
2679             (when (and (string= folder cur-folder)
2680                        (eq number cur-number))
2681               (setq sel-win (selected-window))
2682               (wl-select-buffer view-message-buffer)
2683               (select-window sel-win)
2684               (setq disp t)))))
2685     (if (not disp)
2686         (setq wl-summary-buffer-disp-msg nil))
2687     (when (and (not disp)
2688                (setq mes-win (wl-message-buffer-window)))
2689       (delete-window mes-win)
2690       (run-hooks 'wl-summary-toggle-disp-off-hook))))
2691
2692 (defun wl-summary-goto-folder-subr (&optional folder scan-type other-window
2693                                               sticky interactive scoring)
2694   "Display target folder on summary"
2695   (interactive)
2696   (let* ((keep-cursor (memq this-command
2697                             wl-summary-keep-cursor-command))
2698          (fld (or folder (wl-summary-read-folder wl-default-folder)))
2699          (cur-fld wl-summary-buffer-folder-name)
2700          buf mes hilit reuse-buf
2701          retval entity)
2702     (if (string= fld "")
2703         (setq fld wl-default-folder))
2704     (when (and (not (string= cur-fld fld)) ; folder is moved.
2705                (eq major-mode 'wl-summary-mode)) ; called in summary.
2706       (setq wl-summary-last-visited-folder wl-summary-buffer-folder-name)
2707       (wl-summary-cleanup-temp-marks (wl-summary-sticky-p))
2708       (wl-summary-save-status 'keep)) ;; keep current buffer, anyway.
2709     (setq buf (wl-summary-get-buffer-create fld sticky))
2710     (setq reuse-buf
2711           (save-excursion
2712             (set-buffer buf)
2713             (string= fld wl-summary-buffer-folder-name)))
2714     (unwind-protect
2715         (if reuse-buf
2716             (if interactive
2717                 (switch-to-buffer buf)
2718               (set-buffer buf))
2719           (if other-window
2720               (delete-other-windows))
2721           (set-buffer buf)
2722           (unless (eq major-mode 'wl-summary-mode)
2723             (wl-summary-mode))
2724           (wl-summary-buffer-set-folder fld)
2725           (setq wl-summary-buffer-disp-msg nil)
2726           (setq wl-summary-buffer-last-displayed-msg nil)
2727           (setq wl-summary-buffer-current-msg nil)
2728           (let ((case-fold-search nil)
2729                 (inhibit-read-only t)
2730                 (buffer-read-only nil))
2731             (erase-buffer)
2732             ;; resume summary cache
2733             (if wl-summary-cache-use
2734                 (let* ((dir (elmo-msgdb-expand-path fld))
2735                        (cache (expand-file-name wl-summary-cache-file dir))
2736                        (view (expand-file-name wl-summary-view-file dir)))
2737                   (when (file-exists-p cache)
2738                     (as-binary-input-file
2739                      (insert-file-contents cache))
2740                     (elmo-set-buffer-multibyte
2741                      default-enable-multibyte-characters)
2742                     (decode-mime-charset-region
2743                      (point-min)(point-max)
2744                      wl-summary-buffer-mime-charset))
2745                   (when (file-exists-p view)
2746                     (setq wl-summary-buffer-view
2747                           (wl-summary-load-file-object view)))
2748                   (if (eq wl-summary-buffer-view 'thread)
2749                       (wl-thread-resume-entity fld))))
2750             ;; Load msgdb
2751             (setq wl-summary-buffer-msgdb nil) ; new msgdb
2752             (setq wl-summary-buffer-msgdb
2753                   (wl-summary-msgdb-load-async fld))
2754             (if (null wl-summary-buffer-msgdb)
2755                 (setq wl-summary-buffer-msgdb
2756                       (elmo-msgdb-load (elmo-string fld))))
2757             (wl-summary-count-unread
2758              (elmo-msgdb-get-mark-alist wl-summary-buffer-msgdb))
2759             (wl-summary-update-modeline)))
2760       (wl-summary-buffer-number-column-detect t)
2761       (wl-summary-disp-msg fld (and reuse-buf keep-cursor))
2762       (unless (and reuse-buf keep-cursor)
2763         (setq hilit wl-summary-highlight)
2764         (unwind-protect
2765             (let ((wl-summary-highlight (if reuse-buf wl-summary-highlight))
2766                   (wl-use-scoring
2767                    (if (or scoring interactive) wl-use-scoring)))
2768               (if (and (not scan-type)
2769                        interactive
2770                        (not wl-ask-range))
2771                   (setq scan-type (wl-summary-get-sync-range fld)))
2772               (cond
2773                ((eq scan-type nil)
2774                 (wl-summary-sync 'unset-cursor))
2775                ((eq scan-type 'all)
2776                 (wl-summary-sync 'unset-cursor "all"))
2777                ((eq scan-type 'no-sync))
2778                ((or (eq scan-type 'force-update)
2779                     (eq scan-type 'update))
2780                 (setq mes (wl-summary-sync-force-update 'unset-cursor)))))
2781           (if interactive
2782               (switch-to-buffer buf)
2783             (set-buffer buf))
2784           ;; stick always-sticky-folder
2785           (when (wl-summary-always-sticky-folder-p fld)
2786             (or (wl-summary-sticky-p) (wl-summary-stick t)))
2787           (run-hooks 'wl-summary-prepared-pre-hook)
2788           (set-buffer-modified-p nil)
2789           (goto-char (point-min))
2790           (if (wl-summary-cursor-down t)
2791               (let ((unreadp (wl-thread-next-mark-p
2792                               (wl-thread-entity-get-mark
2793                                (wl-summary-message-number))
2794                               wl-summary-move-order)))
2795                 (cond ((and wl-auto-select-first unreadp)
2796                        (setq retval 'disp-msg))
2797                       ((not unreadp)
2798                        (setq retval 'more-next))))
2799             (goto-char (point-max))
2800             (if (elmo-folder-plugged-p folder)
2801                 (forward-line -1)
2802               (wl-summary-prev))
2803             (setq retval 'more-next))
2804           (setq wl-summary-highlight hilit)
2805           (if (and wl-summary-highlight
2806                    (not reuse-buf))
2807               (if (and wl-summary-highlight-partial-threshold
2808                        (> (count-lines (point-min) (point-max))
2809                           wl-summary-highlight-partial-threshold))
2810                   (save-excursion
2811                     (forward-line (-
2812                                    0
2813                                    (or
2814                                     wl-summary-partial-highlight-above-lines
2815                                     wl-summary-highlight-partial-threshold)))
2816                     (wl-highlight-summary (point) (point-max)))
2817                 (wl-highlight-summary (point-min) (point-max))))
2818           (if (null wl-summary-buffer-msgdb) ;; one more try.
2819               (setq wl-summary-buffer-msgdb
2820                     (elmo-msgdb-load (elmo-string fld))))
2821           (if (eq retval 'disp-msg)
2822               (wl-summary-redisplay))
2823           (if mes (message "%s" mes))
2824           (if (and interactive wl-summary-recenter)
2825               (recenter (/ (- (window-height) 2) 2))))))
2826     ;; set current entity-id
2827     (if (and (not folder)
2828              (setq entity
2829                    (wl-folder-search-entity-by-name fld
2830                                                     wl-folder-entity
2831                                                     'folder)))
2832         ;; entity-id is unknown.
2833         (wl-folder-set-current-entity-id
2834          (wl-folder-get-entity-id entity)))
2835     (unwind-protect
2836         (run-hooks 'wl-summary-prepared-hook)
2837       (set-buffer-modified-p nil))
2838     retval))
2839
2840 (defun wl-summary-summary-line-already-exists-p (parent-number buffer)
2841   "returns the depth."
2842   (set-buffer buffer)
2843   (goto-char (point-max))
2844   (let ((depth 0))
2845     (when (re-search-backward (format "^ *%s..../..\(.*\)..:.. "
2846                                       parent-number) nil t)
2847       (goto-char (match-end 0))
2848       (while (string-match wl-thread-indent-regexp
2849                            (char-to-string
2850                             (char-after (point))))
2851         (setq depth (+ 1 depth))
2852         (forward-char))
2853       (/ depth wl-thread-indent-level-internal))))
2854
2855 (defun wl-summary-goto-bottom-of-current-thread ()
2856   (if (re-search-forward (concat "^" wl-summary-buffer-number-regexp
2857                                  "..../..\(.*\)..:.. [[<]") nil t)
2858       ()
2859     (goto-char (point-max))))
2860
2861 (defun wl-summary-goto-top-of-current-thread ()
2862   (wl-summary-jump-to-msg
2863    (wl-thread-entity-get-number
2864     (wl-thread-entity-get-top-entity (wl-thread-get-entity
2865                                       (wl-summary-message-number))))))
2866
2867 (defun wl-summary-goto-bottom-of-sub-thread (&optional depth)
2868   (interactive)
2869   (let ((depth (or depth
2870                    (wl-thread-get-depth-of-current-line))))
2871     (forward-line 1)
2872     (while (and (not (eobp))
2873                 (>= (wl-thread-get-depth-of-current-line)
2874                     depth))
2875       (forward-line 1))
2876     (beginning-of-line)))
2877
2878 (defun wl-summary-insert-line (line)
2879   "Insert LINE in the Summary."
2880   (if wl-use-highlight-mouse-line
2881       ;; remove 'mouse-face of current line.
2882       (put-text-property
2883        (save-excursion (beginning-of-line)(point))
2884        (save-excursion (end-of-line)(point))
2885        'mouse-face nil))
2886   (insert line "\n")
2887   (if wl-use-highlight-mouse-line
2888       ;; remove 'mouse-face of current line.
2889       (put-text-property
2890        (save-excursion (beginning-of-line)(point))
2891        (save-excursion (end-of-line)(point))
2892        'mouse-face nil))
2893   (condition-case nil ; it's dangerous, so ignore error.
2894       (run-hooks 'wl-summary-line-inserted-hook)
2895     (error (ding)
2896            (message "Error in wl-summary-line-inserted-hook"))))
2897
2898 (defun wl-summary-insert-summary (entity database mark-alist dummy &optional dummy)
2899   (let ((overview-entity entity)
2900         summary-line msg)
2901     (setq msg (elmo-msgdb-overview-entity-get-number entity))
2902     (when (setq summary-line
2903                 (wl-summary-overview-create-summary-line
2904                  msg entity nil 0 mark-alist))
2905       (let ((inhibit-read-only t)
2906             buffer-read-only)
2907         (goto-char (point-max))
2908         (wl-summary-insert-line summary-line)))))
2909
2910 (defun wl-summary-default-subject-filter (subject)
2911   (let ((case-fold-search t))
2912     (setq subject (elmo-replace-in-string subject "[ \t]*\\(re\\|was\\):" ""))
2913     (setq subject (elmo-replace-in-string subject "[ \t]" ""))
2914     (elmo-replace-in-string subject "^\\[.*\\]" "")))
2915
2916 (defun wl-summary-subject-equal (subject1 subject2)
2917   (string= (wl-summary-subject-filter-func-internal subject1)
2918            (wl-summary-subject-filter-func-internal subject2)))
2919
2920 (defmacro wl-summary-put-alike (alike)
2921   (` (elmo-set-hash-val (format "#%d" (wl-count-lines))
2922                         (, alike)
2923                         wl-summary-alike-hashtb)))
2924
2925 (defmacro wl-summary-get-alike ()
2926   (` (elmo-get-hash-val (format "#%d" (wl-count-lines))
2927                         wl-summary-alike-hashtb)))
2928
2929 (defun wl-summary-insert-headers (overview func mime-decode)
2930   (let (ov this last alike)
2931     (buffer-disable-undo (current-buffer))
2932     (make-local-variable 'wl-summary-alike-hashtb)
2933     (setq wl-summary-alike-hashtb (elmo-make-hash (* (length overview) 2)))
2934     (when mime-decode
2935       (elmo-set-buffer-multibyte default-enable-multibyte-characters))
2936     (while (setq ov (pop overview))
2937       (setq this (funcall func ov))
2938       (and this (setq this (std11-unfold-string this)))
2939       (if (equal last this)
2940           (wl-append alike (list ov))
2941         (when last
2942           (wl-summary-put-alike alike)
2943           (insert last ?\n))
2944         (setq alike (list ov)
2945               last this)))
2946     (when last
2947       (wl-summary-put-alike alike)
2948       (insert last ?\n))
2949     (when mime-decode
2950       (decode-mime-charset-region (point-min) (point-max)
2951                                   elmo-mime-charset)
2952       (when (eq mime-decode 'mime)
2953         (eword-decode-region (point-min) (point-max))))
2954     (run-hooks 'wl-summary-insert-headers-hook)))
2955
2956 (defun wl-summary-search-by-subject (entity overview)
2957   (let ((buf (get-buffer-create wl-summary-search-buf-name))
2958         (folder-name wl-summary-buffer-folder-name)
2959         match founds found-entity)
2960     (save-excursion
2961       (set-buffer buf)
2962       (let ((case-fold-search t))
2963         (when (or (not (string= wl-summary-buffer-folder-name folder-name))
2964                   (zerop (buffer-size)))
2965           (setq wl-summary-buffer-folder-name folder-name)
2966           (wl-summary-insert-headers
2967            overview
2968            (function
2969             (lambda (x)
2970               (wl-summary-subject-filter-func-internal
2971                (elmo-msgdb-overview-entity-get-subject-no-decode x))))
2972            t))
2973         (setq match (wl-summary-subject-filter-func-internal
2974                      (elmo-msgdb-overview-entity-get-subject entity)))
2975         (if (string= match "")
2976             (setq match "\n"))
2977         (goto-char (point-max))
2978         (while (and (not founds)
2979                     (not (= (point) (point-min)))
2980                     (search-backward match nil t))
2981           ;; check exactly match
2982           (when (and (bolp)
2983                      (= (point-at-eol)
2984                         (match-end 0)))
2985             (setq found-entity (wl-summary-get-alike))
2986             (if (and found-entity
2987                      ;; Is founded entity myself or children?
2988                      (not (string=
2989                            (elmo-msgdb-overview-entity-get-id entity)
2990                            (elmo-msgdb-overview-entity-get-id (car found-entity))))
2991                      (not (wl-thread-descendant-p
2992                            (elmo-msgdb-overview-entity-get-number entity)
2993                            (elmo-msgdb-overview-entity-get-number (car found-entity)))))
2994                 ;; return matching entity
2995                 (setq founds found-entity))))
2996         (if founds
2997             (car founds))))))
2998
2999 (defun wl-summary-insert-thread-entity (entity overview mark-alist update
3000                                                &optional force-insert)
3001   (let (update-list entity-stack)
3002     (while entity
3003       (let* ((this-id (elmo-msgdb-overview-entity-get-id entity))
3004              (parent-entity
3005               (elmo-msgdb-overview-get-parent-entity entity overview));; temp
3006              ;;(parent-id (elmo-msgdb-overview-entity-get-id parent-entity))
3007              (parent-number (elmo-msgdb-overview-entity-get-number parent-entity))
3008              (case-fold-search t)
3009              msg overview2 cur-entity linked retval delayed-entity)
3010         (setq msg (elmo-msgdb-overview-entity-get-number entity))
3011         (if (and parent-number
3012                  (not (wl-thread-get-entity parent-number))
3013                  (not force-insert))
3014             ;; parent is exists in overview, but not exists in wl-thread-entities
3015             (progn
3016               (wl-append wl-summary-delayed-update
3017                          (list (cons parent-number entity)))
3018               (setq entity nil)) ;; exit loop
3019           ;; Search parent by subject.
3020           (when (and (null parent-number)
3021                      wl-summary-search-parent-by-subject-regexp
3022                      (string-match wl-summary-search-parent-by-subject-regexp
3023                                    (elmo-msgdb-overview-entity-get-subject entity)))
3024             (let ((found (wl-summary-search-by-subject entity overview)))
3025               (when (and found
3026                          (not (member found wl-summary-delayed-update)))
3027                 (setq parent-entity found)
3028                 (setq parent-number
3029                       (elmo-msgdb-overview-entity-get-number parent-entity))
3030                 (setq linked t))))
3031           ;; If subject is change, divide thread.
3032           (if (and parent-number
3033                    wl-summary-divide-thread-when-subject-changed
3034                    (not (wl-summary-subject-equal
3035                          (or (elmo-msgdb-overview-entity-get-subject
3036                               entity) "")
3037                          (or (elmo-msgdb-overview-entity-get-subject
3038                               parent-entity) ""))))
3039               (setq parent-number nil))
3040           ;;
3041           (setq retval
3042                 (wl-thread-insert-message entity overview mark-alist
3043                                           msg parent-number update linked))
3044           (and retval
3045                (wl-append update-list (list retval)))
3046           (setq entity nil) ; exit loop
3047           (while (setq delayed-entity (assq msg wl-summary-delayed-update))
3048             (setq wl-summary-delayed-update
3049                   (delete delayed-entity wl-summary-delayed-update))
3050             ;; update delayed message
3051             (wl-append entity-stack (list (cdr delayed-entity)))))
3052         (if (and (not entity)
3053                  entity-stack)
3054             (setq entity (pop entity-stack)))))
3055     update-list))
3056
3057 (defun wl-summary-update-thread (entity
3058                                  overview
3059                                  mark-alist
3060                                  thr-entity
3061                                  parent-entity)
3062   (let* ((depth 0)
3063          (this-id (elmo-msgdb-overview-entity-get-id entity))
3064          (overview-entity entity)
3065          (parent-id (elmo-msgdb-overview-entity-get-id parent-entity))
3066          (parent-number (elmo-msgdb-overview-entity-get-number parent-entity))
3067          summary-line msg subject-differ)
3068     (cond
3069      ((or (not parent-id)
3070           (string= this-id parent-id))
3071       (goto-char (point-max))
3072       (beginning-of-line))
3073      ;; parent already exists in buffer.
3074      ((setq depth (or (wl-summary-summary-line-already-exists-p
3075                        parent-number (current-buffer)) -1))
3076       (setq depth (+ 1 depth))
3077       (wl-thread-goto-bottom-of-sub-thread)))
3078     (if (and (setq msg (elmo-msgdb-overview-entity-get-number entity)))
3079         (if (setq summary-line
3080                   (wl-summary-overview-create-summary-line
3081                    msg entity parent-entity depth mark-alist
3082                    (wl-thread-maybe-get-children-num msg)
3083                    nil thr-entity))
3084             (let ((inhibit-read-only t)
3085                   (buffer-read-only nil))
3086               (wl-summary-insert-line summary-line))))))
3087
3088 (defun wl-summary-mark-as-unread (&optional number
3089                                             no-server-update
3090                                             no-modeline-update)
3091   (interactive)
3092   (save-excursion
3093     (let* (eol
3094           (inhibit-read-only t)
3095           (buffer-read-only nil)
3096           (folder wl-summary-buffer-folder-name)
3097           (msgdb wl-summary-buffer-msgdb)
3098           (mark-alist (elmo-msgdb-get-mark-alist msgdb))
3099           ;;(number-alist (elmo-msgdb-get-number-alist msgdb))
3100           new-mark visible mark)
3101       (if number
3102           (progn
3103             (setq visible (wl-summary-jump-to-msg number))
3104             (unless (setq mark (cadr (assq number mark-alist)))
3105               (setq mark " ")))
3106         ;; interactive
3107         (setq visible t))
3108       (when visible
3109         (if (null (wl-summary-message-number))
3110             (message "No message.")
3111           (end-of-line)
3112           (setq eol (point))
3113           (re-search-backward (concat "^" wl-summary-buffer-number-regexp
3114                                       "..../..")) ; set cursor line
3115           (beginning-of-line)))
3116       (if (or (and (not visible)
3117                    ;; already exists in msgdb.
3118                    (assq number (elmo-msgdb-get-number-alist msgdb)))
3119               (re-search-forward
3120                (format (concat "^ *\\("
3121                                (if number (int-to-string number)
3122                                  "[0-9]+")
3123                                "\\)[^0-9]\\(%s\\|%s\\)")
3124                        wl-summary-read-uncached-mark
3125                        " ") eol t))
3126           (progn
3127             (setq number (or number (string-to-int (wl-match-buffer 1))))
3128             (setq mark (or mark (elmo-match-buffer 2)))
3129             (save-match-data
3130               (setq new-mark (if (string= mark
3131                                           wl-summary-read-uncached-mark)
3132                                  wl-summary-unread-uncached-mark
3133                                (if (elmo-use-cache-p folder number)
3134                                    wl-summary-unread-mark
3135                                  wl-summary-unread-uncached-mark))))
3136             ;; server side mark
3137             (unless no-server-update
3138               (unless (elmo-mark-as-unread folder (list number)
3139                                            msgdb)
3140                 (error "Setting mark failed")))
3141             (when visible
3142               (delete-region (match-beginning 2) (match-end 2))
3143               (insert new-mark))
3144             (setq mark-alist
3145                   (elmo-msgdb-mark-set mark-alist
3146                                        number
3147                                        new-mark))
3148             (elmo-msgdb-set-mark-alist msgdb mark-alist)
3149             (unless no-modeline-update
3150               (setq wl-summary-buffer-unread-count
3151                     (+ 1 wl-summary-buffer-unread-count))
3152               (wl-summary-update-modeline)
3153               (wl-folder-update-unread
3154                folder
3155                (+ wl-summary-buffer-unread-count
3156                   wl-summary-buffer-new-count)))
3157             (wl-summary-set-mark-modified)
3158             (if (and visible wl-summary-highlight)
3159                 (wl-highlight-summary-current-line))))))
3160   (set-buffer-modified-p nil))
3161
3162 (defun wl-summary-delete (&optional number)
3163   "Mark Delete mark 'D'.
3164 If optional argument NUMBER is specified, mark message specified by NUMBER."
3165   (interactive)
3166   (let* ((buffer-num (wl-summary-message-number))
3167          (msg-num (or number buffer-num))
3168          mark)
3169     (catch 'done
3170       (when (null msg-num)
3171         (if (interactive-p)
3172             (message "No message."))
3173         (throw 'done nil))
3174       (when (setq mark (wl-summary-get-mark msg-num))
3175         (when (wl-summary-reserve-temp-mark-p mark)
3176           (if (interactive-p)
3177               (error "Already marked as `%s'" mark))
3178           (throw 'done nil))
3179         (wl-summary-unmark msg-num))
3180       (if (or (interactive-p)
3181               (eq number buffer-num))
3182           (wl-summary-mark-line "D"))
3183       (setq wl-summary-buffer-delete-list
3184             (cons msg-num wl-summary-buffer-delete-list))
3185       (if (interactive-p)
3186           (if (eq wl-summary-move-direction-downward nil)
3187               (wl-summary-prev)
3188             (wl-summary-next)))
3189       msg-num)))
3190
3191 (defun wl-summary-remove-destination ()
3192   (save-excursion
3193     (let ((inhibit-read-only t)
3194           (buffer-read-only nil)
3195           (buf (current-buffer))
3196           sol eol rs re)
3197       (beginning-of-line)
3198       (setq sol (point))
3199       (end-of-line)
3200       (setq eol (point))
3201       (setq rs (next-single-property-change sol 'wl-summary-destination
3202                                             buf eol))
3203       (setq re (next-single-property-change rs 'wl-summary-destination
3204                                             buf eol))
3205       (put-text-property rs re 'wl-summary-destination nil)
3206       (put-text-property rs re 'invisible nil)
3207       (goto-char re)
3208       (delete-char (- eol re)))))
3209
3210 (defun wl-summary-check-mark (msg mark)
3211   (let ((check-func (cond ((string= mark "o")
3212                            'wl-summary-msg-marked-as-refiled)
3213                           ((string= mark "O")
3214                            'wl-summary-msg-marked-as-copied)
3215                           ((string= mark "D")
3216                            'wl-summary-msg-marked-as-deleted)
3217                           ((string= mark "*")
3218                            'wl-summary-msg-marked-as-target))))
3219     (if check-func
3220         (funcall check-func msg))))
3221
3222 (defun wl-summary-mark-collect (mark &optional begin end)
3223   (save-excursion
3224     (save-restriction
3225       (let (msglist)
3226         (narrow-to-region (or begin (point-min))
3227                           (or end (point-max)))
3228         (goto-char (point-min))
3229         ;; for thread...
3230         (if (eq wl-summary-buffer-view 'thread)
3231             (progn
3232               (while (not (eobp))
3233                 (let* ((number (wl-summary-message-number))
3234                        (entity (wl-thread-get-entity number))
3235                        result)
3236                   ;; opened...only myself is checked.
3237                   (if (wl-summary-check-mark number mark)
3238                       (wl-append msglist (list number)))
3239                   (unless (wl-thread-entity-get-opened entity)
3240                     ;; closed...children is also checked.
3241                     (if (setq result (wl-thread-get-children-msgs-with-mark
3242                                       number
3243                                       mark))
3244                         (wl-append msglist result)))
3245                   (forward-line 1)))
3246               (elmo-uniq-list msglist))
3247           (let* ((case-fold-search nil)
3248                  (re (format (concat wl-summary-message-regexp "%s")
3249                              (regexp-quote mark))))
3250             (while (re-search-forward re nil t)
3251               (setq msglist (cons (wl-summary-message-number) msglist)))
3252             (nreverse msglist)))))))
3253
3254 (defun wl-summary-exec ()
3255   (interactive)
3256   (wl-summary-exec-subr (mapcar 'car wl-summary-buffer-refile-list)
3257                         (reverse wl-summary-buffer-delete-list)
3258                         (mapcar 'car wl-summary-buffer-copy-list)))
3259
3260 (defun wl-summary-exec-region (beg end)
3261   (interactive "r")
3262   (message "Collecting marks ...")
3263   (save-excursion
3264     (goto-char beg)
3265     (beginning-of-line)
3266     (setq beg (point))
3267     (goto-char (1- end))
3268     (forward-line)
3269     (setq end (point))
3270     (wl-summary-exec-subr (wl-summary-mark-collect "o" beg end)
3271                           (wl-summary-mark-collect "D" beg end)
3272                           (wl-summary-mark-collect "O" beg end))))
3273
3274 (defun wl-summary-exec-subr (moves dels copies)
3275   (if (not (or moves dels copies))
3276       (message "No marks")
3277     (save-excursion
3278       (let ((del-fld (wl-summary-get-delete-folder
3279                       wl-summary-buffer-folder-name))
3280             (start (point))
3281             (unread-marks (list wl-summary-unread-cached-mark
3282                                 wl-summary-unread-uncached-mark
3283                                 wl-summary-new-mark))
3284             (refiles (append moves dels))
3285             (refile-executed 0)
3286             (refile-failures 0)
3287             (copy-executed 0)
3288             (copy-failures 0)
3289             (copy-len (length copies))
3290             refile-len
3291             dst-msgs                    ; loop counter
3292             result)
3293         (message "Executing ...")
3294         (while dels
3295           (when (not (assq (car dels) wl-summary-buffer-refile-list))
3296             (wl-append wl-summary-buffer-refile-list
3297                        (list (cons (car dels) del-fld)))
3298             (setq wl-summary-buffer-delete-list
3299                   (delete (car dels) wl-summary-buffer-delete-list)))
3300           (setq dels (cdr dels)))
3301         ;; begin refile...
3302         (setq refile-len (length refiles))
3303         (setq dst-msgs
3304               (wl-inverse-alist refiles wl-summary-buffer-refile-list))
3305         (goto-char start)               ; avoid moving cursor to
3306                                         ; the bottom line.
3307         (while dst-msgs
3308           ;;(elmo-msgdb-add-msgs-to-seen-list
3309           ;; (car (car dst-msgs)) ;dst-folder
3310           ;; (cdr (car dst-msgs)) ;msgs
3311           ;; wl-summary-buffer-msgdb
3312           ;; (concat wl-summary-important-mark
3313           ;;  wl-summary-read-uncached-mark))
3314           (setq result nil)
3315           (condition-case nil
3316               (setq result (elmo-move-msgs wl-summary-buffer-folder-name
3317                                            (cdr (car dst-msgs))
3318                                            (car (car dst-msgs))
3319                                            wl-summary-buffer-msgdb
3320                                            refile-len
3321                                            refile-executed
3322                                            (not (null (cdr dst-msgs)))
3323                                            nil ; no-delete
3324                                            nil ; same-number
3325                                            unread-marks))
3326             (error nil))
3327           (if result                    ; succeeded.
3328               (progn
3329                 ;; update buffer.
3330                 (wl-summary-delete-messages-on-buffer (cdr (car dst-msgs)))
3331                 ;; update refile-alist.
3332                 (setq wl-summary-buffer-refile-list
3333                       (wl-delete-associations (cdr (car dst-msgs))
3334                                              wl-summary-buffer-refile-list)))
3335             (setq refile-failures
3336                   (+ refile-failures (length (cdr (car dst-msgs))))))
3337           (setq refile-executed (+ refile-executed (length (cdr (car dst-msgs)))))
3338           (setq dst-msgs (cdr dst-msgs)))
3339         ;; end refile
3340         ;; begin cOpy...
3341         (setq dst-msgs (wl-inverse-alist copies wl-summary-buffer-copy-list))
3342         (while dst-msgs
3343           ;;(elmo-msgdb-add-msgs-to-seen-list
3344           ;; (car (car dst-msgs)) ;dst-folder
3345           ;; (cdr (car dst-msgs)) ;msgs
3346           ;; wl-summary-buffer-msgdb
3347           ;; (concat wl-summary-important-mark
3348           ;;  wl-summary-read-uncached-mark))
3349           (setq result nil)
3350           (condition-case nil
3351               (setq result (elmo-move-msgs wl-summary-buffer-folder-name
3352                                            (cdr (car dst-msgs))
3353                                            (car (car dst-msgs))
3354                                            wl-summary-buffer-msgdb
3355                                            copy-len
3356                                            copy-executed
3357                                            (not (null (cdr dst-msgs)))
3358                                            t ; t is no-delete (copy)
3359                                            nil ; same number
3360                                            unread-marks))
3361             (error nil))
3362           (if result                    ; succeeded.
3363               (progn
3364                 ;; update buffer.
3365                 (wl-summary-delete-copy-marks-on-buffer (cdr (car dst-msgs)))
3366                 ;; update copy-alist
3367                 (setq wl-summary-buffer-copy-list
3368                       (wl-delete-associations (cdr (car dst-msgs))
3369                                               wl-summary-buffer-copy-list)))
3370             (setq copy-failures
3371                   (+ copy-failures (length (cdr (car dst-msgs))))))
3372           (setq copy-executed (+ copy-executed (length (cdr (car dst-msgs)))))
3373           (setq dst-msgs (cdr dst-msgs)))
3374         ;; end cOpy
3375         (wl-summary-folder-info-update)
3376         (wl-summary-set-message-modified)
3377         (wl-summary-set-mark-modified)
3378         (run-hooks 'wl-summary-exec-hook)
3379         (set-buffer-modified-p nil)
3380         (message (concat "Executing ... done"
3381                          (if (> refile-failures 0)
3382                              (format " (%d refiling failed)" refile-failures)
3383                            "")
3384                          (if (> copy-failures 0)
3385                              (format " (%d copying failed)" copy-failures)
3386                            "")
3387                          "."))))))
3388
3389 (defun wl-summary-read-folder (default &optional purpose ignore-error
3390                                 no-create init)
3391   (let ((fld (completing-read
3392               (format "Folder name %s(%s): " (or purpose "")
3393                       default)
3394               (or wl-folder-completion-func
3395                   (if (memq 'read-folder wl-use-folder-petname)
3396                       (wl-folder-get-entity-with-petname)
3397                     wl-folder-entity-hashtb))
3398               nil nil (or init wl-default-spec)
3399               'wl-read-folder-hist)))
3400     (setq fld (elmo-string (wl-folder-get-realname fld)))
3401     (if (string-match "\n" fld)
3402         (error "Not supported folder name: %s" fld))
3403     (if (or (string= fld wl-default-spec)
3404             (string= fld ""))
3405         (setq fld default))
3406     (unless no-create
3407       (if ignore-error
3408           (ignore-errors (wl-folder-confirm-existence fld))
3409         (wl-folder-confirm-existence fld)))
3410     fld))
3411
3412 (defun wl-summary-print-destination (msg-num folder)
3413   "Print refile destination on line."
3414   (wl-summary-remove-destination)
3415   (let ((inhibit-read-only t)
3416         (folder (copy-sequence folder))
3417         (buffer-read-only nil)
3418         len rs re c)
3419     (setq len (string-width folder))
3420     (if (< len 1) ()
3421       (end-of-line)
3422       (setq re (point))
3423       (setq c 0)
3424       (while (< c len)
3425         (forward-char -1)
3426         (setq c (+ c (char-width (following-char)))))
3427       (setq rs (point))
3428       (put-text-property rs re 'invisible t)
3429       (put-text-property rs re 'wl-summary-destination t)
3430       (goto-char re)
3431       (wl-highlight-refile-destination-string folder)
3432       (insert folder)
3433       (set-buffer-modified-p nil))))
3434
3435 ;; override.
3436 (when wl-on-nemacs
3437   (defun wl-summary-print-destination (msg-num &optional folder))
3438   (defun wl-summary-remove-destination ()))
3439
3440 (defsubst wl-summary-get-mark (number)
3441   "Returns a temporal mark of message specified by NUMBER."
3442   (or (and (memq number wl-summary-buffer-delete-list) "D")
3443       (and (assq number wl-summary-buffer-copy-list) "O")
3444       (and (assq number wl-summary-buffer-refile-list) "o")
3445       (and (assq number wl-summary-buffer-target-mark-list) "*")))
3446
3447 (defsubst wl-summary-reserve-temp-mark-p (mark)
3448   "Returns t if temporal MARK should be reserved."
3449   (member mark wl-summary-reserve-mark-list))
3450
3451 (defun wl-summary-refile (&optional dst number)
3452   "Put refile mark on current line message.
3453 If optional argument DST is specified, put mark without asking
3454 destination folder.
3455 If optional argument NUMBER is specified, mark message specified by NUMBER.
3456
3457 If folder is read-only, message should be copied.
3458 See `wl-refile-policy-alist' for more details."
3459   (interactive)
3460   (let ((policy (wl-get-assoc-list-value wl-refile-policy-alist
3461                                          wl-summary-buffer-folder-name)))
3462     (cond ((eq policy 'copy)
3463            (if (interactive-p)
3464                (call-interactively 'wl-summary-copy)
3465              (wl-summary-copy dst number)))
3466           (t
3467            (wl-summary-refile-subr 'refile (interactive-p) dst number)))))
3468
3469 (defun wl-summary-copy (&optional dst number)
3470   "Put copy mark on current line message.
3471 If optional argument DST is specified, put mark without asking
3472 destination folder.
3473 If optional argument NUMBER is specified, mark message specified by NUMBER."
3474   (interactive)
3475   (wl-summary-refile-subr 'copy (interactive-p) dst number))
3476
3477 (defun wl-summary-refile-subr (copy-or-refile interactive &optional dst number)
3478   (interactive)
3479   (let* ((buffer-num (wl-summary-message-number))
3480          (msg-num (or number buffer-num))
3481          (msgid (and msg-num
3482                      (cdr (assq msg-num
3483                                 (elmo-msgdb-get-number-alist
3484                                  wl-summary-buffer-msgdb)))))
3485          (entity (and msg-num
3486                       (elmo-msgdb-overview-get-entity
3487                        msg-num wl-summary-buffer-msgdb)))
3488          (variable
3489           (intern (format "wl-summary-buffer-%s-list" copy-or-refile)))
3490          folder mark already tmp-folder)
3491     (catch 'done
3492       (when (null entity)
3493         ;; msgdb is empty?
3494         (if interactive
3495             (message "Cannot refile."))
3496         (throw 'done nil))
3497       (when (null msg-num)
3498         (if interactive
3499             (message "No message."))
3500         (throw 'done nil))
3501       (when (setq mark (wl-summary-get-mark msg-num))
3502         (when (wl-summary-reserve-temp-mark-p mark)
3503           (if interactive
3504               (error "Already marked as `%s'" mark))
3505           (throw 'done nil)))
3506       (setq folder (and msg-num
3507                         (or dst (wl-summary-read-folder
3508                                  (or (wl-refile-guess entity) wl-trash-folder)
3509                                  (format "for %s" copy-or-refile)))))
3510       ;; Cache folder hack by okada@opaopa.org
3511       (if (and (eq (car (elmo-folder-get-spec folder)) 'cache)
3512                (not (string= folder
3513                              (setq tmp-folder
3514                                    (concat "'cache/"
3515                                            (elmo-cache-get-path-subr
3516                                             (elmo-msgid-to-cache msgid)))))))
3517           (progn
3518             (setq folder tmp-folder)
3519             (message "Force refile to %s." folder)))
3520       (if (string= folder wl-summary-buffer-folder-name)
3521           (error "Same folder"))
3522       (if (and
3523            (not (elmo-folder-plugged-p wl-summary-buffer-folder-name))
3524            (or (null msgid)
3525                (not (elmo-cache-exists-p msgid))))
3526           (error "Unplugged (no cache or msgid)"))
3527       (if (or (string= folder wl-queue-folder)
3528               (string= folder wl-draft-folder))
3529           (error "Don't %s messages to %s" copy-or-refile folder))
3530       ;; learn for refile.
3531       (if (eq copy-or-refile 'refile)
3532           (wl-refile-learn entity folder))
3533       (wl-summary-unmark msg-num)
3534       (set variable (append
3535                      (symbol-value variable)
3536                      (list (cons msg-num folder))))
3537       (when (or interactive
3538                 (eq number buffer-num))
3539         (wl-summary-mark-line (if (eq copy-or-refile 'refile)
3540                                   "o" "O"))
3541         ;; print refile destination
3542         (wl-summary-print-destination msg-num folder))
3543       (if interactive
3544           (if (eq wl-summary-move-direction-downward nil)
3545               (wl-summary-prev)
3546             (wl-summary-next)))
3547       (run-hooks (intern (format "wl-summary-%s-hook" copy-or-refile)))
3548       (setq wl-summary-buffer-prev-refile-destination folder)
3549       msg-num)))
3550
3551 (defun wl-summary-refile-prev-destination ()
3552   "Refile message to previously refiled destination"
3553   (interactive)
3554   (wl-summary-refile wl-summary-buffer-prev-refile-destination
3555                      (wl-summary-message-number))
3556   (if (eq wl-summary-move-direction-downward nil)
3557       (wl-summary-prev)
3558     (wl-summary-next)))
3559
3560 (defun wl-summary-copy-prev-destination ()
3561   "Refile message to previously refiled destination"
3562   (interactive)
3563   (wl-summary-copy wl-summary-buffer-prev-copy-destination
3564                    (wl-summary-message-number))
3565   (if (eq wl-summary-move-direction-downward nil)
3566       (wl-summary-prev)
3567     (wl-summary-next)))
3568
3569 (defsubst wl-summary-no-auto-refile-message-p (msg mark-alist)
3570   (member (cadr (assq msg mark-alist)) wl-summary-auto-refile-skip-marks))
3571
3572 (defun wl-summary-auto-refile (&optional open-all)
3573   "Set refile mark automatically according to wl-refile-guess-by-rule."
3574   (interactive "P")
3575   (message "Marking...")
3576   (save-excursion
3577     (if (and (eq wl-summary-buffer-view 'thread)
3578              open-all)
3579         (wl-thread-open-all))
3580     (let* ((spec wl-summary-buffer-folder-name)
3581            (overview (elmo-msgdb-get-overview
3582                       wl-summary-buffer-msgdb))
3583            (mark-alist (elmo-msgdb-get-mark-alist
3584                         wl-summary-buffer-msgdb))
3585            checked-dsts
3586            (count 0)
3587            number dst thr-entity)
3588       (goto-line 1)
3589       (while (not (eobp))
3590         (setq number (wl-summary-message-number))
3591         (when (and (not (wl-summary-no-auto-refile-message-p number
3592                                                              mark-alist))
3593                    (setq dst
3594                          (wl-refile-guess-by-rule
3595                           (elmo-msgdb-overview-get-entity
3596                            number wl-summary-buffer-msgdb)))
3597                    (not (equal dst spec)))
3598           (when (not (member dst checked-dsts))
3599             (wl-folder-confirm-existence dst)
3600             (setq checked-dsts (cons dst checked-dsts)))
3601           (if (wl-summary-refile dst number)
3602               (incf count))
3603           (message "Marking...%d message(s)." count))
3604         (if (eq wl-summary-buffer-view 'thread)
3605             ;; process invisible children.
3606             (unless (wl-thread-entity-get-opened
3607                      (setq thr-entity (wl-thread-get-entity number)))
3608               (let ((messages
3609                      (elmo-delete-if
3610                       (function
3611                        (lambda (x)
3612                          (wl-summary-no-auto-refile-message-p
3613                           x mark-alist)))
3614                       (wl-thread-entity-get-descendant thr-entity))))
3615                 (while messages
3616                   (when (and (setq dst
3617                                    (wl-refile-guess-by-rule
3618                                     (elmo-msgdb-overview-get-entity
3619                                      (car messages) wl-summary-buffer-msgdb)))
3620                              (not (equal dst spec)))
3621                     (if (wl-summary-refile dst (car messages))
3622                         (incf count))
3623                     (message "Marking...%d message(s)." count))
3624                   (setq messages (cdr messages))))))
3625         (forward-line))
3626       (if (eq count 0)
3627           (message "No message was marked.")
3628         (message "Marked %d message(s)." count)))))
3629
3630 (defun wl-summary-unmark (&optional number)
3631   "Unmark marks (temporary, refile, copy, delete)of current line.
3632 If optional argument NUMBER is specified, unmark message specified by NUMBER."
3633   (interactive)
3634   (save-excursion
3635     (beginning-of-line)
3636     (let ((inhibit-read-only t)
3637           (buffer-read-only nil)
3638           visible
3639           msg-num
3640           cur-mark
3641           score-mark)
3642       (if number
3643           (setq visible (wl-summary-jump-to-msg number))
3644         (setq visible t))
3645       ;; Delete mark on buffer.
3646       (when (and visible
3647                  (looking-at "^ *\\([0-9]+\\)\\([^0-9]\\)"))
3648         (goto-char (match-end 2))
3649         (or number
3650             (setq number (string-to-int (wl-match-buffer 1))))
3651         (setq cur-mark (wl-match-buffer 2))
3652         (if (string= cur-mark " ")
3653             ()
3654           (delete-region (match-beginning 2) (match-end 2))
3655           (if (setq score-mark (wl-summary-get-score-mark number))
3656               (insert score-mark)
3657             (insert " ")))
3658         (if (or (string= cur-mark "o")
3659                 (string= cur-mark "O"))
3660             (wl-summary-remove-destination))
3661         (if wl-summary-highlight
3662             (wl-highlight-summary-current-line nil nil score-mark))
3663         (set-buffer-modified-p nil))
3664       ;; Remove from temporary mark structure.
3665       (and number
3666            (wl-summary-delete-mark number)))))
3667
3668 (defun wl-summary-msg-marked-as-target (msg)
3669   (if (memq msg wl-summary-buffer-target-mark-list)
3670       t))
3671
3672 (defun wl-summary-msg-marked-as-copied (msg)
3673   (assq msg wl-summary-buffer-copy-list))
3674
3675 (defun wl-summary-msg-marked-as-deleted (msg)
3676   (if (memq msg wl-summary-buffer-delete-list)
3677       t))
3678
3679 (defun wl-summary-msg-marked-as-refiled (msg)
3680   (assq msg wl-summary-buffer-refile-list))
3681
3682 (defun wl-summary-target-mark (&optional number)
3683   "Put target mark '*' on current message.
3684 If optional argument NUMBER is specified, mark message specified by NUMBER."
3685   (interactive)
3686   (let* ((buffer-num (wl-summary-message-number))
3687          (msg-num (or number buffer-num))
3688          mark)
3689     (catch 'done
3690       (when (null msg-num)
3691         (if (interactive-p)
3692             (message "No message."))
3693         (throw 'done nil))
3694       (when (setq mark (wl-summary-get-mark msg-num))
3695         (when (wl-summary-reserve-temp-mark-p mark)
3696           (if (interactive-p)
3697               (error "Already marked as `%s'" mark))
3698           (throw 'done nil))
3699         (wl-summary-unmark msg-num))
3700       (if (or (interactive-p)
3701               (eq number buffer-num))
3702           (wl-summary-mark-line "*"))
3703       (setq wl-summary-buffer-target-mark-list
3704             (cons msg-num wl-summary-buffer-target-mark-list))
3705       (if (interactive-p)
3706           (if (eq wl-summary-move-direction-downward nil)
3707               (wl-summary-prev)
3708             (wl-summary-next)))
3709       msg-num)))
3710
3711
3712 (defun wl-summary-refile-region (beg end)
3713   "Put copy mark on messages in the region specified by BEG and END."
3714   (interactive "r")
3715   (wl-summary-refile-region-subr "refile" beg end))
3716
3717 (defun wl-summary-copy-region (beg end)
3718   "Put copy mark on messages in the region specified by BEG and END."
3719   (interactive "r")
3720   (wl-summary-refile-region-subr "copy" beg end))
3721
3722 (defun wl-summary-refile-region-subr (copy-or-refile beg end)
3723   (save-excursion
3724     (save-restriction
3725       (goto-char beg)
3726       ;; guess by first msg
3727       (let* ((msgid (cdr (assq (wl-summary-message-number)
3728                                (elmo-msgdb-get-number-alist
3729                                 wl-summary-buffer-msgdb))))
3730              (function (intern (format "wl-summary-%s" copy-or-refile)))
3731              (entity (assoc msgid (elmo-msgdb-get-overview
3732                                    wl-summary-buffer-msgdb)))
3733              folder)
3734         (if entity
3735             (setq folder (wl-summary-read-folder (wl-refile-guess entity)
3736                                                  (format "for %s"
3737                                                          copy-or-refile))))
3738         (narrow-to-region beg end)
3739         (if (eq wl-summary-buffer-view 'thread)
3740             (progn
3741               (while (not (eobp))
3742                 (let* ((number (wl-summary-message-number))
3743                        (entity (wl-thread-get-entity number))
3744                        children)
3745                   (if (wl-thread-entity-get-opened entity)
3746                       ;; opened...refile line.
3747                       (funcall function folder number)
3748                     ;; closed
3749                     (setq children (wl-thread-get-children-msgs number))
3750                     (while children
3751                       (funcall function folder (pop children))))
3752                   (forward-line 1))))
3753           (while (not (eobp))
3754             (funcall function folder (wl-summary-message-number))
3755             (forward-line 1)))))))
3756
3757 (defun wl-summary-unmark-region (beg end)
3758   (interactive "r")
3759   (save-excursion
3760     (save-restriction
3761       (narrow-to-region beg end)
3762       (goto-char (point-min))
3763       (if (eq wl-summary-buffer-view 'thread)
3764           (progn
3765             (while (not (eobp))
3766               (let* ((number (wl-summary-message-number))
3767                      (entity (wl-thread-get-entity number)))
3768                 (if (wl-thread-entity-get-opened entity)
3769                     ;; opened...unmark line.
3770                     (wl-summary-unmark)
3771                   ;; closed
3772                   (wl-summary-delete-marks-on-buffer
3773                    (wl-thread-get-children-msgs number))))
3774               (forward-line 1)))
3775         (while (not (eobp))
3776           (wl-summary-unmark)
3777           (forward-line 1))))))
3778
3779 (defun wl-summary-mark-region-subr (function beg end)
3780   (save-excursion
3781     (save-restriction
3782       (narrow-to-region beg end)
3783       (goto-char (point-min))
3784       (if (eq wl-summary-buffer-view 'thread)
3785           (progn
3786             (while (not (eobp))
3787               (let* ((number (wl-summary-message-number))
3788                      (entity (wl-thread-get-entity number))
3789                      (wl-summary-move-direction-downward t)
3790                      children)
3791                 (if (wl-thread-entity-get-opened entity)
3792                     ;; opened...delete line.
3793                     (funcall function number)
3794                   ;; closed
3795                   (setq children (wl-thread-get-children-msgs number))
3796                   (while children
3797                     (funcall function (pop children))))
3798                 (forward-line 1))))
3799         (while (not (eobp))
3800           (funcall function (wl-summary-message-number))
3801           (forward-line 1))))))
3802
3803 (defun wl-summary-delete-region (beg end)
3804   (interactive "r")
3805   (wl-summary-mark-region-subr 'wl-summary-delete beg end))
3806
3807 (defun wl-summary-target-mark-region (beg end)
3808   (interactive "r")
3809   (wl-summary-mark-region-subr 'wl-summary-target-mark beg end))
3810
3811 (defun wl-summary-target-mark-all ()
3812   (interactive)
3813   (wl-summary-target-mark-region (point-min) (point-max))
3814   (setq wl-summary-buffer-target-mark-list
3815         (mapcar 'car
3816                 (elmo-msgdb-get-number-alist wl-summary-buffer-msgdb))))
3817
3818 (defun wl-summary-delete-all-mark (mark)
3819   (goto-char (point-min))
3820   (let ((case-fold-search nil))
3821     (while (re-search-forward (format "^ *[0-9]+%s"
3822                                       (regexp-quote mark)) nil t)
3823       (wl-summary-unmark))
3824     (cond ((string= mark "*")
3825            (setq wl-summary-buffer-target-mark-list nil))
3826           ((string= mark "D")
3827            (setq wl-summary-buffer-delete-list nil))
3828           ((string= mark "O")
3829            (setq wl-summary-buffer-copy-list nil))
3830           ((string= mark "o")
3831            (setq wl-summary-buffer-refile-list nil)))))
3832
3833 (defun wl-summary-unmark-all ()
3834   "Unmark all according to what you input."
3835   (interactive)
3836   (let ((unmarks (string-to-char-list (read-from-minibuffer "Unmark: ")))
3837         cur-mark)
3838     (save-excursion
3839       (while unmarks
3840         (setq cur-mark (char-to-string (car unmarks)))
3841         (wl-summary-delete-all-mark cur-mark)
3842         (setq unmarks (cdr unmarks))))))
3843
3844 (defun wl-summary-target-mark-thread ()
3845   (interactive)
3846   (let (beg end)
3847     (end-of-line)
3848     (wl-summary-goto-top-of-current-thread)
3849     (wl-thread-force-open)
3850     (setq beg (point))
3851     (end-of-line)
3852     (wl-summary-goto-bottom-of-current-thread)
3853 ;    (forward-line -1)
3854     (beginning-of-line)
3855     (setq end (point))
3856     (wl-summary-target-mark-region beg end)))
3857
3858 (defun wl-summary-target-mark-msgs (msgs)
3859   (while msgs
3860     (if (eq wl-summary-buffer-view 'thread)
3861         (wl-thread-jump-to-msg (car msgs))
3862       (wl-summary-jump-to-msg (car msgs)))
3863     (wl-summary-target-mark (wl-summary-message-number))
3864     (setq msgs (cdr msgs))))
3865
3866 (defun wl-summary-pick (&optional from-list delete-marks)
3867   (interactive)
3868   (let ((result (elmo-msgdb-search 
3869                  wl-summary-buffer-folder-name
3870                  (elmo-read-search-condition wl-summary-pick-field-default)
3871                  wl-summary-buffer-msgdb)))
3872     (if delete-marks
3873       (let ((mlist wl-summary-buffer-target-mark-list))
3874         (while mlist
3875           (when (wl-summary-jump-to-msg (car mlist))
3876             (wl-summary-unmark))
3877           (setq mlist (cdr mlist)))
3878         (setq wl-summary-buffer-target-mark-list nil)))
3879     (if from-list
3880         (setq result (elmo-list-filter from-list result)))
3881     (message "%d message(s) are picked." (length result))
3882     (if (null result)
3883         (message "No message was picked.")
3884       (wl-summary-target-mark-msgs result))))
3885
3886 (defun wl-summary-unvirtual ()
3887   "Exit from current virtual folder."
3888   (interactive)
3889   (if (eq 'filter
3890           (elmo-folder-get-type wl-summary-buffer-folder-name))
3891       (wl-summary-goto-folder-subr (nth 2 (elmo-folder-get-spec
3892                                            wl-summary-buffer-folder-name))
3893                                    'update nil nil t)
3894     (error "This folder is not filtered")))
3895
3896 (defun wl-summary-virtual (&optional arg)
3897   "Goto virtual folder."
3898   (interactive "P")
3899   (if arg
3900       (wl-summary-unvirtual)
3901     (wl-summary-goto-folder-subr (concat "/"
3902                                          (elmo-read-search-condition
3903                                           wl-summary-pick-field-default)
3904                                          "/"
3905                                          wl-summary-buffer-folder-name)
3906                                  'update nil nil t)))
3907
3908 (defun wl-summary-delete-all-temp-marks ()
3909   (interactive)
3910   (save-excursion
3911     (goto-char (point-min))
3912     (message "Unmarking...")
3913     (while (not (eobp))
3914       (wl-summary-unmark)
3915       (forward-line))
3916     (message "Unmarking...done.")
3917     (setq wl-summary-buffer-target-mark-list nil)
3918     (setq wl-summary-buffer-delete-list nil)
3919     (setq wl-summary-buffer-refile-list nil)
3920     (setq wl-summary-buffer-copy-list nil)))
3921
3922 (defun wl-summary-delete-mark (number)
3923   "Delete temporary mark of the message specified by NUMBER."
3924   (cond
3925    ((memq number wl-summary-buffer-target-mark-list)
3926     (setq wl-summary-buffer-target-mark-list
3927           (delq number wl-summary-buffer-target-mark-list)))
3928    ((memq number wl-summary-buffer-delete-list)
3929     (setq wl-summary-buffer-delete-list
3930           (delq number wl-summary-buffer-delete-list)))
3931    (t
3932     (let (pair)
3933       (cond
3934        ((setq pair (assq number wl-summary-buffer-copy-list))
3935         (setq wl-summary-buffer-copy-list
3936               (delq pair wl-summary-buffer-copy-list)))
3937        ((setq pair (assq number wl-summary-buffer-refile-list))
3938         (setq wl-summary-buffer-refile-list
3939               (delq pair wl-summary-buffer-refile-list))))))))
3940
3941 (defun wl-summary-mark-line (mark)
3942   "Put MARK on current line. Returns message number."
3943   (save-excursion
3944     (beginning-of-line)
3945     (let ((inhibit-read-only t)
3946           (buffer-read-only nil)
3947           msg-num
3948           cur-mark)
3949       (when (looking-at "^ *\\([0-9]+\\)\\([^0-9]\\)")
3950         (setq msg-num  (string-to-int (wl-match-buffer 1)))
3951         (setq cur-mark (wl-match-buffer 2))
3952         (goto-char (match-end 1))
3953         (delete-region (match-beginning 2) (match-end 2))
3954         ;(wl-summary-delete-mark msg-num)
3955         (insert mark)
3956         (if wl-summary-highlight
3957             (wl-highlight-summary-current-line nil nil t))
3958         (set-buffer-modified-p nil)
3959         msg-num))))
3960
3961 (defun wl-summary-target-mark-delete ()
3962   (interactive)
3963   (save-excursion
3964     (goto-char (point-min))
3965     (let ((regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
3966           number mlist)
3967       (while (re-search-forward regexp nil t)
3968         (let (wl-summary-buffer-disp-msg)
3969           (when (setq number (wl-summary-message-number))
3970             (wl-summary-delete number)
3971             (setq wl-summary-buffer-target-mark-list
3972                   (delq number wl-summary-buffer-target-mark-list)))))
3973       (setq mlist wl-summary-buffer-target-mark-list)
3974       (while mlist
3975         (wl-append wl-summary-buffer-delete-list (list (car mlist)))
3976         (setq wl-summary-buffer-target-mark-list
3977               (delq (car mlist) wl-summary-buffer-target-mark-list))
3978         (setq mlist (cdr mlist))))))
3979
3980 (defun wl-summary-target-mark-prefetch ()
3981   (interactive)
3982   (save-excursion
3983     (let* ((mlist (nreverse wl-summary-buffer-target-mark-list))
3984            (inhibit-read-only t)
3985            (buffer-read-only nil)
3986            (count 0)
3987            (length (length mlist))
3988            (pos (point))
3989            skipped
3990            new-mark)
3991       (while mlist
3992         (setq new-mark (wl-summary-prefetch-msg (car mlist)))
3993         (if new-mark
3994             (progn
3995               (message "Prefetching... %d/%d message(s)"
3996                        (setq count (+ 1 count)) length)
3997               (when (wl-summary-jump-to-msg (car mlist))
3998                 (wl-summary-unmark)
3999                 (when new-mark
4000                   (when (looking-at "^ *[0-9]+[^0-9]\\([^0-9]\\)")
4001                     (delete-region (match-beginning 1) (match-end 1)))
4002                   (goto-char (match-beginning 1))
4003                   (insert new-mark)
4004                   (if wl-summary-highlight
4005                       (wl-highlight-summary-current-line))
4006                   (save-excursion
4007                     (goto-char pos)
4008                     (sit-for 0)))))
4009           (setq skipped (cons (car mlist) skipped)))
4010         (setq mlist (cdr mlist)))
4011       (setq wl-summary-buffer-target-mark-list skipped)
4012       (message "Prefetching... %d/%d message(s)." count length)
4013       (set-buffer-modified-p nil))))
4014
4015 (defun wl-summary-target-mark-refile-subr (copy-or-refile)
4016   (let ((variable
4017          (intern (format "wl-summary-buffer-%s-list" copy-or-refile)))
4018         (function
4019          (intern (format "wl-summary-%s" copy-or-refile)))
4020         regexp number msgid entity folder mlist)
4021     (save-excursion
4022       (goto-char (point-min))
4023       (setq regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
4024       ;; guess by first mark
4025       (when (re-search-forward regexp nil t)
4026         (setq msgid (cdr (assq (setq number (wl-summary-message-number))
4027                                (elmo-msgdb-get-number-alist
4028                                 wl-summary-buffer-msgdb)))
4029               entity (assoc msgid
4030                             (elmo-msgdb-get-overview
4031                              wl-summary-buffer-msgdb)))
4032         (if (null entity)
4033             (error "Cannot %s" copy-or-refile))
4034         (funcall function
4035                  (setq folder (wl-summary-read-folder
4036                                (wl-refile-guess entity)
4037                                (format "for %s" copy-or-refile)))
4038                  number)
4039         (if number
4040             (setq wl-summary-buffer-target-mark-list
4041                   (delq number wl-summary-buffer-target-mark-list)))
4042         (while (re-search-forward regexp nil t)
4043           (let (wl-summary-buffer-disp-msg)
4044             (when (setq number (wl-summary-message-number))
4045               (funcall function folder number)
4046               (setq wl-summary-buffer-target-mark-list
4047                     (delq number wl-summary-buffer-target-mark-list)))))
4048         ;; process invisible messages.
4049         (setq mlist wl-summary-buffer-target-mark-list)
4050         (while mlist
4051           (set variable
4052                (append (symbol-value variable)
4053                        (list (cons (car mlist) folder))))
4054           (setq wl-summary-buffer-target-mark-list
4055                 (delq (car mlist) wl-summary-buffer-target-mark-list))
4056           (setq mlist (cdr mlist)))))))
4057
4058 (defun wl-summary-target-mark-copy ()
4059   (interactive)
4060   (wl-summary-target-mark-refile-subr "copy"))
4061
4062 (defun wl-summary-target-mark-refile ()
4063   (interactive)
4064   (wl-summary-target-mark-refile-subr "refile"))
4065
4066 (defun wl-summary-target-mark-mark-as-read ()
4067   (interactive)
4068   (save-excursion
4069     (goto-char (point-min))
4070     (let ((regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
4071           (inhibit-read-only t)
4072           (buffer-read-only nil)
4073           number mlist)
4074       (while (re-search-forward regexp nil t)
4075         (let (wl-summary-buffer-disp-msg)
4076           ;; delete target-mark from buffer.
4077           (delete-region (match-beginning 1) (match-end 1))
4078           (insert " ")
4079           (setq number (wl-summary-mark-as-read t))
4080           (if wl-summary-highlight
4081               (wl-highlight-summary-current-line))
4082           (if number
4083               (setq wl-summary-buffer-target-mark-list
4084                     (delq number wl-summary-buffer-target-mark-list)))))
4085       (setq mlist wl-summary-buffer-target-mark-list)
4086       (while mlist
4087         (wl-summary-mark-as-read t nil nil (car mlist))
4088         (setq wl-summary-buffer-target-mark-list
4089               (delq (car mlist) wl-summary-buffer-target-mark-list))
4090         (setq mlist (cdr mlist)))
4091       (wl-summary-count-unread
4092        (elmo-msgdb-get-mark-alist wl-summary-buffer-msgdb))
4093       (wl-summary-update-modeline))))
4094
4095 (defun wl-summary-target-mark-mark-as-unread ()
4096   (interactive)
4097   (save-excursion
4098     (goto-char (point-min))
4099     (let ((regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
4100           (inhibit-read-only t)
4101           (buffer-read-only nil)
4102           number mlist)
4103       (while (re-search-forward regexp nil t)
4104         (let (wl-summary-buffer-disp-msg)
4105           ;; delete target-mark from buffer.
4106           (delete-region (match-beginning 1) (match-end 1))
4107           (insert " ")
4108           (setq number (wl-summary-mark-as-unread))
4109           (if wl-summary-highlight
4110               (wl-highlight-summary-current-line))
4111           (if number
4112               (setq wl-summary-buffer-target-mark-list
4113                     (delq number wl-summary-buffer-target-mark-list)))))
4114       (setq mlist wl-summary-buffer-target-mark-list)
4115       (while mlist
4116         (wl-summary-mark-as-unread (car mlist))
4117         ;; (wl-thread-msg-mark-as-unread (car mlist))
4118         (setq wl-summary-buffer-target-mark-list
4119               (delq (car mlist) wl-summary-buffer-target-mark-list))
4120         (setq mlist (cdr mlist)))
4121       (wl-summary-count-unread
4122        (elmo-msgdb-get-mark-alist wl-summary-buffer-msgdb))
4123       (wl-summary-update-modeline))))
4124
4125 (defun wl-summary-target-mark-mark-as-important ()
4126   (interactive)
4127   (save-excursion
4128     (goto-char (point-min))
4129     (let ((regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
4130           (inhibit-read-only t)
4131           (buffer-read-only nil)
4132           number mlist)
4133       (while (re-search-forward regexp nil t)
4134         (let (wl-summary-buffer-disp-msg)
4135           ;; delete target-mark from buffer.
4136           (delete-region (match-beginning 1) (match-end 1))
4137           (insert " ")
4138           (setq number (wl-summary-mark-as-important))
4139           (if wl-summary-highlight
4140               (wl-highlight-summary-current-line))
4141           (if number
4142               (setq wl-summary-buffer-target-mark-list
4143                     (delq number wl-summary-buffer-target-mark-list)))))
4144       (setq mlist wl-summary-buffer-target-mark-list)
4145       (while mlist
4146         (wl-summary-mark-as-important (car mlist))
4147         (wl-thread-msg-mark-as-important (car mlist))
4148         (setq wl-summary-buffer-target-mark-list
4149               (delq (car mlist) wl-summary-buffer-target-mark-list))
4150         (setq mlist (cdr mlist)))
4151       (wl-summary-count-unread
4152        (elmo-msgdb-get-mark-alist wl-summary-buffer-msgdb))
4153       (wl-summary-update-modeline))))
4154
4155 (defun wl-summary-target-mark-save ()
4156   (interactive)
4157   (save-excursion
4158     (goto-char (point-min))
4159     (let ((wl-save-dir
4160            (wl-read-directory-name "Save to directory: " wl-tmp-dir))
4161           (regexp (concat "^" wl-summary-buffer-number-regexp "\\(\\*\\)"))
4162           number mlist)
4163       (if (null (file-exists-p wl-save-dir))
4164           (make-directory wl-save-dir))
4165       (while (re-search-forward regexp nil t)
4166         (let (wl-summary-buffer-disp-msg)
4167           (setq number (wl-summary-save t wl-save-dir))
4168           (wl-summary-unmark)
4169           (if number
4170               (setq wl-summary-buffer-target-mark-list
4171                     (delq number wl-summary-buffer-target-mark-list))))))))
4172
4173 (defun wl-summary-target-mark-pick ()
4174   (interactive)
4175   (wl-summary-pick wl-summary-buffer-target-mark-list 'delete))
4176
4177 (defun wl-summary-mark-as-read (&optional notcrosses
4178                                           leave-server-side-mark-untouched
4179                                           displayed
4180                                           number
4181                                           cached)
4182   (interactive)
4183   (save-excursion
4184     (let* (eol
4185            (inhibit-read-only t)
4186            (buffer-read-only nil)
4187            (folder wl-summary-buffer-folder-name)
4188            (msgdb wl-summary-buffer-msgdb)
4189            (mark-alist (elmo-msgdb-get-mark-alist msgdb))
4190            ;;(number-alist (elmo-msgdb-get-number-alist msgdb))
4191            (case-fold-search nil)
4192            mark stat visible uncached new-mark marked)
4193       (if number
4194           (progn
4195             (setq visible (wl-summary-jump-to-msg number))
4196             (setq mark (cadr (assq number mark-alist))))
4197         (setq visible t))
4198       (beginning-of-line)
4199       (if (or (not visible)
4200               (looking-at
4201                (format "^ *\\([0-9]+\\)[^0-9]\\(%s\\|%s\\|%s\\|%s\\).*$"
4202                        (regexp-quote wl-summary-read-uncached-mark)
4203                        (regexp-quote wl-summary-unread-uncached-mark)
4204                        (regexp-quote wl-summary-unread-cached-mark)
4205                        (regexp-quote wl-summary-new-mark))))
4206           (progn
4207             (setq mark (or mark (wl-match-buffer 2)))
4208             (when mark
4209               (cond
4210                ((string= mark wl-summary-new-mark) ; N
4211                 (setq stat 'new)
4212                 (setq uncached t))
4213                ((string= mark wl-summary-unread-uncached-mark) ; U
4214                 (setq stat 'unread)
4215                 (setq uncached t))
4216                ((string= mark wl-summary-unread-cached-mark)  ; !
4217                 (setq stat 'unread))
4218                (t
4219                 ;; no need to mark server.
4220                 (setq leave-server-side-mark-untouched t))))
4221             (setq number (or number (string-to-int (wl-match-buffer 1))))
4222             ;; set server side mark...
4223             (setq new-mark (if (and uncached
4224                                     (if (elmo-use-cache-p folder number)
4225                                         (not (elmo-folder-local-p folder)))
4226                                     (not cached))
4227                                wl-summary-read-uncached-mark
4228                              nil))
4229             (if (not leave-server-side-mark-untouched)
4230                 (setq marked (elmo-mark-as-read folder
4231                                                 (list number) msgdb)))
4232             (if (or leave-server-side-mark-untouched
4233                     marked)
4234                 (progn
4235                   (cond ((eq stat 'unread)
4236                          (setq wl-summary-buffer-unread-count
4237                                (1- wl-summary-buffer-unread-count)))
4238                         ((eq stat 'new)
4239                          (setq wl-summary-buffer-new-count
4240                                (1- wl-summary-buffer-new-count))))
4241                   (wl-summary-update-modeline)
4242                   (wl-folder-update-unread
4243                    folder
4244                    (+ wl-summary-buffer-unread-count
4245                       wl-summary-buffer-new-count))
4246                   (when (or stat cached)
4247                     (when visible
4248                       (goto-char (match-end 2))
4249                       (delete-region (match-beginning 2) (match-end 2))
4250                       (insert (or new-mark " ")))
4251                     (setq mark-alist
4252                           (elmo-msgdb-mark-set mark-alist number new-mark))
4253                     (elmo-msgdb-set-mark-alist msgdb mark-alist)
4254                     (wl-summary-set-mark-modified))
4255                   (if (and visible wl-summary-highlight)
4256                       (wl-highlight-summary-current-line nil nil t))
4257                   (if (not notcrosses)
4258                       (wl-summary-set-crosspost nil
4259                                                 (and wl-summary-buffer-disp-msg
4260                                                      (interactive-p)))))
4261               (if mark (message "Warning: Changing mark failed.")))))
4262       (set-buffer-modified-p nil)
4263       (if stat
4264           (run-hooks 'wl-summary-unread-message-hook))
4265       number ;return value
4266       )))
4267
4268 (defun wl-summary-mark-as-important (&optional number
4269                                                mark
4270                                                no-server-update)
4271   (interactive)
4272   (if (eq (elmo-folder-get-type wl-summary-buffer-folder-name)
4273           'internal)
4274       (error "Cannot process mark in this folder"))
4275   (save-excursion
4276     (let* (eol
4277           (inhibit-read-only t)
4278           (buffer-read-only nil)
4279           (folder wl-summary-buffer-folder-name)
4280           (msgdb wl-summary-buffer-msgdb)
4281           (mark-alist (elmo-msgdb-get-mark-alist msgdb))
4282           (number-alist (elmo-msgdb-get-number-alist msgdb))
4283           message-id visible)
4284       (if number
4285           (progn
4286             (setq visible (wl-summary-jump-to-msg number))
4287             (setq mark (or mark (cadr (assq number mark-alist)))))
4288         (setq visible t))
4289       (when visible
4290         (if (null (wl-summary-message-number))
4291             (progn
4292               (message "No message.")
4293               (setq visible nil))
4294           (end-of-line)
4295           (setq eol (point))
4296           (re-search-backward (concat "^" wl-summary-buffer-number-regexp
4297                                       "..../..") nil t)) ; set cursor line
4298         )
4299       (beginning-of-line)
4300       (if (re-search-forward "^ *\\([0-9]+\\)[^0-9]\\([^0-9]\\)" eol t)
4301           (progn
4302             (setq number (or number (string-to-int (wl-match-buffer 1))))
4303             (setq mark (or mark (wl-match-buffer 2)))
4304             (setq message-id (cdr (assq number number-alist)))
4305             (if (string= mark wl-summary-important-mark)
4306                 (progn
4307                   ;; server side mark
4308                   (unless no-server-update
4309                     (elmo-unmark-important folder (list number) msgdb)
4310                     (elmo-msgdb-global-mark-delete message-id))
4311                   (when visible
4312                     (delete-region (match-beginning 2) (match-end 2))
4313                     (insert " "))
4314                   (setq mark-alist
4315                         (elmo-msgdb-mark-set mark-alist
4316                                              number
4317                                              nil)))
4318               ;; server side mark
4319               (unless no-server-update
4320                 (elmo-mark-as-important folder (list number) msgdb))
4321               (when visible
4322                 (delete-region (match-beginning 2) (match-end 2))
4323                 (insert wl-summary-important-mark))
4324               (setq mark-alist
4325                     (elmo-msgdb-mark-set mark-alist
4326                                          (string-to-int (wl-match-buffer 1))
4327                                          wl-summary-important-mark))
4328               ;; Force cache message!!
4329               (save-match-data
4330                 (unless (elmo-cache-exists-p message-id)
4331                   (elmo-force-cache-msg folder number message-id
4332                                         (elmo-msgdb-get-location msgdb))))
4333               (unless no-server-update
4334                 (elmo-msgdb-global-mark-set message-id
4335                                             wl-summary-important-mark)))
4336             (elmo-msgdb-set-mark-alist msgdb mark-alist)
4337             (wl-summary-set-mark-modified)))
4338       (if (and visible wl-summary-highlight)
4339           (wl-highlight-summary-current-line nil nil t))))
4340   (set-buffer-modified-p nil)
4341   number)
4342
4343 (defsubst wl-summary-format-date (date-string)
4344   (condition-case nil
4345       (let ((datevec (timezone-fix-time date-string nil
4346                                         wl-summary-fix-timezone)))
4347         (format "%02d/%02d(%s)%02d:%02d"
4348                 (aref datevec 1)
4349                 (aref datevec 2)
4350                 (elmo-date-get-week (aref datevec 0)
4351                                     (aref datevec 1)
4352                                     (aref datevec 2))
4353                 (aref datevec 3)
4354                 (aref datevec 4)))
4355     (error "??/??(??)??:??")))
4356
4357 (defun wl-summary-overview-create-summary-line (msg
4358                                                 entity
4359                                                 parent-entity
4360                                                 depth
4361                                                 mark-alist
4362                                                 &optional
4363                                                 children-num
4364                                                 temp-mark thr-entity
4365                                                 subject-differ)
4366   (let ((wl-mime-charset wl-summary-buffer-mime-charset)
4367         (elmo-mime-charset wl-summary-buffer-mime-charset)
4368         no-parent before-indent
4369         from subject parent-raw-subject parent-subject
4370         mark line
4371         (elmo-lang wl-summary-buffer-weekday-name-lang)
4372         (children-num (if children-num (int-to-string children-num)))
4373         (thr-str "")
4374         linked)
4375     (when thr-entity
4376       (setq thr-str (wl-thread-make-indent-string thr-entity))
4377       (setq linked (wl-thread-entity-get-linked thr-entity)))
4378     (if (string= thr-str "")
4379         (setq no-parent t)) ; no parent
4380     (if (and wl-summary-width
4381              wl-summary-indent-length-limit
4382              (< wl-summary-indent-length-limit
4383                 (string-width thr-str)))
4384         (setq thr-str (wl-set-string-width
4385                        wl-summary-indent-length-limit
4386                        thr-str)))
4387     (setq from
4388           (wl-set-string-width
4389            (if children-num
4390                (- wl-from-width (length children-num) 2)
4391              wl-from-width)
4392            (elmo-delete-char ?\n
4393                              (wl-summary-from-func-internal
4394                               (elmo-msgdb-overview-entity-get-from entity)))))
4395     (setq subject
4396           (elmo-delete-char ?\n
4397                             (or (elmo-msgdb-overview-entity-get-subject
4398                                  entity)
4399                                 wl-summary-no-subject-message)))
4400     (setq parent-raw-subject
4401           (elmo-msgdb-overview-entity-get-subject parent-entity))
4402     (setq parent-subject
4403           (if parent-raw-subject
4404               (elmo-delete-char ?\n parent-raw-subject)))
4405     (setq mark (or (cadr (assq msg mark-alist)) " "))
4406     (setq line
4407           (concat
4408            (setq before-indent
4409                  (format (concat "%"
4410                                  (int-to-string
4411                                   wl-summary-buffer-number-column)
4412                                  "s%s%s%s %s")
4413                          msg
4414                          (or temp-mark " ")
4415                          mark
4416                          (wl-summary-format-date
4417                           (elmo-msgdb-overview-entity-get-date entity))
4418                          (if thr-str thr-str "")))
4419            (format (if linked
4420                        "<%s > %s"
4421                      "[%s ] %s")
4422                    (if children-num
4423                        (concat "+" children-num ": " from)
4424                      (concat " " from))
4425                    (progn
4426                      (setq subject
4427                            (if (or no-parent
4428                                    (null parent-subject)
4429                                    (not (wl-summary-subject-equal
4430                                          subject parent-subject)))
4431                                (wl-summary-subject-func-internal subject) ""))
4432                      (if (and (not wl-summary-width)
4433                               wl-subject-length-limit)
4434                          (truncate-string subject wl-subject-length-limit)
4435                        subject)))))
4436     (if wl-summary-width (setq line
4437                                (wl-set-string-width
4438                                 (- wl-summary-width 1) line)))
4439     (if wl-summary-highlight
4440         (wl-highlight-summary-line-string line
4441                                           mark
4442                                           temp-mark
4443                                           thr-str))
4444     line))
4445
4446 (defsubst wl-summary-buffer-number-column-detect (update)
4447   (let (end)
4448     (save-excursion
4449       (goto-char (point-min))
4450       (setq wl-summary-buffer-number-column
4451             (or
4452              (if (and update
4453                       (setq end (if (re-search-forward "^ *[0-9]+[^0-9]" nil t)
4454                                     (point))))
4455                  (- end (progn (beginning-of-line) (point)) 1))
4456              (wl-get-assoc-list-value wl-summary-number-column-alist
4457                                       wl-summary-buffer-folder-name)
4458              wl-summary-default-number-column))
4459       (setq wl-summary-buffer-number-regexp
4460             (wl-repeat-string "." wl-summary-buffer-number-column)))))
4461
4462 (defsubst wl-summary-proc-wday (wday-str year month mday)
4463   (save-match-data
4464     (if (string-match "\\([A-Z][a-z][a-z]\\).*" wday-str)
4465         (wl-match-string 1 wday-str)
4466       (elmo-date-get-week year month mday))))
4467
4468 (defmacro wl-summary-cursor-move-regex ()
4469   (` (let ((mark-alist
4470             (if (elmo-folder-plugged-p wl-summary-buffer-folder-name)
4471                 (cond ((eq wl-summary-move-order 'new)
4472                        (list
4473                         (list
4474                          wl-summary-new-mark)
4475                         (list
4476                          wl-summary-unread-uncached-mark
4477                          wl-summary-unread-cached-mark
4478                          wl-summary-important-mark)))
4479                       ((eq wl-summary-move-order 'unread)
4480                        (list
4481                        (list
4482                         wl-summary-unread-uncached-mark
4483                         wl-summary-unread-cached-mark
4484                         wl-summary-new-mark)
4485                        (list
4486                         wl-summary-important-mark)))
4487                       (t
4488                        (list
4489                        (list
4490                         wl-summary-unread-uncached-mark
4491                         wl-summary-unread-cached-mark
4492                         wl-summary-new-mark
4493                         wl-summary-important-mark))))
4494               (cond ((eq wl-summary-move-order 'unread)
4495                      (list
4496                      (list
4497                       wl-summary-unread-cached-mark)
4498                      (list
4499                       wl-summary-important-mark)))
4500                     (t
4501                      (list
4502                      (list
4503                       wl-summary-unread-cached-mark
4504                       wl-summary-important-mark)))))))
4505        (mapcar
4506         (function
4507          (lambda (mark-list)
4508            (concat wl-summary-message-regexp
4509                    ".\\("
4510                    (mapconcat 'regexp-quote
4511                               mark-list
4512                               "\\|")
4513                    "\\)\\|"
4514                    wl-summary-message-regexp "\\*")))
4515         mark-alist))))
4516
4517 ;;
4518 ;; Goto unread or important
4519 ;;
4520 (defun wl-summary-cursor-up (&optional hereto)
4521   (interactive "P")
4522   (if (and (not wl-summary-buffer-target-mark-list)
4523            (eq wl-summary-buffer-view 'thread))
4524       (progn
4525         (if (eobp)
4526             (forward-line -1))
4527         (wl-thread-jump-to-prev-unread hereto))
4528     (if hereto
4529         (end-of-line)
4530       (beginning-of-line))
4531     (let ((case-fold-search nil)
4532           regex-list)
4533       (setq regex-list (wl-summary-cursor-move-regex))
4534       (catch 'done
4535         (while regex-list
4536           (when (re-search-backward
4537                  (car regex-list)
4538                  nil t nil)
4539             (beginning-of-line)
4540             (throw 'done t))
4541           (setq regex-list (cdr regex-list)))
4542         (beginning-of-line)
4543         (throw 'done nil)))))
4544
4545 ;;
4546 ;; Goto unread or important
4547 ;; returns t if next message exists in this folder.
4548 (defun wl-summary-cursor-down (&optional hereto)
4549   (interactive "P")
4550   (if (and (null wl-summary-buffer-target-mark-list)
4551            (eq wl-summary-buffer-view 'thread))
4552       (wl-thread-jump-to-next-unread hereto)
4553     (if hereto
4554         (beginning-of-line)
4555       (end-of-line))
4556     (let ((case-fold-search nil)
4557           regex-list)
4558       (setq regex-list (wl-summary-cursor-move-regex))
4559       (catch 'done
4560         (while regex-list
4561           (when (re-search-forward
4562                  (car regex-list)
4563                  nil t nil)
4564             (beginning-of-line)
4565             (throw 'done t))
4566           (setq regex-list (cdr regex-list)))
4567         (beginning-of-line)
4568         (throw 'done nil)))))
4569
4570 (defun wl-summary-save-view-cache ()
4571   (save-excursion
4572     (let* ((dir (elmo-msgdb-expand-path wl-summary-buffer-folder-name))
4573            (cache (expand-file-name wl-summary-cache-file dir))
4574            (view (expand-file-name wl-summary-view-file dir))
4575            ;;(coding-system-for-write wl-cs-cache)
4576            ;;(output-coding-system wl-cs-cache)
4577            (save-view wl-summary-buffer-view)
4578            (tmp-buffer (get-buffer-create " *wl-summary-save-view-cache*"))
4579            (charset wl-summary-buffer-mime-charset))
4580       (if (file-directory-p dir)
4581           (); ok.
4582         (if (file-exists-p dir)
4583             (error "File %s already exists" dir)
4584           (elmo-make-directory dir)))
4585       (if (eq save-view 'thread)
4586           (wl-thread-save-entity dir))
4587       (unwind-protect
4588           (progn
4589             (when (file-writable-p cache)
4590               (copy-to-buffer tmp-buffer (point-min) (point-max))
4591               (with-current-buffer tmp-buffer
4592                 (widen)
4593                 (encode-mime-charset-region
4594                  (point-min) (point-max) charset)
4595                 (as-binary-output-file
4596                  (write-region (point-min)
4597                                (point-max) cache nil 'no-msg))
4598                 (write-region (point-min) (point-max) cache nil
4599                               'no-msg)))
4600             (when (file-writable-p view) ; 'thread or 'sequence
4601               (save-excursion
4602                 (set-buffer tmp-buffer)
4603                 (erase-buffer)
4604                 (prin1 save-view tmp-buffer)
4605                 (princ "\n" tmp-buffer)
4606                 (write-region (point-min) (point-max) view nil 'no-msg))))
4607         ;; kill tmp buffer.
4608         (kill-buffer tmp-buffer)))))
4609
4610 (defsubst wl-summary-get-sync-range (folder)
4611   (intern (or (and
4612                (elmo-folder-plugged-p folder)
4613                (wl-get-assoc-list-value
4614                 wl-folder-sync-range-alist
4615                 folder))
4616               wl-default-sync-range)))
4617
4618 ;; redefined for wl-summary-sync-update
4619 (defun wl-summary-input-range (folder)
4620   "returns update or all or rescan."
4621   ;; for the case when parts are expanded in the bottom of the folder
4622   (let ((input-range-list '("update" "all" "rescan" "first:" "last:"
4623                             "no-sync" "rescan-noscore"))
4624         (default (or (wl-get-assoc-list-value
4625                       wl-folder-sync-range-alist
4626                       folder)
4627                      wl-default-sync-range))
4628         range)
4629     (setq range
4630           (completing-read (format "Range (%s): " default)
4631                            (mapcar
4632                             (function (lambda (x) (cons x x)))
4633                             input-range-list)))
4634     (if (string= range "")
4635         default
4636       range)))
4637
4638 (defun wl-summary-toggle-disp-folder (&optional arg)
4639   (interactive)
4640   (let (fld-buf fld-win
4641         (view-message-buffer (wl-message-get-buffer-create))
4642         (cur-buf (current-buffer))
4643         (summary-win (get-buffer-window (current-buffer))))
4644     (cond
4645      ((eq arg 'on)
4646       (setq wl-summary-buffer-disp-folder t)
4647       ;; hide your folder window
4648       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4649           (if (setq fld-win (get-buffer-window fld-buf))
4650               (delete-window fld-win))))
4651      ((eq arg 'off)
4652       (setq wl-summary-buffer-disp-folder nil)
4653       ;; hide your wl-message window!
4654       (wl-select-buffer view-message-buffer)
4655       (delete-window)
4656       (select-window (get-buffer-window cur-buf))
4657       ;; display wl-folder window!!
4658       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4659           (if (setq fld-win (get-buffer-window fld-buf))
4660               ;; folder win is already displayed.
4661               (select-window fld-win)
4662             ;; folder win is not displayed.
4663             (switch-to-buffer fld-buf))
4664         ;; no folder buf
4665         (wl-folder))
4666       ;; temporarily delete summary-win.
4667       (if summary-win
4668           (delete-window summary-win))
4669       (split-window-horizontally wl-folder-window-width)
4670       (other-window 1)
4671       (switch-to-buffer cur-buf))
4672      (t
4673       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4674           (if (setq fld-win (get-buffer-window fld-buf))
4675               (setq wl-summary-buffer-disp-folder nil)
4676             (setq wl-summary-buffer-disp-folder t)))
4677       (if (not wl-summary-buffer-disp-folder)
4678           ;; hide message window
4679           (let ((mes-win (get-buffer-window view-message-buffer))
4680                 (wl-stay-folder-window t))
4681             (if mes-win (delete-window mes-win))
4682             ;; hide your folder window
4683             (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4684                 (if (setq fld-win (get-buffer-window fld-buf))
4685                     (progn
4686                       (delete-window (get-buffer-window cur-buf))
4687                       (select-window fld-win)
4688                       (switch-to-buffer cur-buf))))
4689             (run-hooks 'wl-summary-toggle-disp-folder-off-hook)
4690             ;; resume message window.
4691             (when mes-win
4692               (wl-select-buffer view-message-buffer)
4693               (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
4694               (select-window (get-buffer-window cur-buf)))
4695             )
4696         (save-excursion
4697           ;; hide message window
4698           (let ((mes-win (get-buffer-window view-message-buffer))
4699                 (wl-stay-folder-window t))
4700             (if mes-win (delete-window mes-win))
4701             (select-window (get-buffer-window cur-buf))
4702             ;; display wl-folder window!!
4703             (if (setq fld-buf (get-buffer wl-folder-buffer-name))
4704                 (if (setq fld-win (get-buffer-window fld-buf))
4705                     ;; folder win is already displayed.
4706                     (select-window fld-win)
4707                   ;; folder win is not displayed...occupy all.
4708                   (switch-to-buffer fld-buf))
4709               ;; no folder buf
4710               (wl-folder))
4711             (split-window-horizontally wl-folder-window-width)
4712             (other-window 1)
4713             (switch-to-buffer cur-buf)
4714             ;; resume message window.
4715             (run-hooks 'wl-summary-toggle-disp-folder-on-hook)
4716             (when mes-win
4717               (wl-select-buffer view-message-buffer)
4718               (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
4719               (select-window (get-buffer-window cur-buf))))
4720           )))))
4721   (run-hooks 'wl-summary-toggle-disp-folder-hook))
4722
4723 (defun wl-summary-toggle-disp-msg (&optional arg)
4724   (interactive)
4725   (let (fld-buf fld-win
4726         (view-message-buffer (wl-message-get-buffer-create))
4727         (cur-buf (current-buffer))
4728         summary-win)
4729     (cond
4730      ((eq arg 'on)
4731       (setq wl-summary-buffer-disp-msg t)
4732       ;; hide your folder window
4733       (if (and (not wl-stay-folder-window)
4734                (setq fld-buf (get-buffer wl-folder-buffer-name)))
4735           (if (setq fld-win (get-buffer-window fld-buf))
4736               (delete-window fld-win))))
4737      ((eq arg 'off)
4738       (wl-delete-all-overlays)
4739       (setq wl-summary-buffer-disp-msg nil)
4740       (save-excursion
4741         (wl-select-buffer view-message-buffer)
4742         (delete-window)
4743         (and (get-buffer-window cur-buf)
4744              (select-window (get-buffer-window cur-buf)))
4745         (run-hooks 'wl-summary-toggle-disp-off-hook)))
4746      (t
4747       (if (get-buffer-window view-message-buffer) ; already displayed
4748           (setq wl-summary-buffer-disp-msg nil)
4749         (setq wl-summary-buffer-disp-msg t))
4750       (if wl-summary-buffer-disp-msg
4751           (progn
4752             (wl-summary-redisplay)
4753             ;; hide your folder window
4754 ;;              (setq fld-buf (get-buffer wl-folder-buffer-name))
4755 ;;              (if (setq fld-win (get-buffer-window fld-buf))
4756 ;;                  (delete-window fld-win)))
4757             (run-hooks 'wl-summary-toggle-disp-on-hook))
4758         (wl-delete-all-overlays)
4759         (save-excursion
4760           (wl-select-buffer view-message-buffer)
4761           (delete-window)
4762           (select-window (get-buffer-window cur-buf))
4763           (run-hooks 'wl-summary-toggle-disp-off-hook))
4764         ;;(switch-to-buffer cur-buf)
4765         )))))
4766
4767 (defun wl-summary-next-line-content ()
4768   (interactive)
4769   (let ((cur-buf (current-buffer)))
4770     (wl-summary-toggle-disp-msg 'on)
4771     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4772       (set-buffer cur-buf)
4773       (wl-message-next-page 1))))
4774
4775 (defun wl-summary-prev-line-content ()
4776   (interactive)
4777   (let ((cur-buf (current-buffer)))
4778     (wl-summary-toggle-disp-msg 'on)
4779     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
4780       (set-buffer cur-buf)
4781       (wl-message-prev-page 1))))
4782
4783 (defun wl-summary-next-page ()
4784   (interactive)
4785   (wl-message-next-page))
4786
4787 (defun wl-summary-prev-page ()
4788   (interactive)
4789   (wl-message-prev-page))
4790
4791 (defsubst wl-summary-no-mime-p (folder)
4792   (wl-string-match-member folder wl-summary-no-mime-folder-list))
4793
4794 (defun wl-summary-set-message-buffer-or-redisplay (&optional ignore-original)
4795   ;; if current message is not displayed, display it.
4796   ;; return t if exists.
4797   (let ((folder wl-summary-buffer-folder-name)
4798         (number (wl-summary-message-number))
4799         cur-folder cur-number message-last-pos
4800         (view-message-buffer (wl-message-get-buffer-create)))
4801     (save-excursion
4802       (set-buffer view-message-buffer)
4803       (setq cur-folder wl-message-buffer-cur-folder)
4804       (setq cur-number wl-message-buffer-cur-number))
4805     (if (and (not ignore-original)
4806              (not
4807               (and (eq number (wl-message-original-buffer-number))
4808                    (string= folder (wl-message-original-buffer-folder)))))
4809         (progn
4810           (if (wl-summary-no-mime-p folder)
4811               (wl-summary-redisplay-no-mime folder number)
4812             (wl-summary-redisplay-internal folder number))
4813           nil)
4814       (if (and (string= folder (or cur-folder ""))
4815                (eq number (or cur-number 0)))
4816           (progn
4817             (set-buffer view-message-buffer)
4818             t)
4819         (if (wl-summary-no-mime-p folder)
4820             (wl-summary-redisplay-no-mime folder number)
4821           (wl-summary-redisplay-internal folder number))
4822         nil))))
4823
4824 (defun wl-summary-target-mark-forward (&optional arg)
4825   (interactive "P")
4826   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
4827         (summary-buf (current-buffer))
4828         (wl-draft-forward t)
4829         start-point
4830         draft-buf)
4831     (wl-summary-jump-to-msg (car mlist))
4832     (wl-summary-forward t)
4833     (setq start-point (point))
4834     (setq draft-buf (current-buffer))
4835     (setq mlist (cdr mlist))
4836     (save-window-excursion
4837       (when mlist
4838         (while mlist
4839           (set-buffer summary-buf)
4840           (wl-summary-jump-to-msg (car mlist))
4841           (wl-summary-redisplay)
4842           (set-buffer draft-buf)
4843           (goto-char (point-max))
4844           (wl-draft-insert-message)
4845           (setq mlist (cdr mlist)))
4846         (wl-draft-body-goto-top)
4847         (wl-draft-enclose-digest-region (point) (point-max)))
4848       (goto-char start-point)
4849       (save-excursion
4850         (set-buffer summary-buf)
4851         (wl-summary-delete-all-temp-marks)))
4852     (run-hooks 'wl-mail-setup-hook)))
4853
4854 (defun wl-summary-target-mark-reply-with-citation (&optional arg)
4855   (interactive "P")
4856   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
4857         (summary-buf (current-buffer))
4858         change-major-mode-hook
4859         start-point
4860         draft-buf)
4861     (wl-summary-jump-to-msg (car mlist))
4862     (wl-summary-reply arg t)
4863     (goto-char (point-max))
4864     (setq start-point (point))
4865     (setq draft-buf (current-buffer))
4866     (save-window-excursion
4867       (while mlist
4868         (set-buffer summary-buf)
4869         (wl-summary-jump-to-msg (car mlist))
4870         (wl-summary-redisplay)
4871         (set-buffer draft-buf)
4872         (goto-char (point-max))
4873         (wl-draft-yank-original)
4874         (setq mlist (cdr mlist)))
4875       (goto-char start-point)
4876       (save-excursion
4877         (set-buffer summary-buf)
4878         (wl-summary-delete-all-temp-marks)))
4879     (run-hooks 'wl-mail-setup-hook)))
4880
4881 (defun wl-summary-reply-with-citation (&optional arg)
4882   (interactive "P")
4883   (when (wl-summary-reply arg t)
4884     (goto-char (point-max))
4885     (wl-draft-yank-original)
4886     (run-hooks 'wl-mail-setup-hook)))
4887
4888 (defun wl-summary-jump-to-msg-by-message-id (&optional id)
4889   (interactive)
4890   (let* ((original (wl-summary-message-number))
4891          (msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
4892          (number-alist (elmo-msgdb-get-number-alist wl-summary-buffer-msgdb))
4893          msg otherfld schar
4894          (errmsg
4895           (format "No message with id \"%s\" in the folder." msgid)))
4896     (if (setq msg (car (rassoc msgid number-alist)))
4897         ;;(wl-summary-jump-to-msg-internal
4898         ;;wl-summary-buffer-folder-name msg 'no-sync)
4899         (progn
4900           (wl-thread-jump-to-msg msg)
4901           t)
4902       ;; for XEmacs!
4903       (if (and elmo-use-database
4904                (setq errmsg
4905                      (format
4906                       "No message with id \"%s\" in the database." msgid))
4907                (setq otherfld (elmo-database-msgid-get msgid)))
4908           (if (cdr (wl-summary-jump-to-msg-internal
4909                     (car otherfld) (nth 1 otherfld) 'no-sync))
4910               t ; succeed.
4911             ;; Back to original.
4912             (wl-summary-jump-to-msg-internal
4913              wl-summary-buffer-folder-name original 'no-sync))
4914         (cond ((eq wl-summary-search-via-nntp 'confirm)
4915                (message "Search message in nntp server \"%s\" <y/n/s(elect)>?"
4916                         elmo-default-nntp-server)
4917                (setq schar (read-char))
4918                (cond ((eq schar ?y)
4919                       (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
4920                      ((eq schar ?s)
4921                       (wl-summary-jump-to-msg-by-message-id-via-nntp
4922                        msgid
4923                        (read-from-minibuffer "NNTP Server: ")))
4924                      (t
4925                       (message errmsg)
4926                       nil)))
4927               (wl-summary-search-via-nntp
4928                (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
4929               (t
4930                (message errmsg)
4931                nil))))))
4932
4933 (defun wl-summary-jump-to-msg-by-message-id-via-nntp (&optional id server-spec)
4934   (interactive)
4935   (let* ((msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
4936          newsgroups folder ret
4937          user server port type spec)
4938     (if server-spec
4939         (if (string-match "^-" server-spec)
4940             (setq spec (elmo-nntp-get-spec server-spec)
4941                   user (nth 2 spec)
4942                   server (nth 3 spec)
4943                   port (nth 4 spec)
4944                   type (nth 5 spec))
4945           (setq server server-spec)))
4946     (when (setq ret (elmo-nntp-get-newsgroup-by-msgid
4947                      msgid
4948                      (or server elmo-default-nntp-server)
4949                      (or user elmo-default-nntp-user)
4950                      (or port elmo-default-nntp-port)
4951                      (or type elmo-default-nntp-stream-type)))
4952       (setq newsgroups (wl-parse-newsgroups ret))
4953       (setq folder (concat "-" (car newsgroups)
4954                            (elmo-nntp-folder-postfix user server port type)))
4955       (catch 'found
4956         (while newsgroups
4957           (if (wl-folder-entity-exists-p (car newsgroups)
4958                                          wl-folder-newsgroups-hashtb)
4959               (throw 'found
4960                      (setq folder (concat "-" (car newsgroups)
4961                                           (elmo-nntp-folder-postfix
4962                                            user server port type)))))
4963           (setq newsgroups (cdr newsgroups)))))
4964     (if ret
4965         (wl-summary-jump-to-msg-internal folder nil 'update msgid)
4966       (message "No message id \"%s\" in nntp server \"%s\"."
4967                msgid (or server elmo-default-nntp-server))
4968       nil)))
4969
4970 (defun wl-summary-jump-to-msg-internal (folder msg scan-type &optional msgid)
4971   (let (wl-auto-select-first entity)
4972     (if (or (string= folder wl-summary-buffer-folder-name)
4973             (y-or-n-p
4974              (format
4975               "Message was found in the folder \"%s\". Jump to it? "
4976               folder)))
4977         (progn
4978           (unwind-protect
4979               (wl-summary-goto-folder-subr
4980                folder scan-type nil nil t)
4981             (if msgid
4982                 (setq msg
4983                       (car (rassoc msgid
4984                                    (elmo-msgdb-get-number-alist
4985                                     wl-summary-buffer-msgdb)))))
4986             (setq entity (wl-folder-search-entity-by-name folder
4987                                                           wl-folder-entity
4988                                                           'folder))
4989             (if entity
4990                 (wl-folder-set-current-entity-id
4991                  (wl-folder-get-entity-id entity))))
4992           (if (null msg)
4993               (message "Message was not found currently in this folder.")
4994             (setq msg (and (wl-thread-jump-to-msg msg) msg)))
4995           (cons folder msg)))))
4996
4997 (defun wl-summary-jump-to-parent-message (arg)
4998   (interactive "P")
4999   (let ((cur-buf (current-buffer))
5000         (number (wl-summary-message-number))
5001         (regexp "\\(<[^<>]*>\\)[ \t]*$")
5002         (i -1) ;; xxx
5003         msg-id msg-num ref-list ref irt)
5004     (if (null number)
5005         (message "No message.")
5006       (when (eq wl-summary-buffer-view 'thread)
5007         (cond ((and arg (not (numberp arg)))
5008                (setq msg-num
5009                      (wl-thread-entity-get-number
5010                       (wl-thread-entity-get-top-entity
5011                        (wl-thread-get-entity number)))))
5012               ((and arg (numberp arg))
5013                (setq i 0)
5014                (setq msg-num number)
5015                (while (< i arg)
5016                  (setq msg-num
5017                        (wl-thread-entity-get-number
5018                         (wl-thread-entity-get-parent-entity
5019                          (wl-thread-get-entity msg-num))))
5020                  (setq i (1+ i))))
5021               (t (setq msg-num
5022                        (wl-thread-entity-get-number
5023                         (wl-thread-entity-get-parent-entity
5024                          (wl-thread-get-entity number)))))))
5025       (when (null msg-num)
5026         (wl-summary-set-message-buffer-or-redisplay)
5027         (set-buffer (wl-message-get-original-buffer))
5028         (message "Searching parent message...")
5029         (setq ref (std11-field-body "References")
5030               irt (std11-field-body "In-Reply-To"))
5031         (cond
5032          ((and arg (not (numberp arg)) ref (not (string= ref ""))
5033                (string-match regexp ref))
5034           ;; The first message of the thread.
5035           (setq msg-id (wl-match-string 1 ref)))
5036          ;; "In-Reply-To:" has only one msg-id.
5037          ((and (null arg) irt (not (string= irt ""))
5038                (string-match regexp irt))
5039           (setq msg-id (wl-match-string 1 irt)))
5040          ((and (or (null arg) (numberp arg)) ref (not (string= ref ""))
5041                (string-match regexp ref))
5042           ;; "^" searching parent, "C-u 2 ^" looking for grandparent.
5043           (while (string-match regexp ref)
5044             (setq ref-list
5045                   (append (list
5046                            (wl-match-string 1 ref))
5047                           ref-list))
5048             (setq ref (substring ref (match-end 0)))
5049             (setq i (1+ i)))
5050           (setq msg-id
5051                 (if (null arg) (nth 0 ref-list) ;; previous
5052                   (if (<= arg i) (nth (1- arg) ref-list)
5053                     (nth i ref-list)))))))
5054       (set-buffer cur-buf)
5055       (cond ((and (null msg-id) (null msg-num))
5056              (message "No parent message!")
5057              nil)
5058             ((and msg-id (wl-summary-jump-to-msg-by-message-id msg-id))
5059              (wl-summary-redisplay)
5060              (message "Searching parent message...done.")
5061              t)
5062             ((and msg-num (wl-summary-jump-to-msg msg-num))
5063              (wl-summary-redisplay)
5064              (message "Searching parent message...done.")
5065              t)
5066             (t ; failed.
5067              (message "Parent message was not found.")
5068              nil)))))
5069
5070 (defun wl-summary-reply (&optional arg without-setup-hook)
5071   "Reply to current message. Default is \"wide\" reply.
5072 Reply to author if invoked with argument."
5073   (interactive "P")
5074   (let ((folder wl-summary-buffer-folder-name)
5075         (number (wl-summary-message-number))
5076         (summary-buf (current-buffer))
5077         mes-buf)
5078     (if number
5079         (unwind-protect
5080             (progn
5081               (wl-summary-redisplay-internal folder number)
5082               (wl-select-buffer
5083                (get-buffer (setq mes-buf (wl-current-message-buffer))))
5084               (set-buffer mes-buf)
5085               (goto-char (point-min))
5086               (or wl-draft-use-frame
5087                   (split-window-vertically))
5088               (other-window 1)
5089               (when (setq mes-buf (wl-message-get-original-buffer))
5090                 (wl-draft-reply mes-buf (not arg) summary-buf)
5091                 (unless without-setup-hook
5092                   (run-hooks 'wl-mail-setup-hook)))
5093               t)))))
5094
5095 (defun wl-summary-write ()
5096   "Write a new draft from Summary."
5097   (interactive)
5098   (wl-draft nil nil nil nil nil
5099             nil nil nil nil nil nil (current-buffer))
5100   (run-hooks 'wl-mail-setup-hook)
5101   (mail-position-on-field "To"))
5102
5103 (defun wl-summary-write-current-newsgroup (&optional folder)
5104   (interactive)
5105   (let* ((folder (or folder wl-summary-buffer-folder-name))
5106          (flist (elmo-folder-get-primitive-folder-list folder))
5107          newsgroups fld ret)
5108     (while (setq fld (car flist))
5109       (if (setq ret
5110                 (cond ((eq 'nntp (elmo-folder-get-type fld))
5111                        (nth 1 (elmo-folder-get-spec fld)))
5112                       ((eq 'localnews (elmo-folder-get-type fld))
5113                        (elmo-replace-in-string
5114                         (nth 1 (elmo-folder-get-spec fld)) "/" "\\."))))
5115           (setq newsgroups (cond (newsgroups
5116                                   (concat newsgroups "," ret))
5117                                  (t ret))))
5118       (setq flist (cdr flist)))
5119     (if newsgroups
5120         (progn
5121           (wl-draft nil nil nil nil nil newsgroups)
5122           (run-hooks 'wl-mail-setup-hook))
5123       (error "%s is not newsgroup" folder))))
5124
5125 (defun wl-summary-forward (&optional without-setup-hook)
5126   (interactive)
5127   (let ((folder wl-summary-buffer-folder-name)
5128         (number (wl-summary-message-number))
5129         (summary-buf (current-buffer))
5130         (wl-draft-forward t)
5131         entity subject num)
5132     (if (null number)
5133         (message "No message.")
5134       (wl-summary-redisplay-internal folder number)
5135       (wl-select-buffer (get-buffer wl-message-buf-name))
5136       (or wl-draft-use-frame
5137           (split-window-vertically))
5138       (other-window 1)
5139       ;; get original subject.
5140       (if summary-buf
5141           (save-excursion
5142             (set-buffer summary-buf)
5143             (setq num (wl-summary-message-number))
5144             (setq entity (assoc (cdr (assq num
5145                                            (elmo-msgdb-get-number-alist
5146                                             wl-summary-buffer-msgdb)))
5147                                 (elmo-msgdb-get-overview
5148                                  wl-summary-buffer-msgdb)))
5149             (and entity
5150                  (setq subject
5151                        (or (elmo-msgdb-overview-entity-get-subject entity)
5152                            "")))))
5153       (wl-draft-forward subject summary-buf)
5154       (unless without-setup-hook
5155         (run-hooks 'wl-mail-setup-hook)))))
5156
5157 (defun wl-summary-click (e)
5158   (interactive "e")
5159   (mouse-set-point e)
5160   (wl-summary-read))
5161
5162 (defun wl-summary-read ()
5163   (interactive)
5164   (let ((folder wl-summary-buffer-folder-name)
5165         (number (wl-summary-message-number))
5166         cur-folder cur-number message-last-pos
5167         (view-message-buffer (get-buffer-create wl-message-buf-name))
5168         (sticky-buf-name (and (wl-summary-sticky-p) wl-message-buf-name))
5169         (summary-buf-name (buffer-name)))
5170     (save-excursion
5171       (set-buffer view-message-buffer)
5172       (when (and sticky-buf-name
5173                  (not (wl-local-variable-p 'wl-message-buf-name
5174                                            (current-buffer))))
5175         (make-local-variable 'wl-message-buf-name)
5176         (setq wl-message-buf-name sticky-buf-name)
5177         (make-local-variable 'wl-message-buffer-cur-summary-buffer)
5178         (setq wl-message-buffer-cur-summary-buffer summary-buf-name))
5179       (setq cur-folder wl-message-buffer-cur-folder)
5180       (setq cur-number wl-message-buffer-cur-number))
5181     (wl-summary-toggle-disp-msg 'on)
5182     (if (and (string= folder cur-folder)
5183              (eq number cur-number))
5184         (progn
5185           (if (wl-summary-next-page)
5186               (wl-summary-down t)))
5187 ;           (wl-summary-scroll-up-content)))
5188       (if (wl-summary-no-mime-p folder)
5189           (wl-summary-redisplay-no-mime folder number)
5190         (wl-summary-redisplay-internal folder number)))))
5191
5192 (defun wl-summary-prev (&optional interactive)
5193   (interactive)
5194   (if wl-summary-move-direction-toggle
5195       (setq wl-summary-move-direction-downward nil))
5196   (let ((type (elmo-folder-get-type wl-summary-buffer-folder-name))
5197         (skip-mark-regexp (mapconcat
5198                            'regexp-quote
5199                            wl-summary-skip-mark-list ""))
5200         goto-next regex-list regex next-entity finfo)
5201     (beginning-of-line)
5202     (if (elmo-folder-plugged-p wl-summary-buffer-folder-name)
5203         (setq regex (format "^%s[^%s]"
5204                             wl-summary-buffer-number-regexp
5205                             skip-mark-regexp))
5206       (setq regex (format "^%s[^%s]\\(%s\\|%s\\| \\)"
5207                           wl-summary-buffer-number-regexp
5208                           skip-mark-regexp
5209                           (regexp-quote wl-summary-unread-cached-mark)
5210                           (regexp-quote wl-summary-important-mark))))
5211     (unless (re-search-backward regex nil t)
5212       (setq goto-next t))
5213     (beginning-of-line)
5214     (if (not goto-next)
5215         (progn
5216           (if wl-summary-buffer-disp-msg
5217               (wl-summary-redisplay)))
5218       (if (or interactive (interactive-p))
5219           (if wl-summary-buffer-prev-folder-func
5220               (funcall wl-summary-buffer-prev-folder-func)
5221             (when wl-auto-select-next
5222               (setq next-entity (wl-summary-get-prev-folder))
5223               (if next-entity
5224                   (setq finfo (wl-folder-get-entity-info next-entity))))
5225             (wl-ask-folder
5226              '(lambda () (wl-summary-next-folder-or-exit next-entity))
5227              (format
5228               "No more messages. Type SPC to go to %s."
5229               (wl-summary-entity-info-msg next-entity finfo))))))))
5230
5231 (defun wl-summary-next (&optional interactive)
5232   (interactive)
5233   (if wl-summary-move-direction-toggle
5234       (setq wl-summary-move-direction-downward t))
5235   (let ((type (elmo-folder-get-type wl-summary-buffer-folder-name))
5236         (skip-mark-regexp (mapconcat
5237                            'regexp-quote
5238                            wl-summary-skip-mark-list ""))
5239         goto-next regex regex-list next-entity finfo)
5240     (end-of-line)
5241     (if (elmo-folder-plugged-p wl-summary-buffer-folder-name)
5242         (setq regex (format "^%s[^%s]"
5243                             wl-summary-buffer-number-regexp
5244                             skip-mark-regexp))
5245       (setq regex (format "^%s[^%s]\\(%s\\|%s\\| \\)"
5246                           wl-summary-buffer-number-regexp
5247                           skip-mark-regexp
5248                           (regexp-quote wl-summary-unread-cached-mark)
5249                           (regexp-quote wl-summary-important-mark))))
5250     (unless (re-search-forward regex nil t)
5251       (forward-line 1)
5252       (setq goto-next t))
5253     (beginning-of-line)
5254     (if (not goto-next)
5255         (if wl-summary-buffer-disp-msg
5256             (wl-summary-redisplay))
5257       (if (or interactive (interactive-p))
5258           (if wl-summary-buffer-next-folder-func
5259               (funcall wl-summary-buffer-next-folder-func)
5260             (when wl-auto-select-next
5261               (setq next-entity (wl-summary-get-next-folder))
5262               (if next-entity
5263                   (setq finfo (wl-folder-get-entity-info next-entity))))
5264             (wl-ask-folder
5265              '(lambda () (wl-summary-next-folder-or-exit next-entity))
5266              (format
5267               "No more messages. Type SPC to go to %s."
5268               (wl-summary-entity-info-msg next-entity finfo))))))))
5269
5270 (defun wl-summary-up (&optional interactive skip-no-unread)
5271   (interactive)
5272   (if wl-summary-move-direction-toggle
5273       (setq wl-summary-move-direction-downward nil))
5274   (if (wl-summary-cursor-up)
5275       (if wl-summary-buffer-disp-msg
5276           (wl-summary-redisplay))
5277     (if (or interactive
5278             (interactive-p))
5279         (if wl-summary-buffer-prev-folder-func
5280             (funcall wl-summary-buffer-prev-folder-func)
5281           (let (next-entity finfo)
5282             (when wl-auto-select-next
5283               (progn
5284                 (setq next-entity (wl-summary-get-prev-unread-folder))
5285                 (if next-entity
5286                     (setq finfo (wl-folder-get-entity-info next-entity)))))
5287             (if (and skip-no-unread
5288                      (eq wl-auto-select-next 'skip-no-unread))
5289                 (wl-summary-next-folder-or-exit next-entity t)
5290               (wl-ask-folder
5291                '(lambda () (wl-summary-next-folder-or-exit next-entity t))
5292                (format
5293                 "No more unread messages. Type SPC to go to %s."
5294                 (wl-summary-entity-info-msg next-entity finfo)))))))))
5295
5296 (defun wl-summary-get-prev-folder ()
5297   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5298         last-entity cur-id)
5299     (when folder-buf
5300       (setq cur-id (save-excursion (set-buffer folder-buf)
5301                                    wl-folder-buffer-cur-entity-id))
5302       (wl-folder-get-prev-folder cur-id))))
5303
5304 (defun wl-summary-get-next-folder ()
5305   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5306         cur-id)
5307     (when folder-buf
5308       (setq cur-id (save-excursion (set-buffer folder-buf)
5309                                    wl-folder-buffer-cur-entity-id))
5310       (wl-folder-get-next-folder cur-id))))
5311
5312 (defun wl-summary-get-next-unread-folder ()
5313   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5314         cur-id)
5315     (when folder-buf
5316       (setq cur-id (save-excursion (set-buffer folder-buf)
5317                                    wl-folder-buffer-cur-entity-id))
5318       (wl-folder-get-next-folder cur-id 'unread))))
5319
5320 (defun wl-summary-get-prev-unread-folder ()
5321   (let ((folder-buf (get-buffer wl-folder-buffer-name))
5322         cur-id)
5323     (when folder-buf
5324       (setq cur-id (save-excursion (set-buffer folder-buf)
5325                                    wl-folder-buffer-cur-entity-id))
5326       (wl-folder-get-prev-folder cur-id 'unread))))
5327
5328 (defun wl-summary-down (&optional interactive skip-no-unread)
5329   (interactive)
5330   (if wl-summary-move-direction-toggle
5331       (setq wl-summary-move-direction-downward t))
5332   (if (wl-summary-cursor-down)
5333       (if wl-summary-buffer-disp-msg
5334           (wl-summary-redisplay))
5335     (if (or interactive
5336             (interactive-p))
5337         (if wl-summary-buffer-next-folder-func
5338             (funcall wl-summary-buffer-next-folder-func)
5339           (let (next-entity finfo)
5340             (when wl-auto-select-next
5341               (setq next-entity (wl-summary-get-next-unread-folder)))
5342             (if next-entity
5343                 (setq finfo (wl-folder-get-entity-info next-entity)))
5344             (if (and skip-no-unread
5345                      (eq wl-auto-select-next 'skip-no-unread))
5346                 (wl-summary-next-folder-or-exit next-entity)
5347               (wl-ask-folder
5348                '(lambda () (wl-summary-next-folder-or-exit next-entity))
5349                (format
5350                 "No more unread messages. Type SPC to go to %s."
5351                 (wl-summary-entity-info-msg next-entity finfo)))))))))
5352
5353 (defun wl-summary-goto-last-displayed-msg ()
5354   (interactive)
5355   (unless wl-summary-buffer-last-displayed-msg
5356     (setq wl-summary-buffer-last-displayed-msg
5357           wl-summary-buffer-current-msg))
5358   (if wl-summary-buffer-last-displayed-msg
5359       (progn
5360         (wl-summary-jump-to-msg wl-summary-buffer-last-displayed-msg)
5361         (if wl-summary-buffer-disp-msg
5362             (wl-summary-redisplay)))
5363     (message "No last message.")))
5364
5365 (defun wl-summary-redisplay (&optional arg)
5366   (interactive "P")
5367   (if (and (not arg)
5368            (wl-summary-no-mime-p wl-summary-buffer-folder-name))
5369       (wl-summary-redisplay-no-mime)
5370     (wl-summary-redisplay-internal nil nil arg)))
5371
5372 (defsubst wl-summary-redisplay-internal (&optional folder number force-reload)
5373   (interactive)
5374   (let* ((msgdb wl-summary-buffer-msgdb)
5375          (fld (or folder wl-summary-buffer-folder-name))
5376          (num (or number (wl-summary-message-number)))
5377          (wl-mime-charset      wl-summary-buffer-mime-charset)
5378          (default-mime-charset wl-summary-buffer-mime-charset)
5379          (wl-message-redisplay-func
5380           wl-summary-buffer-message-redisplay-func)
5381          fld-buf fld-win thr-entity)
5382     (if (and wl-thread-open-reading-thread
5383              (eq wl-summary-buffer-view 'thread)
5384              (not (wl-thread-entity-get-opened
5385                    (setq thr-entity (wl-thread-get-entity
5386                                      num))))
5387              (wl-thread-entity-get-children thr-entity))
5388         (wl-thread-force-open))
5389     (if num
5390         (progn
5391           (setq wl-summary-buffer-disp-msg t)
5392           (setq wl-summary-buffer-last-displayed-msg
5393                 wl-summary-buffer-current-msg)
5394           ;; hide folder window
5395           (if (and (not wl-stay-folder-window)
5396                    (setq fld-buf (get-buffer wl-folder-buffer-name)))
5397               (if (setq fld-win (get-buffer-window fld-buf))
5398                   (delete-window fld-win)))
5399           (setq wl-current-summary-buffer (current-buffer))
5400           (if (wl-message-redisplay fld num 'mime msgdb force-reload)
5401               (wl-summary-mark-as-read nil
5402                                        ;; cached, then change server-mark.
5403                                        (if wl-message-cache-used
5404                                            nil
5405                                          ;; plugged, then leave server-mark.
5406                                          (if (and
5407                                               (not
5408                                                (elmo-folder-local-p
5409                                                 wl-summary-buffer-folder-name))
5410                                               (elmo-folder-plugged-p
5411                                                wl-summary-buffer-folder-name))
5412                                              'leave))
5413                                        t ; displayed
5414                                        nil
5415                                        'cached ; cached by reading.
5416                                        )
5417             )
5418           (setq wl-summary-buffer-current-msg num)
5419           (when wl-summary-recenter
5420             (recenter (/ (- (window-height) 2) 2))
5421             (if (not wl-summary-width)
5422                 (wl-horizontal-recenter)))
5423           (wl-highlight-summary-displaying)
5424           (wl-cache-prefetch-next fld num (current-buffer))
5425           (run-hooks 'wl-summary-redisplay-hook))
5426       (message "No message to display."))))
5427
5428 (defun wl-summary-redisplay-no-mime (&optional folder number)
5429   (interactive)
5430   (let* ((msgdb wl-summary-buffer-msgdb)
5431          (fld (or folder wl-summary-buffer-folder-name))
5432          (num (or number (wl-summary-message-number)))
5433          (wl-mime-charset      wl-summary-buffer-mime-charset)
5434          (default-mime-charset wl-summary-buffer-mime-charset)
5435          wl-break-pages)
5436     (if num
5437         (progn
5438           (setq wl-summary-buffer-disp-msg t)
5439           (setq wl-summary-buffer-last-displayed-msg
5440                 wl-summary-buffer-current-msg)
5441           (setq wl-current-summary-buffer (current-buffer))
5442           (wl-normal-message-redisplay fld num 'no-mime msgdb)
5443           (wl-summary-mark-as-read nil nil t)
5444           (setq wl-summary-buffer-current-msg num)
5445           (when wl-summary-recenter
5446             (recenter (/ (- (window-height) 2) 2))
5447             (if (not wl-summary-width)
5448                 (wl-horizontal-recenter)))
5449           (wl-highlight-summary-displaying)
5450           (run-hooks 'wl-summary-redisplay-hook))
5451       (message "No message to display.")
5452       (wl-ask-folder 'wl-summary-exit
5453                      "No more messages. Type SPC to go to folder mode."))))
5454
5455 (defun wl-summary-redisplay-all-header (&optional folder number)
5456   (interactive)
5457   (let* ((msgdb wl-summary-buffer-msgdb)
5458          (fld (or folder wl-summary-buffer-folder-name))
5459          (num (or number (wl-summary-message-number)))
5460          (wl-mime-charset      wl-summary-buffer-mime-charset)
5461          (default-mime-charset wl-summary-buffer-mime-charset)
5462          (wl-message-redisplay-func wl-summary-buffer-message-redisplay-func))
5463     (if num
5464         (progn
5465           (setq wl-summary-buffer-disp-msg t)
5466           (setq wl-summary-buffer-last-displayed-msg
5467                 wl-summary-buffer-current-msg)
5468           (setq wl-current-summary-buffer (current-buffer))
5469           (if (wl-message-redisplay fld num 'all-header msgdb); t if displayed.
5470               (wl-summary-mark-as-read nil nil t))
5471           (setq wl-summary-buffer-current-msg num)
5472           (when wl-summary-recenter
5473             (recenter (/ (- (window-height) 2) 2))
5474             (if (not wl-summary-width)
5475                 (wl-horizontal-recenter)))
5476           (wl-highlight-summary-displaying)
5477           (run-hooks 'wl-summary-redisplay-hook))
5478       (message "No message to display."))))
5479
5480 (defun wl-summary-jump-to-current-message ()
5481   (interactive)
5482   (let (message-buf message-win)
5483     (if (setq message-buf (get-buffer wl-message-buf-name))
5484         (if (setq message-win (get-buffer-window message-buf))
5485             (select-window message-win)
5486           (wl-select-buffer (get-buffer wl-message-buf-name)))
5487       (wl-summary-redisplay)
5488       (wl-select-buffer (get-buffer wl-message-buf-name)))
5489     (goto-char (point-min))))
5490
5491 (defun wl-summary-cancel-message ()
5492   "Cancel an article on news."
5493   (interactive)
5494   (if (null (wl-summary-message-number))
5495       (message "No message.")
5496     (let ((summary-buf (current-buffer))
5497           message-buf)
5498       (wl-summary-set-message-buffer-or-redisplay)
5499       (if (setq message-buf (wl-message-get-original-buffer))
5500           (set-buffer message-buf))
5501       (unless (wl-message-news-p)
5502         (error "This is not a news article; canceling is impossible"))
5503       (when (yes-or-no-p "Do you really want to cancel this article? ")
5504         (let (from newsgroups message-id distribution buf)
5505           (save-excursion
5506             (setq from (std11-field-body "from")
5507                   newsgroups (std11-field-body "newsgroups")
5508                   message-id (std11-field-body "message-id")
5509                   distribution (std11-field-body "distribution"))
5510             ;; Make sure that this article was written by the user.
5511             (unless (wl-address-user-mail-address-p
5512                      (wl-address-header-extract-address
5513                       (car (wl-parse-addresses from))))
5514               (error "This article is not yours"))
5515             ;; Make control message.
5516             (setq buf (set-buffer (get-buffer-create " *message cancel*")))
5517             (setq wl-draft-buffer-cur-summary-buffer summary-buf)
5518             (buffer-disable-undo (current-buffer))
5519             (erase-buffer)
5520             (insert "Newsgroups: " newsgroups "\n"
5521                     "From: " (wl-address-header-extract-address
5522                               wl-from) "\n"
5523                               "Subject: cmsg cancel " message-id "\n"
5524                               "Control: cancel " message-id "\n"
5525                               (if distribution
5526                                   (concat "Distribution: " distribution "\n")
5527                                 "")
5528                               mail-header-separator "\n"
5529                               wl-summary-cancel-message)
5530             (message "Canceling your message...")
5531             (wl-draft-raw-send t t) ; kill when done, force-pre-hooks.
5532             (message "Canceling your message...done")))))))
5533
5534 (defun wl-summary-supersedes-message ()
5535   "Supersede current message."
5536   (interactive)
5537   (let ((summary-buf (current-buffer))
5538         (mmelmo-force-fetch-entire-message t)
5539         message-buf from)
5540     (wl-summary-set-message-buffer-or-redisplay)
5541     (if (setq message-buf (wl-message-get-original-buffer))
5542         (set-buffer message-buf))
5543     (unless (wl-message-news-p)
5544       (error "This is not a news article; supersedes is impossible"))
5545     (save-excursion
5546       (setq from (std11-field-body "from"))
5547       ;; Make sure that this article was written by the user.
5548       (unless (wl-address-user-mail-address-p
5549                (wl-address-header-extract-address
5550                 (car (wl-parse-addresses from))))
5551         (error "This article is not yours"))
5552       (let* ((message-id (std11-field-body "message-id"))
5553              (followup-to (std11-field-body "followup-to"))
5554              (mail-default-headers
5555               (concat mail-default-headers
5556                       "Supersedes: " message-id "\n"
5557                       (and followup-to
5558                            (concat "Followup-To: " followup-to "\n")))))
5559         (set-buffer (wl-message-get-original-buffer))
5560         (wl-draft-edit-string (buffer-substring (point-min) (point-max)))))))
5561
5562 (defun wl-summary-save (&optional arg wl-save-dir)
5563   (interactive)
5564   (let ((filename)
5565         (num (wl-summary-message-number))
5566         (mmelmo-force-fetch-entire-message t))
5567     (if (null wl-save-dir)
5568         (setq wl-save-dir wl-tmp-dir))
5569     (if num
5570         (save-excursion
5571           (setq filename (expand-file-name
5572                           (int-to-string num)
5573                           wl-save-dir))
5574           (if (null (and arg
5575                          (null (file-exists-p filename))))
5576               (setq filename
5577                     (read-file-name "Save to file: " filename)))
5578
5579           (wl-summary-set-message-buffer-or-redisplay)
5580           (set-buffer (wl-message-get-original-buffer))
5581           (if (and (null arg) (file-exists-p filename))
5582               (if (y-or-n-p "file already exists. override it?")
5583                   (write-region (point-min) (point-max) filename))
5584             (write-region (point-min) (point-max) filename)))
5585       (message "No message to save."))
5586     num))
5587
5588 (defun wl-summary-save-region (beg end)
5589   (interactive "r")
5590   (save-excursion
5591     (save-restriction
5592       (narrow-to-region beg end)
5593       (goto-char (point-min))
5594       (let ((wl-save-dir
5595              (wl-read-directory-name "Save to directory: " wl-tmp-dir)))
5596         (if (null (file-exists-p wl-save-dir))
5597             (make-directory wl-save-dir))
5598         (if (eq wl-summary-buffer-view 'thread)
5599             (progn
5600               (while (not (eobp))
5601                 (let* ((number (wl-summary-message-number))
5602                        (entity (wl-thread-get-entity number)))
5603                   (if (wl-thread-entity-get-opened entity)
5604                       (wl-summary-save t wl-save-dir)
5605                     ;; closed
5606                     (wl-summary-save t wl-save-dir))
5607                   (forward-line 1))))
5608           (while (not (eobp))
5609             (wl-summary-save t wl-save-dir)
5610             (forward-line 1)))))))
5611
5612 ;; mew-summary-pipe-message()
5613 (defun wl-summary-pipe-message (prefix command)
5614   "Send this message via pipe."
5615   (interactive (list current-prefix-arg nil))
5616   (if (null (wl-summary-message-number))
5617       (message "No message.")
5618     (setq command (read-string "Shell command on message: "
5619                                wl-summary-shell-command-last))
5620     (if (y-or-n-p "Send this message to pipe? ")
5621         (save-excursion
5622           (wl-summary-set-message-buffer-or-redisplay)
5623           (set-buffer (wl-message-get-original-buffer))
5624           (if (string= command "")
5625               (setq command wl-summary-shell-command-last))
5626           (goto-char (point-min)) ; perhaps this line won't be necessary
5627           (if prefix
5628               (search-forward "\n\n"))
5629           (shell-command-on-region (point) (point-max) command nil)
5630           (setq wl-summary-shell-command-last command)))))
5631
5632 (defun wl-summary-print-message (&optional arg)
5633   (interactive "P")
5634   (if (null (wl-summary-message-number))
5635       (message "No message.")
5636     (save-excursion
5637       (wl-summary-set-message-buffer-or-redisplay)
5638       (if (or (not (interactive-p))
5639               (y-or-n-p "Print ok?"))
5640           (progn
5641             (let* ((message-buffer (get-buffer wl-message-buf-name))
5642                    ;; (summary-buffer (get-buffer wl-summary-buffer-name))
5643                    (buffer (generate-new-buffer " *print*")))
5644               (set-buffer message-buffer)
5645               (copy-to-buffer buffer (point-min) (point-max))
5646               (set-buffer buffer)
5647               (funcall wl-print-buffer-func)
5648               (kill-buffer buffer)))
5649         (message "")))))
5650
5651 (defun wl-summary-print-message-with-ps-print (&optional filename)
5652   (interactive)
5653   (if (null (wl-summary-message-number))
5654       (message "No message.")
5655     (setq filename (ps-print-preprint current-prefix-arg))
5656     (if (or (not (interactive-p))
5657             (y-or-n-p "Print ok?"))
5658         (let ((summary-buffer (current-buffer))
5659               wl-break-pages)
5660           (save-excursion
5661             ;;(wl-summary-set-message-buffer-or-redisplay)
5662             (wl-summary-redisplay-internal)
5663             (let* ((message-buffer (get-buffer wl-message-buf-name))
5664                    (buffer (generate-new-buffer " *print*"))
5665                    (entity (progn
5666                              (set-buffer summary-buffer)
5667                              (assoc (cdr (assq
5668                                           (wl-summary-message-number)
5669                                           (elmo-msgdb-get-number-alist
5670                                            wl-summary-buffer-msgdb)))
5671                                     (elmo-msgdb-get-overview
5672                                      wl-summary-buffer-msgdb))))
5673                    (wl-ps-subject
5674                     (and entity
5675                          (or (elmo-msgdb-overview-entity-get-subject entity)
5676                              "")))
5677                    (wl-ps-from
5678                     (and entity
5679                          (or (elmo-msgdb-overview-entity-get-from entity) "")))
5680                    (wl-ps-date
5681                     (and entity
5682                          (or (elmo-msgdb-overview-entity-get-date entity) ""))))
5683               (run-hooks 'wl-ps-preprint-hook)
5684               (set-buffer message-buffer)
5685               (copy-to-buffer buffer (point-min) (point-max))
5686               (set-buffer buffer)
5687               (unwind-protect
5688                   (let ((ps-left-header
5689                          (list (concat "(" wl-ps-subject ")")
5690                                (concat "(" wl-ps-from ")")))
5691                         (ps-right-header
5692                          (list "/pagenumberstring load"
5693                                (concat "(" wl-ps-date ")"))))
5694                     (run-hooks 'wl-ps-print-hook)
5695                     (funcall wl-ps-print-buffer-func filename))
5696                 (kill-buffer buffer)))))
5697       (message ""))))
5698
5699 (if (featurep 'ps-print) ; ps-print is available.
5700     (fset 'wl-summary-print-message 'wl-summary-print-message-with-ps-print))
5701
5702 (defun wl-summary-folder-info-update ()
5703   (let ((folder (elmo-string wl-summary-buffer-folder-name))
5704         (num-db (elmo-msgdb-get-number-alist
5705                  wl-summary-buffer-msgdb)))
5706     (wl-folder-set-folder-updated folder
5707                                   (list 0
5708                                         (+ wl-summary-buffer-unread-count
5709                                            wl-summary-buffer-new-count)
5710                                         (length num-db)))))
5711
5712 (defun wl-summary-get-newsgroups ()
5713   (let ((spec-list (elmo-folder-get-primitive-spec-list
5714                     (elmo-string wl-summary-buffer-folder-name)))
5715         ng-list)
5716     (while spec-list
5717       (when (eq (caar spec-list) 'nntp)
5718         (wl-append ng-list (list (nth 1 (car spec-list)))))
5719       (setq spec-list (cdr spec-list)))
5720     ng-list))
5721
5722 (defun wl-summary-set-crosspost (&optional type redisplay)
5723   (let* ((number (wl-summary-message-number))
5724          (spec (elmo-folder-number-get-spec wl-summary-buffer-folder-name
5725                                             number))
5726          (folder (nth 1 spec))
5727          message-buf newsgroups)
5728     (when (eq (car spec) 'nntp)
5729       (if redisplay
5730           (wl-summary-redisplay))
5731       (save-excursion
5732         (if (setq message-buf (wl-message-get-original-buffer))
5733             (set-buffer message-buf))
5734         (setq newsgroups (std11-field-body "newsgroups")))
5735       (when newsgroups
5736         (let* ((msgdb wl-summary-buffer-msgdb)
5737                (num-db (elmo-msgdb-get-number-alist msgdb))
5738                (ng-list (wl-summary-get-newsgroups)) ;; for multi folder
5739                crosspost-folders)
5740           (when (setq crosspost-folders
5741                       (elmo-list-delete ng-list
5742                                         (wl-parse-newsgroups newsgroups t)))
5743             (elmo-crosspost-message-set (cdr (assq number num-db)) ;;message-id
5744                                         crosspost-folders
5745                                         type) ;;not used
5746             (setq wl-crosspost-alist-modified t)))))))
5747
5748 (defun wl-summary-is-crosspost-folder (spec-list fld-list)
5749   (let (fld flds)
5750     (while spec-list
5751       (if (and (eq (caar spec-list) 'nntp)
5752                (member (setq fld (nth 1 (car spec-list))) fld-list))
5753           (wl-append flds (list fld)))
5754       (setq spec-list (cdr spec-list)))
5755     flds))
5756
5757 (defun wl-summary-update-crosspost ()
5758   (let* ((msgdb wl-summary-buffer-msgdb)
5759          (number-alist (elmo-msgdb-get-number-alist msgdb))
5760          (mark-alist (elmo-msgdb-get-mark-alist msgdb))
5761          (spec-list (elmo-folder-get-primitive-spec-list
5762                      (elmo-string wl-summary-buffer-folder-name)))
5763          (alist elmo-crosspost-message-alist)
5764          (crossed 0)
5765          mark ngs num)
5766     (when (assq 'nntp spec-list)
5767       (while alist
5768         (when (setq ngs
5769                     (wl-summary-is-crosspost-folder
5770                      spec-list
5771                      (nth 1 (car alist))))
5772           (when (setq num (car (rassoc (caar alist) number-alist)))
5773             (if (and (setq mark (cadr (assq num mark-alist)))
5774                      (member mark (list wl-summary-new-mark
5775                                         wl-summary-unread-uncached-mark
5776                                         wl-summary-unread-cached-mark)))
5777                 (setq crossed (1+ crossed)))
5778             (if (wl-summary-jump-to-msg num)
5779                 (wl-summary-mark-as-read t);; opened
5780               (wl-summary-mark-as-read t nil nil num)));; closed
5781           ;; delete if message does't exists.
5782           (elmo-crosspost-message-delete (caar alist) ngs)
5783           (setq wl-crosspost-alist-modified t))
5784         (setq alist (cdr alist))))
5785     (if (> crossed 0)
5786         crossed)))
5787
5788 (defun wl-crosspost-alist-load ()
5789   (setq elmo-crosspost-message-alist (elmo-crosspost-alist-load))
5790   (setq wl-crosspost-alist-modified nil))
5791
5792 (defun wl-crosspost-alist-save ()
5793   (when wl-crosspost-alist-modified
5794     ;; delete non-exists newsgroups
5795     (let ((alist elmo-crosspost-message-alist)
5796           newsgroups)
5797       (while alist
5798         (setq newsgroups
5799               (elmo-delete-if
5800                '(lambda (x)
5801                   (not (intern-soft x wl-folder-newsgroups-hashtb)))
5802                (nth 1 (car alist))))
5803         (if newsgroups
5804             (setcar (cdar alist) newsgroups)
5805           (setq elmo-crosspost-message-alist
5806                 (delete (car alist) elmo-crosspost-message-alist)))
5807         (setq alist (cdr alist)))
5808       (elmo-crosspost-alist-save elmo-crosspost-message-alist)
5809       (setq wl-crosspost-alist-modified nil))))
5810
5811 (defun wl-summary-pack-number (&optional arg)
5812   (interactive "P")
5813   (setq wl-summary-buffer-msgdb
5814         (elmo-pack-number
5815          wl-summary-buffer-folder-name wl-summary-buffer-msgdb arg))
5816   (let (wl-use-scoring)
5817     (wl-summary-rescan)))
5818
5819 (defun wl-summary-target-mark-uudecode ()
5820   (interactive)
5821   (let ((mlist (reverse wl-summary-buffer-target-mark-list))
5822         (summary-buf (current-buffer))
5823         (tmp-buf (get-buffer-create "*WL UUENCODE*"))
5824         orig-buf i k filename rc errmsg)
5825     (setq i 1)
5826     (setq k (length mlist))
5827     (set-buffer tmp-buf)
5828     (erase-buffer)
5829     (save-window-excursion
5830       (while mlist
5831         (set-buffer summary-buf)
5832         (wl-summary-jump-to-msg (car mlist))
5833         (wl-summary-redisplay)
5834         (set-buffer (setq orig-buf (wl-message-get-original-buffer)))
5835         (goto-char (point-min))
5836         (cond ((= i 1) ; first
5837                (if (setq filename (wl-message-uu-substring
5838                                    orig-buf tmp-buf t
5839                                    (= i k)))
5840                    nil
5841                  (error "Can't find begin line.")))
5842               ((< i k)
5843                (wl-message-uu-substring orig-buf tmp-buf))
5844               (t ; last
5845                (wl-message-uu-substring orig-buf tmp-buf nil t)))
5846         (setq i (1+ i))
5847         (setq mlist (cdr mlist)))
5848       (set-buffer tmp-buf)
5849       (message "Exec %s..." wl-prog-uudecode)
5850       (unwind-protect
5851           (let ((decode-dir wl-tmp-dir))
5852             (if (not wl-prog-uudecode-no-stdout-option)
5853                 (setq filename (read-file-name "Save to file: "
5854                                                (expand-file-name
5855                                                 (elmo-safe-filename filename)
5856                                                 wl-tmp-dir)))
5857               (setq decode-dir
5858                     (wl-read-directory-name "Save to directory: "
5859                                             wl-tmp-dir))
5860               (setq filename (expand-file-name filename decode-dir)))
5861             (if (file-exists-p filename)
5862                 (or (yes-or-no-p (format "File %s exists. Save anyway? "
5863                                          filename))
5864                     (error "")))
5865             (elmo-bind-directory
5866              decode-dir
5867              (setq rc
5868                    (as-binary-process
5869                     (apply 'call-process-region (point-min) (point-max)
5870                            wl-prog-uudecode t (current-buffer) nil
5871                            wl-prog-uudecode-arg))))
5872             (when (not (= 0 rc))
5873               (setq errmsg (buffer-substring (point-min)(point-max)))
5874               (error "uudecode error: %s" errmsg))
5875             (if (not wl-prog-uudecode-no-stdout-option)
5876                 (let (file-name-handler-alist) ;; void jka-compr
5877                   (as-binary-output-file
5878                    (write-region (point-min) (point-max)
5879                                  filename nil 'no-msg))))
5880             (save-excursion
5881               (set-buffer summary-buf)
5882               (wl-summary-delete-all-temp-marks))
5883             (if (file-exists-p filename)
5884                 (message "Saved as %s" filename)))
5885         (kill-buffer tmp-buf)))))
5886
5887 (defun wl-summary-drop-unsync ()
5888   "Drop all unsync messages."
5889   (interactive)
5890   (if (elmo-folder-pipe-p wl-summary-buffer-folder-name)
5891       (error "You cannot drop unsync messages in this folder"))
5892   (if (or (not (interactive-p))
5893           (y-or-n-p "Drop all unsync messages?"))
5894       (let* ((folder-list (elmo-folder-get-primitive-folder-list
5895                            wl-summary-buffer-folder-name))
5896              (is-multi (elmo-multi-p wl-summary-buffer-folder-name))
5897              (sum 0)
5898              (multi-num 0)
5899              pair)
5900         (message "Dropping...")
5901         (while folder-list
5902           (setq pair (elmo-max-of-folder (car folder-list)))
5903           (when is-multi ;; dirty hack...
5904             (incf multi-num)
5905             (setcar pair (+ (* multi-num elmo-multi-divide-number)
5906                             (car pair))))
5907           (elmo-msgdb-set-number-alist
5908            wl-summary-buffer-msgdb
5909            (nconc
5910             (elmo-msgdb-get-number-alist wl-summary-buffer-msgdb)
5911             (list (cons (car pair) nil))))
5912           (setq sum (+ sum (cdr pair)))
5913           (setq folder-list (cdr folder-list)))
5914         (wl-summary-set-message-modified)
5915         (wl-folder-set-folder-updated wl-summary-buffer-folder-name
5916                                       (list 0
5917                                             (+ wl-summary-buffer-unread-count
5918                                                wl-summary-buffer-new-count)
5919                                             sum))
5920         (message "Dropping...done."))))
5921
5922 (defun wl-summary-default-get-next-msg (msg)
5923   (let (next)
5924     (if (and (not wl-summary-buffer-target-mark-list)
5925              (eq wl-summary-buffer-view 'thread)
5926              (if (eq wl-summary-move-direction-downward nil)
5927                  (setq next (wl-thread-get-prev-unread msg))
5928                (setq next (wl-thread-get-next-unread msg))))
5929         next
5930       (save-excursion
5931         (wl-summary-jump-to-msg msg)
5932         (let (wl-summary-buffer-disp-msg)
5933           (if (eq wl-summary-move-direction-downward nil)
5934               (unless (wl-summary-cursor-up)
5935                 (wl-summary-prev))
5936             (unless (wl-summary-cursor-down)
5937               (wl-summary-next)))
5938           (wl-summary-message-number))))))
5939
5940 (defsubst wl-cache-prefetch-p (fld &optional num)
5941   (cond ((and num wl-cache-prefetch-folder-type-list)
5942          (memq
5943           (elmo-folder-number-get-type fld num)
5944           wl-cache-prefetch-folder-type-list))
5945         (wl-cache-prefetch-folder-type-list
5946          (let ((list wl-cache-prefetch-folder-type-list)
5947                type)
5948            (catch 'done
5949              (while (setq type (pop list))
5950                (if (elmo-folder-contains-type fld type)
5951                    (throw 'done t))))))
5952         ((consp wl-cache-prefetch-folder-list)
5953          (wl-string-match-member fld wl-cache-prefetch-folder-list))
5954         (t
5955          wl-cache-prefetch-folder-list)))
5956
5957 (defconst wl-cache-prefetch-idle-time
5958   (if (featurep 'lisp-float-type) (/ (float 1) (float 10)) 1))
5959
5960 (defun wl-cache-prefetch-next (fld msg &optional summary)
5961   (if (wl-cache-prefetch-p fld)
5962       (if (not elmo-use-buffer-cache)
5963          ;; (message "`elmo-use-buffer-cache' is nil, cache prefetch is disable.")
5964         (save-excursion
5965           (set-buffer (or summary (get-buffer wl-summary-buffer-name)))
5966           (let ((next (funcall wl-cache-prefetch-get-next-func msg)))
5967             (when (and next
5968                        (wl-cache-prefetch-p fld next))
5969               (if (not (fboundp 'run-with-idle-timer))
5970                   (when (sit-for wl-cache-prefetch-idle-time)
5971                     (wl-cache-prefetch-message fld next summary))
5972                 (run-with-idle-timer
5973                  wl-cache-prefetch-idle-time
5974                  nil
5975                  'wl-cache-prefetch-message fld next summary)
5976                 (sit-for 0))))))))
5977
5978 (defvar wl-cache-prefetch-debug nil)
5979 (defun wl-cache-prefetch-message (folder msg summary &optional next)
5980   (when (buffer-live-p summary)
5981     (save-excursion
5982       (set-buffer summary)
5983       (when (string= folder wl-summary-buffer-folder-name)
5984         (unless next
5985           (setq next msg))
5986         (let* ((msgdb wl-summary-buffer-msgdb)
5987                (message-id (cdr (assq next
5988                                       (elmo-msgdb-get-number-alist msgdb)))))
5989           (if (not (elmo-buffer-cache-hit (list folder next message-id)))
5990               (let* ((size (elmo-msgdb-overview-entity-get-size
5991                             (assoc message-id
5992                                    (elmo-msgdb-get-overview msgdb)))))
5993                 (when (or (elmo-local-file-p folder next)
5994                           (not (and (integerp size)
5995                                     wl-cache-prefetch-threshold
5996                                     (>= size wl-cache-prefetch-threshold)
5997                                     (not (elmo-cache-exists-p message-id
5998                                                               folder next)))))
5999                   (if wl-cache-prefetch-debug
6000                       (message "Reading %d..." msg))
6001                   (elmo-buffer-cache-message folder next msgdb)
6002                   (if wl-cache-prefetch-debug
6003                       (message "Reading %d... done" msg))))))))))
6004
6005 (defun wl-summary-save-current-message ()
6006   "Save current message for `wl-summary-yank-saved-message'."
6007   (interactive)
6008   (let ((number (wl-summary-message-number)))
6009     (setq wl-summary-buffer-saved-message number)
6010     (and number (message "No: %s is saved." number))))
6011
6012 (defun wl-summary-yank-saved-message ()
6013   "Set current message as a parent of the saved message."
6014   (interactive)
6015   (if wl-summary-buffer-saved-message
6016       (let ((number (wl-summary-message-number)))
6017         (if (eq wl-summary-buffer-saved-message number)
6018             (message "Cannot set itself as a parent.")
6019           (save-excursion
6020             (wl-thread-jump-to-msg wl-summary-buffer-saved-message)
6021             (wl-thread-set-parent number)
6022             (wl-summary-set-thread-modified))
6023           (setq  wl-summary-buffer-saved-message nil)))
6024     (message "There's no saved message.")))
6025
6026 (require 'product)
6027 (product-provide (provide 'wl-summary) (require 'wl-version))
6028
6029 ;;; wl-summary.el ends here