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