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