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