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