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