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