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