815c234096883c9db2a4994b1d1b30af6ec403f1
[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     (ignore-errors
2900       (setq cur-mark
2901             (elmo-message-mark wl-summary-buffer-elmo-folder number))
2902       (save-excursion
2903         ;; set mark on buffer
2904         (unless (string= (wl-summary-persistent-mark) cur-mark)
2905           (delete-backward-char 1)
2906           (insert (or cur-mark " ")))
2907         (when wl-summary-highlight
2908           (wl-highlight-summary-current-line))))
2909     (set-buffer-modified-p nil)))
2910       
2911
2912 (defsubst wl-summary-mark-as-read-internal (inverse
2913                                             number-or-numbers
2914                                             no-folder-mark
2915                                             no-modeline-update)
2916   (save-excursion
2917     (let ((inhibit-read-only t)
2918           (buffer-read-only nil)
2919           (folder wl-summary-buffer-elmo-folder)
2920           (case-fold-search nil)
2921           unread-message number
2922           number-list mark visible new-mark)
2923       (setq number-list (cond ((numberp number-or-numbers)
2924                                (setq unread-message
2925                                      (member (elmo-message-mark 
2926                                               folder
2927                                               number-or-numbers)
2928                                              (elmo-msgdb-unread-marks)))
2929                                (list number-or-numbers))
2930                               ((and (not (null number-or-numbers))
2931                                     (listp number-or-numbers))
2932                                number-or-numbers)
2933                               ((setq number (wl-summary-message-number))
2934                                ;; interactive
2935                                (setq unread-message
2936                                      (member (elmo-message-mark folder number)
2937                                              (elmo-msgdb-unread-marks)))
2938                                (list number))))
2939       (if (null number-list)
2940           (message "No message.")
2941         (if inverse
2942             (elmo-folder-unmark-read folder number-list no-folder-mark)
2943           (elmo-folder-mark-as-read folder number-list no-folder-mark))
2944         (dolist (number number-list)
2945           (setq visible (wl-summary-jump-to-msg number)
2946                 new-mark (elmo-message-mark folder number))
2947           (unless inverse
2948             (when unread-message
2949               (run-hooks 'wl-summary-unread-message-hook)))
2950           ;; set mark on buffer
2951           (when visible
2952             (unless (string= (wl-summary-persistent-mark) (or new-mark " "))
2953               (delete-backward-char 1)
2954               (insert (or new-mark " ")))
2955             (if (and visible wl-summary-highlight)
2956                 (wl-highlight-summary-current-line))
2957             (set-buffer-modified-p nil)))
2958         (unless no-modeline-update
2959           ;; Update unread numbers.
2960           ;; should elmo-folder-mark-as-read return unread numbers?
2961           (wl-summary-count-unread)
2962           (wl-summary-update-modeline)
2963           (wl-folder-update-unread
2964            (wl-summary-buffer-folder-name)
2965            (+ wl-summary-buffer-unread-count
2966               wl-summary-buffer-new-count)))))))
2967
2968 (defun wl-summary-mark-as-read (&optional number-or-numbers
2969                                           no-folder-mark
2970                                           no-modeline-update)
2971   (interactive)
2972   (wl-summary-mark-as-read-internal nil
2973                                     number-or-numbers
2974                                     no-folder-mark
2975                                     no-modeline-update))
2976
2977 (defun wl-summary-mark-as-unread (&optional number-or-numbers
2978                                             no-folder-mark
2979                                             no-modeline-update)
2980   (interactive)
2981   (wl-summary-mark-as-read-internal 'inverse
2982                                     number-or-numbers
2983                                     no-folder-mark
2984                                     no-modeline-update))
2985
2986 (defsubst wl-summary-mark-as-answered-internal (inverse
2987                                                 number-or-numbers
2988                                                 no-modeline-update)
2989   (save-excursion
2990     (let ((inhibit-read-only t)
2991           (buffer-read-only nil)
2992           (folder wl-summary-buffer-elmo-folder)
2993           (case-fold-search nil)
2994           number number-list mark visible new-mark)
2995       (setq number-list (cond ((numberp number-or-numbers)
2996                                (list number-or-numbers))
2997                               ((and (not (null number-or-numbers))
2998                                     (listp number-or-numbers))
2999                                number-or-numbers)
3000                               ((setq number (wl-summary-message-number))
3001                                ;; interactive
3002                                (list number))))
3003       (if (null number-list)
3004           (message "No message.")
3005         (if inverse
3006             (elmo-folder-unmark-answered folder number-list)
3007           (elmo-folder-mark-as-answered folder number-list))
3008         (dolist (number number-list)
3009           (setq visible (wl-summary-jump-to-msg number)
3010                 new-mark (elmo-message-mark folder number))
3011           ;; set mark on buffer
3012           (when visible
3013             (unless (string= (wl-summary-persistent-mark) (or new-mark " "))
3014               (delete-backward-char 1)
3015               (insert (or new-mark " ")))
3016             (if (and visible wl-summary-highlight)
3017                 (wl-highlight-summary-current-line))
3018             (set-buffer-modified-p nil)))
3019         (unless no-modeline-update
3020           ;; Update unread numbers.
3021           ;; should elmo-folder-mark-as-read return unread numbers?
3022           (wl-summary-count-unread)
3023           (wl-summary-update-modeline)
3024           (wl-folder-update-unread
3025            (wl-summary-buffer-folder-name)
3026            (+ wl-summary-buffer-unread-count
3027               wl-summary-buffer-new-count)))))))
3028
3029 (defun wl-summary-mark-as-answered (&optional number-or-numbers
3030                                               no-modeline-update)
3031   (interactive)
3032   (wl-summary-mark-as-answered-internal
3033    (and (interactive-p)
3034         (member (elmo-message-mark wl-summary-buffer-elmo-folder
3035                                    (wl-summary-message-number))
3036                 (elmo-msgdb-answered-marks)))
3037    number-or-numbers
3038    no-modeline-update))
3039
3040 (defun wl-summary-mark-as-unanswered (&optional number-or-numbers
3041                                               no-modeline-update)
3042   (wl-summary-mark-as-answered-internal 'inverse
3043                                         number-or-numbers
3044                                         no-modeline-update))
3045
3046 (defun wl-summary-mark-as-important (&optional number
3047                                                mark
3048                                                no-server-update)
3049   (interactive)
3050   (if (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
3051           'internal)
3052       (error "Cannot process mark in this folder"))
3053   (save-excursion
3054     (let* (eol
3055           (inhibit-read-only t)
3056           (buffer-read-only nil)
3057           (folder wl-summary-buffer-elmo-folder)
3058           message-id visible cur-mark)
3059       (if number
3060           (progn
3061             (setq visible (wl-summary-jump-to-msg number))
3062             (setq mark (or mark (elmo-message-mark 
3063                                  wl-summary-buffer-elmo-folder number))))
3064         (setq visible t))
3065       (when visible
3066         (if (null (setq number (wl-summary-message-number)))
3067             (progn
3068               (message "No message.")
3069               (setq visible nil))
3070           (end-of-line)
3071           (setq eol (point))
3072           (wl-summary-goto-previous-message-beginning)))
3073       (if (or (and (not visible)
3074                    ;; already exists in msgdb.
3075                    (elmo-message-entity wl-summary-buffer-elmo-folder
3076                                         number))
3077               (setq cur-mark (wl-summary-persistent-mark)))
3078           (progn
3079             (setq number (or number (wl-summary-message-number)))
3080             (setq mark (or mark cur-mark))
3081             (setq message-id (elmo-message-field
3082                               wl-summary-buffer-elmo-folder
3083                               number
3084                               'message-id))
3085             (if (string= mark elmo-msgdb-important-mark)
3086                 (progn
3087                   ;; server side mark
3088                   (save-match-data
3089                     (elmo-folder-unmark-important folder (list number)
3090                                                   no-server-update)
3091                     (unless no-server-update
3092                       (elmo-msgdb-global-mark-delete message-id))
3093                     ;; Remove cache if local folder.
3094                     (if (and (elmo-folder-local-p folder)
3095                              (not (eq 'mark
3096                                       (elmo-folder-type-internal folder))))
3097                         (elmo-file-cache-delete
3098                          (elmo-file-cache-get-path message-id))))
3099                   (when visible
3100                     (delete-backward-char 1)
3101                     (insert (or (elmo-message-mark folder number) " "))))
3102               ;; server side mark
3103               (elmo-folder-mark-as-important folder (list number)
3104                                              no-server-update)
3105               (when visible
3106                 (delete-backward-char 1)
3107                 (insert elmo-msgdb-important-mark))
3108               (if (eq (elmo-file-cache-exists-p message-id) 'entire)
3109                   (elmo-folder-mark-as-read folder (list number))
3110                 ;; Force cache message.
3111                 (elmo-message-encache folder number 'read))
3112               (unless no-server-update
3113                 (elmo-msgdb-global-mark-set message-id
3114                                             elmo-msgdb-important-mark)))))
3115       (if (and visible wl-summary-highlight)
3116           (wl-highlight-summary-current-line))))
3117   (set-buffer-modified-p nil)
3118   number)
3119
3120 ;;; Summary line.
3121 (defvar wl-summary-line-formatter nil)
3122
3123 (defun wl-summary-view-old-p ()
3124   "Return non-nil when summary view cache has old format."
3125   (save-excursion
3126     (goto-char (point-min))
3127     (and wl-summary-buffer-number-list
3128          (not (re-search-forward "\r-?[0-9]+" (point-at-eol) t)))))
3129
3130 (defun wl-summary-line-format-changed-p ()
3131   "Return non-nil when summary line format is changed."
3132   (not (string=
3133         wl-summary-buffer-line-format
3134         (or (elmo-object-load (expand-file-name
3135                                wl-summary-line-format-file
3136                                (elmo-folder-msgdb-path
3137                                 wl-summary-buffer-elmo-folder))
3138                               wl-summary-buffer-mime-charset)
3139             wl-summary-buffer-line-format))))
3140
3141 (defun wl-summary-line-format-save ()
3142   "Save current summary line format."
3143   (elmo-object-save
3144    (expand-file-name wl-summary-line-format-file
3145                      (elmo-folder-msgdb-path
3146                       wl-summary-buffer-elmo-folder))
3147    wl-summary-buffer-line-format
3148    wl-summary-buffer-mime-charset))
3149
3150 (defun wl-summary-line-number ()
3151   (wl-set-string-width
3152    (- wl-summary-buffer-number-column)
3153    (number-to-string
3154     (elmo-msgdb-overview-entity-get-number wl-message-entity))))
3155
3156 (defun wl-summary-line-year ()
3157   (aref wl-datevec 0))
3158 (defun wl-summary-line-month ()
3159   (format "%02d" (aref wl-datevec 1)))
3160 (defun wl-summary-line-day ()
3161   (format "%02d" (aref wl-datevec 2)))
3162 (defun wl-summary-line-day-of-week ()
3163   (condition-case nil
3164       (elmo-date-get-week (aref wl-datevec 0)
3165                           (aref wl-datevec 1)
3166                           (aref wl-datevec 2))
3167     (error "??")))
3168 (defun wl-summary-line-hour ()
3169   (format "%02d" (aref wl-datevec 3)))
3170 (defun wl-summary-line-minute ()
3171   (format "%02d" (aref wl-datevec 4)))
3172
3173 (defun wl-summary-line-size ()
3174   (let ((size (elmo-msgdb-overview-entity-get-size wl-message-entity)))
3175     (if size
3176         (cond
3177          ((<= 1 (/ size 1048576))
3178           (format "%.0fM" (/ size 1048576.0)))
3179          ((<= 1 (/ size 1024))
3180           (format "%.0fK" (/ size 1024.0)))
3181          (t (format "%dB" size)))
3182       "")))
3183
3184 (defun wl-summary-line-subject ()
3185   (let (no-parent subject parent-raw-subject parent-subject)
3186     (if (string= wl-thr-indent-string "")
3187         (setq no-parent t)) ; no parent
3188     (setq subject
3189           (elmo-delete-char ?\n
3190                             (or (elmo-msgdb-overview-entity-get-subject
3191                                  wl-message-entity)
3192                                 wl-summary-no-subject-message)))
3193     (setq parent-raw-subject
3194           (elmo-msgdb-overview-entity-get-subject wl-parent-message-entity))
3195     (setq parent-subject
3196           (if parent-raw-subject
3197               (elmo-delete-char ?\n parent-raw-subject)))
3198     (if (or no-parent
3199             (null parent-subject)
3200             (not (wl-summary-subject-equal
3201                   subject parent-subject)))
3202         (funcall wl-summary-subject-function subject)
3203       "")))
3204
3205 (defun wl-summary-line-from ()
3206   (elmo-delete-char ?\n
3207                     (funcall wl-summary-from-function
3208                              (elmo-msgdb-overview-entity-get-from
3209                               wl-message-entity))))
3210
3211 (defun wl-summary-line-list-info ()
3212   (let ((list-info (wl-summary-get-list-info wl-message-entity)))
3213     (if (car list-info)
3214         (format (if (cdr list-info) "(%s %05.0f)" "(%s)")
3215                 (car list-info) (cdr list-info))
3216       "")))
3217
3218 (defun wl-summary-line-list-count ()
3219   (let ((ml-count (cdr (wl-summary-get-list-info wl-message-entity))))
3220     (if ml-count
3221         (format "%.0f" ml-count)
3222       "")))
3223
3224 (defun wl-summary-line-attached ()
3225   (let ((content-type (elmo-msgdb-overview-entity-get-extra-field
3226                        wl-message-entity "content-type"))
3227         (case-fold-search t))
3228     (if (and content-type
3229              (string-match "multipart/mixed" content-type))
3230         "@"
3231       "")))
3232
3233 (defun wl-summary-create-line (wl-message-entity
3234                                wl-parent-message-entity
3235                                wl-temp-mark
3236                                wl-persistent-mark
3237                                &optional
3238                                wl-thr-children-number
3239                                wl-thr-indent-string
3240                                wl-thr-linked)
3241   "Create a summary line."
3242   (let ((wl-mime-charset wl-summary-buffer-mime-charset)
3243         (elmo-mime-charset wl-summary-buffer-mime-charset)
3244         (elmo-lang wl-summary-buffer-weekday-name-lang)
3245         (wl-datevec (or (ignore-errors (timezone-fix-time
3246                                         (elmo-msgdb-overview-entity-get-date 
3247                                          wl-message-entity)
3248                                         nil
3249                                         wl-summary-fix-timezone))
3250                         (make-vector 5 0)))
3251         (entity wl-message-entity) ; backward compatibility.
3252         line mark)
3253     (if (and wl-thr-indent-string
3254              wl-summary-indent-length-limit
3255              (< wl-summary-indent-length-limit
3256                 (string-width wl-thr-indent-string)))
3257         (setq wl-thr-indent-string (wl-set-string-width
3258                                     wl-summary-indent-length-limit
3259                                     wl-thr-indent-string)))
3260     (setq line (funcall wl-summary-buffer-line-formatter))
3261     (if wl-summary-width (setq line
3262                                (wl-set-string-width
3263                                 (- wl-summary-width 1) line nil
3264                                 'ignore-invalid)))
3265     (setq line (concat line
3266                        "\r"
3267                        (number-to-string
3268                         (elmo-msgdb-overview-entity-get-number 
3269                          wl-message-entity))))
3270     (if wl-summary-highlight
3271         (wl-highlight-summary-line-string line
3272                                           wl-persistent-mark
3273                                           wl-temp-mark
3274                                           wl-thr-indent-string))
3275     line))
3276
3277 (defsubst wl-summary-proc-wday (wday-str year month mday)
3278   (save-match-data
3279     (if (string-match "\\([A-Z][a-z][a-z]\\).*" wday-str)
3280         (wl-match-string 1 wday-str)
3281       (elmo-date-get-week year month mday))))
3282
3283 (defvar wl-summary-move-spec-alist
3284   '((new . ((t . nil)
3285             (p . new)
3286             (p . unread)
3287             (p . important)))
3288     (unread . ((t . nil)
3289                (p . unread)
3290                (p . important)))))
3291
3292 (defsubst wl-summary-next-message (num direction hereto)
3293   (if wl-summary-buffer-next-message-function
3294       (funcall wl-summary-buffer-next-message-function num direction hereto)
3295     (let ((cur-spec (cdr (assq wl-summary-move-order
3296                                wl-summary-move-spec-alist)))
3297           (nums (memq num (if (eq direction 'up)
3298                               (reverse wl-summary-buffer-number-list)
3299                             wl-summary-buffer-number-list)))
3300           flagged-list nums2)
3301       (unless hereto (setq nums (cdr nums)))
3302       (setq nums2 nums)
3303       (if cur-spec
3304           (catch 'done
3305             (while cur-spec
3306               (setq nums nums2)
3307               (cond ((eq (car (car cur-spec)) 'p)
3308                      (if (setq flagged-list
3309                                (elmo-folder-list-flagged
3310                                 wl-summary-buffer-elmo-folder
3311                                 (cdr (car cur-spec))))
3312                          (while nums
3313                            (if (and (memq (car nums) flagged-list)
3314                                     (elmo-message-accessible-p
3315                                      wl-summary-buffer-elmo-folder
3316                                      (car nums)))
3317                                (throw 'done (car nums)))
3318                            (setq nums (cdr nums)))))
3319                     ((eq (car (car cur-spec)) 't)
3320                      (if wl-summary-buffer-target-mark-list
3321                          (while nums
3322                            (if (memq (car nums)
3323                                      wl-summary-buffer-target-mark-list)
3324                                (throw 'done (car nums)))
3325                            (setq nums (cdr nums))))))
3326               (setq cur-spec (cdr cur-spec))))
3327         (car nums)))))
3328
3329 (defsubst wl-summary-cursor-move (direction hereto)
3330   (when (and (eq direction 'up)
3331              (eobp))
3332     (forward-line -1)
3333     (setq hereto t))
3334   (let (num)
3335     (when (setq num (wl-summary-next-message (wl-summary-message-number)
3336                                              direction hereto))
3337       (if (numberp num)
3338           (wl-thread-jump-to-msg num))
3339       t)))
3340 ;;
3341 ;; Goto unread or important
3342 ;; returns t if next message exists in this folder.
3343 (defun wl-summary-cursor-down (&optional hereto)
3344   (interactive "P")
3345   (wl-summary-cursor-move 'down hereto))
3346
3347 (defun wl-summary-cursor-up (&optional hereto)
3348   (interactive "P")
3349   (wl-summary-cursor-move 'up hereto))
3350
3351 (defun wl-summary-save-view-cache ()
3352   (save-excursion
3353     (let* ((dir (elmo-folder-msgdb-path wl-summary-buffer-elmo-folder))
3354            (cache (expand-file-name wl-summary-cache-file dir))
3355            (view (expand-file-name wl-summary-view-file dir))
3356            (save-view wl-summary-buffer-view)
3357            (mark-list (copy-sequence wl-summary-buffer-target-mark-list))
3358            (temp-list (copy-sequence wl-summary-buffer-temp-mark-list))
3359            (tmp-buffer (get-buffer-create " *wl-summary-save-view-cache*"))
3360            (temp-column wl-summary-buffer-temp-mark-column)
3361            (charset wl-summary-buffer-mime-charset))
3362       (if (file-directory-p dir)
3363           (); ok.
3364         (if (file-exists-p dir)
3365             (error "File %s already exists" dir)
3366           (elmo-make-directory dir)))
3367       (if (eq save-view 'thread)
3368           (wl-thread-save-entity dir))
3369       (when wl-summary-check-line-format
3370         (wl-summary-line-format-save))
3371       (unwind-protect
3372           (progn
3373             (when (file-writable-p cache)
3374               (copy-to-buffer tmp-buffer (point-min) (point-max))
3375               (with-current-buffer tmp-buffer
3376                 (widen)
3377                 (make-local-variable 'wl-summary-highlight)
3378                 (setq wl-summary-highlight nil
3379                       wl-summary-buffer-target-mark-list mark-list
3380                       wl-summary-buffer-temp-mark-list temp-list
3381                       wl-summary-buffer-temp-mark-column temp-column)
3382                 (wl-summary-delete-all-temp-marks 'no-msg)
3383                 (encode-coding-region
3384                  (point-min) (point-max)
3385                  (or (and wl-on-mule ; one in mcs-ltn1(apel<10.4) cannot take 2 arg.
3386                           (mime-charset-to-coding-system charset 'LF))
3387                      ;; Mule 2 doesn't have `*ctext*unix'.
3388                      (mime-charset-to-coding-system charset)))
3389                 (write-region-as-binary (point-min)(point-max)
3390                                         cache nil 'no-msg)))
3391             (when (file-writable-p view) ; 'thread or 'sequence
3392               (save-excursion
3393                 (set-buffer tmp-buffer)
3394                 (erase-buffer)
3395                 (prin1 save-view tmp-buffer)
3396                 (princ "\n" tmp-buffer)
3397                 (write-region (point-min) (point-max) view nil 'no-msg))))
3398         ;; kill tmp buffer.
3399         (kill-buffer tmp-buffer)))))
3400
3401 (defsubst wl-summary-get-sync-range (folder)
3402   (intern (or (and
3403                (elmo-folder-plugged-p folder)
3404                (wl-get-assoc-list-value
3405                 wl-folder-sync-range-alist
3406                 (elmo-folder-name-internal folder)))
3407               wl-default-sync-range)))
3408
3409 ;; redefined for wl-summary-sync-update
3410 (defun wl-summary-input-range (folder)
3411   "returns update or all or rescan."
3412   ;; for the case when parts are expanded in the bottom of the folder
3413   (let ((input-range-list '("update" "all" "rescan" "first:" "last:"
3414                             "cache-status"
3415                             "no-sync" "rescan-noscore" "all-visible"))
3416         (default (or (wl-get-assoc-list-value
3417                       wl-folder-sync-range-alist
3418                       folder)
3419                      wl-default-sync-range))
3420         range)
3421     (setq range
3422           (completing-read (format "Range (%s): " default)
3423                            (mapcar
3424                             (function (lambda (x) (cons x x)))
3425                             input-range-list)))
3426     (if (string= range "")
3427         default
3428       range)))
3429
3430 (defun wl-summary-toggle-disp-folder (&optional arg)
3431   (interactive)
3432   (let ((cur-buf (current-buffer))
3433         (summary-win (get-buffer-window (current-buffer)))
3434         fld-buf fld-win)
3435     (cond
3436      ((eq arg 'on)
3437       (setq wl-summary-buffer-disp-folder t)
3438       ;; hide your folder window
3439       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
3440           (if (setq fld-win (get-buffer-window fld-buf))
3441               (delete-window fld-win))))
3442      ((eq arg 'off)
3443       (setq wl-summary-buffer-disp-folder nil)
3444       ;; hide your wl-message window!
3445       (when (buffer-live-p wl-message-buffer)
3446         (wl-message-select-buffer wl-message-buffer)
3447         (delete-window))
3448       (select-window (get-buffer-window cur-buf))
3449       ;; display wl-folder window!!
3450       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
3451           (if (setq fld-win (get-buffer-window fld-buf))
3452               ;; folder win is already displayed.
3453               (select-window fld-win)
3454             ;; folder win is not displayed.
3455             (switch-to-buffer fld-buf))
3456         ;; no folder buf
3457         (wl-folder))
3458       ;; temporarily delete summary-win.
3459       (if summary-win
3460           (delete-window summary-win))
3461       (split-window-horizontally wl-folder-window-width)
3462       (other-window 1)
3463       (switch-to-buffer cur-buf))
3464      (t
3465       (if (setq fld-buf (get-buffer wl-folder-buffer-name))
3466           (if (setq fld-win (get-buffer-window fld-buf))
3467               (setq wl-summary-buffer-disp-folder nil)
3468             (setq wl-summary-buffer-disp-folder t)))
3469       (if (not wl-summary-buffer-disp-folder)
3470           ;; hide message window
3471           (let ((mes-win (and wl-message-buffer
3472                               (get-buffer-window wl-message-buffer)))
3473                 (wl-stay-folder-window t))
3474             (if mes-win (delete-window mes-win))
3475             ;; hide your folder window
3476             (if (setq fld-buf (get-buffer wl-folder-buffer-name))
3477                 (if (setq fld-win (get-buffer-window fld-buf))
3478                     (progn
3479                       (delete-window (get-buffer-window cur-buf))
3480                       (select-window fld-win)
3481                       (switch-to-buffer cur-buf))))
3482             (run-hooks 'wl-summary-toggle-disp-folder-off-hook)
3483             ;; resume message window.
3484             (when mes-win
3485               (wl-message-select-buffer wl-message-buffer)
3486               (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
3487               (select-window (get-buffer-window cur-buf))))
3488         ;; hide message window
3489         (let ((wl-stay-folder-window t)
3490               (mes-win (and wl-message-buffer
3491                             (get-buffer-window wl-message-buffer))))
3492           (if mes-win (delete-window mes-win))
3493           (select-window (get-buffer-window cur-buf))
3494           ;; display wl-folder window!!
3495           (if (setq fld-buf (get-buffer wl-folder-buffer-name))
3496               (if (setq fld-win (get-buffer-window fld-buf))
3497                   ;; folder win is already displayed.
3498                   (select-window fld-win)
3499                 ;; folder win is not displayed...occupy all.
3500                 (switch-to-buffer fld-buf))
3501             ;; no folder buf
3502             (wl-folder))
3503           (split-window-horizontally wl-folder-window-width)
3504           (other-window 1)
3505           (switch-to-buffer cur-buf)
3506           ;; resume message window.
3507           (run-hooks 'wl-summary-toggle-disp-folder-on-hook)
3508           (when mes-win
3509             (wl-message-select-buffer wl-message-buffer)
3510             (run-hooks 'wl-summary-toggle-disp-folder-message-resumed-hook)
3511             (select-window (get-buffer-window cur-buf))))))))
3512   (run-hooks 'wl-summary-toggle-disp-folder-hook))
3513
3514 (defun wl-summary-toggle-disp-msg (&optional arg)
3515   (interactive)
3516   (let ((cur-buf (current-buffer))
3517         fld-buf fld-win
3518         summary-win)
3519     (cond
3520      ((eq arg 'on)
3521       (setq wl-summary-buffer-disp-msg t)
3522       (save-excursion
3523         ;; hide your folder window
3524         (if (and (not wl-stay-folder-window)
3525                  (setq fld-buf (get-buffer wl-folder-buffer-name)))
3526             (if (setq fld-win (get-buffer-window fld-buf))
3527                 (unless (one-window-p fld-win)
3528                   (delete-window fld-win))))))
3529      ((eq arg 'off)
3530       (wl-delete-all-overlays)
3531       (setq wl-summary-buffer-disp-msg nil)
3532       (save-excursion
3533         (when (buffer-live-p wl-message-buffer)
3534           (wl-message-select-buffer wl-message-buffer)
3535           (delete-window)
3536           (and (get-buffer-window cur-buf)
3537                (select-window (get-buffer-window cur-buf))))
3538         (run-hooks 'wl-summary-toggle-disp-off-hook)))
3539      (t
3540       (if (and wl-message-buffer
3541                (get-buffer-window wl-message-buffer)) ; already displayed
3542           (setq wl-summary-buffer-disp-msg nil)
3543         (setq wl-summary-buffer-disp-msg t))
3544       (if wl-summary-buffer-disp-msg
3545           (progn
3546             (wl-summary-redisplay)
3547 ;;; hide your folder window
3548 ;;;         (setq fld-buf (get-buffer wl-folder-buffer-name))
3549 ;;;         (if (setq fld-win (get-buffer-window fld-buf))
3550 ;;;             (delete-window fld-win)))
3551             (run-hooks 'wl-summary-toggle-disp-on-hook))
3552         (wl-delete-all-overlays)
3553         (save-excursion
3554           (wl-message-select-buffer wl-message-buffer)
3555           (delete-window)
3556           (select-window (get-buffer-window cur-buf))
3557           (setq wl-message-buffer nil)
3558           (run-hooks 'wl-summary-toggle-disp-off-hook))
3559 ;;;     (switch-to-buffer cur-buf)
3560         )))
3561     (when wl-summary-lazy-highlight
3562       (wl-highlight-summary-window))))
3563
3564 (defun wl-summary-next-line-content ()
3565   "Show next line of the message."
3566   (interactive)
3567   (let ((cur-buf (current-buffer)))
3568     (wl-summary-toggle-disp-msg 'on)
3569     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
3570       (set-buffer cur-buf)
3571       (wl-message-next-page 1))))
3572
3573 (defun wl-summary-prev-line-content ()
3574   (interactive)
3575   (let ((cur-buf (current-buffer)))
3576     (wl-summary-toggle-disp-msg 'on)
3577     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
3578       (set-buffer cur-buf)
3579       (wl-message-prev-page 1))))
3580
3581 (defun wl-summary-next-page ()
3582   (interactive)
3583   (let ((cur-buf (current-buffer)))
3584     (wl-summary-toggle-disp-msg 'on)
3585     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
3586       (set-buffer cur-buf)
3587       (wl-message-next-page))))
3588
3589 (defun wl-summary-prev-page ()
3590   (interactive)
3591   (let ((cur-buf (current-buffer)))
3592     (wl-summary-toggle-disp-msg 'on)
3593     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
3594       (set-buffer cur-buf)
3595       (wl-message-prev-page))))
3596
3597 (defsubst wl-summary-no-mime-p (folder)
3598   (wl-string-match-member (elmo-folder-name-internal folder)
3599                           wl-summary-no-mime-folder-list))
3600
3601 (defun wl-summary-set-message-buffer-or-redisplay (&rest args)
3602   "Set message buffer.
3603 If message is not displayed yet, display it.
3604 Return t if message exists."
3605   (let ((folder wl-summary-buffer-elmo-folder)
3606         (number (wl-summary-message-number))
3607         cur-folder cur-number message-last-pos)
3608     (when (buffer-live-p wl-message-buffer)
3609       (save-window-excursion
3610         (wl-message-select-buffer wl-message-buffer)
3611         (setq cur-folder wl-message-buffer-cur-folder)
3612         (setq cur-number wl-message-buffer-cur-number)))
3613     (if (and (string= (elmo-folder-name-internal folder) (or cur-folder ""))
3614              (eq number (or cur-number 0)))
3615         (progn
3616           (set-buffer wl-message-buffer)
3617           t)
3618       (if (wl-summary-no-mime-p folder)
3619           (wl-summary-redisplay-no-mime-internal folder number)
3620         (wl-summary-redisplay-internal folder number))
3621       (when (buffer-live-p wl-message-buffer)
3622         (set-buffer wl-message-buffer))
3623       nil)))
3624
3625 (defun wl-summary-target-mark-forward (&optional arg)
3626   (interactive "P")
3627   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
3628         (summary-buf (current-buffer))
3629         (wl-draft-forward t)
3630         start-point
3631         draft-buf)
3632     (wl-summary-jump-to-msg (car mlist))
3633     (wl-summary-forward t)
3634     (setq start-point (point))
3635     (setq draft-buf (current-buffer))
3636     (setq mlist (cdr mlist))
3637     (save-window-excursion
3638       (when mlist
3639         (while mlist
3640           (set-buffer summary-buf)
3641           (wl-summary-jump-to-msg (car mlist))
3642           (wl-summary-redisplay)
3643           (set-buffer draft-buf)
3644           (goto-char (point-max))
3645           (wl-draft-insert-message)
3646           (setq mlist (cdr mlist)))
3647         (wl-draft-body-goto-top)
3648         (wl-draft-enclose-digest-region (point) (point-max)))
3649       (goto-char start-point)
3650       (save-excursion
3651         (set-buffer summary-buf)
3652         (wl-summary-delete-all-temp-marks)))
3653     (run-hooks 'wl-mail-setup-hook)))
3654
3655 (defun wl-summary-target-mark-reply-with-citation (&optional arg)
3656   (interactive "P")
3657   (let ((mlist (nreverse wl-summary-buffer-target-mark-list))
3658         (summary-buf (current-buffer))
3659         change-major-mode-hook
3660         start-point
3661         draft-buf)
3662     (wl-summary-jump-to-msg (car mlist))
3663     (when (wl-summary-reply arg t)
3664       (goto-char (point-max))
3665       (setq start-point (point-marker))
3666       (setq draft-buf (current-buffer))
3667       (save-window-excursion
3668         (while mlist
3669           (set-buffer summary-buf)
3670           (delete-other-windows)
3671           (wl-summary-jump-to-msg (car mlist))
3672           (wl-summary-redisplay)
3673           (set-buffer draft-buf)
3674           (goto-char (point-max))
3675           (wl-draft-yank-original)
3676           (setq mlist (cdr mlist)))
3677         (goto-char start-point)
3678         (save-excursion
3679           (set-buffer summary-buf)
3680           (wl-summary-delete-all-temp-marks)))
3681       (wl-draft-reply-position wl-draft-reply-default-position)
3682       (run-hooks 'wl-mail-setup-hook))))
3683
3684 (defun wl-summary-reply-with-citation (&optional arg)
3685   (interactive "P")
3686   (when (wl-summary-reply arg t)
3687     (goto-char (point-max))
3688     (wl-draft-yank-original)
3689     (wl-draft-reply-position wl-draft-reply-default-position)
3690     (run-hooks 'wl-mail-setup-hook)))
3691
3692 (defun wl-summary-jump-to-msg-by-message-id (&optional id)
3693   (interactive)
3694   (let* ((original (wl-summary-message-number))
3695          (msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
3696          (entity (elmo-message-entity wl-summary-buffer-elmo-folder msgid))
3697          msg otherfld schar
3698          (errmsg (format "No message with id \"%s\" in the folder." msgid)))
3699     (if (setq msg (elmo-message-entity-number entity))
3700         (progn
3701           (wl-thread-jump-to-msg msg)
3702           t)
3703       ;; for XEmacs!
3704       (if (and elmo-use-database
3705                (setq errmsg
3706                      (format
3707                       "No message with id \"%s\" in the database." msgid))
3708                (setq otherfld (elmo-database-msgid-get msgid)))
3709           (if (cdr (wl-summary-jump-to-msg-internal
3710                     (car otherfld) (nth 1 otherfld) 'no-sync))
3711               t ; succeed.
3712             ;; Back to original.
3713             (wl-summary-jump-to-msg-internal
3714              (wl-summary-buffer-folder-name) original 'no-sync))
3715         (cond ((eq wl-summary-search-via-nntp 'confirm)
3716                (require 'elmo-nntp)
3717                (message "Search message in nntp server \"%s\" <y/n/s(elect)>? "
3718                         elmo-nntp-default-server)
3719                (setq schar (let ((cursor-in-echo-area t)) (read-char)))
3720                (cond ((eq schar ?y)
3721                       (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
3722                      ((eq schar ?s)
3723                       (wl-summary-jump-to-msg-by-message-id-via-nntp
3724                        msgid
3725                        (read-from-minibuffer "NNTP Server: ")))
3726                      (t
3727                       (message "%s" errmsg)
3728                       nil)))
3729               ((or (eq wl-summary-search-via-nntp 'force)
3730                    (and
3731                     (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
3732                         'nntp)
3733                     wl-summary-search-via-nntp))
3734                (wl-summary-jump-to-msg-by-message-id-via-nntp msgid))
3735               (t
3736                (message "%s" errmsg)
3737                nil))))))
3738
3739 (defun wl-summary-jump-to-msg-by-message-id-via-nntp (&optional id server-spec)
3740   (interactive)
3741   (let* ((msgid (elmo-string (or id (read-from-minibuffer "Message-ID: "))))
3742          newsgroups folder ret
3743          user server port type spec)
3744     (if server-spec
3745         (if (string-match "^-" server-spec)
3746             (setq spec (wl-folder-get-elmo-folder server-spec)
3747                   user (elmo-net-folder-user-internal spec)
3748                   server (elmo-net-folder-server-internal spec)
3749                   port (elmo-net-folder-port-internal spec)
3750                   type (elmo-net-folder-stream-type-internal spec))
3751           (setq server server-spec)))
3752     (when (setq ret (elmo-nntp-get-newsgroup-by-msgid
3753                      msgid
3754                      (or server elmo-nntp-default-server)
3755                      (or user elmo-nntp-default-user)
3756                      (or port elmo-nntp-default-port)
3757                      (or type elmo-nntp-default-stream-type)))
3758       (setq newsgroups (elmo-nntp-parse-newsgroups ret))
3759       (setq folder (concat "-" (car newsgroups)
3760                            (elmo-nntp-folder-postfix user server port type)))
3761       (catch 'found
3762         (while newsgroups
3763           (if (wl-folder-entity-exists-p (car newsgroups)
3764                                          wl-folder-newsgroups-hashtb)
3765               (throw 'found
3766                      (setq folder (concat "-" (car newsgroups)
3767                                           (elmo-nntp-folder-postfix
3768                                            user server port type)))))
3769           (setq newsgroups (cdr newsgroups)))))
3770     (if ret
3771         (wl-summary-jump-to-msg-internal folder nil 'update msgid)
3772       (message "No message id \"%s\" in nntp server \"%s\"."
3773                msgid (or server elmo-nntp-default-server))
3774       nil)))
3775
3776 (defun wl-summary-jump-to-msg-internal (folder msg scan-type &optional msgid)
3777   (let (wl-auto-select-first entity)
3778     (if (or (string= folder (wl-summary-buffer-folder-name))
3779             (y-or-n-p
3780              (format
3781               "Message was found in the folder \"%s\". Jump to it? "
3782               folder)))
3783         (progn
3784           (unwind-protect
3785               (wl-summary-goto-folder-subr
3786                folder scan-type nil nil t)
3787             (if msgid
3788                 (setq msg
3789                       (elmo-message-entity-number
3790                        (elmo-message-entity
3791                         wl-summary-buffer-elmo-folder
3792                         msgid))))
3793             (setq entity (wl-folder-search-entity-by-name folder
3794                                                           wl-folder-entity
3795                                                           'folder))
3796             (if entity
3797                 (wl-folder-set-current-entity-id
3798                  (wl-folder-get-entity-id entity))))
3799           (if (null msg)
3800               (message "Message was not found currently in this folder.")
3801             (setq msg (and (wl-thread-jump-to-msg msg) msg)))
3802           (cons folder msg)))))
3803
3804 (defun wl-summary-jump-to-parent-message (arg)
3805   (interactive "P")
3806   (let ((cur-buf (current-buffer))
3807         (disp-msg wl-summary-buffer-disp-msg)
3808         (number (wl-summary-message-number))
3809         (regexp "\\(<[^<>]*>\\)[ \t]*$")
3810         (i -1) ;; xxx
3811         msg-id msg-num ref-list ref irt)
3812     (if (null number)
3813         (message "No message.")
3814       (when (eq wl-summary-buffer-view 'thread)
3815         (cond ((and arg (not (numberp arg)))
3816                (setq msg-num
3817                      (wl-thread-entity-get-number
3818                       (wl-thread-entity-get-top-entity
3819                        (wl-thread-get-entity number)))))
3820               ((and arg (numberp arg))
3821                (setq i 0)
3822                (setq msg-num number)
3823                (while (< i arg)
3824                  (setq msg-num
3825                        (wl-thread-entity-get-number
3826                         (wl-thread-entity-get-parent-entity
3827                          (wl-thread-get-entity msg-num))))
3828                  (setq i (1+ i))))
3829               (t (setq msg-num
3830                        (wl-thread-entity-get-number
3831                         (wl-thread-entity-get-parent-entity
3832                          (wl-thread-get-entity number)))))))
3833       (when (null msg-num)
3834         (wl-summary-set-message-buffer-or-redisplay)
3835         (set-buffer (wl-message-get-original-buffer))
3836         (message "Searching parent message...")
3837         (setq ref (std11-field-body "References")
3838               irt (std11-field-body "In-Reply-To"))
3839         (cond
3840          ((and arg (not (numberp arg)) ref (not (string= ref ""))
3841                (string-match regexp ref))
3842           ;; The first message of the thread.
3843           (setq msg-id (wl-match-string 1 ref)))
3844          ;; "In-Reply-To:" has only one msg-id.
3845          ((and (null arg) irt (not (string= irt ""))
3846                (string-match regexp irt))
3847           (setq msg-id (wl-match-string 1 irt)))
3848          ((and (or (null arg) (numberp arg)) ref (not (string= ref ""))
3849                (string-match regexp ref))
3850           ;; "^" searching parent, "C-u 2 ^" looking for grandparent.
3851           (while (string-match regexp ref)
3852             (setq ref-list
3853                   (append (list
3854                            (wl-match-string 1 ref))
3855                           ref-list))
3856             (setq ref (substring ref (match-end 0)))
3857             (setq i (1+ i)))
3858           (setq msg-id
3859                 (if (null arg) (nth 0 ref-list) ;; previous
3860                   (if (<= arg i) (nth (1- arg) ref-list)
3861                     (nth i ref-list))))))
3862         (set-buffer cur-buf)
3863         (or disp-msg (wl-summary-toggle-disp-msg 'off)))
3864       (cond ((and (null msg-id) (null msg-num))
3865              (message "No parent message!")
3866              nil)
3867             ((and msg-id (wl-summary-jump-to-msg-by-message-id msg-id))
3868              (if wl-summary-buffer-disp-msg (wl-summary-redisplay))
3869              (message "Searching parent message...done")
3870              t)
3871             ((and msg-num (wl-summary-jump-to-msg msg-num))
3872              (if wl-summary-buffer-disp-msg (wl-summary-redisplay))
3873              (message "Searching parent message...done")
3874              t)
3875             (t ; failed.
3876              (message "Parent message was not found.")
3877              nil)))))
3878
3879 (defun wl-summary-reply (&optional arg without-setup-hook)
3880   "Reply to current message. Default is \"wide\" reply.
3881 Reply to author if invoked with ARG."
3882   (interactive "P")
3883   (let ((folder wl-summary-buffer-elmo-folder)
3884         (number (wl-summary-message-number))
3885         (summary-buf (current-buffer))
3886         (winconf (current-window-configuration))
3887         mes-buf)
3888     (when number
3889       (save-excursion
3890         (wl-summary-redisplay-internal folder number))
3891       (setq mes-buf wl-message-buffer)
3892       (wl-message-select-buffer wl-message-buffer)
3893       (set-buffer mes-buf)
3894       (goto-char (point-min))
3895       (condition-case err
3896           (when (setq mes-buf (wl-message-get-original-buffer))
3897             (wl-draft-reply mes-buf arg summary-buf number)
3898             (wl-draft-reply-position wl-draft-reply-default-position)
3899             (unless without-setup-hook
3900               (run-hooks 'wl-mail-setup-hook)))
3901         (error (set-window-configuration winconf)
3902                (signal (car err)(cdr err))))
3903       (with-current-buffer summary-buf
3904         (elmo-folder-mark-as-answered folder (list number))
3905         (wl-summary-update-mark number))
3906       t)))
3907
3908 (defun wl-summary-write ()
3909   "Write a new draft from Summary."
3910   (interactive)
3911   (wl-draft (list (cons 'To ""))
3912             nil nil nil nil (wl-summary-buffer-folder-name))
3913   (run-hooks 'wl-mail-setup-hook)
3914   (mail-position-on-field "To"))
3915
3916 (defvar wl-summary-write-current-folder-functions
3917   '(wl-folder-get-newsgroups
3918     wl-folder-guess-mailing-list-by-refile-rule
3919     wl-folder-guess-mailing-list-by-folder-name)
3920   "Newsgroups or Mailing List address guess functions list.
3921 Call from `wl-summary-write-current-folder'.
3922 When guess function return nil, challenge next guess-function.")
3923
3924 (defun wl-summary-write-current-folder (&optional folder)
3925   "Write message to current FOLDER's newsgroup or mailing-list.
3926 Use function list is `wl-summary-write-current-folder-functions'."
3927   (interactive)
3928   ;; default FOLDER is current buffer folder
3929   (setq folder (or folder (wl-summary-buffer-folder-name)))
3930   (let ((func-list wl-summary-write-current-folder-functions)
3931         guess-list guess-func)
3932     (while func-list
3933       (setq guess-list (funcall (car func-list) folder))
3934       (if (null guess-list)
3935           (setq func-list (cdr func-list))
3936         (setq guess-func (car func-list))
3937         (setq func-list nil)))
3938     (if (null guess-func)
3939         (wl-summary-write)
3940       (unless (or (stringp (nth 0 guess-list))
3941                   (stringp (nth 1 guess-list))
3942                   (stringp (nth 2 guess-list)))
3943         (error "Invalid value return guess function `%s'"
3944                (symbol-name guess-func)))
3945       (wl-draft (list (cons 'To (nth 0 guess-list))
3946                       (cons 'Cc (nth 1 guess-list))
3947                       (cons 'Newsgroups (nth 2 guess-list)))
3948                 nil nil nil nil folder)
3949       (run-hooks 'wl-mail-setup-hook)
3950       (mail-position-on-field "Subject"))))
3951
3952 (defun wl-summary-forward (&optional without-setup-hook)
3953   ""
3954   (interactive)
3955   (let ((folder wl-summary-buffer-elmo-folder)
3956         (number (wl-summary-message-number))
3957         (summary-buf (current-buffer))
3958         (wl-draft-forward t)
3959         mes-buf
3960         entity subject num)
3961     (if (null number)
3962         (message "No message.")
3963       (if (and (elmo-message-use-cache-p folder number)
3964                (eq (elmo-file-cache-status
3965                     (elmo-file-cache-get
3966                      (elmo-message-field folder number 'message-id)))
3967                    'section))
3968           ;; Reload.
3969           (wl-summary-redisplay-internal nil nil 'force-reload)
3970         (wl-summary-redisplay-internal folder number))
3971       (setq mes-buf wl-message-buffer)
3972       (wl-message-select-buffer mes-buf)
3973       ;; get original subject.
3974       (if summary-buf
3975           (save-excursion
3976             (set-buffer summary-buf)
3977             (setq subject
3978                   (or (elmo-message-field folder number 'subject) ""))))
3979       (set-buffer mes-buf)
3980       (wl-draft-forward subject summary-buf)
3981       (unless without-setup-hook
3982         (run-hooks 'wl-mail-setup-hook)))))
3983
3984 (defun wl-summary-click (e)
3985   (interactive "e")
3986   (mouse-set-point e)
3987   (wl-summary-read))
3988
3989 (defun wl-summary-read ()
3990   "Proceed reading message in the summary buffer."
3991   (interactive)
3992   (let ((cur-buf (current-buffer)))
3993     (wl-summary-toggle-disp-msg 'on)
3994     (when (wl-summary-set-message-buffer-or-redisplay 'ignore-original)
3995       (set-buffer cur-buf)
3996       (if (wl-message-next-page)
3997           (wl-summary-down t)))))
3998
3999 (defsubst wl-summary-cursor-move-surface (downward interactive)
4000   (if wl-summary-move-direction-toggle
4001       (setq wl-summary-move-direction-downward downward))
4002   (let ((start (point))
4003         (skip-tmark-regexp (wl-regexp-opt wl-summary-skip-mark-list))
4004         (skip t)
4005         (column (current-column))
4006         skip-pmark-regexp goto-next next-entity finfo)
4007     (if (elmo-folder-plugged-p wl-summary-buffer-elmo-folder)
4008         ()
4009       (setq skip-pmark-regexp
4010             (wl-regexp-opt (list " "
4011                                  elmo-msgdb-unread-cached-mark
4012                                  elmo-msgdb-important-mark))))
4013     (beginning-of-line)
4014     (let (case-fold-search)
4015       (while (and skip
4016                   (not (if downward (eobp) (bobp))))
4017         (if downward
4018             (forward-line 1)
4019           (forward-line -1))
4020         (setq skip (or (string-match skip-tmark-regexp
4021                                      (save-excursion
4022                                        (wl-summary-temp-mark)))
4023                        (and skip-pmark-regexp
4024                             (not (string-match
4025                                   skip-pmark-regexp
4026                                   (save-excursion
4027                                     (wl-summary-persistent-mark)))))))))
4028     (if (if downward (eobp) (and (bobp) skip)) (setq goto-next t))
4029     (if (or (eobp) (and (bobp) skip))
4030         (goto-char start))
4031     (move-to-column column)
4032
4033     (if (not goto-next)
4034         (if wl-summary-buffer-disp-msg
4035             (wl-summary-redisplay))
4036       (if interactive
4037           (cond
4038            ((and (not downward) wl-summary-buffer-prev-folder-function)
4039             (funcall wl-summary-buffer-prev-folder-function))
4040            ((and downward wl-summary-buffer-next-folder-function)
4041             (funcall wl-summary-buffer-next-folder-function))
4042            (t
4043             (when wl-auto-select-next
4044               (setq next-entity
4045                     (if downward
4046                         (wl-summary-get-next-folder)
4047                       (wl-summary-get-prev-folder)))
4048               (if next-entity
4049                   (setq finfo (wl-folder-get-entity-info next-entity))))
4050             (wl-ask-folder
4051              '(lambda () (wl-summary-next-folder-or-exit next-entity))
4052              (format
4053               "No more messages. Type SPC to go to %s."
4054               (wl-summary-entity-info-msg next-entity finfo)))))))))
4055
4056 (defun wl-summary-prev (&optional interactive)
4057   (interactive)
4058   (wl-summary-cursor-move-surface nil (or interactive (interactive-p))))
4059
4060 (defun wl-summary-next (&optional interactive)
4061   (interactive)
4062   (wl-summary-cursor-move-surface t (or interactive (interactive-p))))
4063
4064 (defun wl-summary-up (&optional interactive skip-no-unread)
4065   ""
4066   (interactive)
4067   (if wl-summary-move-direction-toggle
4068       (setq wl-summary-move-direction-downward nil))
4069   (if (wl-summary-cursor-up)
4070       (if wl-summary-buffer-disp-msg
4071           (wl-summary-redisplay))
4072     (if (or interactive
4073             (interactive-p))
4074         (if wl-summary-buffer-prev-folder-function
4075             (funcall wl-summary-buffer-prev-folder-function)
4076           (let (next-entity finfo)
4077             (when wl-auto-select-next
4078               (progn
4079                 (setq next-entity (wl-summary-get-prev-unread-folder))
4080                 (if next-entity
4081                     (setq finfo (wl-folder-get-entity-info next-entity)))))
4082             (if (and skip-no-unread
4083                      (eq wl-auto-select-next 'skip-no-unread))
4084                 (wl-summary-next-folder-or-exit next-entity t)
4085               (wl-ask-folder
4086                '(lambda () (wl-summary-next-folder-or-exit next-entity t))
4087                (format
4088                 "No more unread messages. Type SPC to go to %s."
4089                 (wl-summary-entity-info-msg next-entity finfo)))))))))
4090
4091 (defun wl-summary-get-prev-folder ()
4092   (let ((folder-buf (get-buffer wl-folder-buffer-name))
4093         last-entity 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-prev-folder cur-id))))
4098
4099 (defun wl-summary-get-next-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))))
4106
4107 (defun wl-summary-get-next-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-next-folder cur-id 'unread))))
4114
4115 (defun wl-summary-get-prev-unread-folder ()
4116   (let ((folder-buf (get-buffer wl-folder-buffer-name))
4117         cur-id)
4118     (when folder-buf
4119       (setq cur-id (save-excursion (set-buffer folder-buf)
4120                                    wl-folder-buffer-cur-entity-id))
4121       (wl-folder-get-prev-folder cur-id 'unread))))
4122
4123 (defun wl-summary-down (&optional interactive skip-no-unread)
4124   (interactive)
4125   (if wl-summary-move-direction-toggle
4126       (setq wl-summary-move-direction-downward t))
4127   (if (wl-summary-cursor-down)
4128       (if wl-summary-buffer-disp-msg
4129           (wl-summary-redisplay))
4130     (if (or interactive
4131             (interactive-p))
4132         (if wl-summary-buffer-next-folder-function
4133             (funcall wl-summary-buffer-next-folder-function)
4134           (let (next-entity finfo)
4135             (when wl-auto-select-next
4136               (setq next-entity (wl-summary-get-next-unread-folder)))
4137             (if next-entity
4138                 (setq finfo (wl-folder-get-entity-info next-entity)))
4139             (if (and skip-no-unread
4140                      (eq wl-auto-select-next 'skip-no-unread))
4141                 (wl-summary-next-folder-or-exit next-entity)
4142               (wl-ask-folder
4143                '(lambda () (wl-summary-next-folder-or-exit next-entity))
4144                (format
4145                 "No more unread messages. Type SPC to go to %s."
4146                 (wl-summary-entity-info-msg next-entity finfo)))))))))
4147
4148 (defun wl-summary-goto-last-displayed-msg ()
4149   (interactive)
4150   (unless wl-summary-buffer-last-displayed-msg
4151     (setq wl-summary-buffer-last-displayed-msg
4152           wl-summary-buffer-current-msg))
4153   (if wl-summary-buffer-last-displayed-msg
4154       (progn
4155         (wl-summary-jump-to-msg wl-summary-buffer-last-displayed-msg)
4156         (if wl-summary-buffer-disp-msg
4157             (wl-summary-redisplay)))
4158     (message "No last message.")))
4159
4160 (defun wl-summary-redisplay (&optional arg)
4161   (interactive "P")
4162   (if (and (not arg)
4163            (wl-summary-no-mime-p wl-summary-buffer-elmo-folder))
4164       (wl-summary-redisplay-no-mime)
4165     (wl-summary-redisplay-internal nil nil arg)))
4166
4167 (defsubst wl-summary-redisplay-internal (&optional folder number force-reload)
4168   (interactive)
4169   (let* ((folder (or folder wl-summary-buffer-elmo-folder))
4170          (num (or number (wl-summary-message-number)))
4171          (wl-mime-charset      wl-summary-buffer-mime-charset)
4172          (default-mime-charset wl-summary-buffer-mime-charset)
4173          no-folder-mark fld-buf fld-win thr-entity)
4174     (if (and wl-thread-open-reading-thread
4175              (eq wl-summary-buffer-view 'thread)
4176              (not (wl-thread-entity-get-opened
4177                    (setq thr-entity (wl-thread-get-entity
4178                                      num))))
4179              (wl-thread-entity-get-children thr-entity))
4180         (wl-thread-force-open))
4181     (if num
4182         (progn
4183           (setq wl-summary-buffer-disp-msg t)
4184           (setq wl-summary-buffer-last-displayed-msg
4185                 wl-summary-buffer-current-msg)
4186           ;; hide folder window
4187           (if (and (not wl-stay-folder-window)
4188                    (setq fld-buf (get-buffer wl-folder-buffer-name)))
4189               (if (setq fld-win (get-buffer-window fld-buf))
4190                   (delete-window fld-win)))
4191           (setq wl-current-summary-buffer (current-buffer))
4192           (setq no-folder-mark
4193                 ;; If cache is used, change folder-mark.
4194                 (if (wl-message-redisplay folder num
4195                                           'mime
4196                                           (or
4197                                            force-reload
4198                                            (string= (elmo-folder-name-internal
4199                                                      folder)
4200                                                     wl-draft-folder)))
4201                     nil
4202                   ;; plugged, then leave folder-mark.
4203                   (if (and (not (elmo-folder-local-p
4204                                  wl-summary-buffer-elmo-folder))
4205                            (elmo-folder-plugged-p
4206                             wl-summary-buffer-elmo-folder))
4207                       'leave)))
4208           (when (elmo-message-use-cache-p folder num)
4209             (elmo-message-set-cached folder num t))
4210           (ignore-errors
4211             (if (member (elmo-message-mark wl-summary-buffer-elmo-folder
4212                                            num)
4213                         (elmo-msgdb-unread-marks))
4214                 (wl-summary-mark-as-read num no-folder-mark)
4215               (wl-summary-update-mark)))
4216           (setq wl-summary-buffer-current-msg num)
4217           (when wl-summary-recenter
4218             (recenter (/ (- (window-height) 2) 2))
4219             (if (not wl-summary-indent-length-limit)
4220                 (wl-horizontal-recenter)))
4221           (wl-highlight-summary-displaying)
4222           (wl-message-buffer-prefetch-next folder num
4223                                            wl-message-buffer-prefetch-depth
4224                                            (current-buffer)
4225                                            wl-summary-buffer-mime-charset)
4226           (run-hooks 'wl-summary-redisplay-hook))
4227       (message "No message to display."))))
4228
4229 (defun wl-summary-redisplay-no-mime (&optional ask-coding)
4230   "Display message without MIME decoding.
4231 If ASK-CODING is non-nil, coding-system for the message is asked."
4232   (interactive "P")
4233   (let ((elmo-mime-display-as-is-coding-system
4234          (if ask-coding
4235              (or (read-coding-system "Coding system: ")
4236                  elmo-mime-display-as-is-coding-system)
4237            elmo-mime-display-as-is-coding-system)))
4238     (wl-summary-redisplay-no-mime-internal)))
4239
4240 (defun wl-summary-redisplay-no-mime-internal (&optional folder number)
4241   (let* ((fld (or folder wl-summary-buffer-elmo-folder))
4242          (num (or number (wl-summary-message-number)))
4243          wl-break-pages)
4244     (if num
4245         (progn
4246           (setq wl-summary-buffer-disp-msg t)
4247           (setq wl-summary-buffer-last-displayed-msg
4248                 wl-summary-buffer-current-msg)
4249           (setq wl-current-summary-buffer (current-buffer))
4250           (wl-message-redisplay fld num 'as-is
4251                                 (string= (elmo-folder-name-internal fld)
4252                                          wl-draft-folder))
4253           (wl-summary-mark-as-read num)
4254           (setq wl-summary-buffer-current-msg num)
4255           (when wl-summary-recenter
4256             (recenter (/ (- (window-height) 2) 2))
4257             (if (not wl-summary-indent-length-limit)
4258                 (wl-horizontal-recenter)))
4259           (wl-highlight-summary-displaying)
4260           (run-hooks 'wl-summary-redisplay-hook))
4261       (message "No message to display.")
4262       (wl-ask-folder 'wl-summary-exit
4263                      "No more messages. Type SPC to go to folder mode."))))
4264
4265 (defun wl-summary-redisplay-all-header (&optional folder number)
4266   (interactive)
4267   (let* ((fld (or folder wl-summary-buffer-elmo-folder))
4268          (num (or number (wl-summary-message-number)))
4269          (wl-mime-charset      wl-summary-buffer-mime-charset)
4270          (default-mime-charset wl-summary-buffer-mime-charset))
4271     (if num
4272         (progn
4273           (setq wl-summary-buffer-disp-msg t)
4274           (setq wl-summary-buffer-last-displayed-msg
4275                 wl-summary-buffer-current-msg)
4276           (setq wl-current-summary-buffer (current-buffer))
4277           (if (wl-message-redisplay fld num 'all-header
4278                                     (string= (elmo-folder-name-internal fld)
4279                                              wl-draft-folder))
4280               (wl-summary-mark-as-read num))
4281           (setq wl-summary-buffer-current-msg num)
4282           (when wl-summary-recenter
4283             (recenter (/ (- (window-height) 2) 2))
4284             (if (not wl-summary-indent-length-limit)
4285                 (wl-horizontal-recenter)))
4286           (wl-highlight-summary-displaying)
4287           (run-hooks 'wl-summary-redisplay-hook))
4288       (message "No message to display."))))
4289
4290 (defun wl-summary-jump-to-current-message ()
4291   "Jump into Message buffer."
4292   (interactive)
4293   (let (message-buf message-win)
4294     (if (setq message-buf wl-message-buffer)
4295         (if (setq message-win (get-buffer-window message-buf))
4296             (select-window message-win)
4297           (wl-message-select-buffer wl-message-buffer))
4298       (wl-summary-redisplay)
4299       (wl-message-select-buffer wl-message-buffer))))
4300
4301 (defun wl-summary-cancel-message ()
4302   "Cancel an article on news."
4303   (interactive)
4304   (if (null (wl-summary-message-number))
4305       (message "No message.")
4306     (let ((summary-buf (current-buffer))
4307           message-buf)
4308       (wl-summary-set-message-buffer-or-redisplay)
4309       (if (setq message-buf (wl-message-get-original-buffer))
4310           (set-buffer message-buf))
4311       (unless (wl-message-news-p)
4312         (set-buffer summary-buf)
4313         (if (and (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
4314                      'nntp)
4315                  (y-or-n-p "Cannot get Newsgroups. Fetch again? "))
4316             (progn
4317               (wl-summary-redisplay t)
4318               (wl-summary-supersedes-message))
4319           (error "This is not a news article; supersedes is impossible")))
4320       (when (yes-or-no-p "Do you really want to cancel this article? ")
4321         (let (from newsgroups message-id distribution buf)
4322           (save-excursion
4323             (setq from (std11-field-body "from")
4324                   newsgroups (std11-field-body "newsgroups")
4325                   message-id (std11-field-body "message-id")
4326                   distribution (std11-field-body "distribution"))
4327             ;; Make sure that this article was written by the user.
4328             (unless (wl-address-user-mail-address-p
4329                      (wl-address-header-extract-address
4330                       (car (wl-parse-addresses from))))
4331               (error "This article is not yours"))
4332             ;; Make control message.
4333             (setq buf (set-buffer (get-buffer-create " *message cancel*")))
4334             (setq wl-draft-buffer-cur-summary-buffer summary-buf)
4335             (buffer-disable-undo (current-buffer))
4336             (erase-buffer)
4337             (insert "Newsgroups: " newsgroups "\n"
4338                     "From: " (wl-address-header-extract-address
4339                               wl-from) "\n"
4340                               "Subject: cmsg cancel " message-id "\n"
4341                               "Control: cancel " message-id "\n"
4342                               (if distribution
4343                                   (concat "Distribution: " distribution "\n")
4344                                 "")
4345                               mail-header-separator "\n"
4346                               wl-summary-cancel-message)
4347             (message "Canceling your message...")
4348             (wl-draft-raw-send t t) ; kill when done, force-pre-hooks.
4349             (message "Canceling your message...done")))))))
4350
4351 (defun wl-summary-supersedes-message ()
4352   "Supersede current message."
4353   (interactive)
4354   (wl-summary-toggle-disp-msg 'off)
4355   (let ((summary-buf (current-buffer))
4356         message-buf from)
4357     (wl-summary-set-message-buffer-or-redisplay)
4358     (if (setq message-buf (wl-message-get-original-buffer))
4359         (set-buffer message-buf))
4360     (unless (wl-message-news-p)
4361       (set-buffer summary-buf)
4362       (if (and (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder)
4363                    'nntp)
4364                (y-or-n-p "Cannot get Newsgroups. Fetch again? "))
4365           (progn
4366             (wl-summary-redisplay t)
4367             (wl-summary-supersedes-message))
4368         (error "This is not a news article; supersedes is impossible")))
4369     (save-excursion
4370       (setq from (std11-field-body "from"))
4371       ;; Make sure that this article was written by the user.
4372       (unless (wl-address-user-mail-address-p
4373                (wl-address-header-extract-address
4374                 (car (wl-parse-addresses from))))
4375         (error "This article is not yours"))
4376       (let* ((message-id (std11-field-body "message-id"))
4377              (followup-to (std11-field-body "followup-to"))
4378              (mail-default-headers
4379               (concat mail-default-headers
4380                       "Supersedes: " message-id "\n"
4381                       (and followup-to
4382                            (concat "Followup-To: " followup-to "\n")))))
4383         (if message-buf (set-buffer message-buf))
4384         (wl-draft-edit-string (buffer-substring (point-min) (point-max)))))))
4385
4386 (defun wl-summary-save (&optional arg wl-save-dir)
4387   "Save current message to disk."
4388   (interactive)
4389   (let ((filename)
4390         (num (wl-summary-message-number)))
4391     (if (null wl-save-dir)
4392         (setq wl-save-dir wl-temporary-file-directory))
4393     (if num
4394         (save-excursion
4395           (setq filename (expand-file-name
4396                           (int-to-string num)
4397                           wl-save-dir))
4398           (if (null (and arg
4399                          (null (file-exists-p filename))))
4400               (setq filename
4401                     (read-file-name "Save to file: " filename)))
4402
4403           (wl-summary-set-message-buffer-or-redisplay)
4404           (set-buffer (wl-message-get-original-buffer))
4405           (if (and (null arg) (file-exists-p filename))
4406               (if (y-or-n-p "File already exists.  override it? ")
4407                   (write-region (point-min) (point-max) filename))
4408             (write-region (point-min) (point-max) filename)))
4409       (message "No message to save."))
4410     num))
4411
4412 (defun wl-summary-save-region (beg end)
4413   (interactive "r")
4414   (save-excursion
4415     (save-restriction
4416       (narrow-to-region beg end)
4417       (goto-char (point-min))
4418       (let ((wl-save-dir
4419              (wl-read-directory-name "Save to directory: "
4420                                      wl-temporary-file-directory)))
4421         (if (null (file-exists-p wl-save-dir))
4422             (make-directory wl-save-dir))
4423         (if (eq wl-summary-buffer-view 'thread)
4424             (progn
4425               (while (not (eobp))
4426                 (let* ((number (wl-summary-message-number))
4427                        (entity (wl-thread-get-entity number)))
4428                   (if (wl-thread-entity-get-opened entity)
4429                       (wl-summary-save t wl-save-dir)
4430                     ;; closed
4431                     (wl-summary-save t wl-save-dir))
4432                   (forward-line 1))))
4433           (while (not (eobp))
4434             (wl-summary-save t wl-save-dir)
4435             (forward-line 1)))))))
4436
4437 ;; mew-summary-pipe-message()
4438 (defun wl-summary-pipe-message (prefix command)
4439   "Send this message via pipe."
4440   (interactive (list current-prefix-arg nil))
4441   (if (null (wl-summary-message-number))
4442       (message "No message.")
4443     (setq command (read-string "Shell command on message: "
4444                                wl-summary-shell-command-last))
4445     (if (y-or-n-p "Send this message to pipe? ")
4446         (wl-summary-pipe-message-subr prefix command))))
4447
4448 (defun wl-summary-target-mark-pipe (prefix command)
4449   "Send each marked messages via pipe."
4450   (interactive (list current-prefix-arg nil))
4451   (if (null wl-summary-buffer-target-mark-list)
4452       (message "No marked message.")
4453     (setq command (read-string "Shell command on each marked message: "
4454                                wl-summary-shell-command-last))
4455     (when (y-or-n-p "Send each marked message to pipe? ")
4456       (while (car wl-summary-buffer-target-mark-list)
4457         (let ((num (car wl-summary-buffer-target-mark-list)))
4458           (wl-thread-jump-to-msg num)
4459           (wl-summary-pipe-message-subr prefix command)
4460           (wl-summary-unmark num))))))
4461
4462 (defun wl-summary-pipe-message-subr (prefix command)
4463   (save-excursion
4464     (wl-summary-set-message-buffer-or-redisplay)
4465     (set-buffer (wl-message-get-original-buffer))
4466     (if (string= command "")
4467         (setq command wl-summary-shell-command-last))
4468     (goto-char (point-min)) ; perhaps this line won't be necessary
4469     (if prefix
4470         (search-forward "\n\n"))
4471     (shell-command-on-region (point) (point-max) command nil)
4472     (setq wl-summary-shell-command-last command)))
4473
4474 (defun wl-summary-print-message (&optional arg)
4475   (interactive "P")
4476   (if (null (wl-summary-message-number))
4477       (message "No message.")
4478     (save-excursion
4479       (wl-summary-set-message-buffer-or-redisplay)
4480       (if (or (not (interactive-p))
4481               (y-or-n-p "Print ok? "))
4482           (progn
4483             (let ((buffer (generate-new-buffer " *print*")))
4484               (copy-to-buffer buffer (point-min) (point-max))
4485               (set-buffer buffer)
4486               (funcall wl-print-buffer-function)
4487               (kill-buffer buffer)))
4488         (message "")))))
4489
4490 (defun wl-summary-print-message-with-ps-print (&optional filename)
4491   "Print message via ps-print."
4492   (interactive)
4493   (if (null (wl-summary-message-number))
4494       (message "No message.")
4495     (setq filename (ps-print-preprint current-prefix-arg))
4496     (if (or (not (interactive-p))
4497             (y-or-n-p "Print ok? "))
4498         (let ((summary-buffer (current-buffer))
4499               wl-break-pages)
4500           (save-excursion
4501             (wl-summary-set-message-buffer-or-redisplay)
4502             ;; (wl-summary-redisplay-internal)
4503             (let* ((buffer (generate-new-buffer " *print*"))
4504                    (entity (progn
4505                              (set-buffer summary-buffer)
4506                              (elmo-message-entity
4507                               wl-summary-buffer-elmo-folder
4508                               (wl-summary-message-number))))
4509                    (wl-ps-subject
4510                     (and entity
4511                          (or (elmo-msgdb-overview-entity-get-subject entity)
4512                              "")))
4513                    (wl-ps-from
4514                     (and entity
4515                          (or (elmo-msgdb-overview-entity-get-from entity) "")))
4516                    (wl-ps-date
4517                     (and entity
4518                          (or (elmo-msgdb-overview-entity-get-date entity) ""))))
4519               (run-hooks 'wl-ps-preprint-hook)
4520               (set-buffer wl-message-buffer)
4521               (copy-to-buffer buffer (point-min) (point-max))
4522               (set-buffer buffer)
4523               (unwind-protect
4524                   (let ((ps-left-header
4525                          (list (concat "(" wl-ps-subject ")")
4526                                (concat "(" wl-ps-from ")")))
4527                         (ps-right-header
4528                          (list "/pagenumberstring load"
4529                                (concat "(" wl-ps-date ")"))))
4530                     (run-hooks 'wl-ps-print-hook)
4531                     (funcall wl-ps-print-buffer-function filename))
4532                 (kill-buffer buffer)))))
4533       (message ""))))
4534
4535 (if (featurep 'ps-print) ; ps-print is available.
4536     (fset 'wl-summary-print-message 'wl-summary-print-message-with-ps-print))
4537
4538 (defun wl-summary-target-mark-print ()
4539   (interactive)
4540   (if (null wl-summary-buffer-target-mark-list)
4541       (message "No marked message.")
4542     (when (y-or-n-p "Print all marked messages. OK? ")
4543       (while (car wl-summary-buffer-target-mark-list)
4544         (let ((num (car wl-summary-buffer-target-mark-list)))
4545           (wl-thread-jump-to-msg num)
4546           (wl-summary-print-message)
4547           (wl-summary-unmark num))))))
4548
4549 (defun wl-summary-folder-info-update ()
4550   (wl-folder-set-folder-updated
4551    (elmo-string (wl-summary-buffer-folder-name))
4552    (list 0
4553          (+ wl-summary-buffer-unread-count
4554             wl-summary-buffer-new-count)
4555          (elmo-folder-length
4556           wl-summary-buffer-elmo-folder))))
4557
4558 (defun wl-summary-get-original-buffer ()
4559   "Get original buffer for the current summary."
4560   (save-excursion
4561     (wl-summary-set-message-buffer-or-redisplay)
4562     (wl-message-get-original-buffer)))
4563
4564 (defun wl-summary-pack-number (&optional arg)
4565   (interactive "P")
4566   (elmo-folder-pack-numbers wl-summary-buffer-elmo-folder)
4567   (let (wl-use-scoring)
4568     (wl-summary-rescan)))
4569
4570 (defun wl-summary-target-mark-uudecode ()
4571   (interactive)
4572   (let ((mlist (reverse wl-summary-buffer-target-mark-list))
4573         (summary-buf (current-buffer))
4574         (tmp-buf (get-buffer-create "*WL UUENCODE*"))
4575         orig-buf i k filename rc errmsg)
4576     (setq i 1)
4577     (setq k (length mlist))
4578     (set-buffer tmp-buf)
4579     (erase-buffer)
4580     (save-window-excursion
4581       (while mlist
4582         (set-buffer summary-buf)
4583         (wl-summary-jump-to-msg (car mlist))
4584         (wl-summary-redisplay)
4585         (set-buffer (setq orig-buf (wl-summary-get-original-buffer)))
4586         (goto-char (point-min))
4587         (cond ((= i 1) ; first
4588                (if (setq filename (wl-message-uu-substring
4589                                    orig-buf tmp-buf t
4590                                    (= i k)))
4591                    nil
4592                  (error "Can't find begin line")))
4593               ((< i k)
4594                (wl-message-uu-substring orig-buf tmp-buf))
4595               (t ; last
4596                (wl-message-uu-substring orig-buf tmp-buf nil t)))
4597         (setq i (1+ i))
4598         (setq mlist (cdr mlist)))
4599       (set-buffer tmp-buf)
4600       (message "Exec %s..." wl-prog-uudecode)
4601       (unwind-protect
4602           (let ((decode-dir wl-temporary-file-directory))
4603             (if (not wl-prog-uudecode-no-stdout-option)
4604                 (setq filename (read-file-name "Save to file: "
4605                                                (expand-file-name
4606                                                 (elmo-safe-filename filename)
4607                                                 wl-temporary-file-directory)))
4608               (setq decode-dir
4609                     (wl-read-directory-name "Save to directory: "
4610                                             wl-temporary-file-directory))
4611               (setq filename (expand-file-name filename decode-dir)))
4612             (if (file-exists-p filename)
4613                 (or (yes-or-no-p (format "File %s exists. Save anyway? "
4614                                          filename))
4615                     (error "")))
4616             (elmo-bind-directory
4617              decode-dir
4618              (setq rc
4619                    (as-binary-process
4620                     (apply 'call-process-region (point-min) (point-max)
4621                            wl-prog-uudecode t (current-buffer) nil
4622                            wl-prog-uudecode-arg))))
4623             (when (not (= 0 rc))
4624               (setq errmsg (buffer-substring (point-min)(point-max)))
4625               (error "Uudecode error: %s" errmsg))
4626             (if (not wl-prog-uudecode-no-stdout-option)
4627                 (let (file-name-handler-alist) ;; void jka-compr
4628                   (as-binary-output-file
4629                    (write-region (point-min) (point-max)
4630                                  filename nil 'no-msg))))
4631             (save-excursion
4632               (set-buffer summary-buf)
4633               (wl-summary-delete-all-temp-marks))
4634             (if (file-exists-p filename)
4635                 (message "Saved as %s" filename)))
4636         (kill-buffer tmp-buf)))))
4637
4638 ;; Someday
4639 ;; (defun wl-summary-drop-unsync ()
4640 ;;   "Drop all unsync messages."
4641 ;;   (interactive)
4642 ;;   (if (elmo-folder-pipe-p (wl-summary-buffer-folder-name))
4643 ;;       (error "You cannot drop unsync messages in this folder"))
4644 ;;   (if (or (not (interactive-p))
4645 ;;        (y-or-n-p "Drop all unsync messages? "))
4646 ;;       (let* ((folder-list (elmo-folder-get-primitive-folder-list
4647 ;;                         (wl-summary-buffer-folder-name)))
4648 ;;           (is-multi (elmo-multi-p (wl-summary-buffer-folder-name)))
4649 ;;           (sum 0)
4650 ;;           (multi-num 0)
4651 ;;           pair)
4652 ;;      (message "Dropping...")
4653 ;;      (while folder-list
4654 ;;        (setq pair (elmo-folder-message-numbers (car folder-list)))
4655 ;;        (when is-multi ;; dirty hack...
4656 ;;          (incf multi-num)
4657 ;;          (setcar pair (+ (* multi-num elmo-multi-divide-number)
4658 ;;                          (car pair))))
4659 ;;        (elmo-msgdb-set-number-alist
4660 ;;         (wl-summary-buffer-msgdb)
4661 ;;         (nconc
4662 ;;          (elmo-msgdb-get-number-alist (wl-summary-buffer-msgdb))
4663 ;;          (list (cons (car pair) nil))))
4664 ;;        (setq sum (+ sum (cdr pair)))
4665 ;;        (setq folder-list (cdr folder-list)))
4666 ;;      (wl-summary-set-message-modified)
4667 ;;      (wl-folder-set-folder-updated (wl-summary-buffer-folder-name)
4668 ;;                                    (list 0
4669 ;;                                          (+ wl-summary-buffer-unread-count
4670 ;;                                             wl-summary-buffer-new-count)
4671 ;;                                          sum))
4672 ;;      (message "Dropping...done"))))
4673
4674 (defun wl-summary-default-get-next-msg (msg)
4675   (or (wl-summary-next-message msg
4676                                (if wl-summary-move-direction-downward 'down
4677                                  'up)
4678                                nil)
4679       (cadr (memq msg (if wl-summary-move-direction-downward
4680                           wl-summary-buffer-number-list
4681                         (reverse wl-summary-buffer-number-list))))))
4682
4683 (defun wl-summary-save-current-message ()
4684   "Save current message for `wl-summary-yank-saved-message'."
4685   (interactive)
4686   (let ((number (wl-summary-message-number)))
4687     (setq wl-summary-buffer-saved-message number)
4688     (and number (message "No: %s is saved." number))))
4689
4690 (defun wl-summary-yank-saved-message ()
4691   "Set current message as a parent of the saved message."
4692   (interactive)
4693   (if wl-summary-buffer-saved-message
4694       (let ((number (wl-summary-message-number)))
4695         (if (eq wl-summary-buffer-saved-message number)
4696             (message "Cannot set itself as a parent.")
4697           (save-excursion
4698             (wl-thread-jump-to-msg wl-summary-buffer-saved-message)
4699             (wl-thread-set-parent number)
4700             (wl-summary-set-thread-modified))
4701           (setq  wl-summary-buffer-saved-message nil)))
4702     (message "There's no saved message.")))
4703
4704 (require 'product)
4705 (product-provide (provide 'wl-summary) (require 'wl-version))
4706
4707 ;;; wl-summary.el ends here