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