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