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