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