* test-elmo-util.el (test-elmo-number-set-delete-1): New testcase.
[elisp/wanderlust.git] / elmo / elmo.el
index 0dcfae0..b111675 100644 (file)
@@ -46,7 +46,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
@@ -84,6 +85,7 @@ Otherwise, entire fetching of the message is aborted without confirmation."
   (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-global-flag-detach "elmo-flag")
   (autoload 'elmo-global-flag-detach-messages "elmo-flag")
   (autoload 'elmo-global-flag-set "elmo-flag")
@@ -117,6 +119,7 @@ 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
@@ -140,8 +143,8 @@ If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
     (setq original (elmo-string name))
     (if type
        (progn
     (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)))))
@@ -232,10 +235,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 +315,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.
@@ -368,6 +377,9 @@ FLAG is a symbol which is one of the following:
   `all'       (remove all flags)
 If optional IS-LOCAL is non-nil, update only local (not server) status.")
 
   `all'       (remove all flags)
 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.")
@@ -375,8 +387,10 @@ FOLDER is the ELMO folder structure.")
 (luna-define-generic elmo-folder-append-buffer (folder &optional flags
                                                       number)
   "Append current buffer as a new message.
 (luna-define-generic elmo-folder-append-buffer (folder &optional flags
                                                       number)
   "Append current buffer as a new message.
-FOLDER is the destination folder(ELMO folder structure).
-FLAGS is the status of appended message (list of symbols).
+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 possible\).
 Return nil on failure.")
 If optional argument NUMBER is specified, the new message number is set
 \(if possible\).
 Return nil on failure.")
@@ -393,7 +407,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.")
@@ -456,6 +471,10 @@ 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.")
 
+(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))
 
@@ -683,16 +702,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.
@@ -743,6 +763,11 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
     (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)
@@ -789,7 +814,7 @@ 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
        ;;(insert-file-contents-as-binary filename)
        (elmo-message-fetch folder number
                            (elmo-make-fetch-strategy 'entire
@@ -797,7 +822,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
                                                      nil
                                                      cache-path)
                            nil (current-buffer) t)
                                                      nil
                                                      cache-path)
                            nil (current-buffer) t)
-       (elmo-set-buffer-multibyte default-enable-multibyte-characters)
+       (set-buffer-multibyte default-enable-multibyte-characters)
        (decode-coding-region (point-min) (point-max)
                              elmo-mime-display-as-is-coding-system)
        (elmo-buffer-field-condition-match condition number numbers)))))
        (decode-coding-region (point-min) (point-max)
                              elmo-mime-display-as-is-coding-system)
        (elmo-buffer-field-condition-match condition number numbers)))))
@@ -827,6 +852,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)
@@ -897,8 +955,7 @@ 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)
        (in-folder  (elmo-folder-list-messages folder))
        append-list delete-list diff)
     (cons (if (equal in-folder in-db)
@@ -973,17 +1030,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
@@ -1007,18 +1063,22 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
                    (> (buffer-size) 0)
                    (elmo-folder-append-buffer
                     folder
                    (> (buffer-size) 0)
                    (elmo-folder-append-buffer
                     folder
-                    (or flags '(read))
+                    (let ((this-id (elmo-message-field src-folder (car numbers)
+                                                       'message-id)))
+                      (and this-id
+                           (string= this-id
+                                    (elmo-msgdb-get-message-id-from-buffer))
+                           (or (elmo-message-flags src-folder (car numbers))
+                               '(read))))
                     (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.
@@ -1048,8 +1108,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))
@@ -1104,6 +1163,12 @@ If CACHED is t, message is set as cached.")
   (elmo-msgdb-copy-message-entity (elmo-message-entity-handler 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.
@@ -1140,14 +1205,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.
@@ -1186,7 +1251,7 @@ NUMBER is a number of the message.
 FIELD is a symbol of the field.")
 
 (luna-define-method elmo-message-field ((folder elmo-folder) number field)
 FIELD is a symbol of the field.")
 
 (luna-define-method elmo-message-field ((folder elmo-folder) number field)
-  (elmo-message-entity-field (elmo-message-entity folder number) field))
+  (elmo-msgdb-message-field (elmo-folder-msgdb folder) number field))
 
 (luna-define-generic elmo-message-set-field (folder number field value)
   "Set message field value in the msgdb.
 
 (luna-define-generic elmo-message-set-field (folder number field value)
   "Set message field value in the msgdb.
@@ -1283,11 +1348,11 @@ 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)))
              (t
               ;; Do nothing.
               (setq duplicates nil)))
@@ -1406,7 +1471,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.
 
@@ -1414,6 +1480,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.")
 
@@ -1421,47 +1489,47 @@ 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
+           (unless disable-killed
+             (setq diff-new (elmo-living-messages diff-new killed-list)))
+           (when mask
+             (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 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 (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
@@ -1490,7 +1558,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.")
@@ -1655,6 +1730,8 @@ 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)
 
 ;; Obsolete functions.
 ;; 2001-12-11: *-dir -> *-directory
 
 ;; Obsolete functions.
 ;; 2001-12-11: *-dir -> *-directory