fix the last change
[elisp/wanderlust.git] / wl / wl-summary.el
index 2aebd02..59a1f7d 100644 (file)
@@ -60,7 +60,7 @@
 (defvar dragdrop-drop-functions)
 (defvar scrollbar-height)
 (defvar mail-reply-buffer)
-(defvar elmo-global-flag-list)
+(defvar elmo-global-flags)
 
 (defvar wl-summary-buffer-name "Summary")
 (defvar wl-summary-mode-map nil)
@@ -91,7 +91,7 @@
 (defvar wl-summary-buffer-temp-mark-column nil)
 (defvar wl-summary-buffer-persistent-mark-column nil)
 
-(defvar wl-summary-buffer-unsync-mark-number-list nil)
+(defvar wl-summary-buffer-persistent-mark-version 0)
 
 (defvar wl-summary-buffer-persistent nil)
 (defvar wl-summary-buffer-thread-nodes nil)
 (defvar wl-summary-buffer-line-format nil)
 (defvar wl-summary-buffer-mode-line-formatter nil)
 (defvar wl-summary-buffer-mode-line nil)
-(defvar wl-summary-buffer-display-as-is nil)
+(defvar wl-summary-buffer-display-mime-mode 'mime)
+(defvar wl-summary-buffer-display-header-mode 'partial)
 
 (defvar wl-thread-indent-level-internal nil)
 (defvar wl-thread-have-younger-brother-str-internal nil)
 (make-variable-buffer-local 'wl-summary-buffer-number-column)
 (make-variable-buffer-local 'wl-summary-buffer-temp-mark-column)
 (make-variable-buffer-local 'wl-summary-buffer-persistent-mark-column)
-(make-variable-buffer-local 'wl-summary-buffer-unsync-mark-number-list)
+(make-variable-buffer-local 'wl-summary-buffer-persistent-mark-version)
 (make-variable-buffer-local 'wl-summary-buffer-persistent)
 (make-variable-buffer-local 'wl-summary-buffer-thread-nodes)
 (make-variable-buffer-local 'wl-summary-buffer-prev-refile-destination)
 (make-variable-buffer-local 'wl-summary-buffer-line-format)
 (make-variable-buffer-local 'wl-summary-buffer-mode-line-formatter)
 (make-variable-buffer-local 'wl-summary-buffer-mode-line)
-(make-variable-buffer-local 'wl-summary-buffer-display-as-is)
+(make-variable-buffer-local 'wl-summary-buffer-display-mime-mode)
+(make-variable-buffer-local 'wl-summary-buffer-display-header-mode)
 
 (defvar wl-datevec)
 (defvar wl-thr-indent-string)
@@ -209,42 +211,25 @@ summary's folder name matches with `wl-summary-showto-folder-regexp'
 and (2) sender address is yours.
 
 See also variable `wl-use-petname'."
-  (let (retval tos ng)
-    (unless
-       (and (eq major-mode 'wl-summary-mode)
+  (let ((translator (if wl-use-petname
+                       (lambda (string)
+                         (or (funcall wl-summary-get-petname-function string)
+                             (car (std11-extract-address-components string))
+                             string))
+                     #'identity))
+       to ng)
+    (or (and (eq major-mode 'wl-summary-mode)
             (stringp wl-summary-showto-folder-regexp)
             (string-match wl-summary-showto-folder-regexp
                           (wl-summary-buffer-folder-name))
             (wl-address-user-mail-address-p from)
             (cond
-             ((and (setq tos (elmo-message-entity-field
-                              wl-message-entity 'to t))
-                   (not (string= "" tos)))
-              (setq retval
-                    (concat "To:"
-                            (mapconcat
-                             (function
-                              (lambda (to)
-                                (eword-decode-string
-                                 (if wl-use-petname
-                                     (or
-                                      (funcall
-                                       wl-summary-get-petname-function to)
-                                      (car
-                                       (std11-extract-address-components to))
-                                      to)
-                                   to))))
-                             (wl-parse-addresses tos)
-                             ","))))
-             ((setq ng (elmo-message-entity-field
-                        wl-message-entity 'newsgroups))
-              (setq retval (concat "Ng:" ng)))))
-      (if wl-use-petname
-         (setq retval (or (funcall wl-summary-get-petname-function from)
-                          (car (std11-extract-address-components from))
-                          from))
-       (setq retval from)))
-    retval))
+             ((setq to (elmo-message-entity-field wl-message-entity 'to))
+              (concat "To:" (mapconcat translator to ",")))
+             ((setq ng (elmo-message-entity-field wl-message-entity
+                                                  'newsgroups))
+              (concat "Ng:" ng))))
+       (funcall translator from))))
 
 (defun wl-summary-simple-from (string)
   (if wl-use-petname
@@ -394,6 +379,11 @@ See also variable `wl-use-petname'."
     ()
   (setq wl-summary-mode-map (make-keymap))
   (suppress-keymap wl-summary-mode-map)
+  (substitute-key-definition 'kill-buffer
+                            'wl-summary-mimic-kill-buffer
+                            wl-summary-mode-map
+                            global-map)
+  ;; basic commands
   (define-key wl-summary-mode-map " "    'wl-summary-read)
   (define-key wl-summary-mode-map "."    'wl-summary-redisplay)
   (define-key wl-summary-mode-map "<"    'wl-summary-display-top)
@@ -435,7 +425,7 @@ See also variable `wl-use-petname'."
   (define-key wl-summary-mode-map "\C-c\C-a" 'wl-addrmgr)
   (define-key wl-summary-mode-map "\C-c\C-p" 'wl-summary-previous-buffer)
   (define-key wl-summary-mode-map "\C-c\C-n" 'wl-summary-next-buffer)
-  (define-key wl-summary-mode-map "H"    'wl-summary-redisplay-all-header)
+  (define-key wl-summary-mode-map "H"    'wl-summary-toggle-all-header)
   (define-key wl-summary-mode-map "M"    'wl-summary-toggle-mime)
   (define-key wl-summary-mode-map "B"    'wl-summary-burst)
   (define-key wl-summary-mode-map "Z"    'wl-status-update)
@@ -576,6 +566,15 @@ See also variable `wl-use-petname'."
    "Menu used in Summary mode."
    wl-summary-mode-menu-spec))
 
+(defun wl-summary-mimic-kill-buffer (buffer)
+  "Kill the current (Summary) buffer with query."
+  (interactive "bKill buffer: ")
+  (if (or (not buffer)
+         (string-equal buffer "")
+         (string-equal buffer (buffer-name)))
+      (wl-summary-exit 'force-exit)
+    (kill-buffer buffer)))
+
 (defsubst wl-summary-message-visible-p (number)
   "Return non-nil if the message with NUMBER is visible."
   (or (eq wl-summary-buffer-view 'sequence)
@@ -594,7 +593,8 @@ See also variable `wl-use-petname'."
        (save-excursion
          (goto-char beg)
          (while (and (< (point) end) (not (eobp)))
-           (when (null (get-text-property (point) 'face))
+           (when (or (null (get-text-property (point) 'face))
+                     (wl-summary-persistent-mark-invalid-p))
              (setq number (wl-summary-message-number))
              (when number
                (setq flags (elmo-message-flags wl-summary-buffer-elmo-folder
@@ -616,6 +616,79 @@ See also variable `wl-use-petname'."
        (wl-summary-lazy-update-mark
         (list 'wl-summary-update-mark-window))))
 
+(defun wl-summary-after-resize-function (frame)
+  "Called from `window-size-change-functions'."
+  (save-excursion
+    (save-selected-window
+      (select-frame frame)
+      (walk-windows
+       (lambda (window)
+        (set-buffer (window-buffer window))
+        (when (eq major-mode 'wl-summary-mode)
+          (run-hook-with-args 'wl-summary-buffer-window-scroll-functions
+                              window)))
+       'nomini frame))))
+
+;; Handler of event from elmo-folder
+(defun wl-summary-update-persistent-mark-on-event (buffer numbers)
+  (save-excursion
+    (set-buffer buffer)
+    (if wl-summary-lazy-update-mark
+       (let ((window-list (get-buffer-window-list (current-buffer) 'nomini t))
+             invalidate)
+         (dolist (number numbers)
+           (when (wl-summary-message-visible-p number)
+             (if (catch 'visible
+                   (let ((window-list window-list)
+                         win)
+                     (while (setq win (car window-list))
+                       (when (wl-summary-jump-to-msg number
+                                                     (window-start win)
+                                                     (window-end win))
+                         (throw 'visible t))
+                       (setq window-list (cdr window-list)))))
+                 (wl-summary-update-persistent-mark number)
+               (setq invalidate t))))
+         (when invalidate
+           (wl-summary-invalidate-persistent-mark)
+           (dolist (win window-list)
+             (wl-summary-validate-persistent-mark
+              (window-start win)
+              (window-end win)))))
+      (dolist (number numbers)
+       (when (and (wl-summary-message-visible-p number)
+                  (wl-summary-jump-to-msg number))
+         (wl-summary-update-persistent-mark number))))))
+
+(defun wl-summary-buffer-attach ()
+  (when wl-summary-buffer-elmo-folder
+    (elmo-connect-signal
+     wl-summary-buffer-elmo-folder
+     'flag-changed
+     (current-buffer)
+     (elmo-define-signal-handler (buffer folder numbers)
+       (wl-summary-update-persistent-mark-on-event buffer numbers)))
+    (elmo-connect-signal
+     wl-summary-buffer-elmo-folder
+     'cache-changed
+     (current-buffer)
+     (elmo-define-signal-handler (buffer folder number)
+       (wl-summary-update-persistent-mark-on-event buffer (list number))))
+    (elmo-connect-signal
+     wl-summary-buffer-elmo-folder
+     'update-overview
+     (current-buffer)
+     (elmo-define-signal-handler (buffer folder number)
+       (with-current-buffer buffer
+        (wl-summary-rescan-message number))))))
+
+(defun wl-summary-buffer-detach ()
+  (when (and (eq major-mode 'wl-summary-mode)
+            wl-summary-buffer-elmo-folder)
+    (elmo-disconnect-signal 'flag-changed (current-buffer))
+    (elmo-disconnect-signal 'cache-changed (current-buffer))
+    (elmo-disconnect-signal 'update-overview (current-buffer))))
+
 (defun wl-status-update ()
   (interactive)
   (wl-address-init))
@@ -652,21 +725,18 @@ If optional USE-CACHE is non-nil, use cache if exists."
        (folder wl-summary-buffer-elmo-folder))
     (if (null number)
        (message "No message.")
-      (elmo-set-work-buf
-       (elmo-message-fetch folder
-                          number
-                          (elmo-make-fetch-strategy
-                           'entire
-                           use-cache ; use cache
-                           nil ; save cache (should `t'?)
-                           (and
-                            use-cache
-                            (elmo-file-cache-get-path
-                             (elmo-message-field folder number 'message-id))))
-                          nil
-                          (current-buffer)
-                          'unread)
-       (buffer-string)))))
+      (elmo-message-fetch-string folder
+                                number
+                                (elmo-make-fetch-strategy
+                                 'entire
+                                 use-cache ; use cache
+                                 nil ; save cache (should `t'?)
+                                 (and
+                                  use-cache
+                                  (elmo-file-cache-get-path
+                                   (elmo-message-field folder number
+                                                       'message-id))))
+                                'unread))))
 
 (defun wl-summary-reedit (&optional arg)
   "Re-edit current message.
@@ -674,7 +744,7 @@ If ARG is non-nil, Supersedes message"
   (interactive "P")
   (wl-summary-toggle-disp-msg 'off)
   (cond
-   ((not (wl-summary-message-number))
+   ((null (wl-summary-message-number))
     (message "No message."))
    (arg
     (wl-summary-supersedes-message))
@@ -684,7 +754,7 @@ If ARG is non-nil, Supersedes message"
        (mail-position-on-field "Newsgroups")
       (mail-position-on-field "To")))
    (t
-    (wl-draft-edit-string (wl-summary-message-string)))))
+    (wl-draft-edit-string (wl-summary-message-string 'maybe)))))
 
 (defun wl-summary-resend-bounced-mail ()
   "Re-mail the current message.
@@ -763,14 +833,13 @@ you."
          wl-summary-buffer-persistent-mark-column persistent)))
 
 (defun wl-summary-buffer-set-folder (folder)
+  (wl-summary-buffer-detach)
   (if (stringp folder)
       (setq folder (wl-folder-get-elmo-folder folder)))
   (setq wl-summary-buffer-elmo-folder folder)
   (make-local-variable 'wl-message-buffer)
-  (setq wl-summary-buffer-mime-charset (or (wl-get-assoc-list-value
-                                           wl-folder-mime-charset-alist
-                                           (elmo-folder-name-internal folder))
-                                          wl-mime-charset))
+  (setq wl-summary-buffer-mime-charset (wl-folder-mime-charset
+                                       (elmo-folder-name-internal folder)))
   (setq wl-summary-buffer-weekday-name-lang
        (or (wl-get-assoc-list-value
             wl-folder-weekday-name-lang-alist
@@ -799,6 +868,7 @@ you."
   (setq wl-summary-buffer-persistent
        (wl-folder-persistent-p (elmo-folder-name-internal folder)))
   (elmo-folder-set-persistent-internal folder wl-summary-buffer-persistent)
+  (wl-summary-buffer-attach)
   ;; process duplicates.
   (elmo-folder-set-process-duplicates-internal
    folder (cdr (elmo-string-matched-assoc
@@ -841,6 +911,8 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
 ;;;(setq default-directory (or wl-tmp-dir (expand-file-name "~/")))
   (setq buffer-read-only t)
   (setq truncate-lines t)
+  (when (boundp 'show-trailing-whitespace)
+    (setq show-trailing-whitespace nil))
 ;;;(make-local-variable 'tab-width)
 ;;;(setq tab-width 1)
   (buffer-disable-undo (current-buffer))
@@ -854,7 +926,12 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
     (let ((hook (if wl-on-xemacs 'pre-idle-hook 'window-scroll-functions)))
       (make-local-hook hook)
       (dolist (function wl-summary-buffer-window-scroll-functions)
-       (add-hook hook function nil t))))
+       (add-hook hook function nil t)))
+    (add-hook 'window-size-change-functions
+             #'wl-summary-after-resize-function))
+  (dolist (hook '(change-major-mode-hook kill-buffer-hook))
+    (make-local-hook hook)
+    (add-hook hook #'wl-summary-buffer-detach nil t))
   ;; This hook may contain the function `wl-setup-summary' for reasons
   ;; of system internal to accord facilities for the Emacs variants.
   (run-hooks 'wl-summary-mode-hook))
@@ -869,11 +946,9 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
 (defun wl-summary-overview-entity-compare-by-date (x y)
   "Compare entity X and Y by date."
   (condition-case nil
-      (string<
-       (timezone-make-date-sortable
-       (elmo-message-entity-field x 'date))
-       (timezone-make-date-sortable
-       (elmo-message-entity-field y 'date)))
+      (elmo-time<
+       (elmo-message-entity-field x 'date)
+       (elmo-message-entity-field y 'date))
     (error))) ;; ignore error.
 
 (defun wl-summary-overview-entity-compare-by-number (x y)
@@ -885,12 +960,10 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
 (defun wl-summary-overview-entity-compare-by-from (x y)
   "Compare entity X and Y by from."
   (string<
-   (wl-address-header-extract-address
-    (or (elmo-message-entity-field x 'from t)
-       wl-summary-no-from-message))
-   (wl-address-header-extract-address
-    (or (elmo-message-entity-field y 'from t)
-       wl-summary-no-from-message))))
+   (or (elmo-message-entity-field x 'from)
+       wl-summary-no-from-message)
+   (or (elmo-message-entity-field y 'from)
+       wl-summary-no-from-message)))
 
 (defun wl-summary-overview-entity-compare-by-subject (x y)
   "Compare entity X and Y by subject."
@@ -899,38 +972,54 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
 
 (defun wl-summary-get-list-info (entity)
   "Returns (\"ML-name\" . ML-count) of ENTITY."
-  (let (sequence ml-name ml-count subject return-path delivered-to mailing-list)
-    (setq sequence (elmo-message-entity-field entity 'x-sequence)
-         ml-name (or (elmo-message-entity-field entity 'x-ml-name)
-                     (and sequence
-                          (car (split-string sequence " "))))
-         ml-count (or (elmo-message-entity-field entity 'x-mail-count)
-                      (elmo-message-entity-field entity 'x-ml-count)
-                      (and sequence
-                           (cadr (split-string sequence " ")))))
-    (and (setq subject (elmo-message-entity-field entity 'subject t))
-        (setq subject (elmo-delete-char ?\n subject))
-        (string-match "^\\s(\\(\\S)+\\)[ :]\\([0-9]+\\)\\s)[ \t]*" subject)
-        (progn
-          (or ml-name (setq ml-name (match-string 1 subject)))
-          (or ml-count (setq ml-count (match-string 2 subject)))))
-    (and (setq return-path
-              (elmo-message-entity-field entity 'return-path))
-        (string-match "^<\\([^@>]+\\)-return-\\([0-9]+\\)-" return-path)
-        (progn
-          (or ml-name (setq ml-name (match-string 1 return-path)))
-          (or ml-count (setq ml-count (match-string 2 return-path)))))
-    (and (setq delivered-to
-              (elmo-message-entity-field entity 'delivered-to))
-        (string-match "^mailing list \\([^@]+\\)@" delivered-to)
-        (or ml-name (setq ml-name (match-string 1 delivered-to))))
-    (and (setq mailing-list
-              (elmo-message-entity-field entity 'mailing-list))
-        ;; *-help@, *-owner@, etc.
-        (string-match "\\(^\\|; \\)contact \\([^@]+\\)-[^-@]+@" mailing-list)
-        (or ml-name (setq ml-name (match-string 2 mailing-list))))
-    (cons (and ml-name (car (split-string ml-name " ")))
-         (and ml-count (string-to-int ml-count)))))
+  (or (elmo-message-entity-field entity 'ml-info)
+      (let (sequence ml-name ml-count subject
+                    return-path delivered-to mailing-list
+                    list-post list-id)
+       (setq sequence (elmo-message-entity-field entity 'x-sequence)
+             ml-name (or (elmo-message-entity-field entity 'x-ml-name)
+                         (and sequence
+                              (car (split-string sequence " "))))
+             ml-count (or (elmo-message-entity-field entity 'x-mail-count)
+                          (elmo-message-entity-field entity 'x-ml-count)
+                          (and sequence
+                               (cadr (split-string sequence " ")))))
+       (and (setq subject (elmo-message-entity-field entity 'subject))
+            (setq subject (elmo-delete-char ?\n subject))
+            (string-match "^\\s(\\(\\S)+\\)[ :]\\([0-9]+\\)\\s)[ \t]*"
+                          subject)
+            (progn
+              (or ml-name (setq ml-name (match-string 1 subject)))
+              (or ml-count (setq ml-count (match-string 2 subject)))))
+       (and (setq return-path
+                  (elmo-message-entity-field entity 'return-path))
+            (string-match "^<\\([^@>]+\\)-return-\\([0-9]+\\)-" return-path)
+            (progn
+              (or ml-name (setq ml-name (match-string 1 return-path)))
+              (or ml-count (setq ml-count (match-string 2 return-path)))))
+       (or ml-name
+           (and (setq list-post (elmo-message-entity-field entity 'list-post))
+                (string-match "<mailto:\\(.+\\)@" list-post)
+                (setq ml-name (match-string 1 list-post))))
+       (or ml-name
+           (and (setq list-id (elmo-message-entity-field entity 'list-id))
+                (or (string-match "<\\([^.]+\\)\\." list-id)
+                    (string-match "^\\([^.]+\\)\\." list-id))
+                (setq ml-name (match-string 1 list-id))))
+       (or ml-name
+           (and (setq delivered-to
+                      (elmo-message-entity-field entity 'delivered-to))
+                (string-match "^mailing list \\([^@]+\\)@" delivered-to)
+                (setq ml-name (match-string 1 delivered-to))))
+       (or ml-name
+           (and (setq mailing-list
+                      (elmo-message-entity-field entity 'mailing-list))
+                ;; *-help@, *-owner@, etc.
+                (string-match "\\(^\\|; \\)contact \\([^@]+\\)-[^-@]+@"
+                              mailing-list)
+                (setq ml-name (match-string 2 mailing-list))))
+       (cons (and ml-name (car (split-string ml-name " ")))
+             (and ml-count (string-to-int ml-count))))))
 
 (defun wl-summary-overview-entity-compare-by-list-info (x y)
   "Compare entity X and Y by mailing-list info."
@@ -969,6 +1058,40 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
   (interactive "P")
   (wl-summary-rescan "size" reverse))
 
+(defun wl-summary-sort-function-from-spec (spec reverse)
+  (let (funtion)
+    (when (string-match "^!\\(.+\\)$" spec)
+      (setq spec (match-string 1 spec)
+           reverse (not reverse)))
+    (setq funtion
+         (intern (format "wl-summary-overview-entity-compare-by-%s" spec)))
+    (if reverse
+       `(lambda (x y) (not (,funtion x y)))
+      funtion)))
+
+(defun wl-summary-sort-messages (numbers sort-by reverse)
+  (let* ((functions (mapcar
+                    (lambda (spec)
+                      (wl-summary-sort-function-from-spec spec reverse))
+                    (if (listp sort-by) sort-by (list sort-by))))
+        (predicate (if (= (length functions) 1)
+                       (car functions)
+                     (lambda (x y)
+                       (let ((functions functions))
+                         (catch 'done
+                           (dolist (function functions)
+                             (when (funcall function x y)
+                               (throw 'done t))
+                             (when (funcall function y x)
+                               (throw 'done nil)))))))))
+    (mapcar #'elmo-message-entity-number
+           (sort (mapcar (lambda (number)
+                           (elmo-message-entity
+                            wl-summary-buffer-elmo-folder
+                            number))
+                         numbers)
+                 predicate))))
+
 (defun wl-summary-rescan (&optional sort-by reverse disable-killed disable-thread)
   "Rescan current folder without updating."
   (interactive)
@@ -984,33 +1107,23 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
         (and disable-thread wl-summary-search-parent-by-subject-regexp))
        (wl-summary-divide-thread-when-subject-changed
         (and disable-thread wl-summary-divide-thread-when-subject-changed))
-       (predicate (and sort-by
-                       (intern (format "wl-summary-overview-entity-compare-by-%s"
-                                       sort-by))))
-       (sort-label (if reverse "Reverse sorting" "Sorting"))
        (i 0)
        num
        expunged)
     (erase-buffer)
     (message "Re-scanning...")
-    (when sort-by
-      (message "%s by %s..." sort-label sort-by)
-      (setq numbers
-           (sort numbers
-                 (lambda (x y)
-                   (funcall
-                    predicate
-                    (elmo-message-entity wl-summary-buffer-elmo-folder x)
-                    (elmo-message-entity wl-summary-buffer-elmo-folder y)))))
-      (if reverse (setq numbers (nreverse numbers)))
-      (message "%s by %s...done" sort-label sort-by))
+    (when (and sort-by numbers)
+      (let ((action  (if reverse "Reverse sorting" "Sorting")))
+       (message "%s by %s..." action sort-by)
+       (setq numbers (wl-summary-sort-messages numbers sort-by reverse))
+       (message "%s by %s...done" action sort-by)))
     (setq num (length numbers))
     (setq wl-thread-entity-hashtb (elmo-make-hash (* num 2))
          wl-thread-entity-list nil
          wl-thread-entities nil
          wl-summary-scored nil
          wl-summary-buffer-number-list nil
-         wl-summary-buffer-unsync-mark-number-list nil
+         wl-summary-buffer-persistent-mark-version 0
          wl-summary-buffer-target-mark-list nil
          wl-summary-buffer-temp-mark-list nil
          wl-summary-delayed-update nil)
@@ -1058,6 +1171,57 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
     (forward-line -1)
     (set-buffer-modified-p nil)))
 
+(defun wl-summary-rescan-message (number &optional reparent)
+  "Rescan current message without updating."
+  (interactive (list (wl-summary-message-number) current-prefix-arg))
+  (let ((start-number (wl-summary-message-number))
+       (start-column (current-column)))
+    (when (wl-summary-jump-to-msg number)
+      (let* ((folder wl-summary-buffer-elmo-folder)
+            (entity (elmo-message-entity folder number))
+            (inhibit-read-only t))
+       (if (eq wl-summary-buffer-view 'thread)
+           (let* ((thread-entity (wl-thread-get-entity number))
+                  (thread-parent (wl-thread-entity-get-parent thread-entity))
+                  (entity-parent (elmo-message-entity-number
+                                  (elmo-message-entity-parent folder entity)))
+                  update-top-list)
+             (if (and (not reparent)
+                      (eq thread-parent entity-parent))
+                 (progn
+                   (wl-thread-entity-set-linked thread-entity nil)
+                   (wl-thread-update-line-on-buffer-sub nil number))
+               (let ((replacements
+                      (cons number
+                            (wl-thread-entity-get-descendant thread-entity))))
+                 (wl-thread-delete-message number 'deep 'update)
+                 (wl-thread-cleanup-symbols replacements)
+                 (dolist (number replacements)
+                   (setq update-top-list
+                         (nconc
+                          update-top-list
+                          (wl-summary-insert-thread
+                           (elmo-message-entity folder number)
+                           folder
+                           'update))))
+                 (when update-top-list
+                   (wl-thread-update-indent-string-thread
+                    (elmo-uniq-list update-top-list))))))
+           (delete-region (point-at-bol) (1+ (point-at-eol)))
+           (wl-summary-insert-line
+            (wl-summary-create-line entity nil
+                                    (wl-summary-temp-mark number)
+                                    (elmo-message-flags folder number)
+                                    (elmo-message-cached-p folder number)))))
+      (when (and wl-summary-buffer-disp-msg
+                wl-summary-buffer-current-msg)
+       (save-excursion
+         (when (wl-summary-jump-to-msg wl-summary-buffer-current-msg)
+           (wl-highlight-summary-displaying))))
+      (wl-summary-set-message-modified)
+      (wl-summary-jump-to-msg start-number)
+      (move-to-column start-column))))
+
 (defun wl-summary-next-folder-or-exit (&optional next-entity upward)
   (if (and next-entity
           wl-auto-select-next)
@@ -1299,18 +1463,17 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
       (if body (setq candidates (append candidates body)))
       (setq fields (cdr fields)))
     (setq candidates (elmo-uniq-list candidates))
-    (elmo-set-work-buf
-     (set-buffer-multibyte default-enable-multibyte-characters)
-     (mapcar (function
-             (lambda (x)
-               (setq components (std11-extract-address-components x))
-               (cons (nth 1 components)
-                     (and (car components)
-                          (eword-decode-string
-                           (decode-mime-charset-string
-                            (car components)
-                            mime-charset))))))
-            candidates))))
+    (elmo-with-enable-multibyte
+      (mapcar (function
+              (lambda (x)
+                (setq components (std11-extract-address-components x))
+                (cons (nth 1 components)
+                      (and (car components)
+                           (eword-decode-string
+                            (decode-mime-charset-string
+                             (car components)
+                             mime-charset))))))
+             candidates))))
 
 (defun wl-summary-edit-addresses-subr (the-email name-in-addr)
   ;; returns nil if there's no change.
@@ -1474,7 +1637,7 @@ If ARG is non-nil, checking is omitted."
                            (or
                             (elmo-message-entity-field
                              wl-message-entity
-                             'from t)
+                             'from)
                             "??")))))
                       " ]")
                      size))))
@@ -1483,20 +1646,11 @@ If ARG is non-nil, checking is omitted."
            (save-excursion
              (save-match-data
                ;; online
-               (if (or arg (not file-cached))
-                   (elmo-message-encache
-                    wl-summary-buffer-elmo-folder
-                    number))
+               (when (or arg (not file-cached))
+                 (elmo-message-encache wl-summary-buffer-elmo-folder
+                                       number))
                (elmo-message-set-cached wl-summary-buffer-elmo-folder
-                                        number t)
-               (when (and (wl-summary-jump-to-msg number)
-                          (wl-summary-update-persistent-mark))
-                 (sit-for 0)
-                 (wl-summary-count-unread)
-                 (wl-summary-update-modeline)
-                 (wl-folder-update-unread
-                  (wl-summary-buffer-folder-name)
-                  wl-summary-buffer-unread-count)))
+                                        number t))
              t)
          nil)))))
 
@@ -1658,15 +1812,10 @@ If ARG is non-nil, checking is omitted."
       (let ((folder wl-summary-buffer-elmo-folder)
            (cur-buf (current-buffer)))
        (message "Setting all msgs as read...")
-       (elmo-folder-set-flag
+       (elmo-folder-unset-flag
         folder
         (elmo-folder-list-flagged folder 'unread 'in-msgdb)
-        'read)
-       (save-excursion
-         (goto-char (point-min))
-         (while (not (eobp))
-           (wl-summary-update-persistent-mark)
-           (forward-line 1)))
+        'unread)
        (wl-folder-update-unread (wl-summary-buffer-folder-name) 0)
        (setq wl-summary-buffer-unread-count 0)
        (setq wl-summary-buffer-new-count    0)
@@ -1681,7 +1830,7 @@ If ARG is non-nil, checking is omitted."
           number)
       (setq number (wl-summary-message-number))
       (elmo-message-set-cached folder number nil)
-      (when (wl-summary-update-persistent-mark)
+      (ignore-errors
        (elmo-file-cache-delete
         (elmo-file-cache-get-path
          (elmo-message-field wl-summary-buffer-elmo-folder
@@ -1701,7 +1850,6 @@ If ARG is non-nil, checking is omitted."
        (setq msgid (elmo-message-field folder number 'message-id))
        (elmo-message-set-cached folder number
                                 (elmo-file-cache-exists-p msgid))
-       (wl-summary-update-persistent-mark)
        (forward-line 1))
       (wl-summary-count-unread)
       (wl-summary-update-modeline)
@@ -1755,12 +1903,7 @@ If ARG is non-nil, checking is omitted."
     (goto-char beg)
     (while (and (< (point) end) (not (eobp)))
       (when (or (not check)
-               (let ((number (wl-summary-message-number)))
-                 (when (memq number wl-summary-buffer-unsync-mark-number-list)
-                   (setq wl-summary-buffer-unsync-mark-number-list
-                         (delq number
-                               wl-summary-buffer-unsync-mark-number-list))
-                   t)))
+               (wl-summary-persistent-mark-invalid-p))
        (wl-summary-update-persistent-mark))
       (forward-line 1))))
 
@@ -1783,20 +1926,22 @@ This function is defined for `window-scroll-functions'"
 (defun wl-summary-sort (reverse)
   "Sort summary lines into the selected order; argument means descending order."
   (interactive "P")
-  (wl-summary-rescan
-   (completing-read
-    (format "%s by (%s): "
-           (if reverse "Reverse sort" "Sort")
-           (symbol-name wl-summary-default-sort-spec))
-    (mapcar (lambda (spec)
-             (list (symbol-name spec)))
-           wl-summary-sort-specs)
-    nil t nil nil (symbol-name wl-summary-default-sort-spec))
-   reverse))
+  (let ((default-value (symbol-name wl-summary-default-sort-spec)))
+    (wl-summary-rescan
+     (wl-completing-read-multiple
+      (format "%s by (%s): " (if reverse "Reverse sort" "Sort") default-value)
+      (nconc
+       (mapcar (lambda (spec) (list (symbol-name spec)))
+              wl-summary-sort-specs)
+       (mapcar (lambda (spec) (list (concat "!" (symbol-name spec))))
+              wl-summary-sort-specs))
+      nil t nil nil
+      default-value)
+     reverse)))
 
 (defun wl-summary-get-available-flags (&optional include-specials)
   (let ((flags (elmo-uniq-list
-               (append elmo-global-flag-list
+               (append elmo-global-flags
                        (copy-sequence elmo-preserved-flags))
                #'delq)))
     (if include-specials
@@ -1867,7 +2012,7 @@ This function is defined for `window-scroll-functions'"
                                            (not disable-killed)
                                            'in-msgdb)
                                           wl-summary-buffer-number-list))
-               (setq append-list (car diff))
+               (setq append-list (sort (car diff) #'<))
                (setq delete-list (cadr diff))
 
                (when delete-list
@@ -1890,7 +2035,8 @@ This function is defined for `window-scroll-functions'"
                    (wl-append update-top-list update-thread))
                  (if elmo-use-database
                      (elmo-database-msgid-put
-                      (car entity) (elmo-folder-name-internal folder)
+                      (elmo-message-entity-field entity 'message-id)
+                      (elmo-folder-name-internal folder)
                       (elmo-message-entity-number entity)))
                  (when (> num elmo-display-progress-threshold)
                    (setq i (+ i 1))
@@ -2015,18 +2161,25 @@ This function is defined for `window-scroll-functions'"
   (setq wl-summary-buffer-mode-line
        (funcall wl-summary-buffer-mode-line-formatter)))
 
-(defun wl-summary-jump-to-msg (&optional number)
-  (interactive "NJump to Number:")
-  (let ((num (or number
-                (string-to-int
-                 (read-from-minibuffer "Jump to Message(No.): ")))))
-    (setq num (int-to-string num))
-    (beginning-of-line)
-    (if (or (and (re-search-forward (concat "\r" num "[^0-9]") nil t)
-                (progn (backward-char 1) t))
-           (re-search-backward (concat "\r" num "[^0-9]") nil t))
-       (progn (beginning-of-line) t)
-      nil)))
+(defun wl-summary-jump-to-msg (&optional number beg end)
+  (interactive "NJump to Message (No.): ")
+  (when number
+    (let ((pos (point))
+         regexp)
+      (setq regexp (concat "\r" (int-to-string number) "[^0-9]"))
+      (if (and beg end (or (< pos beg) (< end pos)))
+         (progn
+           (goto-char beg)
+           (if (re-search-forward regexp end t)
+               (progn (backward-char 1) (beginning-of-line) t)
+             (goto-char pos)
+             nil))
+       (beginning-of-line)
+       (if (or (and (re-search-forward regexp end t)
+                    (progn (backward-char 1) t))
+               (re-search-backward regexp beg t))
+           (progn (beginning-of-line) t)
+         nil)))))
 
 (defun wl-summary-highlight-msgs (msgs)
   (save-excursion
@@ -2102,21 +2255,16 @@ If ARG, without confirm."
 
 (defun wl-summary-load-file-object (filename)
   "Load lisp object from dir."
-  (save-excursion
-    (let ((tmp-buffer (get-buffer-create " *wl-summary-load-file-object*"))
-         insert-file-contents-pre-hook   ; To avoid autoconv-xmas...
+  (with-temp-buffer
+    (let (insert-file-contents-pre-hook        ; To avoid autoconv-xmas...
          insert-file-contents-post-hook
          ret-val)
       (if (not (file-readable-p filename))
          ()
-       (set-buffer tmp-buffer)
        (as-binary-input-file (insert-file-contents filename))
-       (setq ret-val
-             (condition-case nil
-                 (read (current-buffer))
-               (error (error "Reading failed")))))
-      (kill-buffer tmp-buffer)
-      ret-val)))
+       (condition-case nil
+           (read (current-buffer))
+         (error (error "Reading failed")))))))
 
 (defun wl-summary-goto-folder (&optional arg)
   (interactive "P")
@@ -2179,7 +2327,7 @@ If ARG, without confirm."
                   wl-summary-buffer-message-modified
                   wl-summary-buffer-thread-modified
                   wl-summary-buffer-number-list
-                  wl-summary-buffer-unsync-mark-number-list
+                  wl-summary-buffer-persistent-mark-version
                   wl-summary-buffer-folder-name
                   wl-summary-buffer-line-formatter)
                 (and (eq wl-summary-buffer-view 'thread)
@@ -2301,11 +2449,14 @@ If ARG, without confirm."
          (unless (eq major-mode 'wl-summary-mode)
            (wl-summary-mode))
          (wl-summary-buffer-set-folder folder)
-         (setq wl-summary-buffer-display-as-is
-               (wl-summary-no-mime-p wl-summary-buffer-elmo-folder))
+         (setq wl-summary-buffer-display-mime-mode
+               (if (wl-summary-no-mime-p wl-summary-buffer-elmo-folder)
+                   'as-is
+                 'mime))
          (setq wl-summary-buffer-disp-msg nil)
          (setq wl-summary-buffer-last-displayed-msg nil)
          (setq wl-summary-buffer-current-msg nil)
+         (setq wl-summary-buffer-persistent-mark-version 0)
          (let ((inhibit-read-only t)
                (buffer-read-only nil))
            (erase-buffer)
@@ -2343,8 +2494,6 @@ If ARG, without confirm."
            (wl-summary-update-modeline)))
       (unless (eq wl-summary-buffer-view 'thread)
        (wl-summary-make-number-list))
-      (setq wl-summary-buffer-unsync-mark-number-list
-           (copy-sequence wl-summary-buffer-number-list))
       (when (and wl-summary-cache-use
                 (or (and wl-summary-check-line-format
                          (wl-summary-line-format-changed-p))
@@ -2422,7 +2571,8 @@ If ARG, without confirm."
              (wl-message-buffer-prefetch
               folder
               (wl-summary-message-number)
-              wl-message-buffer-prefetch-depth
+              (min (or wl-message-buffer-prefetch-depth 0)
+                   (1- wl-message-buffer-cache-size))
               (current-buffer)
               wl-summary-buffer-mime-charset))
          (if mes (message "%s" mes))
@@ -2482,6 +2632,12 @@ If ARG, without confirm."
        (save-excursion (end-of-line)(point))
        'mouse-face nil))
   (insert line "\n")
+  (save-excursion
+    (forward-line -1)
+    (let* ((number (wl-summary-message-number))
+          (mark-info (wl-summary-registered-temp-mark number)))
+      (when (and mark-info (nth 2 mark-info))
+       (wl-summary-print-argument number (nth 2 mark-info)))))
   (if wl-use-highlight-mouse-line
       ;; remove 'mouse-face of current line.
       (put-text-property
@@ -2513,7 +2669,7 @@ If ARG, without confirm."
 (defun wl-summary-default-subject-filter (subject)
   (setq subject (elmo-replace-in-string subject "[ \t]*\\(re\\|was\\)[:>]" ""))
   (setq subject (elmo-replace-in-string subject "[ \t]" ""))
-  (elmo-replace-in-string subject "^\\[.*\\]" ""))
+  (elmo-replace-in-string subject "^\\[[^]]*\\]" ""))
 
 (defun wl-summary-subject-equal (subject1 subject2)
   (string= (funcall wl-summary-subject-filter-function subject1)
@@ -2528,7 +2684,7 @@ If ARG, without confirm."
   (` (elmo-get-hash-val (format "#%d" (wl-count-lines))
                        wl-summary-alike-hashtb)))
 
-(defun wl-summary-insert-headers (folder func mime-decode)
+(defun wl-summary-insert-headers (folder func &optional mime-decode)
   (let ((numbers (elmo-folder-list-messages folder 'visible t))
        ov this last alike)
     (buffer-disable-undo (current-buffer))
@@ -2572,12 +2728,10 @@ If ARG, without confirm."
           (function
            (lambda (x)
              (funcall wl-summary-subject-filter-function
-                      (elmo-message-entity-field x 'subject))))
-          t)
+                      (elmo-message-entity-field x 'subject)))))
          (message "Creating subject cache...done"))
        (setq match (funcall wl-summary-subject-filter-function
-                            (elmo-message-entity-field entity 'subject
-                                                       'decode)))
+                            (elmo-message-entity-field entity 'subject)))
        (if (string= match "")
            (setq match "\n"))
        (goto-char (point-max))
@@ -2667,10 +2821,9 @@ If ARG, without confirm."
        (if (and parent-number
                 wl-summary-divide-thread-when-subject-changed
                 (not (wl-summary-subject-equal
-                      (or (elmo-message-entity-field entity
-                                                     'subject t) "")
+                      (or (elmo-message-entity-field entity 'subject) "")
                       (or (elmo-message-entity-field parent-entity
-                                                     'subject t) ""))))
+                                                     'subject) ""))))
            (setq parent-number nil))
        (setq retval
              (wl-thread-insert-message entity
@@ -2738,7 +2891,7 @@ If ARG, without confirm."
                          'in-msgdb)
                         (error "No messages")))
           (condition (car (elmo-parse-search-condition
-                           (elmo-read-search-condition
+                           (wl-read-search-condition
                             wl-summary-pick-field-default))))
           (result (elmo-folder-search wl-summary-buffer-elmo-folder
                                       condition
@@ -2779,7 +2932,7 @@ If ARG, exit virtual folder."
   (if arg
       (wl-summary-unvirtual)
     (wl-summary-goto-folder-subr (concat "/"
-                                        (elmo-read-search-condition
+                                        (wl-read-search-condition
                                          wl-summary-pick-field-default)
                                         "/"
                                         (wl-summary-buffer-folder-name))
@@ -2815,6 +2968,31 @@ If ARG, exit virtual folder."
        (wl-summary-get-score-mark number)
        " ")))
 
+(defun wl-summary-persistent-mark-invalid-p ()
+  (not
+   (equal
+    ;; mey be nil.
+    (get-text-property (point) 'wl-summary-persistent-mark-version)
+    wl-summary-buffer-persistent-mark-version)))
+
+(defun wl-summary-validate-persistent-mark (beg end)
+  (let ((inhibit-read-only t)
+       (buffer-read-only nil))
+    (put-text-property beg end
+                      'wl-summary-persistent-mark-version
+                      wl-summary-buffer-persistent-mark-version)
+    (set-buffer-modified-p nil)))
+
+(defun wl-summary-validate-persistent-mark-string (string)
+  (put-text-property 0 (length string)
+                    'wl-summary-persistent-mark-version
+                    wl-summary-buffer-persistent-mark-version
+                    string))
+
+(defun wl-summary-invalidate-persistent-mark ()
+  (setq wl-summary-buffer-persistent-mark-version
+       (1+ wl-summary-buffer-persistent-mark-version)))
+
 (defsubst wl-summary-persistent-mark-string (folder flags cached)
   "Return the persistent mark string.
 The mark is decided according to the FOLDER, FLAGS and CACHED."
@@ -2996,11 +3174,14 @@ Return non-nil if the mark is updated"
                (buffer-read-only nil)
                (mark (buffer-substring (- (point) 1) (point)))
                (new-mark (wl-summary-persistent-mark number flags)))
-           (unless (string= new-mark mark)
-             (delete-backward-char 1)
-             (insert new-mark)
-             (wl-summary-set-message-modified)
-             t))))
+           (prog1
+               (unless (string= new-mark mark)
+                 (delete-backward-char 1)
+                 (insert new-mark)
+                 (wl-summary-set-message-modified)
+                 t)
+             (wl-summary-validate-persistent-mark (point-at-bol)
+                                                  (point-at-eol))))))
     (when wl-summary-highlight
       (wl-highlight-summary-current-line))
     (set-buffer-modified-p nil)))
@@ -3012,7 +3193,7 @@ Return non-nil if the mark is updated"
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
          unread-message number
-         number-list visible)
+         number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (setq unread-message
                                     (elmo-message-flagged-p
@@ -3036,14 +3217,11 @@ Return non-nil if the mark is updated"
        (if inverse
            (elmo-folder-set-flag folder number-list 'unread no-folder-mark)
          (elmo-folder-unset-flag folder number-list 'unread no-folder-mark))
-       (dolist (number number-list)
-         (setq visible (wl-summary-jump-to-msg number))
-         (unless inverse
-           (when unread-message
-             (run-hooks 'wl-summary-unread-message-hook)))
-         ;; set mark on buffer
-         (when visible
-           (wl-summary-update-persistent-mark)))
+       (when (and unread-message
+                  (not inverse))
+         (dolist (number number-list)
+           (wl-summary-jump-to-msg number)
+           (run-hooks 'wl-summary-unread-message-hook)))
        (unless no-modeline-update
          ;; Update unread numbers.
          (wl-summary-count-unread)
@@ -3079,7 +3257,7 @@ Return non-nil if the mark is updated"
   "Set persistent mark."
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
-         number number-list visible)
+         number number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (list number-or-numbers))
                              ((and (not (null number-or-numbers))
@@ -3096,10 +3274,6 @@ Return non-nil if the mark is updated"
              (if inverse
                  (elmo-folder-unset-flag folder number-list flag no-server)
                (elmo-folder-set-flag folder number-list flag no-server))
-             (dolist (number number-list)
-               ;; set mark on buffer
-               (when (wl-summary-jump-to-msg number)
-                 (wl-summary-update-persistent-mark)))
              (unless no-modeline-update
                ;; Update unread numbers.
                ;; should elmo-flag-mark-as-read return unread numbers?
@@ -3121,7 +3295,7 @@ Return non-nil if the mark is updated"
     (let ((completion-ignore-case t))
       (setq flag (intern (downcase
                          (completing-read
-                          "Flag: "
+                          "Mark name: "
                           (mapcar (lambda (flag)
                                     (list (capitalize (symbol-name flag))))
                                   (wl-summary-get-available-flags))
@@ -3144,7 +3318,7 @@ Return non-nil if the mark is updated"
     (let ((completion-ignore-case t))
       (setq flag (intern (downcase
                          (completing-read
-                          "Flag: "
+                          "Mark name: "
                           (mapcar (lambda (flag)
                                     (list (capitalize (symbol-name flag))))
                                   (wl-summary-get-available-flags))
@@ -3164,7 +3338,7 @@ Return non-nil if the mark is updated"
        flag)
     (setq flag (intern (downcase
                        (completing-read
-                        "Flag: "
+                        "Mark name: "
                         (mapcar (lambda (flag)
                                   (list (capitalize (symbol-name flag))))
                                 (wl-summary-get-available-flags))
@@ -3214,18 +3388,22 @@ Return non-nil if the mark is updated"
                  "Flags: "
                  (mapcar (lambda (flag)
                            (list (capitalize (symbol-name flag))))
-                         elmo-global-flag-list)
+                         elmo-global-flags)
                  nil nil (mapconcat (lambda (flag)
                                       (capitalize (symbol-name flag)))
                                     flags
                                     ",")))))
     (dolist (flag new-flags)
-      (unless (memq flag elmo-global-flag-list)
-       (if (y-or-n-p (format "Flag `%s' does not exist yet. Create?"
+      (unless (memq flag elmo-global-flags)
+       (when (elmo-local-flag-p flag)
+         (error "Cannot treat `%s'." flag))
+       (unless (elmo-flag-valid-p flag)
+         (error "Invalid char in `%s'" flag))
+       (if (y-or-n-p (format "Flag `%s' is not registered yet. Register?"
                              (capitalize (symbol-name flag))))
-           (setq elmo-global-flag-list (append
-                                        elmo-global-flag-list
-                                        (list flag)))
+           (setq elmo-global-flags (append
+                                    elmo-global-flags
+                                    (list flag)))
          (error "Stopped"))))
     new-flags))
 
@@ -3236,7 +3414,7 @@ Return non-nil if the mark is updated"
                                        remove-all)
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
-         number number-list visible)
+         number number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (list number-or-numbers))
                              ((and (not (null number-or-numbers))
@@ -3252,23 +3430,15 @@ Return non-nil if the mark is updated"
       (if (null number-list)
          (message "No message.")
        (dolist (number number-list)
-         (elmo-message-set-global-flags folder number flags local)
-         (setq visible (wl-summary-jump-to-msg number))
-         ;; set mark on buffer
-         (when visible
-           (wl-summary-update-persistent-mark))))
+         (elmo-message-set-global-flags folder number flags local)))
       flags)))
 
 (defun wl-summary-set-flags (&optional remove)
   (interactive "P")
-  (if (eq 'flag (elmo-folder-type-internal wl-summary-buffer-elmo-folder))
-      (error "Cannot process flags in this folder"))
   (wl-summary-set-flags-internal nil nil nil remove))
 
 (defun wl-summary-mark-as-important (&optional prompt)
   (interactive "P")
-  (if (eq 'flag (elmo-folder-type-internal wl-summary-buffer-elmo-folder))
-      (error "Cannot process flags in this folder"))
   (if prompt
       (wl-summary-set-flags-internal)
     (wl-summary-set-persistent-mark-internal
@@ -3351,18 +3521,16 @@ Return non-nil if the mark is updated"
          (elmo-delete-char ?\n
                            (or (elmo-message-entity-field
                                 wl-message-entity
-                                'subject t)
+                                'subject)
                                wl-summary-no-subject-message)))
     (setq parent-raw-subject
-         (elmo-message-entity-field wl-parent-message-entity
-                                    'subject t))
+         (elmo-message-entity-field wl-parent-message-entity 'subject))
     (setq parent-subject
          (if parent-raw-subject
              (elmo-delete-char ?\n parent-raw-subject)))
     (if (or no-parent
            (null parent-subject)
-           (not (wl-summary-subject-equal
-                 subject parent-subject)))
+           (not (wl-summary-subject-equal subject parent-subject)))
        (funcall wl-summary-subject-function subject)
       "")))
 
@@ -3371,7 +3539,7 @@ Return non-nil if the mark is updated"
                    (funcall wl-summary-from-function
                             (elmo-message-entity-field
                              wl-message-entity
-                             'from t))))
+                             'from))))
 
 (defun wl-summary-line-list-info ()
   (let ((list-info (wl-summary-get-list-info wl-message-entity)))
@@ -3419,13 +3587,10 @@ Return non-nil if the mark is updated"
                             wl-cached))
        (elmo-mime-charset wl-summary-buffer-mime-charset)
        (elmo-lang wl-summary-buffer-weekday-name-lang)
-       (wl-datevec (or (ignore-errors (timezone-fix-time
-                                       (elmo-message-entity-field
-                                        wl-message-entity
-                                        'date)
-                                       nil
-                                       wl-summary-fix-timezone))
-                       (make-vector 5 0)))
+       (wl-datevec (or (elmo-time-to-datevec
+                        (elmo-message-entity-field wl-message-entity 'date)
+                        wl-summary-fix-timezone)
+                       (make-vector 7 0)))
        (entity wl-message-entity) ; backward compatibility.
        line mark)
     (if (and wl-thr-indent-string
@@ -3445,6 +3610,7 @@ Return non-nil if the mark is updated"
                       (number-to-string
                        (elmo-message-entity-number
                         wl-message-entity))))
+    (wl-summary-validate-persistent-mark-string line)
     (if wl-summary-highlight
        (wl-highlight-summary-line-string
         (elmo-message-entity-number wl-message-entity)
@@ -3571,11 +3737,9 @@ Return non-nil if the mark is updated"
                  (write-region-as-binary (point-min)(point-max)
                                          cache nil 'no-msg)))
              (when (file-writable-p view) ; 'thread or 'sequence
-               (save-excursion
-                 (set-buffer tmp-buffer)
-                 (erase-buffer)
-                 (prin1 save-view tmp-buffer)
-                 (princ "\n" tmp-buffer)
+               (with-temp-buffer
+                 (prin1 save-view (current-buffer))
+                 (princ "\n" (current-buffer))
                  (write-region (point-min) (point-max) view nil 'no-msg))))
          ;; kill tmp buffer.
          (kill-buffer tmp-buffer))))))
@@ -3823,8 +3987,7 @@ Return t if message exists."
        (progn
          (set-buffer wl-message-buffer)
          t)
-      (wl-summary-redisplay-internal folder number nil
-                                    wl-summary-buffer-display-as-is)
+      (wl-summary-redisplay-internal folder number)
       (when (buffer-live-p wl-message-buffer)
        (set-buffer wl-message-buffer))
       nil)))
@@ -4097,9 +4260,7 @@ Reply to author if invoked with ARG."
     (when number
       (save-excursion
        (wl-summary-set-message-buffer-or-redisplay))
-      (setq mes-buf wl-message-buffer)
       (wl-message-select-buffer wl-message-buffer)
-      (set-buffer mes-buf)
       (condition-case err
          (when (setq mes-buf (wl-message-get-original-buffer))
            (wl-draft-reply mes-buf arg summary-buf number)
@@ -4162,7 +4323,6 @@ Use function list is `wl-summary-write-current-folder-functions'."
        (number (wl-summary-message-number))
        (summary-buf (current-buffer))
        (wl-draft-forward t)
-       mes-buf
        entity subject num)
     (if (null number)
        (message "No message.")
@@ -4174,17 +4334,10 @@ Use function list is `wl-summary-write-current-folder-functions'."
          ;; Reload.
          (wl-summary-redisplay-internal nil nil 'force-reload)
        (wl-summary-redisplay-internal folder number))
-      (setq mes-buf wl-message-buffer)
-      (wl-message-select-buffer mes-buf)
-      ;; get original subject.
-      (if summary-buf
-         (save-excursion
-           (set-buffer summary-buf)
-           (setq subject
-                 (or (elmo-message-entity-field
-                      (elmo-message-entity folder number) 'subject 'decode)
-                     ""))))
-      (set-buffer mes-buf)
+      (wl-message-select-buffer wl-message-buffer)
+      (setq subject (with-current-buffer
+                       wl-message-buffer-original-buffer
+                     (std11-field-body "Subject")))
       (wl-draft-forward subject summary-buf number)
       (with-current-buffer summary-buf (run-hooks 'wl-summary-forward-hook))
       (unless without-setup-hook
@@ -4357,50 +4510,99 @@ Use function list is `wl-summary-write-current-folder-functions'."
            (wl-summary-redisplay)))
     (message "No last message.")))
 
-(defun wl-summary-toggle-mime (&optional no-mime)
+(defun wl-summary-message-display-type ()
+  (when (and wl-summary-buffer-disp-msg
+            (buffer-live-p wl-message-buffer)
+            wl-summary-buffer-current-msg
+            (wl-summary-message-number)
+            (= (wl-summary-message-number) wl-summary-buffer-current-msg))
+    (wl-message-buffer-display-type wl-message-buffer)))
+
+(defun wl-summary-buffer-display-mime-mode ()
+  (or (wl-message-display-type-property (wl-summary-message-display-type)
+                                       :mime)
+      wl-summary-buffer-display-mime-mode))
+
+(defun wl-summary-buffer-display-header-mode ()
+  (or (wl-message-display-type-property (wl-summary-message-display-type)
+                                       :header)
+      wl-summary-buffer-display-header-mode))
+
+(defun wl-summary-toggle-mime (&optional arg)
   "Toggle MIME decoding.
-If NO-MIME is non-nil, force displaying the message without MIME decoding
-and ask coding-system for the message."
+If ARG is non-nil, ask coding-system to display the message in the current
+MIME analysis mode.
+
+If ARG is numeric number, decode message as following:
+1: Enable MIME analysis.
+2: Enable MIME analysis only for headers.
+3: Disable MIME analysis."
   (interactive "P")
-  (if no-mime
-      (wl-summary-redisplay-no-mime 'ask-coding)
-    (setq wl-summary-buffer-display-as-is
-         (not wl-summary-buffer-display-as-is))
-    (wl-summary-redisplay)
-    (wl-summary-update-modeline)
-    (message "MIME decoding: %s"
-            (if wl-summary-buffer-display-as-is "OFF" "ON"))))
+  (let ((mime-mode (wl-summary-buffer-display-mime-mode))
+       (elmo-mime-display-as-is-coding-system
+        elmo-mime-display-as-is-coding-system))
+    (if (and (consp arg) (> (prefix-numeric-value arg) 4))
+       (progn
+         (setq wl-summary-buffer-display-mime-mode mime-mode)
+         (wl-summary-update-modeline))
+      (cond
+       ((numberp arg)
+       (setq mime-mode (case arg
+                         (1 'mime)
+                         (2 'header-only)
+                         (3 'as-is)
+;;;                      (4 'decode-only)
+                         (5 'no-merge))))
+       (arg
+       ;; Specify coding-system (doesn't change the MIME mode).
+       (setq elmo-mime-display-as-is-coding-system
+             (if (and arg
+                      (not (wl-message-mime-analysis-p
+                            (wl-summary-message-display-type))))
+                 (or (read-coding-system "Coding system: ")
+                     elmo-mime-display-as-is-coding-system)
+               elmo-mime-display-as-is-coding-system)))
+       (t
+       ;; Change the MIME mode.
+       (setq mime-mode (or (cadr (memq mime-mode
+                                       wl-summary-display-mime-mode-list))
+                           (car wl-summary-display-mime-mode-list)))))
+      (wl-summary-redisplay-internal nil nil arg mime-mode))
+    (message "MIME decoding: %s%s"
+            (upcase (symbol-name mime-mode))
+            (if (and (not (eq mime-mode 'mime))
+                     (not (eq elmo-mime-display-as-is-coding-system
+                              wl-cs-autoconv)))
+                (concat " ("
+                        (symbol-name elmo-mime-display-as-is-coding-system)
+                        ")")
+              ""))))
 
 (defun wl-summary-redisplay (&optional arg)
   "Redisplay message."
   (interactive "P")
-  (wl-summary-redisplay-internal nil nil arg
-                                wl-summary-buffer-display-as-is))
-
-(defun wl-summary-redisplay-all-header (&optional arg)
-  "Redisplay message with all header."
-  (interactive "P")
-  (wl-summary-redisplay-internal nil nil arg
-                                wl-summary-buffer-display-as-is 'all-header))
+  (apply #'wl-summary-redisplay-internal nil nil arg
+        (unless (and (consp arg) (> (prefix-numeric-value arg) 4))
+          (list wl-summary-buffer-display-mime-mode
+                wl-summary-buffer-display-header-mode))))
 
-(defun wl-summary-redisplay-no-mime (&optional ask-coding)
-  "Display message without MIME decoding.
-If ASK-CODING is non-nil, coding-system for the message is asked."
+(defun wl-summary-toggle-all-header (&optional arg)
+  "Toggle displaying message with all header."
   (interactive "P")
-  (let ((elmo-mime-display-as-is-coding-system
-        (if ask-coding
-            (or (read-coding-system "Coding system: ")
-                elmo-mime-display-as-is-coding-system)
-          elmo-mime-display-as-is-coding-system)))
-    (wl-summary-redisplay-internal nil nil nil 'as-is 'all-header)))
+  (let ((header-mode (wl-summary-buffer-display-header-mode)))
+    (if (and (consp arg) (> (prefix-numeric-value arg) 4))
+       (setq wl-summary-buffer-display-header-mode header-mode)
+      (wl-summary-redisplay-internal
+       nil nil arg nil
+       (if (eq header-mode 'all) 'partial 'all)))))
 
 (defun wl-summary-redisplay-internal (&optional folder number force-reload
-                                               as-is all-header)
+                                               mime-mode header-mode)
   (let* ((folder (or folder wl-summary-buffer-elmo-folder))
         (num (or number (wl-summary-message-number)))
         (wl-mime-charset      wl-summary-buffer-mime-charset)
         (default-mime-charset wl-summary-buffer-mime-charset)
-        no-folder-mark fld-buf fld-win thr-entity
+        fld-buf fld-win thr-entity
         (elmo-message-fetch-confirm (or elmo-message-fetch-confirm
                                         (and force-reload
                                              elmo-message-fetch-threshold))))
@@ -4422,40 +4624,39 @@ If ASK-CODING is non-nil, coding-system for the message is asked."
              (if (setq fld-win (get-buffer-window fld-buf))
                  (delete-window fld-win)))
          (setq wl-current-summary-buffer (current-buffer))
-         (setq no-folder-mark
-               ;; If cache is used, change folder-mark.
-               (if (wl-message-redisplay folder num
-                                         as-is all-header
-                                         (or
-                                          force-reload
-                                          (string= (elmo-folder-name-internal
-                                                    folder)
-                                                   wl-draft-folder)))
-                   nil
-                 ;; plugged, then leave folder-mark.
-                 (if (and (not (elmo-folder-local-p
-                                wl-summary-buffer-elmo-folder))
-                          (elmo-folder-plugged-p
-                           wl-summary-buffer-elmo-folder))
-                     'leave)))
+         (wl-message-redisplay folder num
+                               (wl-message-make-display-type
+                                (or mime-mode
+                                    (wl-summary-buffer-display-mime-mode))
+                                (or header-mode
+                                    (wl-summary-buffer-display-header-mode)))
+                               (or force-reload
+                                   (string= (elmo-folder-name-internal folder)
+                                            wl-draft-folder)))
          (when (elmo-message-use-cache-p folder num)
            (elmo-message-set-cached folder num t))
          (ignore-errors
            (if (elmo-message-flagged-p wl-summary-buffer-elmo-folder
                                        num
                                        'unread)
-               (wl-summary-mark-as-read num no-folder-mark)
-             (wl-summary-update-persistent-mark)))
+               (wl-summary-mark-as-read num)
+             (wl-summary-count-unread)
+             (wl-summary-update-modeline)
+             (wl-folder-update-unread
+              (wl-summary-buffer-folder-name)
+              wl-summary-buffer-unread-count)))
          (setq wl-summary-buffer-current-msg num)
          (when wl-summary-recenter
            (recenter (/ (- (window-height) 2) 2))
            (if (not wl-summary-indent-length-limit)
                (wl-horizontal-recenter)))
          (wl-highlight-summary-displaying)
-         (wl-message-buffer-prefetch-next folder num
-                                          wl-message-buffer-prefetch-depth
-                                          (current-buffer)
-                                          wl-summary-buffer-mime-charset)
+         (wl-message-buffer-prefetch-next
+          folder num
+          (min (or wl-message-buffer-prefetch-depth 0)
+               (1- wl-message-buffer-cache-size))
+          (current-buffer)
+          wl-summary-buffer-mime-charset)
          (run-hooks 'wl-summary-redisplay-hook))
       (message "No message to display."))))
 
@@ -4560,25 +4761,23 @@ If ASK-CODING is non-nil, coding-system for the message is asked."
   (interactive)
   (let ((filename)
        (num (wl-summary-message-number)))
-    (if (null wl-save-dir)
-       (setq wl-save-dir wl-temporary-file-directory))
+    (unless wl-save-dir
+      (setq wl-save-dir wl-temporary-file-directory))
     (if num
        (save-excursion
          (setq filename (expand-file-name
                          (concat (int-to-string num)
                                  wl-summary-save-file-suffix)
                          wl-save-dir))
-         (if (null (and arg
-                        (null (file-exists-p filename))))
-             (setq filename
-                   (read-file-name "Save to file: " filename)))
-
+         (when (or (null arg)
+                   (file-exists-p filename))
+           (setq filename (read-file-name "Save to file: " filename)))
          (wl-summary-set-message-buffer-or-redisplay)
          (set-buffer (wl-message-get-original-buffer))
-         (if (and (null arg) (file-exists-p filename))
-             (if (y-or-n-p "File already exists.  override it? ")
-                 (write-region (point-min) (point-max) filename))
-           (write-region (point-min) (point-max) filename)))
+         (when (or arg
+                   (not (file-exists-p filename))
+                   (y-or-n-p "File already exists.  override it? "))
+           (write-region-as-binary (point-min) (point-max) filename)))
       (message "No message to save."))
     num))
 
@@ -4672,7 +4871,6 @@ If ASK-CODING is non-nil, coding-system for the message is asked."
              wl-break-pages)
          (save-excursion
            (wl-summary-set-message-buffer-or-redisplay)
-           ;; (wl-summary-redisplay-internal)
            (let* ((buffer (generate-new-buffer " *print*"))
                   (entity (progn
                             (set-buffer summary-buffer)
@@ -4680,15 +4878,14 @@ If ASK-CODING is non-nil, coding-system for the message is asked."
                              wl-summary-buffer-elmo-folder
                              (wl-summary-message-number))))
                   (wl-ps-subject
-                   (and entity
-                        (or (elmo-message-entity-field entity 'subject t)
-                            "")))
+                   (or (elmo-message-entity-field entity 'subject 'string)
+                       ""))
                   (wl-ps-from
-                   (and entity
-                        (or (elmo-message-entity-field entity 'from t) "")))
+                   (or (elmo-message-entity-field entity 'from 'string)
+                       ""))
                   (wl-ps-date
-                   (and entity
-                        (or (elmo-message-entity-field entity 'date) ""))))
+                   (or (elmo-message-entity-field entity 'date 'string)
+                       "")))
              (run-hooks 'wl-ps-preprint-hook)
              (set-buffer wl-message-buffer)
              (copy-to-buffer buffer (point-min) (point-max))