New file.
authorteranisi <teranisi>
Tue, 15 Jul 2003 15:43:31 +0000 (15:43 +0000)
committerteranisi <teranisi>
Tue, 15 Jul 2003 15:43:31 +0000 (15:43 +0000)
wl/wl-action.el [new file with mode: 0644]

diff --git a/wl/wl-action.el b/wl/wl-action.el
new file mode 100644 (file)
index 0000000..65b0413
--- /dev/null
@@ -0,0 +1,854 @@
+;;; wl-action.el --- Mark and actions in the Summary mode for Wanderlust.
+
+;; Copyright (C) 2003 Yuuichi Teranishi <teranisi@gohome.org>
+
+;; Author: Yuuichi Teranishi <teranisi@gohome.org>
+;; Keywords: mail, net news
+
+;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+;;
+
+;;; Commentary:
+;;
+
+;;; Code:
+;;
+
+(require 'wl-summary)
+
+(defsubst wl-summary-action-mark (action)
+  (nth 0 action))
+(defsubst wl-summary-action-symbol (action)
+  (nth 1 action))
+(defsubst wl-summary-action-argument-function (action)
+  (nth 2 action))
+(defsubst wl-summary-action-set-function (action)
+  (nth 3 action))
+(defsubst wl-summary-action-exec-function (action)
+  (nth 4 action))
+(defsubst wl-summary-action-face (action)
+  (nth 5 action))
+(defsubst wl-summary-action-docstring (action)
+  (nth 6 action))
+
+;; Set mark
+(defun wl-summary-set-mark (&optional set-mark number interactive data)
+  (interactive)
+  "Set temporary mark SET-MARK on the message with NUMBER.
+NUMBER is the message number to set the mark on.
+INTERACTIVE is set as t if it have to run interactively.
+DATA is passed to the set-action function of the action as an argument.
+Return number if put mark succeed"
+  (let* ((set-mark (or set-mark
+                      (completing-read "Mark: " wl-summary-mark-action-list)))
+        (current (wl-summary-message-number))
+        (action (assoc set-mark wl-summary-mark-action-list))
+        visible mark cur-mark)
+    (save-excursion
+      ;; Put mark
+      (setq visible (or
+                    ;; not-interactive and visible
+                    (and number (wl-summary-jump-to-msg number))
+                    ;; interactive
+                    (and (null number) current))
+           number (or number current))
+      (when (and interactive
+                (null data)
+                (wl-summary-action-argument-function action))
+       (setq data (funcall (wl-summary-action-argument-function action)
+                           (wl-summary-action-symbol action)
+                           number)))
+      (when (setq cur-mark (nth 1 (wl-summary-registered-temp-mark number)))
+       (when (and (wl-summary-reserve-temp-mark-p cur-mark)
+                  interactive)
+         (error "Already marked as `%s'" cur-mark)))
+      (wl-summary-unset-mark number)
+      (when visible
+       (wl-summary-mark-line set-mark)
+       (when wl-summary-highlight
+         (wl-highlight-summary-current-line))
+       (when data
+         (wl-summary-print-destination number data)))
+      ;; Set action.
+      (funcall (wl-summary-action-set-function action)
+              number
+              (wl-summary-action-mark action)
+              data)
+      (set-buffer-modified-p nil))
+    ;; Move the cursor.
+    (if (or interactive (interactive-p))
+       (if (eq wl-summary-move-direction-downward nil)
+           (wl-summary-prev)
+         (wl-summary-next)))
+    ;; Return value.
+    number))
+
+(defun wl-summary-register-target-mark (number mark)
+  (or (memq number wl-summary-buffer-target-mark-list)
+      (setq wl-summary-buffer-target-mark-list
+           (cons number wl-summary-buffer-target-mark-list))))
+
+(defun wl-summary-unregister-target-mark (number)
+  (delq number wl-summary-buffer-target-mark-list))
+
+(defun wl-summary-have-target-mark-p (number)
+  (memq number wl-summary-buffer-target-mark-list))
+
+(defun wl-summary-target-mark-set-action (action)
+  (unless (eq (wl-summary-action-symbol action) 'target-mark)
+    (save-excursion
+      (goto-char (point-min))
+      (let ((numlist wl-summary-buffer-number-list)
+           number mlist data)
+       ;; use firstly marked message.
+       (when (wl-summary-action-argument-function action)
+         (while numlist
+           (if (memq (car numlist) wl-summary-buffer-target-mark-list)
+               (setq number (car numlist)
+                     numlist nil))
+           (setq numlist (cdr numlist)))
+         (setq data (funcall (wl-summary-action-argument-function action)
+                             action number)))
+       (while (not (eobp))
+         (when (string= (wl-summary-temp-mark) "*")
+           (let (wl-summary-buffer-disp-msg)
+             (when (setq number (wl-summary-message-number))
+               (wl-summary-set-mark (wl-summary-action-mark action)
+                                    number nil data)
+               (setq wl-summary-buffer-target-mark-list
+                     (delq number wl-summary-buffer-target-mark-list)))))
+         (forward-line 1))
+       (setq mlist wl-summary-buffer-target-mark-list)
+       (while mlist
+         (wl-summary-register-temp-mark (car mlist)
+                                        (wl-summary-action-mark action) data)
+         (setq wl-summary-buffer-target-mark-list
+               (delq (car mlist) wl-summary-buffer-target-mark-list))
+         (setq mlist (cdr mlist)))))))
+
+;; wl-summary-buffer-temp-mark-list specification
+;; ((1 "D" nil)(2 "o" "+fuga")(3 "O" "+hoge"))
+(defun wl-summary-register-temp-mark (number mark mark-info)
+  (let ((elem (assq number wl-summary-buffer-temp-mark-list)))
+    (setq wl-summary-buffer-temp-mark-list
+         (delq elem wl-summary-buffer-temp-mark-list)))
+  (setq wl-summary-buffer-temp-mark-list
+       (cons (list number mark mark-info) wl-summary-buffer-temp-mark-list)))
+
+(defun wl-summary-unregister-temp-mark (number)
+  (let ((elem (assq number wl-summary-buffer-temp-mark-list)))
+    (setq wl-summary-buffer-temp-mark-list
+         (delq elem wl-summary-buffer-temp-mark-list))))
+
+(defun wl-summary-registered-temp-mark (number)
+  (assq number wl-summary-buffer-temp-mark-list))
+
+(defun wl-summary-collect-temp-mark (mark &optional begin end)
+  (if (or begin end)
+      (save-excursion
+       (save-restriction
+         (let (mark-list)
+           (narrow-to-region (or begin (point-min))(or end (point-max)))
+           (goto-char (point-min))
+           ;; for thread...
+           (if (eq wl-summary-buffer-view 'thread)
+               (let (number entity mark-info)
+                 (while (not (eobp))
+                   (setq number (wl-summary-message-number)
+                         entity (wl-thread-get-entity number)
+                         mark-info (wl-summary-registered-temp-mark number))
+                   ;; toplevel message mark.
+                   (when (string= (nth 1 mark-info) mark)
+                     (setq mark-list (cons mark-info mark-list)))
+                   ;; When thread is closed...children should also be checked.
+                   (unless (wl-thread-entity-get-opened entity)
+                     (dolist (msg (wl-thread-get-children-msgs number))
+                       (setq mark-info (wl-summary-registered-temp-mark
+                                        msg))
+                       (when (string= (nth 1 mark-info) mark)
+                         (setq mark-list (cons mark-info mark-list)))))
+                   (forward-line 1)))
+             (let (number mark-info)
+               (while (not (eobp))
+                 (setq number (wl-summary-message-number)
+                       mark-info (wl-summary-registered-temp-mark number))
+                 (when (string= (nth 1 mark-info) mark)
+                   (setq mark-list (cons mark-info mark-list)))
+                 (forward-line 1))))
+           mark-list)))
+    (let (mark-list)
+      (dolist (mark-info wl-summary-buffer-temp-mark-list)
+       (when (string= (nth 1 mark-info) mark)
+         (setq mark-list (cons mark-info mark-list))))
+      mark-list)))
+
+;; Unset mark
+(defun wl-summary-unset-mark (&optional number interactive)
+  "Unset temporary mark of the message with NUMBER.
+NUMBER is the message number to unset the mark.
+If not specified, the message on the cursor position is treated.
+Optional INTERACTIVE is non-nil when it should be called interactively.
+Return number if put mark succeed"
+  (interactive)
+  (save-excursion
+    (beginning-of-line)
+    (let ((buffer-read-only nil)
+         visible mark action)
+      (if number
+         (setq visible (wl-summary-jump-to-msg number))
+       (setq visible t))
+      (setq number (or number (wl-summary-message-number)))
+      ;; Delete mark on buffer.
+      (when visible
+       (setq mark (wl-summary-temp-mark))
+       (unless (string= mark " ")
+         (delete-backward-char 1)
+         (insert (or (wl-summary-get-score-mark number)
+                     " "))
+         (setq action (assoc mark wl-summary-mark-action-list))
+         (when wl-summary-highlight
+           (wl-highlight-summary-current-line))
+         (when (wl-summary-action-argument-function action)
+           (wl-summary-remove-destination)))
+       (set-buffer-modified-p nil))
+      ;; Remove from temporal mark structure.
+      (wl-summary-unregister-target-mark number)
+      (wl-summary-unregister-temp-mark number)))
+  ;; Move the cursor.
+  ;;  (if (or interactive (interactive-p))
+  ;;      (if (eq wl-summary-move-direction-downward nil)
+  ;;     (wl-summary-prev)
+  ;;   (wl-summary-next))))
+  )
+
+(defun wl-summary-make-destination-numbers-list (mark-list)
+  (let (dest-numbers dest-number)
+    (dolist (elem mark-list)
+      (setq dest-number (assoc (nth 2 elem) dest-numbers))
+      (if dest-number
+         (unless (memq (car elem) (cdr dest-number))
+           (nconc dest-number (list (car elem))))
+       (setq dest-numbers (nconc dest-numbers
+                                 (list
+                                  (list (nth 2 elem)
+                                        (car elem)))))))
+    dest-numbers))
+
+(defun wl-summary-move-mark-list-messages (mark-list folder-name message)
+  (if (null mark-list)
+      (message "No marks")
+    (save-excursion
+      (let ((start (point))
+           (refiles (mapcar 'car mark-list))
+           (refile-failures 0)
+           refile-len
+           dst-msgs                    ; loop counter
+           result)
+       ;; begin refile...
+       (setq refile-len (length refiles))
+       (goto-char start)               ; avoid moving cursor to
+                                       ; the bottom line.
+       (when (> refile-len elmo-display-progress-threshold)
+         (elmo-progress-set 'elmo-folder-move-messages
+                            refile-len message))
+       (setq result nil)
+       (condition-case nil
+           (setq result (elmo-folder-move-messages
+                         wl-summary-buffer-elmo-folder
+                         refiles
+                         (if (eq folder-name 'null)
+                             'null
+                           (wl-folder-get-elmo-folder folder-name))
+                         (wl-summary-buffer-msgdb)
+                         (not (null (cdr dst-msgs)))
+                         nil ; no-delete
+                         nil ; same-number
+                         t))
+         (error nil))
+       (when result            ; succeeded.
+         ;; update buffer.
+         (wl-summary-delete-messages-on-buffer refiles)
+         ;; update wl-summary-buffer-temp-mark-list.
+         (dolist (mark-info mark-list)
+           (setq wl-summary-buffer-temp-mark-list
+                 (delq mark-info wl-summary-buffer-temp-mark-list))))
+       (elmo-progress-clear 'elmo-folder-move-messages)
+       (wl-summary-set-message-modified)
+       ;; Return the operation failed message numbers.
+       (if result
+           0
+         (length refiles))))))
+
+(defun wl-summary-get-refile-destination-subr (action number learn)
+  (let* ((number (or number (wl-summary-message-number)))
+        (msgid (and number
+                    (elmo-message-field wl-summary-buffer-elmo-folder
+                                        number 'message-id)))
+        (entity (and number
+                     (elmo-message-entity wl-summary-buffer-elmo-folder
+                                          number)))
+        folder cur-mark tmp-folder)
+    (catch 'done
+      (when (null entity)
+       (message "Cannot decide destination.")
+       (throw 'done nil))
+      (when (null number)
+       (message "No message.")
+       (throw 'done nil))
+      (setq folder (wl-summary-read-folder
+                   (or (wl-refile-guess entity) wl-trash-folder)
+                   (format "for %s " action)))
+      ;; Cache folder hack by okada@opaopa.org
+      (when (and (eq (elmo-folder-type-internal
+                     (wl-folder-get-elmo-folder
+                      (wl-folder-get-realname folder))) 'cache)
+                (not (string= folder
+                              (setq tmp-folder
+                                    (concat "'cache/"
+                                            (elmo-cache-get-path-subr
+                                             (elmo-msgid-to-cache msgid)))))))
+       (setq folder tmp-folder)
+       (message "Force refile to %s." folder))
+      (if (string= folder (wl-summary-buffer-folder-name))
+         (error "Same folder"))
+      (if (or (not (elmo-folder-writable-p (wl-folder-get-elmo-folder folder)))
+             (string= folder wl-queue-folder)
+             (string= folder wl-draft-folder))
+         (error "Don't set as target: %s" folder))
+      ;; learn for refile.
+      (when learn
+       (wl-refile-learn entity folder))
+      folder)))
+
+;;; Actions
+(defun wl-summary-define-mark-action ()
+  (interactive)
+  (dolist (action wl-summary-mark-action-list)
+    (fset (intern (format "wl-summary-%s" (wl-summary-action-symbol action)))
+         `(lambda (&optional number data)
+            ,(wl-summary-action-docstring action)
+            (interactive)
+            (wl-summary-set-mark ,(wl-summary-action-mark action)
+                                 number (interactive-p))))
+    (fset (intern (format "wl-summary-%s-region"
+                         (wl-summary-action-symbol action)))
+         `(lambda (beg end)
+            ,(wl-summary-action-docstring action)
+            (interactive "r")
+            (goto-char beg)
+            (wl-summary-mark-region-subr
+             ,(intern (format "wl-summary-%s"
+                              (wl-summary-action-symbol action)))
+             beg end
+             (if (wl-summary-action-argument-function action)
+                 (funcall (wl-summary-action-argument-function action)
+                          (wl-summary-action-symbol action)
+                          (wl-summary-message-number))))))
+    (fset (intern (format "wl-summary-target-mark-%s"
+                         (wl-summary-action-symbol action)))
+         `(lambda ()
+            ,(wl-summary-action-docstring action)
+            (interactive)
+            (wl-summary-target-mark-set-action action)))))
+
+(defun wl-summary-get-dispose-folder (folder)
+  (if (string= folder wl-trash-folder)
+      'null
+    (let* ((type (or (wl-get-assoc-list-value wl-dispose-folder-alist folder)
+                    'trash)))
+      (cond ((stringp type)
+            type)
+           ((or (equal type 'remove) (equal type 'null))
+            'null)
+           (t;; (equal type 'trash)
+            (let ((trash-folder (wl-folder-get-elmo-folder wl-trash-folder)))
+              (unless (elmo-folder-exists-p trash-folder)
+                (if (y-or-n-p
+                     (format "Trash Folder %s does not exist, create it? "
+                             wl-trash-folder))
+                    (elmo-folder-create trash-folder)
+                  (error "Trash Folder is not created"))))
+            wl-trash-folder)))))
+
+;; Dispose action.
+(defun wl-summary-exec-action-dispose (mark-list)
+  (wl-summary-move-mark-list-messages mark-list
+                                     (wl-summary-get-dispose-folder
+                                      (wl-summary-buffer-folder-name))
+                                     "Disposing messages..."))
+
+;; Delete action.
+(defun wl-summary-exec-action-delete (mark-list)
+  (wl-summary-move-mark-list-messages mark-list
+                                     'null
+                                     "Deleting messages..."))
+
+;; Refile action
+(defun wl-summary-set-action-refile (number mark data)
+  (let ((policy (wl-get-assoc-list-value wl-refile-policy-alist
+                                        (wl-summary-buffer-folder-name)))
+       (elem wl-summary-mark-action-list))
+    (if (eq policy 'copy)
+       (while elem
+         (when (eq (wl-summary-action-symbol (car elem)) 'copy)
+           (wl-summary-register-temp-mark number
+                                          (wl-summary-action-mark (car elem))
+                                          data)
+           (setq elem nil))
+         (setq elem (cdr elem)))
+      (wl-summary-register-temp-mark number mark data)
+      (setq wl-summary-buffer-prev-refile-destination data))))
+
+(defun wl-summary-get-refile-destination (action number)
+  "Decide refile destination."
+  (wl-summary-get-refile-destination-subr action number t))
+
+(defun wl-summary-exec-action-refile (mark-list)
+  (save-excursion
+    (let ((start (point))
+         (failures 0)
+         (refile-len (length mark-list))
+         dst-msgs ; loop counter
+         result)
+      ;; begin refile...
+      (setq dst-msgs
+           (wl-summary-make-destination-numbers-list mark-list))
+      (goto-char start)        ; avoid moving cursor to the bottom line.
+      (when (> refile-len elmo-display-progress-threshold)
+       (elmo-progress-set 'elmo-folder-move-messages
+                          refile-len "Moving messages..."))
+      (while dst-msgs
+       (setq result nil)
+       (condition-case nil
+           (setq result (elmo-folder-move-messages
+                           wl-summary-buffer-elmo-folder
+                           (cdr (car dst-msgs))
+                           (wl-folder-get-elmo-folder
+                            (car (car dst-msgs)))
+                           (wl-summary-buffer-msgdb)
+                           (not (null (cdr dst-msgs)))
+                           nil ; no-delete
+                           nil ; same-number
+                           t))
+         (error nil))
+       (if result              ; succeeded.
+           (progn
+             ;; update buffer.
+             (wl-summary-delete-messages-on-buffer (cdr (car dst-msgs)))
+             (setq wl-summary-buffer-temp-mark-list
+                   (wl-delete-associations 
+                    (cdr (car dst-msgs))
+                    wl-summary-buffer-temp-mark-list)))
+         (setq failures
+               (+ failures (length (cdr (car dst-msgs))))))
+       (setq dst-msgs (cdr dst-msgs)))
+      (elmo-progress-clear 'elmo-folder-move-messages)
+      failures)))
+
+;; Copy action
+(defun wl-summary-get-copy-destination (action number)
+  (wl-summary-get-refile-destination-subr action number nil))
+
+(defun wl-summary-exec-action-copy (mark-list)
+  (save-excursion
+    (let ((start (point))
+         (failures 0)
+         (refile-len (length mark-list))
+         dst-msgs ; loop counter
+         result)
+      ;; begin refile...
+      (setq dst-msgs
+           (wl-summary-make-destination-numbers-list mark-list))
+      (goto-char start)        ; avoid moving cursor to the bottom line.
+      (when (> refile-len elmo-display-progress-threshold)
+       (elmo-progress-set 'elmo-folder-move-messages
+                          refile-len "Copying messages..."))
+      (while dst-msgs
+       (setq result nil)
+       (condition-case nil
+           (setq result (elmo-folder-move-messages
+                           wl-summary-buffer-elmo-folder
+                           (cdr (car dst-msgs))
+                           (wl-folder-get-elmo-folder
+                            (car (car dst-msgs)))
+                           (wl-summary-buffer-msgdb)
+                           (not (null (cdr dst-msgs)))
+                           t ; t is no-delete (copy)
+                           nil ; same-number
+                           t))
+         (error nil))
+       (if result              ; succeeded.
+           (progn
+             ;; update buffer.
+             (wl-summary-delete-copy-marks-on-buffer (cdr (car dst-msgs)))
+             (setq wl-summary-buffer-temp-mark-list
+                   (wl-delete-associations 
+                    (cdr (car dst-msgs))
+                    wl-summary-buffer-temp-mark-list)))
+         (setq failures
+               (+ failures (length (cdr (car dst-msgs))))))
+       (setq dst-msgs (cdr dst-msgs)))
+      (elmo-progress-clear 'elmo-folder-move-messages)
+      failures)))
+
+;; Prefetch.
+(defun wl-summary-exec-action-prefetch (mark-list)
+  (save-excursion
+    (let* ((buffer-read-only nil)
+          (count 0)
+          (length (length mark-list))
+          (mark-list-copy (copy-sequence mark-list))
+          (pos (point))
+          (failures 0)
+          new-mark)
+      (dolist (mark-info mark-list-copy)
+       (message "Prefetching...(%d/%d)"
+                (setq count (+ 1 count)) length)
+       (setq new-mark (wl-summary-prefetch-msg (car mark-info)))
+       (if new-mark
+           (progn
+             (wl-summary-unset-mark (car mark-info))
+             (when (wl-summary-jump-to-msg (car mark-info))
+               (wl-summary-persistent-mark) ; move
+               (delete-backward-char 1)
+               (insert new-mark)
+               (when wl-summary-highlight
+                 (wl-highlight-summary-current-line))
+               (save-excursion
+                 (goto-char pos)
+                 (sit-for 0))))
+         (incf failures)))
+      (message "Prefetching...done")
+      0)))
+
+;;;
+(defun wl-summary-remove-destination ()
+  (save-excursion
+    (let ((inhibit-read-only t)
+         (buffer-read-only nil)
+         (buf (current-buffer))
+         sol eol rs re)
+      (beginning-of-line)
+      (setq sol (point))
+      (search-forward "\r")
+      (forward-char -1)
+      (setq eol (point))
+      (setq rs (next-single-property-change sol 'wl-summary-destination
+                                           buf eol))
+      (setq re (next-single-property-change rs 'wl-summary-destination
+                                           buf eol))
+      (put-text-property rs re 'wl-summary-destination nil)
+      (put-text-property rs re 'invisible nil)
+      (goto-char re)
+      (delete-char (- eol re)))))
+
+(defun wl-summary-collect-numbers-region (begin end)
+  "Return a list of message number in the region specified by BEGIN and END."
+  (save-excursion
+    (save-restriction
+      (let (numbers)
+       (narrow-to-region (or begin (point-min))(or end (point-max)))
+       (goto-char (point-min))
+       ;; for thread...
+       (if (eq wl-summary-buffer-view 'thread)
+           (let (number entity mark-info)
+             (while (not (eobp))
+               (setq numbers (cons (wl-summary-message-number) numbers)
+                     entity (wl-thread-get-entity number))
+               ;; When thread is closed...children should also be checked.
+               (unless (wl-thread-entity-get-opened entity)
+                 (dolist (msg (wl-thread-get-children-msgs number))
+                   (setq numbers (cons msg numbers))))
+               (forward-line 1)))
+         (let (number mark-info)
+           (while (not (eobp))
+             (setq numbers (cons (wl-summary-message-number) numbers))
+             (forward-line 1))))
+       numbers))))
+
+(defun wl-summary-exec (&optional numbers)
+  (interactive)
+  (let ((failures 0)
+       collected pair action modified)
+    (dolist (action wl-summary-mark-action-list)
+      (setq collected (cons (cons 
+                            (wl-summary-action-mark action)
+                            nil) collected)))
+    (dolist (mark-info wl-summary-buffer-temp-mark-list)
+      (if numbers
+         (when (memq (nth 0 mark-info) numbers)
+           (setq pair (assoc (nth 1 mark-info) collected)))
+       (setq pair (assoc (nth 1 mark-info) collected)))
+      (setq pair (assoc (nth 1 mark-info) collected))
+      (setcdr pair (cons mark-info (cdr pair))))
+    ;; collected is a pair of
+    ;; mark-string and a list of mark-info
+    (dolist (pair collected)
+      (setq action (assoc (car pair) wl-summary-mark-action-list))
+      (when (and (cdr pair) (wl-summary-action-exec-function action))
+       (setq modified t)
+       (setq failures (+ failures (funcall
+                                   (wl-summary-action-exec-function action)
+                                   (cdr pair))))))
+    (when modified
+      (wl-summary-set-message-modified))
+    (run-hooks 'wl-summary-exec-hook)
+    ;; message buffer is not up-to-date
+    (unless (and wl-message-buffer
+                (eq (wl-summary-message-number)
+                    (with-current-buffer wl-message-buffer
+                      wl-message-buffer-cur-number)))
+      (wl-summary-toggle-disp-msg 'off)
+      (setq wl-message-buffer nil))
+    (set-buffer-modified-p nil)
+    (message "Executing...done%s"
+            (if (> failures 0)
+                (format " (%d failed)" failures)
+              ""))))
+
+(defun wl-summary-exec-region (beg end)
+  (interactive "r")
+  (wl-summary-exec
+   (wl-summary-collect-numbers-region beg end)))
+
+(defun wl-summary-read-folder (default &optional purpose ignore-error
+                               no-create init)
+  (let ((fld (completing-read
+             (format "Folder name %s(%s): " (or purpose "")
+                     default)
+             'wl-folder-complete-folder
+             nil nil (or init wl-default-spec)
+             'wl-read-folder-hist)))
+    (if (or (string= fld wl-default-spec)
+           (string= fld ""))
+       (setq fld default))
+    (setq fld (elmo-string (wl-folder-get-realname fld)))
+    (if (string-match "\n" fld)
+       (error "Not supported folder name: %s" fld))
+    (unless no-create
+      (if ignore-error
+         (condition-case nil
+             (wl-folder-confirm-existence
+              (wl-folder-get-elmo-folder
+               fld))
+           (error))
+       (wl-folder-confirm-existence (wl-folder-get-elmo-folder
+                                     fld))))
+    fld))
+
+(defun wl-summary-print-destination (msg-num folder)
+  "Print refile destination on line."
+  (wl-summary-remove-destination)
+  (save-excursion
+    (let ((inhibit-read-only t)
+         (folder (copy-sequence folder))
+         (buffer-read-only nil)
+         len rs re c)
+      (setq len (string-width folder))
+      (if (< len 1) ()
+       ;;(end-of-line)
+       (beginning-of-line)
+       (search-forward "\r")
+       (forward-char -1)
+       (setq re (point))
+       (setq c 0)
+       (while (< c len)
+         (forward-char -1)
+         (setq c (+ c (char-width (following-char)))))
+       (and (> c len) (setq folder (concat " " folder)))
+       (setq rs (point))
+       (when wl-summary-width
+         (put-text-property rs re 'invisible t))
+       (put-text-property rs re 'wl-summary-destination t)
+       (goto-char re)
+       (wl-highlight-refile-destination-string folder)
+       (insert folder)
+       (set-buffer-modified-p nil)))))
+
+(defsubst wl-summary-reserve-temp-mark-p (mark)
+  "Return t if temporal MARK should be reserved."
+  (member mark wl-summary-reserve-mark-list))
+
+(defun wl-summary-refile-prev-destination ()
+  "Refile message to previously refiled destination."
+  (interactive)
+  (funcall (symbol-function 'wl-summary-refile)
+          wl-summary-buffer-prev-refile-destination
+          (wl-summary-message-number))
+  (if (eq wl-summary-move-direction-downward nil)
+      (wl-summary-prev)
+    (wl-summary-next)))
+
+(defsubst wl-summary-no-auto-refile-message-p (msg)
+  (member (elmo-msgdb-get-mark (wl-summary-buffer-msgdb) msg)
+         wl-summary-auto-refile-skip-marks))
+
+(defun wl-summary-auto-refile (&optional open-all)
+  "Set refile mark automatically according to 'wl-refile-guess-by-rule'."
+  (interactive "P")
+  (message "Marking...")
+  (save-excursion
+    (if (and (eq wl-summary-buffer-view 'thread)
+            open-all)
+       (wl-thread-open-all))
+    (let* ((spec (wl-summary-buffer-folder-name))
+          checked-dsts
+          (count 0)
+          number dst thr-entity)
+      (goto-line 1)
+      (while (not (eobp))
+       (setq number (wl-summary-message-number))
+       (dolist (number (cons number
+                             (and (eq wl-summary-buffer-view 'thread)
+                                  ;; process invisible children.
+                                  (not (wl-thread-entity-get-opened
+                                        (setq thr-entity
+                                              (wl-thread-get-entity number))))
+                                  (wl-thread-entity-get-descendant
+                                   thr-entity))))
+         (when (and (not (wl-summary-no-auto-refile-message-p
+                          number))
+                    (setq dst
+                          (wl-folder-get-realname
+                           (wl-refile-guess-by-rule
+                            (elmo-msgdb-overview-get-entity
+                             number (wl-summary-buffer-msgdb)))))
+                    (not (equal dst spec))
+                    (let ((pair (assoc dst checked-dsts))
+                          ret)
+                      (if pair
+                          (cdr pair)
+                        (setq ret
+                              (condition-case nil
+                                  (progn
+                                    (wl-folder-confirm-existence
+                                     (wl-folder-get-elmo-folder dst))
+                                    t)
+                                (error)))
+                        (setq checked-dsts (cons (cons dst ret) checked-dsts))
+                        ret)))
+           (if (funcall (symbol-function 'wl-summary-refile) dst number)
+               (incf count))
+           (message "Marking...%d message(s)." count)))
+       (forward-line))
+      (if (eq count 0)
+         (message "No message was marked.")
+       (message "Marked %d message(s)." count)))))
+
+(defun wl-summary-unmark (&optional number)
+  "Unmark marks (temporary, refile, copy, delete)of current line.
+If optional argument NUMBER is specified, unmark message specified by NUMBER."
+  (interactive)
+  (wl-summary-unset-mark number (interactive-p)))
+
+(defun wl-summary-target-mark (&optional number)
+  "Put target mark '*' on current message.
+If optional argument NUMBER is specified, mark message specified by NUMBER."
+  (interactive)
+  (wl-summary-set-mark "*" number (interactive-p)))
+
+(defun wl-summary-unmark-region (beg end)
+  (interactive "r")
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (if (eq wl-summary-buffer-view 'thread)
+         (progn
+           (while (not (eobp))
+             (let* ((number (wl-summary-message-number))
+                    (entity (wl-thread-get-entity number)))
+               (if (wl-thread-entity-get-opened entity)
+                   ;; opened...unmark line.
+                   (wl-summary-unmark)
+                 ;; closed
+                 (wl-summary-delete-marks-on-buffer
+                  (wl-thread-get-children-msgs number))))
+             (forward-line 1)))
+       (while (not (eobp))
+         (wl-summary-unmark)
+         (forward-line 1))))))
+
+(defun wl-summary-mark-region-subr (function beg end data)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (if (eq wl-summary-buffer-view 'thread)
+         (progn
+           (while (not (eobp))
+             (let* ((number (wl-summary-message-number))
+                    (entity (wl-thread-get-entity number))
+                    (wl-summary-move-direction-downward t)
+                    children)
+               (if (wl-thread-entity-get-opened entity)
+                   ;; opened...delete line.
+                   (funcall function number data)
+                 ;; closed
+                 (setq children (wl-thread-get-children-msgs number))
+                 (while children
+                   (funcall function (pop children) data)))
+               (forward-line 1))))
+       (while (not (eobp))
+         (funcall function (wl-summary-message-number) data)
+         (forward-line 1))))))
+
+(defun wl-summary-target-mark-region (beg end)
+  (interactive "r")
+  (wl-summary-mark-region-subr 'wl-summary-target-mark beg end nil))
+
+(defun wl-summary-target-mark-all ()
+  (interactive)
+  (wl-summary-target-mark-region (point-min) (point-max))
+  (setq wl-summary-buffer-target-mark-list
+       (mapcar 'car
+               (elmo-msgdb-get-number-alist (wl-summary-buffer-msgdb)))))
+
+(defun wl-summary-delete-all-mark (mark)
+  (goto-char (point-min))
+  (while (not (eobp))
+    (when (string= (wl-summary-temp-mark) mark)
+      (wl-summary-unmark))
+    (forward-line 1))
+  (let (deleted)
+    (dolist (mark-info wl-summary-buffer-temp-mark-list)
+      (when (string= (nth 1 mark-info) mark)
+       (setq deleted (cons mark-info deleted))))
+    (dolist (delete deleted)
+      (setq wl-summary-buffer-temp-mark-list
+           (delq delete wl-summary-buffer-temp-mark-list)))))
+
+(defun wl-summary-unmark-all ()
+  "Unmark all according to what you input."
+  (interactive)
+  (let ((unmarks (string-to-char-list (read-from-minibuffer "Unmark: ")))
+       cur-mark)
+    (save-excursion
+      (while unmarks
+       (setq cur-mark (char-to-string (car unmarks)))
+       (wl-summary-delete-all-mark cur-mark)
+       (setq unmarks (cdr unmarks))))))
+
+(defun wl-summary-target-mark-thread ()
+  (interactive)
+  (wl-thread-call-region-func 'wl-summary-target-mark-region t))
+
+(require 'product)
+(product-provide (provide 'wl-action) (require 'wl-version))
+
+;;; wl-action.el ends here