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