Fixed.
[elisp/wanderlust.git] / elmo / elmo.el
index b933422..5e9787a 100644 (file)
@@ -35,6 +35,7 @@
 (require 'elmo-vars)
 (require 'elmo-util)
 (require 'elmo-msgdb)
 (require 'elmo-vars)
 (require 'elmo-util)
 (require 'elmo-msgdb)
+(require 'elmo-signal)
 
 (eval-when-compile (require 'cl))
 
 
 (eval-when-compile (require 'cl))
 
@@ -46,7 +47,8 @@
 
 (defcustom elmo-message-fetch-threshold 30000
   "Fetch threshold."
 
 (defcustom elmo-message-fetch-threshold 30000
   "Fetch threshold."
-  :type 'integer
+  :type '(choice (integer :tag "Threshold (bytes)")
+                (const :tag "No limitation" nil))
   :group 'elmo)
 
 (defcustom elmo-message-fetch-confirm t
   :group 'elmo)
 
 (defcustom elmo-message-fetch-confirm t
@@ -58,7 +60,8 @@ Otherwise, entire fetching of the message is aborted without confirmation."
 
 (defcustom elmo-folder-update-threshold 500
   "Update threshold."
 
 (defcustom elmo-folder-update-threshold 500
   "Update threshold."
-  :type 'integer
+  :type '(choice (integer :tag "Number of messages")
+                (const :tag "No limitation" nil))
   :group 'elmo)
 
 (defcustom elmo-folder-update-confirm t
   :group 'elmo)
 
 (defcustom elmo-folder-update-confirm t
@@ -66,6 +69,12 @@ Otherwise, entire fetching of the message is aborted without confirmation."
   :type 'boolean
   :group 'elmo)
 
   :type 'boolean
   :group 'elmo)
 
+(defcustom elmo-msgdb-path-encode-threshold nil
+  "*Encode msgdb path if its length is longer than this value."
+  :type '(choice (const :tag "No encode" nil)
+                number)
+  :group 'elmo)
+
 (defvar elmo-message-displaying nil
   "A global switch to indicate message is displaying or not.")
 
 (defvar elmo-message-displaying nil
   "A global switch to indicate message is displaying or not.")
 
@@ -79,17 +88,37 @@ Otherwise, entire fetching of the message is aborted without confirmation."
 (elmo-define-error 'elmo-authenticate-error "Login failed" 'elmo-open-error)
 (elmo-define-error 'elmo-imap4-bye-error "IMAP4 session was terminated" 'elmo-open-error)
 
 (elmo-define-error 'elmo-authenticate-error "Login failed" 'elmo-open-error)
 (elmo-define-error 'elmo-imap4-bye-error "IMAP4 session was terminated" 'elmo-open-error)
 
+;; Event declarations
+(elmo-define-signal flag-changing (number old-flags new-flags)
+  "Notify the changing flag of the messages with NUMBER.")
+
+(elmo-define-signal flag-changed (numbers)
+  "Notify the change flag of the messages with NUMBERS.")
+
+(elmo-define-signal status-changed (numbers)
+  "Notify the change status of the message with NUMBERS.")
+
+(elmo-define-signal update-overview (number)
+  "Notify update overview of the message with NUMBER.")
+
+(elmo-define-signal message-number-changed (old-number new-number)
+  "Notify change of message number within the folder.")
+
 ;; autoloads
 (eval-and-compile
 ;; autoloads
 (eval-and-compile
+  (autoload 'md5 "md5")
   (autoload 'elmo-dop-queue-flush "elmo-dop")
   (autoload 'elmo-nntp-post "elmo-nntp")
   (autoload 'elmo-global-flag-p "elmo-flag")
   (autoload 'elmo-dop-queue-flush "elmo-dop")
   (autoload 'elmo-nntp-post "elmo-nntp")
   (autoload 'elmo-global-flag-p "elmo-flag")
+  (autoload 'elmo-local-flag-p "elmo-flag")
   (autoload 'elmo-global-flag-detach "elmo-flag")
   (autoload 'elmo-global-flag-detach-messages "elmo-flag")
   (autoload 'elmo-global-flag-set "elmo-flag")
   (autoload 'elmo-get-global-flags "elmo-flag")
   (autoload 'elmo-global-flag-detach "elmo-flag")
   (autoload 'elmo-global-flag-detach-messages "elmo-flag")
   (autoload 'elmo-global-flag-set "elmo-flag")
   (autoload 'elmo-get-global-flags "elmo-flag")
+  (autoload 'elmo-global-flags-initialize "elmo-flag")
   (autoload 'elmo-global-mark-migrate "elmo-flag")
   (autoload 'elmo-global-mark-migrate "elmo-flag")
-  (autoload 'elmo-folder-list-global-flag-messages "elmo-flag"))
+  (autoload 'elmo-folder-list-global-flag-messages "elmo-flag")
+  (autoload 'elmo-search-register-engine "elmo-search"))
 
 (defun elmo-define-folder (prefix backend)
   "Define a folder.
 
 (defun elmo-define-folder (prefix backend)
   "Define a folder.
@@ -117,9 +146,11 @@ If a folder name begins with PREFIX, use BACKEND."
                                     path   ; directory path for msgdb.
                                     msgdb  ; msgdb (may be nil).
                                     killed-list  ; killed list.
                                     path   ; directory path for msgdb.
                                     msgdb  ; msgdb (may be nil).
                                     killed-list  ; killed list.
+                                    flag-table   ; flag table.
                                     persistent   ; non-nil if persistent.
                                     process-duplicates  ; read or hide
                                     biff   ; folder for biff
                                     persistent   ; non-nil if persistent.
                                     process-duplicates  ; read or hide
                                     biff   ; folder for biff
+                                    mime-charset ; charset for encode & decode
                                     ))
   (luna-define-internal-accessors 'elmo-folder))
 
                                     ))
   (luna-define-internal-accessors 'elmo-folder))
 
@@ -132,16 +163,18 @@ If a folder name begins with PREFIX, use BACKEND."
   (` (luna-send (, folder) (, message) (, folder) (,@ args))))
 
 ;;;###autoload
   (` (luna-send (, folder) (, message) (, folder) (,@ args))))
 
 ;;;###autoload
-(defun elmo-make-folder (name &optional non-persistent)
+(defun elmo-make-folder (name &optional non-persistent mime-charset)
   "Make an ELMO folder structure specified by NAME.
   "Make an ELMO folder structure specified by NAME.
-If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
+If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved.
+If optional argument MIME-CHARSET is specified, it is used for
+encode and decode a multibyte string."
   (let ((type (elmo-folder-type name))
        prefix split class folder original)
     (setq original (elmo-string name))
     (if type
        (progn
   (let ((type (elmo-folder-type name))
        prefix split class folder original)
     (setq original (elmo-string name))
     (if type
        (progn
-         (setq prefix (substring name 0 1))
-         (setq name (substring name 1)))
+         (setq prefix (elmo-string (substring name 0 1)))
+         (setq name (elmo-string (substring name 1))))
       (setq type (intern (car (setq split (split-string name ":")))))
       (if (>= (length split) 2)
          (setq name (substring name (+ 1 (length (car split)))))
       (setq type (intern (car (setq split (split-string name ":")))))
       (if (>= (length split) 2)
          (setq name (substring name (+ 1 (length (car split)))))
@@ -153,10 +186,18 @@ If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
                                   :type type
                                   :prefix prefix
                                   :name original
                                   :type type
                                   :prefix prefix
                                   :name original
-                                  :persistent (not non-persistent)))
+                                  :persistent (not non-persistent)
+                                  :mime-charset mime-charset))
     (save-match-data
       (elmo-folder-send folder 'elmo-folder-initialize name))))
 
     (save-match-data
       (elmo-folder-send folder 'elmo-folder-initialize name))))
 
+(defvar elmo-get-folder-function nil)
+
+(defun elmo-get-folder (name)
+  (or (and elmo-get-folder-function
+          (funcall elmo-get-folder-function name))
+      (elmo-make-folder name)))
+
 ;; Note that this function is for internal use only.
 (luna-define-generic elmo-folder-msgdb (folder)
   "Return the msgdb of FOLDER (on-demand loading).
 ;; Note that this function is for internal use only.
 (luna-define-generic elmo-folder-msgdb (folder)
   "Return the msgdb of FOLDER (on-demand loading).
@@ -232,10 +273,10 @@ If second optional IN-MSGDB is non-nil, only messages in the msgdb are listed.")
       (setq list (elmo-msgdb-list-messages (elmo-folder-msgdb folder))))
     (if visible-only
        (elmo-living-messages list killed-list)
       (setq list (elmo-msgdb-list-messages (elmo-folder-msgdb folder))))
     (if visible-only
        (elmo-living-messages list killed-list)
-      (if in-msgdb
-         (elmo-uniq-list
-          (nconc (elmo-number-set-to-number-list killed-list) list)
-          #'delq)
+      (if (and in-msgdb killed-list)
+         (elmo-uniq-sorted-list
+          (sort (nconc (elmo-number-set-to-number-list killed-list) list) #'<)
+          #'eq)
        list))))
 
 (luna-define-generic elmo-folder-list-messages-internal (folder &optional
        list))))
 
 (luna-define-generic elmo-folder-list-messages-internal (folder &optional
@@ -312,12 +353,18 @@ Otherwise, all descendent folders are returned.")
   "Rename FOLDER to NEW-NAME (string).")
 
 (luna-define-generic elmo-folder-delete-messages (folder numbers)
   "Rename FOLDER to NEW-NAME (string).")
 
 (luna-define-generic elmo-folder-delete-messages (folder numbers)
-  "Delete messages.
+  "Delete messages with msgdb entity.
 FOLDER is the ELMO folder structure.
 NUMBERS is a list of message numbers to be deleted.
 It is not recommended to use this function other than internal use.
 Use `elmo-folder-move-messages' with dst-folder 'null instead.")
 
 FOLDER is the ELMO folder structure.
 NUMBERS is a list of message numbers to be deleted.
 It is not recommended to use this function other than internal use.
 Use `elmo-folder-move-messages' with dst-folder 'null instead.")
 
+(luna-define-generic elmo-folder-delete-messages-internal (folder numbers)
+  "Delete messages, but no delete msgdb entity.
+FOLDER is the ELMO folder structure.
+NUMBERS is a list of message numbers to be deleted.
+Override this method by each implement of `elmo-folder'.")
+
 (luna-define-generic elmo-folder-search (folder condition &optional numbers)
   "Search and return list of message numbers.
 FOLDER is the ELMO folder structure.
 (luna-define-generic elmo-folder-search (folder condition &optional numbers)
   "Search and return list of message numbers.
 FOLDER is the ELMO folder structure.
@@ -365,19 +412,26 @@ FLAG is a symbol which is one of the following:
   `important' (remove important flag)
 'sugar' flag:
   `read'      (set unread flag)
   `important' (remove important flag)
 'sugar' flag:
   `read'      (set unread flag)
+  `all'       (remove all flags)
 If optional IS-LOCAL is non-nil, update only local (not server) status.")
 
 If optional IS-LOCAL is non-nil, update only local (not server) status.")
 
+(luna-define-generic elmo-message-flag-available-p (folder number flag)
+  "Return non-nil when a message in the FOLDER with NUMBER treats FLAG.")
+
 (luna-define-generic elmo-folder-next-message-number (folder)
   "The next message number that will be assigned to a new message.
 FOLDER is the ELMO folder structure.")
 
 (luna-define-generic elmo-folder-next-message-number (folder)
   "The next message number that will be assigned to a new message.
 FOLDER is the ELMO folder structure.")
 
-(luna-define-generic elmo-folder-append-buffer (folder &optional flag
+(luna-define-generic elmo-folder-append-buffer (folder &optional flags
                                                       number)
   "Append current buffer as a new message.
                                                       number)
   "Append current buffer as a new message.
-FOLDER is the destination folder(ELMO folder structure).
-FLAG is the status of appended message.
+FOLDER is the destination folder (ELMO folder structure).
+FLAGS is the flag list for the appended message (list of symbols).
+If FLAGS contain `read', the message is appended as `not-unread'.
+If it is nil, the appended message will be treated as `new'.
 If optional argument NUMBER is specified, the new message number is set
 If optional argument NUMBER is specified, the new message number is set
-\(if possible\).")
+\(if possible\).
+Return nil on failure.")
 
 (luna-define-generic elmo-folder-append-messages (folder
                                                  src-folder
 
 (luna-define-generic elmo-folder-append-messages (folder
                                                  src-folder
@@ -391,7 +445,8 @@ Caller should make sure FOLDER is `writable'.
 SRC-FOLDER is the source ELMO folder structure.
 NUMBERS is the message numbers to be appended in the SRC-FOLDER.
 If second optional argument SAME-NUMBER is specified,
 SRC-FOLDER is the source ELMO folder structure.
 NUMBERS is the message numbers to be appended in the SRC-FOLDER.
 If second optional argument SAME-NUMBER is specified,
-message number is preserved \(if possible\).")
+message number is preserved \(if possible\).
+Returns a list of message numbers successfully appended.")
 
 (luna-define-generic elmo-folder-pack-numbers (folder)
   "Pack message numbers of FOLDER.")
 
 (luna-define-generic elmo-folder-pack-numbers (folder)
   "Pack message numbers of FOLDER.")
@@ -454,6 +509,23 @@ Return newly created temporary directory name which contains temporary files.")
 FOLDER is a ELMO folder structure.
 NUMBER is a number of the message.")
 
 FOLDER is a ELMO folder structure.
 NUMBER is a number of the message.")
 
+(defun elmo-message-flags-for-append (folder number &optional message-id)
+  "Return a list of flags for `elmo-folder-append-buffer'.
+FOLDER is a ELMO folder structure.
+NUMBER is a number of the message.
+If optional argument MESSAGES-ID is not specified, get it from current buffer."
+  (let ((this-id (elmo-message-field folder number 'message-id)))
+    (and this-id
+        (string= this-id (or message-id
+                             (elmo-msgdb-get-message-id-from-buffer)))
+        (or (elmo-message-flags folder number)
+            ;; message exists, but no flag.
+            '(read)))))
+
+(luna-define-method elmo-message-flag-available-p ((folder elmo-folder) number
+                                                  flag)
+  (elmo-msgdb-flag-available-p (elmo-folder-msgdb folder) flag))
+
 (luna-define-method elmo-message-flags ((folder elmo-folder) number)
   (elmo-msgdb-flags (elmo-folder-msgdb folder) number))
 
 (luna-define-method elmo-message-flags ((folder elmo-folder) number)
   (elmo-msgdb-flags (elmo-folder-msgdb folder) number))
 
@@ -468,97 +540,94 @@ NUMBER is a message number to test."
       (t
        (memq flag cur-flags)))))
 
       (t
        (memq flag cur-flags)))))
 
-(luna-define-generic elmo-find-fetch-strategy
-  (folder entity &optional ignore-cache)
-;; Returns the message fetching strategy suitable for the message.
-;; FOLDER is the ELMO folder structure.
-;; ENTITY is the overview entity of the message in the folder.
-;; If optional argument IGNORE-CACHE is non-nil, cache is ignored.
-;; Returned value is a elmo-fetch-strategy object.
-;; If return value is nil, message should not be nil.
-  )
+(luna-define-generic elmo-find-fetch-strategy (folder number
+                                                     &optional
+                                                     ignore-cache
+                                                     require-entireness)
+  "Return the message fetching strategy suitable for the message with NUMBER.
+FOLDER is the ELMO folder structure.
+If optional argument IGNORE-CACHE is non-nil, existing cache is ignored.
+If second optional argument REQUIRE-ENTIRENESS is non-nil,
+ensure that entireness of the returned strategy is entire.
+Returned value is a elmo-fetch-strategy object.
+If return value is nil, message should not be nil.")
 
 (defmacro elmo-make-fetch-strategy (entireness
                                    &optional
                                    use-cache
                                    save-cache
                                    cache-path)
 
 (defmacro elmo-make-fetch-strategy (entireness
                                    &optional
                                    use-cache
                                    save-cache
                                    cache-path)
-;; Make elmo-message-fetching strategy.
-;; ENTIRENESS is 'entire or 'section.
-;; 'entire means fetch message entirely at once.
-;; 'section means fetch message section by section.
-;; If optional USE-CACHE is non-nil, existing cache is used and otherwise,
-;; existing cache is thrown away.
-;; If SAVE-CACHE is non-nil, fetched message is saved.
-;; CACHE-PATH is the cache path to be used as a message cache file.
-  (` (vector (, entireness)
-            (, use-cache) (, save-cache) (, cache-path))))
+  "Make elmo-message-fetching strategy.
+ENTIRENESS is 'entire or 'section.
+'entire means fetch message entirely at once.
+'section means fetch message section by section.
+If optional USE-CACHE is non-nil, existing cache is used and otherwise,
+existing cache is thrown away.
+If SAVE-CACHE is non-nil, fetched message is saved.
+CACHE-PATH is the cache path to be used as a message cache file."
+  `(vector ,entireness ,use-cache ,save-cache ,cache-path))
 
 (defmacro elmo-fetch-strategy-entireness (strategy)
 
 (defmacro elmo-fetch-strategy-entireness (strategy)
-  ;; Return entireness of STRATEGY.
-  (` (aref (, strategy) 0)))
+  "Return entireness of STRATEGY."
+  `(aref ,strategy 0))
 
 (defmacro elmo-fetch-strategy-use-cache (strategy)
 
 (defmacro elmo-fetch-strategy-use-cache (strategy)
-  ;; Return use-cache of STRATEGY.
-  (` (aref (, strategy) 1)))
+  "Return use-cache of STRATEGY."
+  `(aref ,strategy 1))
 
 (defmacro elmo-fetch-strategy-save-cache (strategy)
 
 (defmacro elmo-fetch-strategy-save-cache (strategy)
-  ;; Return save-cache of STRATEGY.
-  (` (aref (, strategy) 2)))
+  "Return save-cache of STRATEGY."
+  `(aref ,strategy 2))
 
 (defmacro elmo-fetch-strategy-cache-path (strategy)
 
 (defmacro elmo-fetch-strategy-cache-path (strategy)
-  ;;  Return cache-path of STRATEGY.
-  (` (aref (, strategy) 3)))
-
-(luna-define-method elmo-find-fetch-strategy
-  ((folder elmo-folder) entity &optional ignore-cache)
-  (let (cache-file size message-id number)
-    (setq size (elmo-message-entity-field entity 'size))
-    (setq message-id (elmo-message-entity-field entity 'message-id))
-    (setq number (elmo-message-entity-number entity))
-    (setq cache-file (elmo-file-cache-get message-id))
-    (setq ignore-cache (or ignore-cache
-                          (null (elmo-message-use-cache-p folder number))))
-    (if (or ignore-cache
-           (null (elmo-file-cache-status cache-file)))
-       ;; No cache or ignore-cache.
-       (if (and (not (elmo-folder-local-p folder))
-                elmo-message-fetch-threshold
-                (integerp size)
-                (>= size elmo-message-fetch-threshold)
-                (or (not elmo-message-fetch-confirm)
-                    (not (prog1 (y-or-n-p
-                                 (format "Fetch entire message(%dbytes)? "
-                                         size))
-                           (message "")))))
-           ;; Don't fetch message at all.
-           nil
-         ;; Don't use existing cache and fetch entire message at once.
-         (elmo-make-fetch-strategy
-          'entire nil
-          (elmo-message-use-cache-p folder number)
-          (elmo-file-cache-path cache-file)))
-      ;; Cache exists.
-      (if (not ignore-cache)
-         (elmo-make-fetch-strategy
-          'entire
-          ;; ...But ignore current section cache and re-fetch
-          ;; if section cache.
-          (not (eq (elmo-file-cache-status cache-file) 'section))
-          ;; Save cache.
-          (elmo-message-use-cache-p folder number)
-          (elmo-file-cache-path cache-file))))))
+  "Return cache-path of STRATEGY."
+  `(aref ,strategy 3))
+
+(luna-define-method elmo-find-fetch-strategy ((folder elmo-folder) number
+                                             &optional
+                                             ignore-cache
+                                             require-entireness)
+  (let ((entity (elmo-message-entity folder number)))
+    (if (null entity)
+       (elmo-make-fetch-strategy 'entire)
+      (let* ((size (elmo-message-entity-field entity 'size))
+            (message-id (elmo-message-entity-field entity 'message-id))
+            (cache-file (elmo-file-cache-get message-id))
+            (use-cache (elmo-message-use-cache-p folder number)))
+       (if (and (not ignore-cache)
+                use-cache
+                (eq (elmo-file-cache-status cache-file) 'entire))
+           ;; Cache exists and use it.
+           (elmo-make-fetch-strategy
+            'entire
+            t                          ; Use cache.
+            use-cache                  ; Save cache.
+            (elmo-file-cache-path cache-file))
+         ;; No cache or ignore-cache.
+         (if (and (not (elmo-folder-local-p folder))
+                  (not require-entireness)
+                  elmo-message-fetch-threshold
+                  (integerp size)
+                  (>= size elmo-message-fetch-threshold)
+                  (or (not elmo-message-fetch-confirm)
+                      (not (prog1
+                               (y-or-n-p
+                                (format "Fetch entire message(%dbytes)? "
+                                        size))
+                             (message "")))))
+             ;; Don't fetch message at all.
+             nil
+           ;; Don't use existing cache and fetch entire message at once.
+           (elmo-make-fetch-strategy
+            'entire
+            nil                        ; Don't use cache.
+            use-cache                  ; Save cache.
+            (elmo-file-cache-path cache-file))))))))
 
 (luna-define-method elmo-folder-list-messages-internal
   ((folder elmo-folder) &optional visible-only)
   t)
 
 
 (luna-define-method elmo-folder-list-messages-internal
   ((folder elmo-folder) &optional visible-only)
   t)
 
-(defun elmo-folder-encache (folder numbers &optional unread)
-  "Encache messages in the FOLDER with NUMBERS.
-If UNREAD is non-nil, messages are not flaged as read."
-  (dolist (number numbers)
-    (elmo-message-encache folder number unread)))
-
 (luna-define-generic elmo-message-encache (folder number &optional read)
   "Encache message in the FOLDER with NUMBER.
 If READ is non-nil, message is flaged as read.")
 (luna-define-generic elmo-message-encache (folder number &optional read)
   "Encache message in the FOLDER with NUMBER.
 If READ is non-nil, message is flaged as read.")
@@ -566,15 +635,16 @@ If READ is non-nil, message is flaged as read.")
 (luna-define-method elmo-message-encache ((folder elmo-folder) number
                                          &optional read)
   (let (path)
 (luna-define-method elmo-message-encache ((folder elmo-folder) number
                                          &optional read)
   (let (path)
-    (elmo-message-fetch
-     folder number
-     (elmo-make-fetch-strategy 'entire
-                              nil ;use-cache
-                              t   ;save-cache
-                              (setq path (elmo-file-cache-get-path
-                                          (elmo-message-field
-                                           folder number 'message-id))))
-     nil nil (not read))
+    (with-temp-buffer
+      (elmo-message-fetch
+       folder number
+       (elmo-make-fetch-strategy 'entire
+                                nil ;use-cache
+                                t   ;save-cache
+                                (setq path (elmo-file-cache-get-path
+                                            (elmo-message-field
+                                             folder number 'message-id))))
+       (not read)))
     path))
 
 (luna-define-generic elmo-message-fetch-bodystructure (folder number strategy)
     path))
 
 (luna-define-generic elmo-message-fetch-bodystructure (folder number strategy)
@@ -582,32 +652,15 @@ If READ is non-nil, message is flaged as read.")
 
 (luna-define-generic elmo-message-fetch (folder number strategy
                                                &optional
 
 (luna-define-generic elmo-message-fetch (folder number strategy
                                                &optional
-                                               section
-                                               outbuf
-                                               unread)
-  "Fetch a message and return as a string.
-FOLDER is the ELMO folder structure.
-NUMBER is the number of the message in the FOLDER.
-STRATEGY is the message fetching strategy.
-If optional argument SECTION is specified, only the SECTION of the message
-is fetched (if possible).
-If second optional argument OUTBUF is specified, fetched message is
-inserted to the buffer and returns t if fetch was ended successfully.
-If third optional argument UNREAD is non-nil, message is not flaged as read.
-Returns non-nil if fetching was succeed.")
-
-(luna-define-generic elmo-message-fetch-with-cache-process (folder
-                                                           number strategy
-                                                           &optional
-                                                           section
-                                                           unread)
-  "Fetch a message into current buffer with cache process.
+                                               unread
+                                               section)
+  "Fetch a message into current buffer.
 FOLDER is the ELMO folder structure.
 NUMBER is the number of the message in the FOLDER.
 STRATEGY is the message fetching strategy.
 FOLDER is the ELMO folder structure.
 NUMBER is the number of the message in the FOLDER.
 STRATEGY is the message fetching strategy.
-If optional argument SECTION is specified, only the SECTION of the message
-is fetched (if possible).
-If second optional argument UNREAD is non-nil, message is not flaged as read.
+If optional argument UNREAD is non-nil, message is not flaged as read.
+If second optional argument SECTION is specified, only the
+SECTION of the message is fetched (if possible).
 Returns non-nil if fetching was succeed.")
 
 (luna-define-generic elmo-message-fetch-internal (folder number strategy
 Returns non-nil if fetching was succeed.")
 
 (luna-define-generic elmo-message-fetch-internal (folder number strategy
@@ -681,16 +734,17 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
   (elmo-generic-folder-commit folder))
 
 (defun elmo-generic-folder-commit (folder)
   (elmo-generic-folder-commit folder))
 
 (defun elmo-generic-folder-commit (folder)
-  (let ((msgdb (elmo-folder-msgdb-internal folder)))
-    (when (and msgdb (elmo-folder-persistent-p folder))
-      (when (elmo-msgdb-message-modified-p msgdb)
-       (elmo-folder-set-info-max-by-numdb
-        folder
-        (elmo-folder-list-messages folder nil 'in-msgdb))
-       (elmo-msgdb-killed-list-save
-        (elmo-folder-msgdb-path folder)
-        (elmo-folder-killed-list-internal folder)))
-      (elmo-msgdb-save msgdb))))
+  (when (elmo-folder-persistent-p folder)
+    (let ((msgdb (elmo-folder-msgdb-internal folder)))
+      (when msgdb
+       (when (elmo-msgdb-message-modified-p msgdb)
+         (elmo-folder-set-info-max-by-numdb
+          folder
+          (elmo-folder-list-messages folder nil 'in-msgdb)))
+       (elmo-msgdb-save msgdb)))
+    (elmo-msgdb-killed-list-save
+     (elmo-folder-msgdb-path folder)
+     (elmo-folder-killed-list-internal folder))))
 
 (luna-define-method elmo-folder-close-internal ((folder elmo-folder))
   ;; do nothing.
 
 (luna-define-method elmo-folder-close-internal ((folder elmo-folder))
   ;; do nothing.
@@ -731,16 +785,24 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
     t))
 
 (luna-define-method elmo-folder-rename ((folder elmo-folder) new-name)
     t))
 
 (luna-define-method elmo-folder-rename ((folder elmo-folder) new-name)
-  (let* ((new-folder (elmo-make-folder new-name)))
+  (let* ((new-folder (elmo-make-folder
+                     new-name
+                     nil
+                     (elmo-folder-mime-charset-internal folder))))
     (unless (eq (elmo-folder-type-internal folder)
                (elmo-folder-type-internal new-folder))
       (error "Not same folder type"))
     (unless (eq (elmo-folder-type-internal folder)
                (elmo-folder-type-internal new-folder))
       (error "Not same folder type"))
-    (if (or (file-exists-p (elmo-folder-msgdb-path new-folder))
-           (elmo-folder-exists-p new-folder))
-       (error "Already exists folder: %s" new-name))
+    (when (or (file-exists-p (elmo-folder-msgdb-path new-folder))
+             (elmo-folder-exists-p new-folder))
+      (error "Already exists folder: %s" new-name))
     (elmo-folder-send folder 'elmo-folder-rename-internal new-folder)
     (elmo-msgdb-rename-path folder new-folder)))
 
     (elmo-folder-send folder 'elmo-folder-rename-internal new-folder)
     (elmo-msgdb-rename-path folder new-folder)))
 
+(luna-define-method elmo-folder-delete-messages ((folder elmo-folder)
+                                                numbers)
+  (and (elmo-folder-delete-messages-internal folder numbers)
+       (elmo-folder-detach-messages folder numbers)))
+
 (luna-define-method elmo-folder-search ((folder elmo-folder)
                                        condition
                                        &optional numbers)
 (luna-define-method elmo-folder-search ((folder elmo-folder)
                                        condition
                                        &optional numbers)
@@ -750,6 +812,14 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
     (setq results (elmo-msgdb-search msgdb condition numbers))
     (if (listp results)
        results
     (setq results (elmo-msgdb-search msgdb condition numbers))
     (if (listp results)
        results
+      (elmo-condition-optimize condition)
+      (when (and (consp condition)
+                (eq (car condition) 'and)
+                (listp (setq results (elmo-msgdb-search msgdb
+                                                        (nth 1 condition)
+                                                        numbers))))
+       (setq numbers results
+             condition (nth 2 condition)))
       (let ((len (length numbers))
            matched)
        (elmo-with-progress-display (> len elmo-display-progress-threshold)
       (let ((len (length numbers))
            matched)
        (elmo-with-progress-display (> len elmo-display-progress-threshold)
@@ -771,6 +841,22 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
        (message "Searching...done")
        (nreverse matched)))))
 
        (message "Searching...done")
        (nreverse matched)))))
 
+(defun elmo-message-buffer-match-condition (condition number)
+  (let* ((handler (luna-make-entity 'modb-buffer-entity-handler))
+        (result (elmo-condition-match
+                 condition
+                 (lambda (condition handler entity)
+                   (elmo-msgdb-message-match-condition handler
+                                                       condition
+                                                       entity))
+                 (list
+                  handler
+                  (elmo-msgdb-make-message-entity
+                   handler
+                   :number number
+                   :buffer (current-buffer))))))
+    (and result (not (elmo-filter-condition-p result)))))
+
 (luna-define-method elmo-message-match-condition ((folder elmo-folder)
                                                  number condition
                                                  numbers)
 (luna-define-method elmo-message-match-condition ((folder elmo-folder)
                                                  number condition
                                                  numbers)
@@ -787,18 +873,18 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
                     cache-path))))
     (when (and filename (file-readable-p filename))
       (with-temp-buffer
                     cache-path))))
     (when (and filename (file-readable-p filename))
       (with-temp-buffer
-       (elmo-set-buffer-multibyte nil)
+       (set-buffer-multibyte nil)
        ;;(insert-file-contents-as-binary filename)
        (elmo-message-fetch folder number
                            (elmo-make-fetch-strategy 'entire
                                                      (and cache t)
                                                      nil
                                                      cache-path)
        ;;(insert-file-contents-as-binary filename)
        (elmo-message-fetch folder number
                            (elmo-make-fetch-strategy 'entire
                                                      (and cache t)
                                                      nil
                                                      cache-path)
-                           nil (current-buffer) t)
-       (elmo-set-buffer-multibyte default-enable-multibyte-characters)
+                           'unread)
+       (set-buffer-multibyte default-enable-multibyte-characters)
        (decode-coding-region (point-min) (point-max)
                              elmo-mime-display-as-is-coding-system)
        (decode-coding-region (point-min) (point-max)
                              elmo-mime-display-as-is-coding-system)
-       (elmo-buffer-field-condition-match condition number numbers)))))
+       (elmo-message-buffer-match-condition condition number)))))
 
 (luna-define-method elmo-folder-pack-numbers ((folder elmo-folder))
   nil) ; default is noop.
 
 (luna-define-method elmo-folder-pack-numbers ((folder elmo-folder))
   nil) ; default is noop.
@@ -825,6 +911,39 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
 (luna-define-method elmo-folder-have-subfolder-p ((folder elmo-folder))
   t)
 
 (luna-define-method elmo-folder-have-subfolder-p ((folder elmo-folder))
   t)
 
+;; Flag table
+(luna-define-generic elmo-folder-flag-table (folder &optional if-exists)
+  "Return the flag-table of FOLDER.
+If optional argument IF-EXISTS is nil, load on demand.
+\(For internal use only.\)")
+
+(luna-define-generic elmo-folder-close-flag-table (folder)
+  "Close flag-table of FOLDER.")
+
+(luna-define-method elmo-folder-flag-table ((folder elmo-folder)
+                                           &optional if-exists)
+  (or (elmo-folder-flag-table-internal folder)
+      (unless if-exists
+       (elmo-folder-set-flag-table-internal
+        folder
+        (elmo-flag-table-load (elmo-folder-msgdb-path folder))))))
+
+(luna-define-method elmo-folder-close-flag-table ((folder elmo-folder))
+  (elmo-flag-table-save (elmo-folder-msgdb-path folder)
+                       (elmo-folder-flag-table folder))
+  (elmo-folder-set-flag-table-internal folder nil))
+
+(defun elmo-folder-preserve-flags (folder msgid flags)
+  "Preserve FLAGS into FOLDER for a message that has MSGID."
+  (when (and msgid flags)
+    (let ((flag-table (elmo-folder-flag-table folder 'if-exists))
+         load-now)
+      (when (setq load-now (null flag-table))
+       (setq flag-table (elmo-folder-flag-table folder)))
+      (elmo-flag-table-set flag-table msgid flags)
+      (when load-now
+       (elmo-folder-close-flag-table folder)))))
+
 ;;; Folder info
 ;; Folder info is a message number information cache (hashtable)
 (defsubst elmo-folder-get-info (folder &optional hashtb)
 ;;; Folder info
 ;; Folder info is a message number information cache (hashtable)
 (defsubst elmo-folder-get-info (folder &optional hashtb)
@@ -895,13 +1014,12 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
 
 (defsubst elmo-strict-folder-diff (folder)
   "Return folder diff information strictly from FOLDER."
 
 (defsubst elmo-strict-folder-diff (folder)
   "Return folder diff information strictly from FOLDER."
-  (let ((in-db (sort (elmo-msgdb-list-messages (elmo-folder-msgdb folder))
-                    '<))
+  (let ((in-db (sort (elmo-folder-list-messages folder nil 'in-msgdb) '<))
        (in-folder  (elmo-folder-list-messages folder))
        append-list delete-list diff)
     (cons (if (equal in-folder in-db)
              0
        (in-folder  (elmo-folder-list-messages folder))
        append-list delete-list diff)
     (cons (if (equal in-folder in-db)
              0
-           (setq diff (elmo-list-diff in-folder in-db nil))
+           (setq diff (elmo-list-diff in-folder in-db))
            (setq append-list (car diff))
            (setq delete-list (cadr diff))
            (if append-list
            (setq append-list (car diff))
            (setq delete-list (cadr diff))
            (if append-list
@@ -971,17 +1089,16 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
 (defun elmo-generic-folder-append-messages (folder src-folder numbers
                                                   same-number)
   (let ((src-msgdb-exists (not (zerop (elmo-folder-length src-folder))))
 (defun elmo-generic-folder-append-messages (folder src-folder numbers
                                                   same-number)
   (let ((src-msgdb-exists (not (zerop (elmo-folder-length src-folder))))
-       unseen table flags
+       unseen table
        succeed-numbers failure cache id)
        succeed-numbers failure cache id)
-    (setq table (elmo-flag-table-load (elmo-folder-msgdb-path folder)))
+    (setq table (elmo-folder-flag-table folder))
     (with-temp-buffer
       (set-buffer-multibyte nil)
       (while numbers
        (setq failure nil
              id (and src-msgdb-exists
                      (elmo-message-field src-folder (car numbers)
     (with-temp-buffer
       (set-buffer-multibyte nil)
       (while numbers
        (setq failure nil
              id (and src-msgdb-exists
                      (elmo-message-field src-folder (car numbers)
-                                         'message-id))
-             flags (elmo-message-flags src-folder (car numbers)))
+                                         'message-id)))
        (condition-case nil
            (setq cache (elmo-file-cache-get id)
                  failure
        (condition-case nil
            (setq cache (elmo-file-cache-get id)
                  failure
@@ -1000,23 +1117,20 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
                                 'entire t nil
                                 (elmo-file-cache-path cache)))
                           (error "Unplugged")))
                                 'entire t nil
                                 (elmo-file-cache-path cache)))
                           (error "Unplugged")))
-                    nil (current-buffer)
                     'unread)
                    (> (buffer-size) 0)
                    (elmo-folder-append-buffer
                     folder
                     'unread)
                    (> (buffer-size) 0)
                    (elmo-folder-append-buffer
                     folder
-                    (or flags '(read))
+                    (elmo-message-flags-for-append src-folder (car numbers))
                     (if same-number (car numbers))))))
          (error (setq failure t)))
        ;; FETCH & APPEND finished
        (unless failure
                     (if same-number (car numbers))))))
          (error (setq failure t)))
        ;; FETCH & APPEND finished
        (unless failure
-         (when id
-           (elmo-flag-table-set table id flags))
          (setq succeed-numbers (cons (car numbers) succeed-numbers)))
        (elmo-progress-notify 'elmo-folder-move-messages)
        (setq numbers (cdr numbers)))
       (when (elmo-folder-persistent-p folder)
          (setq succeed-numbers (cons (car numbers) succeed-numbers)))
        (elmo-progress-notify 'elmo-folder-move-messages)
        (setq numbers (cdr numbers)))
       (when (elmo-folder-persistent-p folder)
-       (elmo-flag-table-save (elmo-folder-msgdb-path folder) table))
+       (elmo-folder-close-flag-table folder))
       succeed-numbers)))
 
 ;; Arguments should be reduced.
       succeed-numbers)))
 
 ;; Arguments should be reduced.
@@ -1046,8 +1160,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
          (elmo-folder-close dst-folder)))
       (if (and (not no-delete) succeeds)
          (progn
          (elmo-folder-close dst-folder)))
       (if (and (not no-delete) succeeds)
          (progn
-           (if (and (elmo-folder-delete-messages src-folder succeeds)
-                    (elmo-folder-detach-messages src-folder succeeds))
+           (if (elmo-folder-delete-messages src-folder succeeds)
                (progn
                  (elmo-global-flag-detach-messages
                   src-folder succeeds (eq dst-folder 'null))
                (progn
                  (elmo-global-flag-detach-messages
                   src-folder succeeds (eq dst-folder 'null))
@@ -1071,7 +1184,19 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
   (or (elmo-folder-path-internal folder)
       (elmo-folder-set-path-internal
        folder
   (or (elmo-folder-path-internal folder)
       (elmo-folder-set-path-internal
        folder
-       (elmo-folder-expand-msgdb-path folder))))
+       (if (null elmo-msgdb-path-encode-threshold)
+          (elmo-folder-expand-msgdb-path folder)
+        (let* ((path (directory-file-name
+                      (elmo-folder-expand-msgdb-path folder)))
+               (dirname (file-name-nondirectory path)))
+          (if (<= (length dirname) elmo-msgdb-path-encode-threshold)
+              path
+            (require 'md5)
+            (setq dirname (md5 dirname))
+            (when (> (length dirname) elmo-msgdb-path-encode-threshold)
+              (error "Cannot shrink msgdb path for `%s'"
+                     (elmo-folder-name-internal folder)))
+            (expand-file-name dirname (file-name-directory path))))))))
 
 (luna-define-generic elmo-message-cached-p (folder number)
   "Return non-nil if the message is cached.")
 
 (luna-define-generic elmo-message-cached-p (folder number)
   "Return non-nil if the message is cached.")
@@ -1079,11 +1204,20 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
 (luna-define-method elmo-message-cached-p ((folder elmo-folder) number)
   (elmo-message-flagged-p folder number 'cached))
 
 (luna-define-method elmo-message-cached-p ((folder elmo-folder) number)
   (elmo-message-flagged-p folder number 'cached))
 
+(luna-define-generic elmo-message-killed-p (folder number)
+  "Return non-nil if the message is killed.")
+
+(luna-define-method elmo-message-killed-p ((folder elmo-folder) number)
+  (let ((killed-list (elmo-folder-killed-list-internal folder)))
+    (and killed-list
+        (elmo-number-set-member number killed-list))))
+
 (defun elmo-message-accessible-p (folder number)
   "Get accessibility of the message.
 Return non-nil when message is accessible."
   (or (elmo-folder-plugged-p folder)
       (elmo-folder-local-p folder)
 (defun elmo-message-accessible-p (folder number)
   "Get accessibility of the message.
 Return non-nil when message is accessible."
   (or (elmo-folder-plugged-p folder)
       (elmo-folder-local-p folder)
+      (< number 0) ; in dop spool
       (elmo-message-cached-p folder number)))
 
 (luna-define-generic elmo-message-set-cached (folder number cached)
       (elmo-message-cached-p folder number)))
 
 (luna-define-generic elmo-message-set-cached (folder number cached)
@@ -1096,12 +1230,19 @@ If CACHED is t, message is set as cached.")
                                             number cached)
   (if cached
       (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number 'cached)
                                             number cached)
   (if cached
       (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number 'cached)
-    (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number 'cached)))
+    (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number 'cached))
+  (elmo-emit-signal 'status-changed folder (list number)))
 
 (defun elmo-message-copy-entity (entity)
   (elmo-msgdb-copy-message-entity (elmo-message-entity-handler entity)
                                  entity))
 
 
 (defun elmo-message-copy-entity (entity)
   (elmo-msgdb-copy-message-entity (elmo-message-entity-handler entity)
                                  entity))
 
+(luna-define-generic elmo-message-number (folder message-id)
+  "Get message number from MSGDB which corresponds to MESSAGE-ID.")
+
+(luna-define-method elmo-message-number ((folder elmo-folder) message-id)
+  (elmo-msgdb-message-number (elmo-folder-msgdb folder) message-id))
+
 (luna-define-generic elmo-message-entity (folder key)
   "Return the message-entity structure which matches to the KEY.
 KEY is a number or a string.
 (luna-define-generic elmo-message-entity (folder key)
   "Return the message-entity structure which matches to the KEY.
 KEY is a number or a string.
@@ -1138,14 +1279,14 @@ ENTITY is the message-entity to get the parent.")
 
 (luna-define-generic elmo-folder-count-flags (folder)
   "Count flagged message number in the msgdb of the FOLDER.
 
 (luna-define-generic elmo-folder-count-flags (folder)
   "Count flagged message number in the msgdb of the FOLDER.
-Return a list of numbers (`new' `unread' `answered')")
+Return alist of flag and numbers.
+Example:
+\(\(new . 10\)
+  \(unread . 20\)
+  \(answered . 3\)\)")
 
 (luna-define-method elmo-folder-count-flags ((folder elmo-folder))
 
 (luna-define-method elmo-folder-count-flags ((folder elmo-folder))
-  (let* ((flag-count (elmo-msgdb-flag-count (elmo-folder-msgdb folder)))
-        (new (or (cdr (assq 'new flag-count)) 0))
-        (unread (or (cdr (assq 'unread flag-count)) 0))
-        (answered(or (cdr (assq 'answered flag-count)) 0)))
-    (list new (- unread new) answered)))
+  (elmo-msgdb-flag-count (elmo-folder-msgdb folder)))
 
 (defun elmo-message-set-flag (folder number flag &optional is-local)
   "Set message flag.
 
 (defun elmo-message-set-flag (folder number flag &optional is-local)
   "Set message flag.
@@ -1177,16 +1318,18 @@ If optional IS-LOCAL is non-nil, update only local (not server) status."
   ;; XXX Transitional implementation.
   (elmo-folder-unset-flag folder (list number) flag is-local))
 
   ;; XXX Transitional implementation.
   (elmo-folder-unset-flag folder (list number) flag is-local))
 
-(luna-define-generic elmo-message-field (folder number field)
+(luna-define-generic elmo-message-field (folder number field &optional type)
   "Get message field value in the msgdb.
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message.
   "Get message field value in the msgdb.
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message.
-FIELD is a symbol of the field.")
+FIELD is a symbol of the field.
+If optional argument TYPE is specified, return converted value.")
 
 
-(luna-define-method elmo-message-field ((folder elmo-folder) number field)
-  (elmo-message-entity-field (elmo-message-entity folder number) field))
+(luna-define-method elmo-message-field ((folder elmo-folder)
+                                       number field &optional type)
+  (elmo-msgdb-message-field (elmo-folder-msgdb folder) number field type))
 
 
-(luna-define-generic elmo-message-field (folder number field value)
+(luna-define-generic elmo-message-set-field (folder number field value)
   "Set message field value in the msgdb.
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message.
   "Set message field value in the msgdb.
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message.
@@ -1210,12 +1353,17 @@ VALUE is a value to set.")
                                          &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
                                          &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
-      (when (elmo-global-flag-p flag)
-       (let ((message-id (elmo-message-field folder number 'message-id)))
-         (elmo-global-flag-set flag folder number message-id)))
-      (elmo-msgdb-set-flag (elmo-folder-msgdb folder)
-                          number
-                          flag))))
+      (let ((old-flags (elmo-message-flags folder number)))
+       (when (elmo-global-flag-p flag)
+         (let ((message-id (elmo-message-field folder number 'message-id)))
+           (elmo-global-flag-set flag folder number message-id)))
+       (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number flag)
+       (elmo-emit-signal 'flag-changing
+                         folder
+                         number
+                         old-flags
+                         (elmo-message-flags folder number))))
+    (elmo-emit-signal 'flag-changed folder numbers)))
 
 (defun elmo-message-has-global-flag-p (folder number)
   "Return non-nil when the message in the FOLDER with NUMBER has global flag."
 
 (defun elmo-message-has-global-flag-p (folder number)
   "Return non-nil when the message in the FOLDER with NUMBER has global flag."
@@ -1249,11 +1397,16 @@ If Optional LOCAL is non-nil, don't update server flag."
                                            &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
                                            &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
-      (when (elmo-global-flag-p flag)
-       (elmo-global-flag-detach flag folder number 'always))
-      (elmo-msgdb-unset-flag (elmo-folder-msgdb folder)
-                            number
-                            flag))))
+      (let ((old-flags (elmo-message-flags folder number)))
+       (when (elmo-global-flag-p flag)
+         (elmo-global-flag-detach flag folder number 'always))
+       (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number flag)
+       (elmo-emit-signal 'flag-changing
+                         folder
+                         number
+                         old-flags
+                         (elmo-message-flags folder number))))
+    (elmo-emit-signal 'flag-changed folder numbers)))
 
 (luna-define-method elmo-folder-process-crosspost ((folder elmo-folder))
   ;; Do nothing.
 
 (luna-define-method elmo-folder-process-crosspost ((folder elmo-folder))
   ;; Do nothing.
@@ -1281,24 +1434,26 @@ If Optional LOCAL is non-nil, don't update server flag."
               ;; Let duplicates be a temporary killed message.
               (elmo-folder-kill-messages folder duplicates)
               ;; Should be flag as read.
               ;; Let duplicates be a temporary killed message.
               (elmo-folder-kill-messages folder duplicates)
               ;; Should be flag as read.
-              (elmo-folder-set-flag folder duplicates 'read))
+              (elmo-folder-unset-flag folder duplicates 'unread))
              ((eq (elmo-folder-process-duplicates-internal folder)
                   'read)
               ;; Flag as read duplicates.
              ((eq (elmo-folder-process-duplicates-internal folder)
                   'read)
               ;; Flag as read duplicates.
-              (elmo-folder-set-flag folder duplicates 'read))
+              (elmo-folder-unset-flag folder duplicates 'unread))
              (t
               ;; Do nothing.
               (setq duplicates nil)))
        (length duplicates))
     0))
 
              (t
               ;; Do nothing.
               (setq duplicates nil)))
        (length duplicates))
     0))
 
-(defun elmo-folder-confirm-appends (appends)
+(defun elmo-folder-confirm-appends (folder appends)
   (let ((len (length appends))
        in)
     (if (and elmo-folder-update-threshold
             (> len elmo-folder-update-threshold)
             elmo-folder-update-confirm)
   (let ((len (length appends))
        in)
     (if (and elmo-folder-update-threshold
             (> len elmo-folder-update-threshold)
             elmo-folder-update-confirm)
-       (if (y-or-n-p (format "Too many messages(%d).  Update all? " len))
+       (if (y-or-n-p (format
+                      "Too many messages(%d) in %s.  Update all? "
+                      len (elmo-folder-name-internal folder)))
            appends
          (setq in elmo-folder-update-threshold)
          (catch 'end
            appends
          (setq in elmo-folder-update-threshold)
          (catch 'end
@@ -1323,26 +1478,21 @@ If Optional LOCAL is non-nil, don't update server flag."
                                                      number strategy)
   nil)
 
                                                      number strategy)
   nil)
 
+(defun elmo-message-fetch-string (folder number strategy
+                                        &optional
+                                        unread
+                                        section)
+  (with-temp-buffer
+    (set-buffer-multibyte nil)
+    (when (elmo-message-fetch folder number strategy unread section)
+      (buffer-string))))
+
 (luna-define-method elmo-message-fetch ((folder elmo-folder)
                                        number strategy
                                        &optional
 (luna-define-method elmo-message-fetch ((folder elmo-folder)
                                        number strategy
                                        &optional
-                                       section
-                                       outbuf
-                                       unread)
-  (if outbuf
-      (with-current-buffer outbuf
-       (erase-buffer)
-       (elmo-message-fetch-with-cache-process folder number
-                                              strategy section unread))
-    (with-temp-buffer
-      (elmo-message-fetch-with-cache-process folder number
-                                            strategy section unread)
-      (buffer-string))))
-
-(luna-define-method elmo-message-fetch-with-cache-process ((folder elmo-folder)
-                                                          number strategy
-                                                          &optional
-                                                          section unread)
+                                       unread
+                                       section)
+  (erase-buffer)
   (let ((cache-path (elmo-fetch-strategy-cache-path strategy))
        (method-priorities
         (cond ((eq (elmo-fetch-strategy-use-cache strategy) 'maybe)
   (let ((cache-path (elmo-fetch-strategy-cache-path strategy))
        (method-priorities
         (cond ((eq (elmo-fetch-strategy-use-cache strategy) 'maybe)
@@ -1351,28 +1501,33 @@ If Optional LOCAL is non-nil, don't update server flag."
                '(cache entity))
               (t
                '(entity))))
                '(cache entity))
               (t
                '(entity))))
-       result err)
+       result err updated-server-flag)
     (while (and method-priorities
     (while (and method-priorities
-               (null result))
+               (not result))
       (setq result
            (case (car method-priorities)
              (cache
               (elmo-file-cache-load cache-path section))
              (entity
       (setq result
            (case (car method-priorities)
              (cache
               (elmo-file-cache-load cache-path section))
              (entity
-              (when (and (condition-case error
-                             (elmo-message-fetch-internal folder number
-                                                          strategy
-                                                          section
-                                                          unread)
-                           (error (setq err error) nil))
-                         (> (buffer-size) 0))
+              (when (condition-case error
+                        (elmo-message-fetch-internal folder number
+                                                     strategy
+                                                     section
+                                                     unread)
+                      (error (setq err error) nil))
+                (setq updated-server-flag t)
                 (when (and (elmo-fetch-strategy-save-cache strategy)
                            cache-path)
                   (elmo-file-cache-save cache-path section))
                 t)))
            method-priorities (cdr method-priorities)))
                 (when (and (elmo-fetch-strategy-save-cache strategy)
                            cache-path)
                   (elmo-file-cache-save cache-path section))
                 t)))
            method-priorities (cdr method-priorities)))
-    (or result
-       (and err (signal (car err) (cdr err))))))
+    (if result
+       (when (and (not unread)
+                  (elmo-message-flagged-p folder number 'unread))
+         (elmo-message-unset-flag folder number 'unread updated-server-flag))
+      (when err
+       (signal (car err) (cdr err))))
+    result))
 
 (defun elmo-folder-kill-messages-range (folder beg end)
   (elmo-folder-set-killed-list-internal
 
 (defun elmo-folder-kill-messages-range (folder beg end)
   (elmo-folder-set-killed-list-internal
@@ -1383,13 +1538,29 @@ If Optional LOCAL is non-nil, don't update server flag."
 
 (defun elmo-folder-kill-messages (folder numbers)
   "Kill(hide) messages in the FOLDER with NUMBERS."
 
 (defun elmo-folder-kill-messages (folder numbers)
   "Kill(hide) messages in the FOLDER with NUMBERS."
-  (let ((msgdb (elmo-folder-msgdb folder))
-       (killed (elmo-folder-killed-list-internal folder)))
-    (dolist (number numbers)
-      (elmo-number-set-append killed number)
-      (elmo-msgdb-unset-flag msgdb number 'all))
-    (elmo-folder-set-killed-list-internal folder killed)))
+  (elmo-folder-set-killed-list-internal
+   folder
+   (elmo-number-set-append-list
+    (elmo-folder-killed-list-internal folder)
+    numbers))
+  (elmo-folder-unset-flag folder numbers 'all 'local-only))
+
+(luna-define-generic elmo-folder-recover-messages (folder numbers)
+  "Recover killed messages in the FOLDER with NUMBERS.")
 
 
+(luna-define-method elmo-folder-recover-messages ((folder elmo-folder) numbers)
+  (let ((msgdb (elmo-folder-msgdb folder)))
+    (elmo-folder-set-killed-list-internal
+     folder
+     (elmo-number-set-delete-list
+      (elmo-folder-killed-list-internal folder)
+      numbers))
+    (dolist (number numbers)
+      (if (elmo-file-cache-exists-p
+          (elmo-message-field folder number 'message-id))
+         (elmo-msgdb-set-flag msgdb number 'cached)
+       (elmo-msgdb-unset-flag msgdb number 'cached)))
+    (elmo-emit-signal 'status-changed folder numbers)))
 
 (luna-define-method elmo-folder-clear ((folder elmo-folder)
                                       &optional keep-killed)
 
 (luna-define-method elmo-folder-clear ((folder elmo-folder)
                                       &optional keep-killed)
@@ -1405,7 +1576,8 @@ If Optional LOCAL is non-nil, don't update server flag."
                                              &optional
                                              disable-killed
                                              ignore-msgdb
                                              &optional
                                              disable-killed
                                              ignore-msgdb
-                                             no-check)
+                                             no-check
+                                             mask)
   "Synchronize the folder data to the newest status.
 FOLDER is the ELMO folder structure.
 
   "Synchronize the folder data to the newest status.
 FOLDER is the ELMO folder structure.
 
@@ -1413,6 +1585,8 @@ If optional DISABLE-KILLED is non-nil, killed messages are also synchronized.
 If optional IGNORE-MSGDB is non-nil, current msgdb is thrown away except
 flag status.
 If NO-CHECK is non-nil, rechecking folder is skipped.
 If optional IGNORE-MSGDB is non-nil, current msgdb is thrown away except
 flag status.
 If NO-CHECK is non-nil, rechecking folder is skipped.
+If optional argument MASK is specified and is a list of message numbers,
+synchronize messages only which are contained the list.
 Return amount of cross-posted messages.
 If update process is interrupted, return nil.")
 
 Return amount of cross-posted messages.
 If update process is interrupted, return nil.")
 
@@ -1420,47 +1594,48 @@ If update process is interrupted, return nil.")
                                             &optional
                                             disable-killed
                                             ignore-msgdb
                                             &optional
                                             disable-killed
                                             ignore-msgdb
-                                            no-check)
-  (let ((killed-list (elmo-folder-killed-list-internal folder))
-       (before-append t)
-       old-msgdb diff diff-2 delete-list new-list new-msgdb flag
-       flag-table crossed after-append)
-    (setq old-msgdb (elmo-folder-msgdb folder))
-    (setq flag-table (elmo-flag-table-load (elmo-folder-msgdb-path folder)))
+                                            no-check
+                                            mask)
+  (let ((old-msgdb (elmo-folder-msgdb folder))
+       (killed-list (elmo-folder-killed-list-internal folder))
+       (flag-table (elmo-flag-table-load (elmo-folder-msgdb-path folder)))
+       (before-append t))
     (when ignore-msgdb
       (elmo-msgdb-flag-table (elmo-folder-msgdb folder) flag-table)
       (elmo-folder-clear folder (not disable-killed)))
     (unless no-check (elmo-folder-check folder))
     (condition-case nil
     (when ignore-msgdb
       (elmo-msgdb-flag-table (elmo-folder-msgdb folder) flag-table)
       (elmo-folder-clear folder (not disable-killed)))
     (unless no-check (elmo-folder-check folder))
     (condition-case nil
-       (progn
+       (let ((killed-list (elmo-folder-killed-list-internal folder))
+             diff-new diff-del
+             delete-list new-list new-msgdb crossed)
          (message "Checking folder diff...")
          (message "Checking folder diff...")
-         (setq diff (elmo-list-diff (elmo-folder-list-messages
-                                     folder
-                                     (not disable-killed))
-                                    (elmo-folder-list-messages
-                                     folder
-                                     (not disable-killed)
-                                     'in-msgdb)))
+         (elmo-set-list
+          '(diff-new diff-del)
+          (elmo-list-diff (elmo-folder-list-messages folder)
+                          (elmo-folder-list-messages folder nil 'in-msgdb)))
+         (when diff-new
+           (setq diff-new (sort diff-new #'<))
+           (unless disable-killed
+             (setq diff-new (elmo-living-messages diff-new killed-list)))
+           (when (and mask (not ignore-msgdb))
+             (setq diff-new (elmo-list-filter mask diff-new))))
          (message "Checking folder diff...done")
          (message "Checking folder diff...done")
-         (setq new-list (elmo-folder-confirm-appends (car diff)))
-         ;; Set killed list as ((1 . MAX-OF-DISAPPEARED))
-         (when (and (not (eq (length (car diff))
-                             (length new-list)))
-                    (setq diff-2 (elmo-list-diff (car diff) new-list)))
-           (elmo-folder-kill-messages-range
-            folder
-            (car (car diff-2))
-            (nth (- (length (car diff-2)) 1) (car diff-2))))
-         (setq delete-list (cadr diff))
-         (if (or (equal diff '(nil nil))
-                 (equal diff '(nil))
-                 (and (eq (length (car diff)) 0)
-                      (eq (length (cadr diff)) 0)))
+         (setq new-list (elmo-folder-confirm-appends folder diff-new))
+         ;; Append to killed list as (MIN-OF-DISAPPEARED . MAX-OF-DISAPPEARED)
+         (when (not (eq (length diff-new)
+                        (length new-list)))
+           (let* ((diff (elmo-list-diff diff-new new-list))
+                  (disappeared (sort (car diff) #'<)))
+             (when disappeared
+               (elmo-folder-kill-messages-range folder
+                                                (car disappeared)
+                                                (elmo-last disappeared)))))
+         (setq delete-list diff-del)
+         (if (and (null diff-new) (null diff-del))
              (progn
                (elmo-folder-update-number folder)
                (elmo-folder-process-crosspost folder)
              (progn
                (elmo-folder-update-number folder)
                (elmo-folder-process-crosspost folder)
-               0 ; no updates.
-               )
+               0)                      ; `0' means no updates.
            (when delete-list
              (elmo-folder-detach-messages folder delete-list))
            (when new-list
            (when delete-list
              (elmo-folder-detach-messages folder delete-list))
            (when new-list
@@ -1489,7 +1664,14 @@ If update process is interrupted, return nil.")
 
 (luna-define-method elmo-folder-detach-messages ((folder elmo-folder)
                                                 numbers)
 
 (luna-define-method elmo-folder-detach-messages ((folder elmo-folder)
                                                 numbers)
-  (elmo-msgdb-delete-messages (elmo-folder-msgdb folder) numbers))
+  (when (elmo-msgdb-delete-messages (elmo-folder-msgdb folder) numbers)
+    ;; Remove NUMBERS from killed message list.
+    (elmo-folder-set-killed-list-internal
+     folder
+     (elmo-number-set-delete-list
+      (elmo-folder-killed-list-internal folder)
+      numbers))
+    t))
 
 (luna-define-generic elmo-folder-length (folder)
   "Return number of messages in the FOLDER.")
 
 (luna-define-generic elmo-folder-length (folder)
   "Return number of messages in the FOLDER.")
@@ -1502,7 +1684,8 @@ If update process is interrupted, return nil.")
 (defun elmo-folder-msgdb-load (folder &optional silent)
   (unless silent
     (message "Loading msgdb for %s..." (elmo-folder-name-internal folder)))
 (defun elmo-folder-msgdb-load (folder &optional silent)
   (unless silent
     (message "Loading msgdb for %s..." (elmo-folder-name-internal folder)))
-  (let ((msgdb (elmo-load-msgdb (elmo-folder-msgdb-path folder))))
+  (let ((msgdb (elmo-load-msgdb (elmo-folder-msgdb-path folder)
+                               (elmo-folder-mime-charset-internal folder))))
     (elmo-folder-set-info-max-by-numdb
      folder
      (elmo-msgdb-list-messages msgdb))
     (elmo-folder-set-info-max-by-numdb
      folder
      (elmo-msgdb-list-messages msgdb))
@@ -1574,6 +1757,43 @@ Return a hashtable for newsgroups."
     (elmo-make-directory temp-dir)
     temp-dir))
 
     (elmo-make-directory temp-dir)
     temp-dir))
 
+;; ELMO status structure.
+(defmacro elmo-message-status (folder number &optional flags killed)
+  "Make ELMO status structure from FOLDER and NUMBER.
+A value in this structure is cached at first access."
+  `(vector ,folder ,number ,flags ,killed))
+
+(defmacro elmo-message-status-folder (status)
+  `(aref ,status 0))
+
+(defmacro elmo-message-status-number (status)
+  `(aref ,status 1))
+
+(defmacro elmo-message-status-set-flags (status flags)
+  `(aset ,status 2 (or ,flags '(read))))
+
+(defsubst elmo-message-status-flags (status)
+  (or (aref status 2)
+      (elmo-message-status-set-flags
+       status
+       (elmo-message-flags (elmo-message-status-folder status)
+                          (elmo-message-status-number status)))))
+
+(defsubst elmo-message-status-cached-p (status)
+  (memq 'cached (elmo-message-status-flags status)))
+
+(defmacro elmo-message-status-set-killed (status killed)
+  `(aset ,status 3 (if ,killed 'killed 'living)))
+
+(defsubst elmo-message-status-killed-p (status)
+  (eq 'killed
+      (or (aref status 3)
+         (elmo-message-status-set-killed
+          status
+          (elmo-message-killed-p (elmo-message-status-folder status)
+                                 (elmo-message-status-number status))))))
+
+;;;
 (defun elmo-init ()
   "Initialize ELMO module."
   (elmo-crosspost-message-alist-load)
 (defun elmo-init ()
   "Initialize ELMO module."
   (elmo-crosspost-message-alist-load)
@@ -1616,7 +1836,7 @@ Return a hashtable for newsgroups."
 (elmo-define-folder ?|  'pipe)
 (elmo-define-folder ?.  'maildir)
 (elmo-define-folder ?'  'internal)
 (elmo-define-folder ?|  'pipe)
 (elmo-define-folder ?.  'maildir)
 (elmo-define-folder ?'  'internal)
-(elmo-define-folder ?\[  'nmz)
+(elmo-define-folder ?\[  'search)
 (elmo-define-folder ?@  'shimbun)
 
 ;;; Obsolete variables.
 (elmo-define-folder ?@  'shimbun)
 
 ;;; Obsolete variables.
@@ -1654,6 +1874,15 @@ Return a hashtable for newsgroups."
                               'elmo-cache-directory)
 (elmo-define-obsolete-variable 'elmo-msgdb-dir
                               'elmo-msgdb-directory)
                               'elmo-cache-directory)
 (elmo-define-obsolete-variable 'elmo-msgdb-dir
                               'elmo-msgdb-directory)
+(elmo-define-obsolete-variable 'elmo-global-flag-list
+                              'elmo-global-flags)
+(elmo-define-obsolete-variable 'elmo-nmz-default-index-path
+                              'elmo-search-namazu-default-index-path)
+(elmo-define-obsolete-variable 'elmo-nmz-index-alias-alist
+                              'elmo-search-namazu-index-alias-alist)
+(elmo-define-obsolete-variable 'elmo-nmz-use-drive-letter
+                              'elmo-search-use-drive-letter)
+
 
 ;; Obsolete functions.
 ;; 2001-12-11: *-dir -> *-directory
 
 ;; Obsolete functions.
 ;; 2001-12-11: *-dir -> *-directory