Synch up with main trunk.
[elisp/wanderlust.git] / elmo / elmo.el
index 120640f..ef66b76 100644 (file)
@@ -1,4 +1,4 @@
-;;; elmo.el -- Elisp Library for Message Orchestration
+;;; elmo.el --- Elisp Library for Message Orchestration.
 
 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
 
@@ -77,7 +77,7 @@ Otherwise, entire fetching of the message is aborted without confirmation."
 (elmo-define-error 'elmo-error "Error" 'error)
 (elmo-define-error 'elmo-open-error "Cannot open" 'elmo-error)
 (elmo-define-error 'elmo-authenticate-error "Login failed" 'elmo-open-error)
-(elmo-define-error 'elmo-imap4-bye-error "IMAP4 BYE response" 'elmo-open-error)
+(elmo-define-error 'elmo-imap4-bye-error "IMAP4 session was terminated" 'elmo-open-error)
 
 (defun elmo-define-folder (prefix backend)
   "Define a folder.
@@ -109,6 +109,7 @@ If a folder name begins with PREFIX, use BACKEND."
                                     message-modified ; message is modified.
                                     mark-modified    ; mark is modified.
                                     process-duplicates  ; read or hide
+                                    biff   ; folder for biff
                                     ))
   (luna-define-internal-accessors 'elmo-folder))
 
@@ -133,7 +134,9 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
          (setq prefix (substring name 0 1))
          (setq name (substring name 1)))
       (setq type (intern (car (setq split (split-string name ":")))))
-      (setq name (substring name (+ 1 (length (car split)))))
+      (if (> (length split) 2)
+         (setq name (substring name (+ 1 (length (car split)))))
+       (error "Error in folder name `%s'" original))
       (setq prefix (concat (car split) ":")))
     (setq class (format "elmo-%s" (symbol-name type)))
     (require (intern class))
