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