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