@@ -145,11 +148,13 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
     (save-match-data
       (elmo-folder-send folder 'elmo-folder-initialize name))))
 
-(defmacro elmo-folder-msgdb (folder)
-  "Return the msgdb of FOLDER (on-demand loading)."
-  (` (or (elmo-folder-msgdb-internal (, folder))
-        (elmo-folder-set-msgdb-internal (, folder)
-                                        (elmo-msgdb-load (, folder))))))
+(luna-define-generic elmo-folder-msgdb (folder)
+  "Return the msgdb of FOLDER (on-demand loading).")
+
+(luna-define-method elmo-folder-msgdb ((folder elmo-folder))
+  (or (elmo-folder-msgdb-internal folder)
+      (elmo-folder-set-msgdb-internal folder
+                                     (elmo-msgdb-load folder))))
 
 (luna-define-generic elmo-folder-open (folder &optional load-msgdb)
   "Open and setup (load saved status) FOLDER.
@@ -191,7 +196,9 @@ If optional KEEP-KILLED is non-nil, killed-list is not cleared.")
   "Get diff of FOLDER.
 If optional NUMBERS is set, it is used as current NUMBERS.
 Otherwise, saved status for folder is used for comparison.
-Return value is a cons cell of NEWS and MESSAGES.")
+Return value is cons cell or list:
+ - a cons cell (NEWS . MESSAGES)
+ - a list (RECENT UNSEEN MESSAGES) ; RECENT means NEWS, UNSEEN means UNREAD.")
 
 (luna-define-generic elmo-folder-status (folder)
   "Returns a cons cell of (MAX-NUMBER . MESSAGES) in the FOLDER.")
@@ -199,56 +206,72 @@ Return value is a cons cell of NEWS and MESSAGES.")
 (luna-define-generic elmo-folder-reserve-status-p (folder)
   "If non-nil, the folder should not close folder after `elmo-folder-status'.")
 
-(defun elmo-folder-list-messages (folder &optional visible-only)
+(defun elmo-folder-list-messages (folder &optional visible-only in-msgdb)
   "Return a list of message numbers contained in FOLDER.
-If optional VISIBLE-ONLY is non-nil, killed messages are not listed."
-  (let ((list (elmo-folder-list-messages-internal folder visible-only))
-       (killed (elmo-folder-killed-list-internal folder))
-       numbers)
-    (setq numbers
-         (if (listp list)
-             list
-           ;; Not available, use current list.
-           (mapcar
-            'car
-            (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))))
-    (elmo-living-messages numbers killed)))
-
-(defun elmo-folder-list-unreads (folder unread-marks)
-  "Return a list of unread message numbers contained in FOLDER.
-UNREAD-MARKS is the unread marks."
-  (let ((list (elmo-folder-list-unreads-internal folder
-                                                unread-marks)))
-    (if (listp list)
-       list
-      ;; Not available, use current mark.
-      (delq nil
-           (mapcar
-            (function
-             (lambda (x)
-               (if (member (cadr x) unread-marks)
-                   (car x))))
-            (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))))
-
-(defun elmo-folder-list-importants (folder important-mark)
-  "Returns a list of important message numbers contained in FOLDER.
-IMPORTANT-MARK is the important mark."
-  (let ((importants (elmo-folder-list-importants-internal folder important-mark))
-       (number-alist (elmo-msgdb-get-number-alist
-                      (elmo-folder-msgdb folder)))
-       num-pair result)
+If optional VISIBLE-ONLY is non-nil, killed messages are not listed.
+If second optional IN-MSGDB is non-nil, only messages in the msgdb are listed."
+  (let ((list (if in-msgdb
+                 t
+               (elmo-folder-list-messages-internal folder visible-only))))
+    (elmo-living-messages
+     (if (listp list)
+        list
+       ;; Use current list.
+       (mapcar
+       'car
+       (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder))))
+     (elmo-folder-killed-list-internal folder))))
+
+(luna-define-generic elmo-folder-list-unreads (folder)
+  "Return a list of unread message numbers contained in FOLDER.")
+(luna-define-generic elmo-folder-list-importants (folder)
+  "Return a list of important message numbers contained in FOLDER.")
+(luna-define-generic elmo-folder-list-answereds (folder)
+  "Return a list of answered message numbers contained in FOLDER.")
+
+(luna-define-method elmo-folder-list-unreads ((folder elmo-folder))
+  (delq nil
+       (mapcar
+        (lambda (x)
+          (if (member (cadr x) (elmo-msgdb-unread-marks))
+              (car x)))
+        (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))
+
+;; TODO: Should reconsider the structure of global mark.
+(defun elmo-folder-list-messages-with-global-mark (folder mark)
+  (let (entity msgs)
     (dolist (mark-pair (or elmo-msgdb-global-mark-alist
                           (setq elmo-msgdb-global-mark-alist
                                 (elmo-object-load
                                  (expand-file-name
                                   elmo-msgdb-global-mark-filename
-                                  elmo-msgdb-dir)))))
-      (if (and (string= important-mark (cdr mark-pair))
-              (setq num-pair (rassoc (car mark-pair) number-alist)))
-         (setq result (cons (car num-pair) result))))
-    (if (listp importants)
-       (elmo-uniq-list (nconc result importants))
-      result)))
+                                  elmo-msgdb-directory)))))
+      (if (and (string= mark (cdr mark-pair))
+              (setq entity
+                    (elmo-msgdb-overview-get-entity (car mark-pair)
+                                                    (elmo-folder-msgdb
+                                                     folder))))
+         (setq msgs (cons (elmo-msgdb-overview-entity-get-number entity)
+                          msgs))))
+    msgs))
+
+(luna-define-method elmo-folder-list-importants ((folder elmo-folder))
+  (elmo-uniq-list
+   (nconc
+    (elmo-folder-list-messages-with-global-mark folder
+                                               elmo-msgdb-important-mark)
+    (elmo-folder-list-messages-mark-match folder
+                                         (regexp-quote
+                                          elmo-msgdb-important-mark)))))
+
+(luna-define-method elmo-folder-list-answereds ((folder elmo-folder))
+  (delq nil
+       (mapcar
+        (function
+         (lambda (x)
+           (if (member (cadr x) (elmo-msgdb-answered-marks))
+               (car x))))
+        (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))
 
 (luna-define-generic elmo-folder-list-messages-internal (folder &optional
                                                                visible-only)
@@ -256,24 +279,10 @@ IMPORTANT-MARK is the important mark."
   ;; Return t if the message list is not available.
   )
 
-(luna-define-generic elmo-folder-list-unreads-internal (folder
-                                                       unread-marks
-                                                       &optional mark-alist)
-  ;; Return a list of unread message numbers contained in FOLDER.
-  ;; If optional MARK-ALIST is set, it is used as mark-alist.
-  ;; Return t if this feature is not available.
-  )
-
-(luna-define-generic elmo-folder-list-importants-internal (folder
-                                                          important-mark)
-  ;; Return a list of important message numbers contained in FOLDER.
-  ;; Return t if this feature is not available.
-  )
-
 (luna-define-generic elmo-folder-list-subfolders (folder &optional one-level)
   "Returns a list of subfolders contained in FOLDER.
 If optional argument ONE-LEVEL is non-nil, only children of FOLDER is returned.
-(a folder which have children is returned as a list)
+\(a folder which have children is returned as a list\)
 Otherwise, all descendent folders are returned.")
 
 (luna-define-generic elmo-folder-have-subfolder-p (folder)
@@ -311,17 +320,22 @@ NUMBERS is a list of message numbers to be deleted.")
 (luna-define-generic elmo-folder-search (folder condition &optional numbers)
   "Search and return list of message numbers.
 FOLDER is the ELMO folder structure.
-CONDITION is a condition string for searching.
+CONDITION is a condition structure for searching.
 If optional argument NUMBERS is specified and is a list of message numbers,
 messages are searched from the list.")
 
-(luna-define-generic elmo-folder-msgdb-create
-  (folder numbers new-mark already-mark seen-mark important-mark seen-list)
+(luna-define-generic elmo-message-match-condition (folder number
+                                                         condition
+                                                         numbers)
+  "Return non-nil when the message in the FOLDER with NUMBER is matched.
+CONDITION is a condition structure for testing.
+NUMBERS is a list of message numbers,
+use to be test for \"last\" and \"first\" predicates.")
+
+(luna-define-generic elmo-folder-msgdb-create (folder numbers seen-list)
   "Create a message database (implemented in each backends).
 FOLDER is the ELMO folder structure.
 NUMBERS is a list of message numbers to create msgdb.
-NEW-MARK, ALREADY-MARK, SEEN-MARK, and IMPORTANT-MARK are mark string for
-new message, unread but cached message, read message and important message.
 SEEN-LIST is a list of message-id string which should be treated as read.")
 
 (luna-define-generic elmo-folder-unmark-important (folder numbers)
@@ -344,6 +358,34 @@ NUMBERS is a list of message numbers to be processed.")
 FOLDER is the ELMO folder structure.
 NUMBERS is a list of message numbers to be processed.")
 
+(luna-define-generic elmo-folder-unmark-answered (folder numbers)
+  "Un-mark messages as answered.
+FOLDER is the ELMO folder structure.
+NUMBERS is a list of message numbers to be processed.")
+
+(luna-define-generic elmo-folder-mark-as-answered (folder numbers)
+  "Mark messages as answered.
+FOLDER is the ELMO folder structure.
+NUMBERS is a list of message numbers to be processed.")
+
+(luna-define-generic elmo-folder-set-status (folder numbers status)
+  "Set message status.
+FOLDER is the ELMO folder structure.
+NUMBERS is a list of message numbers to be set status.
+STATUS is a symbol which is one of the following:
+`read'      ... Messages which are already read.
+`important' ... Messages which are marked as important.
+`answered'  ... Messages which are marked as answered.")
+
+(luna-define-generic elmo-folder-unset-status (folder numbers status)
+  "Unset message status.
+FOLDER is the ELMO folder structure.
+NUMBERS is a list of message numbers to be unset status.
+STATUS is a symbol which is one of the following:
+`read'      ... Messages which are already read.
+`important' ... Messages which are marked as important.
+`answered'  ... Messages which are marked as answered.")
+
 (luna-define-generic elmo-folder-append-buffer (folder unread &optional number)
   "Append current buffer as a new message.
 FOLDER is the destination folder(ELMO folder structure).
@@ -354,7 +396,6 @@ If optional argument NUMBER is specified, the new message number is set
 (luna-define-generic elmo-folder-append-messages (folder
                                                  src-folder
                                                  numbers
-                                                 unread-marks
                                                  &optional
                                                  same-number)
   "Append messages from folder.
@@ -363,7 +404,6 @@ Caller should make sure FOLDER is `writable'.
 (Can be checked with `elmo-folder-writable-p').
 SRC-FOLDER is the source ELMO folder structure.
 NUMBERS is the message numbers to be appended in the SRC-FOLDER.
-UNREAD-MARKS is a list of unread mark string.
 If second optional argument SAME-NUMBER is specified,
 message number is preserved (if possible).")
 
@@ -472,6 +512,8 @@ Return newly created temporary directory name which contains temporary files.")
     (setq message-id (elmo-msgdb-overview-entity-get-id entity))
     (setq number (elmo-msgdb-overview-entity-get-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.
@@ -506,23 +548,18 @@ Return newly created temporary directory name which contains temporary files.")
   ((folder elmo-folder) &optional visible-only)
   t)
 
-(luna-define-method elmo-folder-list-unreads-internal
-  ((folder elmo-folder) unread-marks &optional mark-alist)
-  t)
-
-(luna-define-method elmo-folder-list-importants-internal
-  ((folder elmo-folder) important-mark)
-  t)
-
-(defun elmo-folder-encache (folder numbers)
-  "Encache messages in the FOLDER with NUMBERS."
+(defun elmo-folder-encache (folder numbers &optional unread)
+  "Encache messages in the FOLDER with NUMBERS.
+If UNREAD is non-nil, messages are not marked as read."
   (dolist (number numbers)
-    (elmo-message-encache folder number)))
+    (elmo-message-encache folder number unread)))
 
-(luna-define-generic elmo-message-encache (folder number)
-  "Encache message in the FOLDER with NUMBER.")
+(luna-define-generic elmo-message-encache (folder number &optional read)
+  "Encache message in the FOLDER with NUMBER.
+If READ is non-nil, message is marked as read.")
 
-(luna-define-method elmo-message-encache ((folder elmo-folder) number)
+(luna-define-method elmo-message-encache ((folder elmo-folder) number
+                                         &optional read)
   (elmo-message-fetch
    folder number
    (elmo-make-fetch-strategy 'entire
@@ -531,7 +568,7 @@ Return newly created temporary directory name which contains temporary files.")
                             (elmo-file-cache-get-path
                              (elmo-message-field
                               folder number 'message-id)))
-   nil nil 'unread))
+   nil nil (not read)))
 
 (luna-define-generic elmo-message-fetch (folder number strategy
                                                &optional
@@ -595,14 +632,35 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
 (luna-define-generic elmo-folder-append-msgdb (folder append-msgdb)
   "Append  APPEND-MSGDB to the current msgdb of the folder.")
 
+(luna-define-generic elmo-folder-newsgroups (folder)
+  "Return list of newsgroup name of FOLDER.")
+
+(luna-define-generic elmo-folder-search-requires-msgdb-p (folder condition)
+  "Return non-nil if searching in FOLDER by CONDITION requires msgdb fetch.")
+
+(defun elmo-folder-search-requires-msgdb-p-internal (folder condition)
+  (if (listp condition)
+      (or (elmo-folder-search-requires-msgdb-p-internal
+          folder (nth 1 condition))
+         (elmo-folder-search-requires-msgdb-p-internal
+          folder (nth 2 condition)))
+    (and (not (string= (elmo-filter-key condition) "last"))
+        (not (string= (elmo-filter-key condition) "first")))))
+
+(luna-define-method elmo-folder-search-requires-msgdb-p ((folder elmo-folder)
+                                                        condition)
+  (elmo-folder-search-requires-msgdb-p-internal folder condition))
+
+(luna-define-method elmo-folder-newsgroups ((folder elmo-folder))
+  nil)
+
 (luna-define-method elmo-folder-open ((folder elmo-folder)
                                      &optional load-msgdb)
   (elmo-generic-folder-open folder load-msgdb))
 
 (defun elmo-generic-folder-open (folder load-msgdb)
   (let ((inhibit-quit t))
-    (if load-msgdb
-       (elmo-folder-set-msgdb-internal folder (elmo-msgdb-load folder)))
+    (if load-msgdb (elmo-folder-msgdb folder))
     (elmo-folder-set-killed-list-internal
      folder
      (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder))))
@@ -668,11 +726,14 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
   (elmo-folder-persistent-internal folder))
 
 (luna-define-method elmo-folder-creatable-p ((folder elmo-folder))
-  t) ; default is creatable.
+  nil) ; default is not creatable.
 
 (luna-define-method elmo-folder-writable-p ((folder elmo-folder))
   nil) ; default is not writable.
 
+(luna-define-method elmo-folder-delete ((folder elmo-folder))
+  (elmo-msgdb-delete-path folder))
+
 (luna-define-method elmo-folder-rename ((folder elmo-folder) new-name)
   (let* ((new-folder (elmo-make-folder new-name)))
     (unless (eq (elmo-folder-type-internal folder)
@@ -684,6 +745,91 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
     (elmo-folder-send folder 'elmo-folder-rename-internal new-folder)
     (elmo-msgdb-rename-path folder new-folder)))
 
+(defsubst elmo-folder-search-fast (folder condition numbers)
+  (when (and numbers
+            (vectorp condition)
+            (member (elmo-filter-key condition) '("first" "last" "mark")))
+    (if (string= (elmo-filter-key condition) "mark")
+       (let ((msgdb (elmo-folder-msgdb folder)))
+         ;; msgdb should be synchronized at this point.
+         (cond
+          ((string= (elmo-filter-value condition) "unread")
+           (elmo-folder-list-unreads folder))
+          ((string= (elmo-filter-value condition) "important")
+           (elmo-folder-list-importants folder))
+          ((string= (elmo-filter-value condition) "answered")
+           (elmo-folder-list-answereds folder))
+          ((string= (elmo-filter-value condition) "any")
+           (nconc (elmo-folder-list-unreads folder)
+                  (elmo-folder-list-importants folder)
+                  (elmo-folder-list-answereds folder)))))
+      (let ((len (length numbers))
+           (lastp (string= (elmo-filter-key condition) "last"))
+           (value (string-to-number (elmo-filter-value condition))))
+       (when (eq (elmo-filter-type condition) 'unmatch)
+         (setq lastp (not lastp)
+               value  (- len value)))
+       (if lastp
+           (nthcdr (max (- len value) 0) numbers)
+         (when (> value 0)
+           (let ((last (nthcdr (1- value) numbers)))
+             (when last
+               (setcdr last nil))
+             numbers)))))))
+
+(luna-define-method elmo-folder-search ((folder elmo-folder)
+                                       condition
+                                       &optional numbers)
+  (let ((numbers (or numbers (elmo-folder-list-messages folder))))
+    (or (elmo-folder-search-fast folder condition numbers)
+       (let ((msgdb (elmo-folder-msgdb folder))
+             (len (length numbers))
+             matched)
+         (when (> len elmo-display-progress-threshold)
+           (elmo-progress-set 'elmo-folder-search len "Searching..."))
+         (unwind-protect
+             (dolist (number numbers)
+               (let ((entity (elmo-msgdb-overview-get-entity number msgdb))
+                     result)
+                 (if entity
+                     (setq result (elmo-msgdb-match-condition
+                                   condition
+                                   entity
+                                   numbers))
+                   (setq result condition))
+                 (when (elmo-filter-condition-p result)
+                   (setq result (elmo-message-match-condition
+                                 folder
+                                 number
+                                 condition
+                                 numbers)))
+                 (when result
+                   (setq matched (cons number matched))))
+               (elmo-progress-notify 'elmo-folder-search))
+           (elmo-progress-clear 'elmo-folder-search))
+         (nreverse matched)))))
+
+(luna-define-method elmo-message-match-condition ((folder elmo-folder)
+                                                 number condition
+                                                 numbers)
+  (let ((filename (cond
+                  ((elmo-message-file-name folder number))
+                  ((let* ((cache (elmo-file-cache-get
+                                  (elmo-message-field folder number
+                                                      'message-id)))
+                          (cache-path (elmo-file-cache-path cache)))
+                     (when (and cache-path
+                                (not (elmo-cache-path-section-p cache-path)))
+                       cache-path))))))
+    (when (and filename
+              (file-readable-p filename))
+      (with-temp-buffer
+       (insert-file-contents-as-binary filename)
+       (elmo-set-buffer-multibyte default-enable-multibyte-characters)
+       ;; Should consider charset?
+       (decode-mime-charset-region (point-min) (point-max) elmo-mime-charset)
+       (elmo-buffer-field-condition-match condition number numbers)))))
+
 (luna-define-method elmo-folder-pack-numbers ((folder elmo-folder))
   nil) ; default is noop.
 
@@ -766,6 +912,18 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
      info-alist)
     (setq elmo-folder-info-hashtb hashtb)))
 
+(defsubst elmo-diff-new (diff)
+  (car diff))
+
+(defsubst elmo-diff-unread (diff)
+  (when (consp (cdr diff))
+    (nth 1 diff)))
+
+(defsubst elmo-diff-all (diff)
+  (if (consp (cdr diff))
+      (nth 2 diff)
+    (cdr diff)))
+
 (defsubst elmo-strict-folder-diff (folder)
   "Return folder diff information strictly from FOLDER."
   (let* ((dir (elmo-folder-msgdb-path folder))
@@ -820,8 +978,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
                     (if (and in-folder
                              (null in-db))
                         (cdr in-folder)
-                      (if (null (car in-folder))
-                          nil))))
+                      (car in-folder))))
       (setq messages (cdr in-folder))
       (if (and unsync messages (> unsync messages))
          (setq unsync messages))
@@ -845,41 +1002,48 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
 (luna-define-method elmo-folder-append-messages ((folder elmo-folder)
                                                 src-folder
                                                 numbers
-                                                unread-marks
                                                 &optional
                                                 same-number)
   (elmo-generic-folder-append-messages folder src-folder numbers
-                                      unread-marks same-number))
+                                      same-number))
 
 (defun elmo-generic-folder-append-messages (folder src-folder numbers
-                                                  unread-marks same-number)
+                                                  same-number)
   (let (unseen seen-list succeed-numbers failure cache)
     (with-temp-buffer
+      (set-buffer-multibyte nil)
       (while numbers
        (setq failure nil)
        (condition-case nil
-           (progn
-             (elmo-message-fetch
-              src-folder (car numbers)
-              (if (and (not (elmo-folder-plugged-p src-folder))
-                       elmo-enable-disconnected-operation
-                       (setq cache (elmo-file-cache-get
-                                    (elmo-message-field
-                                     src-folder (car numbers)
-                                     'message-id)))
-                       (eq (elmo-file-cache-status cache) 'entire))
-                  (elmo-make-fetch-strategy
-                   'entire t nil (elmo-file-cache-path cache))
-                (elmo-make-fetch-strategy 'entire t))
-              nil (current-buffer)
-              'unread)
-             (unless (eq (buffer-size) 0)
-               (elmo-folder-append-buffer
-                folder
-                (setq unseen (member (elmo-message-mark
-                                      src-folder (car numbers))
-                                     unread-marks))
-                (if same-number (car numbers)))))
+           (setq cache (elmo-file-cache-get
+                        (elmo-message-field src-folder
+                                            (car numbers)
+                                            'message-id))
+                 failure
+                 (not
+                  (and
+                   (elmo-message-fetch
+                    src-folder (car numbers)
+                    (if (elmo-folder-plugged-p src-folder)
+                        (elmo-make-fetch-strategy
+                         'entire 'maybe nil
+                         (and cache (elmo-file-cache-path cache)))
+                      (or (and elmo-enable-disconnected-operation
+                               cache
+                               (eq (elmo-file-cache-status cache) 'entire)
+                               (elmo-make-fetch-strategy
+                                'entire t nil
+                                (elmo-file-cache-path cache)))
+                          (error "Unplugged")))
+                    nil (current-buffer)
+                    'unread)
+                   (> (buffer-size) 0)
+                   (elmo-folder-append-buffer
+                    folder
+                    (setq unseen (member (elmo-message-mark
+                                          src-folder (car numbers))
+                                         (elmo-msgdb-unread-marks)))
+                    (if same-number (car numbers))))))
          (error (setq failure t)))
        ;; FETCH & APPEND finished
        (unless failure
@@ -889,6 +1053,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
                                   'message-id)
                                  seen-list)))
          (setq succeed-numbers (cons (car numbers) succeed-numbers)))
+       (elmo-progress-notify 'elmo-folder-move-messages)
        (setq numbers (cdr numbers)))
       (if (and seen-list (elmo-folder-persistent-p folder))
          (elmo-msgdb-seen-save (elmo-folder-msgdb-path folder)
@@ -899,21 +1064,15 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
 
 ;; Arguments should be reduced.
 (defun elmo-folder-move-messages (src-folder msgs dst-folder
-                                            &optional msgdb all done
+                                            &optional msgdb
                                             no-delete-info
                                             no-delete
                                             same-number
-                                            unread-marks
                                             save-unread)
   (save-excursion
     (let* ((messages msgs)
           (elmo-inhibit-display-retrieval-progress t)
           (len (length msgs))
-          (all-msg-num (or all len))
-          (done-msg-num (or done 0))
-          (progress-message (if no-delete
-                                "Copying messages..."
-                              "Moving messages..."))
           succeeds i result)
       (if (eq dst-folder 'null)
          (setq succeeds messages)
@@ -926,7 +1085,6 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
          (unless (setq succeeds (elmo-folder-append-messages dst-folder
                                                              src-folder
                                                              messages
-                                                             unread-marks
                                                              same-number))
            (error "move: append message to %s failed"
                   (elmo-folder-name-internal dst-folder)))
@@ -939,13 +1097,8 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
            (setq seen-list
                  (elmo-msgdb-add-msgs-to-seen-list
                   msgs (elmo-folder-msgdb src-folder)
-                  unread-marks seen-list))
+                  seen-list))
            (elmo-msgdb-seen-save dir seen-list))))
-      (when (and done
-                (> all-msg-num elmo-display-progress-threshold))
-       (elmo-display-progress
-        'elmo-folder-move-messages progress-message
-        (/ (* done-msg-num 100) all-msg-num)))
       (if (and (not no-delete) succeeds)
          (progn
            (if (not no-delete-info)
@@ -982,7 +1135,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
   "Get mark of the message.
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message."
-  (cadr (assq number (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))
+  (elmo-msgdb-get-mark (elmo-folder-msgdb folder) number))
 
 (defun elmo-folder-list-messages-mark-match (folder mark-regexp)
   "List messages in the FOLDER which have a mark that matches MARK-REGEXP"
@@ -999,33 +1152,13 @@ NUMBER is a number of the message."
 FOLDER is the ELMO folder structure.
 NUMBER is a number of the message.
 FIELD is a symbol of the field."
-  (case field
-    (message-id (elmo-msgdb-overview-entity-get-id
-                (elmo-msgdb-overview-get-entity
-                 number (elmo-folder-msgdb folder))))
-    (subject (elmo-msgdb-overview-entity-get-subject
-             (elmo-msgdb-overview-get-entity
-              number (elmo-folder-msgdb folder))))
-    (size (elmo-msgdb-overview-entity-get-size
-          (elmo-msgdb-overview-get-entity
-           number (elmo-folder-msgdb folder))))
-    (date (elmo-msgdb-overview-entity-get-date
-          (elmo-msgdb-overview-get-entity
-           number (elmo-folder-msgdb folder))))
-    (to (elmo-msgdb-overview-entity-get-to
-        (elmo-msgdb-overview-get-entity
-         number (elmo-folder-msgdb folder))))
-    (cc (elmo-msgdb-overview-entity-get-cc
-        (elmo-msgdb-overview-get-entity
-         number (elmo-folder-msgdb folder))))))
+  (elmo-msgdb-get-field (elmo-folder-msgdb folder) number field))
 
 (defun elmo-message-set-mark (folder number mark)
-  "Set mark for the message in the FOLDER with NUMBER as MARK."
-  (elmo-msgdb-set-mark-alist
+  ;; Set mark for the message in the FOLDER with NUMBER as MARK.
+  (elmo-msgdb-set-mark
    (elmo-folder-msgdb folder)
-   (elmo-msgdb-mark-set
-    (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder))
-    number mark)))
+   number mark))
 
 (luna-define-method elmo-message-use-cache-p ((folder elmo-folder) number)
   nil) ; default is not use cache.
@@ -1033,18 +1166,55 @@ FIELD is a symbol of the field."
 (luna-define-method elmo-message-folder ((folder elmo-folder) number)
   folder) ; default is folder
 
-(luna-define-method elmo-folder-unmark-important ((folder elmo-folder) numbers)
-  t)
+(luna-define-method elmo-folder-unmark-important ((folder elmo-folder)
+                                                 numbers)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-unset-status (elmo-folder-msgdb folder)
+                              folder
+                              number
+                              'important))))
 
 (luna-define-method elmo-folder-mark-as-important ((folder elmo-folder)
                                                   numbers)
-  t)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-set-status (elmo-folder-msgdb folder)
+                            folder
+                            number
+                            'important))))
 
 (luna-define-method elmo-folder-unmark-read ((folder elmo-folder) numbers)
-  t)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-unset-status (elmo-folder-msgdb folder)
+                              folder
+                              number
+                              'read))))
 
 (luna-define-method elmo-folder-mark-as-read ((folder elmo-folder) numbers)
-  t)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-set-status (elmo-folder-msgdb folder)
+                            folder
+                            number
+                            'read))))
+
+(luna-define-method elmo-folder-unmark-answered ((folder elmo-folder) numbers)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-unset-status (elmo-folder-msgdb folder)
+                              folder
+                              number
+                              'answered))))
+
+(luna-define-method elmo-folder-mark-as-answered ((folder elmo-folder) numbers)
+  (when (elmo-folder-msgdb-internal folder)
+    (dolist (number numbers)
+      (elmo-msgdb-set-status (elmo-folder-msgdb folder)
+                            folder
+                            number
+                            'answered))))
 
 (luna-define-method elmo-folder-process-crosspost ((folder elmo-folder)
                                                   &optional
@@ -1063,6 +1233,10 @@ FIELD is a symbol of the field."
             pair overview
             to-be-deleted
             mark-alist)
+       (elmo-folder-set-msgdb-internal folder
+                                       (elmo-msgdb-append
+                                        (elmo-folder-msgdb folder)
+                                        append-msgdb))
        (while cur
          (setq all-alist (delq (car cur) all-alist))
          ;; same message id exists.
@@ -1088,10 +1262,6 @@ FIELD is a symbol of the field."
              (t
               ;; Do nothing.
               (setq to-be-deleted nil)))
-       (elmo-folder-set-msgdb-internal folder
-                                       (elmo-msgdb-append
-                                        (elmo-folder-msgdb folder)
-                                        append-msgdb t))
        (length to-be-deleted))
     0))
 
@@ -1102,9 +1272,10 @@ FIELD is a symbol of the field."
 (defun elmo-folder-confirm-appends (appends)
   (let ((len (length appends))
        in)
-    (if (and (> len elmo-folder-update-threshold)
+    (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).  Continue? " len))
+       (if (y-or-n-p (format "Too many messages(%d).  Update all? " len))
            appends
          (setq in elmo-folder-update-threshold)
          (catch 'end
@@ -1114,11 +1285,12 @@ FIELD is a symbol of the field."
                    in (string-to-int in))
              (if (< len in)
                  (throw 'end len))
-             (if (y-or-n-p (format "%d messages are disappeared.  OK? "
+             (if (y-or-n-p (format "%d messages are not appeared.  OK? "
                                    (max (- len in) 0)))
                  (throw 'end in))))
          (nthcdr (max (- len in) 0) appends))
-      (if (and (> len elmo-folder-update-threshold)
+      (if (and elmo-folder-update-threshold
+              (> len elmo-folder-update-threshold)
               (not elmo-folder-update-confirm))
          (nthcdr (max (- len elmo-folder-update-threshold) 0) appends)
        appends))))
@@ -1133,8 +1305,7 @@ FIELD is a symbol of the field."
       (with-current-buffer outbuf
        (erase-buffer)
        (elmo-message-fetch-with-cache-process folder number
-                                              strategy section unread)
-       t)
+                                              strategy section unread))
     (with-temp-buffer
       (elmo-message-fetch-with-cache-process folder number
                                             strategy section unread)
@@ -1144,24 +1315,37 @@ FIELD is a symbol of the field."
                                                           number strategy
                                                           &optional
                                                           section unread)
-  (let (cache-path cache-file)
-    (if (and (elmo-fetch-strategy-use-cache strategy)
-            (setq cache-path (elmo-fetch-strategy-cache-path strategy))
-            (setq cache-file (elmo-file-cache-expand-path
-                              cache-path
-                              section))
-            (file-exists-p cache-file)
-            (or (not (elmo-cache-path-section-p cache-file))
-                (not (eq (elmo-fetch-strategy-entireness strategy) 'entire))))
-       (insert-file-contents-as-binary cache-file)
-      (elmo-message-fetch-internal folder number strategy section unread)
-      (elmo-delete-cr-buffer)
-      (when (and (> (buffer-size) 0)
-                (elmo-fetch-strategy-save-cache strategy)
-                (elmo-fetch-strategy-cache-path strategy))
-       (elmo-file-cache-save
-        (elmo-fetch-strategy-cache-path strategy)
-        section)))))
+  (let ((cache-path (elmo-fetch-strategy-cache-path strategy))
+       (method-priorities
+        (cond ((eq (elmo-fetch-strategy-use-cache strategy) 'maybe)
+               '(entity cache))
+              ((elmo-fetch-strategy-use-cache strategy)
+               '(cache entity))
+              (t
+               '(entity))))
+       result err)
+    (while (and method-priorities
+               (null result))
+      (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))
+                (elmo-delete-cr-buffer)
+                (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))))))
 
 (luna-define-method elmo-folder-clear ((folder elmo-folder)
                                       &optional keep-killed)
@@ -1170,29 +1354,17 @@ FIELD is a symbol of the field."
   (elmo-folder-set-msgdb-internal folder (elmo-msgdb-clear)))
 
 (defun elmo-folder-synchronize (folder
-                               new-mark             ;"N"
-                               unread-uncached-mark ;"U"
-                               unread-cached-mark   ;"!"
-                               read-uncached-mark   ;"u"
-                               important-mark       ;"$"
                                &optional ignore-msgdb
                                no-check)
   "Synchronize the folder data to the newest status.
 FOLDER is the ELMO folder structure.
-NEW-MARK, UNREAD-CACHED-MARK, READ-UNCACHED-MARK, and IMPORTANT-MARK
-are mark strings for new messages, unread but cached messages,
-read but not cached messages, and important messages.
 If optional IGNORE-MSGDB is non-nil, current msgdb is thrown away except
 read mark status. If IGNORE-MSGDB is 'visible-only, only visible messages
-\(the messages which are not in the killed-list\) are thrown away and 
+\(the messages which are not in the killed-list\) are thrown away and
 synchronized.
 If NO-CHECK is non-nil, rechecking folder is skipped.
 
-Return a list of
-\(NEW-MSGDB DELETE-LIST CROSSED\)
-NEW-MSGDB is the newly appended msgdb.
-DELETE-LIST is a list of deleted message number.
-CROSSED is cross-posted message number.
+Return a list of a cross-posted message number.
 If update process is interrupted, return nil."
   (let ((killed-list (elmo-folder-killed-list-internal folder))
        (before-append t)
@@ -1208,11 +1380,9 @@ If update process is interrupted, return nil."
                      (elmo-folder-msgdb folder)))
     (if ignore-msgdb
        (progn
-         (setq seen-list (nconc
-                          (elmo-msgdb-mark-alist-to-seen-list
-                           number-alist mark-alist
-                           (concat important-mark read-uncached-mark))
-                          seen-list))
+         (setq seen-list (nconc (elmo-msgdb-seen-list
+                                 (elmo-folder-msgdb folder))
+                                seen-list))
          (elmo-folder-clear folder (eq ignore-msgdb 'visible-only))))
     (unless no-check (elmo-folder-check folder))
     (condition-case nil
@@ -1235,16 +1405,7 @@ If update process is interrupted, return nil."
                              (length new-list)))
                     (setq diff-2 (elmo-list-diff (car diff) new-list)))
            (elmo-msgdb-append-to-killed-list folder (car diff-2)))
-         ;; Don't delete important marked messages.
-         (setq delete-list
-               (if (eq (elmo-folder-type-internal folder) 'mark)
-                   (cadr diff)
-                 (elmo-delete-if
-                  (lambda (x)
-                    (and (setq mark (cadr (assq x mark-alist)))
-                         (string= mark important-mark)))
-                  ;; delete message list
-                  (cadr diff))))
+         (setq delete-list (cadr diff))
          (if (or (equal diff '(nil nil))
                  (equal diff '(nil))
                  (and (eq (length (car diff)) 0)
@@ -1252,19 +1413,16 @@ If update process is interrupted, return nil."
              (progn
                (elmo-folder-update-number folder)
                (elmo-folder-process-crosspost folder)
-               (list nil nil nil) ; no updates.
+               0 ; no updates.
                )
            (if delete-list (elmo-msgdb-delete-msgs
                             (elmo-folder-msgdb folder) delete-list))
            (when new-list
              (setq new-msgdb (elmo-folder-msgdb-create
-                              folder
-                              new-list
-                              new-mark unread-cached-mark
-                              read-uncached-mark important-mark
-                              seen-list))
+                              folder new-list seen-list))
              (elmo-msgdb-change-mark (elmo-folder-msgdb folder)
-                                     new-mark unread-uncached-mark)
+                                     elmo-msgdb-new-mark
+                                     elmo-msgdb-unread-uncached-mark)
              ;; Clear seen-list.
              (if (elmo-folder-persistent-p folder)
                  (setq seen-list (elmo-msgdb-seen-save
@@ -1277,7 +1435,7 @@ If update process is interrupted, return nil."
              (elmo-folder-set-message-modified-internal folder t)
              (elmo-folder-set-mark-modified-internal folder t))
            ;; return value.
-           (list new-msgdb delete-list crossed)))
+           (or crossed 0)))
       (quit
        ;; Resume to the original status.
        (if before-append
@@ -1291,44 +1449,18 @@ If update process is interrupted, return nil."
    (elmo-msgdb-get-number-alist
     (elmo-folder-msgdb folder))))
 
-;;;
-(defun elmo-msgdb-search (folder condition msgdb)
-  "Search messages which satisfy CONDITION from FOLDER with MSGDB."
-  (let* ((condition (car (elmo-parse-search-condition condition)))
-        (overview (elmo-msgdb-get-overview msgdb))
-        (number-alist (elmo-msgdb-get-number-alist msgdb))
-        (number-list (mapcar 'car number-alist))
-        (length (length overview))
-        (i 0)
-        result)
-    (if (not (elmo-condition-in-msgdb-p condition))
-       (elmo-folder-search folder condition number-list)
-      (while overview
-       (if (elmo-msgdb-search-internal condition (car overview)
-                                       number-list)
-           (setq result
-                 (cons
-                  (elmo-msgdb-overview-entity-get-number (car overview))
-                  result)))
-       (setq i (1+ i))
-       (elmo-display-progress
-        'elmo-msgdb-search "Searching..." (/ (* i 100) length))
-       (setq overview (cdr overview)))
-      (nreverse result))))
-
-(defun elmo-msgdb-load (folder)
-  (message "Loading msgdb for %s..." (elmo-folder-name-internal folder))
-  (let* ((path (elmo-folder-msgdb-path folder))
-        (overview (elmo-msgdb-overview-load path))
-        (msgdb (list overview
-                     (elmo-msgdb-number-load path)
-                     (elmo-msgdb-mark-load path)
-                     (elmo-msgdb-make-overview-hashtb overview))))
-    (message "Loading msgdb for %s...done" (elmo-folder-name-internal folder))
+(defun elmo-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))))
     (elmo-folder-set-info-max-by-numdb folder
                                       (elmo-msgdb-get-number-alist msgdb))
+    
+    (unless silent
+      (message "Loading msgdb for %s...done"
+              (elmo-folder-name-internal folder)))
     msgdb))
-
+  
 (defun elmo-msgdb-delete-path (folder)
   (let ((path (elmo-folder-msgdb-path folder)))
     (if (file-directory-p path)
@@ -1383,7 +1515,7 @@ Return a hashtable for newsgroups."
       (elmo-crosspost-alist-save elmo-crosspost-message-alist)
       (setq elmo-crosspost-message-alist-modified nil))))
 
-(defun elmo-folder-make-temp-dir (folder)
+(defun elmo-folder-make-temporary-directory (folder)
   ;; Make a temporary directory for FOLDER.
   (let ((temp-dir (make-temp-name
                   (concat
@@ -1442,12 +1574,16 @@ Return a hashtable for newsgroups."
                               'elmo-imap4-default-user)
 (elmo-define-obsolete-variable 'elmo-default-imap4-port
                               'elmo-imap4-default-port)
+(elmo-define-obsolete-variable 'elmo-default-imap4-stream-type
+                              'elmo-imap4-default-stream-type)
 (elmo-define-obsolete-variable 'elmo-default-nntp-server
                               'elmo-nntp-default-server)
 (elmo-define-obsolete-variable 'elmo-default-nntp-user
                               'elmo-nntp-default-user)
 (elmo-define-obsolete-variable 'elmo-default-nntp-port
                               'elmo-nntp-default-port)
+(elmo-define-obsolete-variable 'elmo-default-nntp-stream-type
+                              'elmo-nntp-default-stream-type)
 (elmo-define-obsolete-variable 'elmo-default-pop3-server
                               'elmo-pop3-default-server)
 (elmo-define-obsolete-variable 'elmo-default-pop3-user
@@ -1456,9 +1592,23 @@ Return a hashtable for newsgroups."
                               'elmo-pop3-default-authenticate-type)
 (elmo-define-obsolete-variable 'elmo-default-pop3-port
                               'elmo-pop3-default-port)
+(elmo-define-obsolete-variable 'elmo-default-pop3-stream-type
+                              'elmo-pop3-default-stream-type)
+(elmo-define-obsolete-variable 'elmo-cache-dirname
+                              'elmo-cache-directory)
+(elmo-define-obsolete-variable 'elmo-msgdb-dir
+                              'elmo-msgdb-directory)
+
+;; Obsolete functions.
+;; 2001-12-11: *-dir -> *-directory
+(defalias 'elmo-folder-make-temp-dir 'elmo-folder-make-temporary-directory)
+(make-obsolete 'elmo-folder-make-temp-dir
+              'elmo-folder-make-temporary-directory)
+
 
 ;; autoloads
 (autoload 'elmo-dop-queue-flush "elmo-dop")
+(autoload 'elmo-nntp-post "elmo-nntp")
 
 (require 'product)
 (product-provide (provide 'elmo) (require 'elmo-version))