This commit was manufactured by cvs2svn to create tag 'merged-trunk-to-wl-
[elisp/wanderlust.git] / elmo / elmo.el
index 61520d3..642834e 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>
 
 
 ;;; Commentary:
 ;;
-;; APIs which can be used before opened:
-
-;; elmo-make-folder
-;; elmo-folder-diff
-;; elmo-folder-open
 
 ;;; Code:
-;; 
+;;
 
-(require 'product)
 (require 'luna)
 
+(require 'elmo-version)                        ; reduce recursive-load-depth
 (require 'elmo-vars)
 (require 'elmo-util)
 (require 'elmo-msgdb)
@@ -55,7 +50,8 @@
   :group 'elmo)
 
 (defcustom elmo-message-fetch-confirm t
-  "Confirm fetching if message size is larger than `elmo-fetch-threshold'.
+  "If non-nil, confirm fetching if message size is larger than
+`elmo-message-fetch-threshold'.
 Otherwise, entire fetching of the message is aborted without confirmation."
   :type 'boolean
   :group 'elmo)
@@ -70,6 +66,9 @@ Otherwise, entire fetching of the message is aborted without confirmation."
   :type 'boolean
   :group 'elmo)
 
+(defvar elmo-message-displaying nil
+  "A global switch to indicate message is displaying or not.")
+
 ;;; internal
 (defvar elmo-folder-type-alist nil)
 
@@ -78,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 +108,8 @@ If a folder name begins with PREFIX, use BACKEND."
                                     persistent   ; non-nil if persistent.
                                     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,8 +148,16 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
     (save-match-data
       (elmo-folder-send folder 'elmo-folder-initialize name))))
 
-(luna-define-generic elmo-folder-open (folder)
-  "Open and setup (load saved status) FOLDER.")
+(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-open (folder &optional load-msgdb)
+  "Open and setup (load saved status) FOLDER.
+If optional LOAD-MSGDB is non-nil, msgdb is loaded.
+(otherwise, msgdb is loaded on-demand)")
 
 (luna-define-generic elmo-folder-open-internal (folder)
   "Open FOLDER (without loading saved folder status).")
@@ -154,6 +165,10 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
 (luna-define-generic elmo-folder-check (folder)
   "Check the FOLDER to obtain newest information at the next list operation.")
 
+(luna-define-generic elmo-folder-clear (folder &optional keep-killed)
+  "Clear FOLDER to the initial state.
+If optional KEEP-KILLED is non-nil, killed-list is not cleared.")
+
 (luna-define-generic elmo-folder-commit (folder)
   "Save current status of FOLDER.")
 
@@ -169,6 +184,9 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
 (luna-define-generic elmo-folder-set-plugged (folder plugged &optional add)
   "Set FOLDER as plugged.")
 
+(luna-define-generic elmo-net-port-info (folder)
+  "Get port information of FOLDER.")
+
 (luna-define-generic elmo-folder-use-flag-p (folder)
   "Returns t if FOLDER treats unread/important flag itself.")
 
@@ -176,11 +194,16 @@ If optional argument NON-PERSISTENT is non-nil, folder is treated as
   "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.")
 
+(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)
   "Return a list of message numbers contained in FOLDER.
 If optional VISIBLE-ONLY is non-nil, killed messages are not listed."
@@ -215,17 +238,22 @@ UNREAD-MARKS is the unread marks."
 (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 ((list (elmo-folder-list-importants-internal folder important-mark)))
-    (if (listp list)
-       list
-      ;; Not available, use current mark.
-      (delq nil
-           (mapcar
-            (function
-             (lambda (x)
-               (if (string= (cadr x) important-mark)
-                   (car x))))
-            (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))))
+  (let ((importants (elmo-folder-list-importants-internal folder important-mark))
+       (number-alist (elmo-msgdb-get-number-alist
+                      (elmo-folder-msgdb folder)))
+       num-pair result)
+    (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-directory)))))
+      (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)))
 
 (luna-define-generic elmo-folder-list-messages-internal (folder &optional
                                                                visible-only)
@@ -253,6 +281,9 @@ If optional argument ONE-LEVEL is non-nil, only children of FOLDER is returned.
 (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)
+  "Return non-nil when FOLDER has subfolders.")
+
 (luna-define-generic elmo-folder-exists-p (folder)
   "Returns non-nil when FOLDER exists.")
 
@@ -469,7 +500,7 @@ Return newly created temporary directory name which contains temporary files.")
       (if (not ignore-cache)
          (elmo-make-fetch-strategy
           'entire
-          ;; ...But ignore current section cache and re-fetch 
+          ;; ...But ignore current section cache and re-fetch
           ;; if section cache.
           (not (eq (elmo-file-cache-status cache-file) 'section))
           ;; Save cache.
@@ -477,7 +508,7 @@ Return newly created temporary directory name which contains temporary files.")
           (elmo-file-cache-path cache-file))))))
 
 (luna-define-method elmo-folder-list-messages-internal
-  ((folder elmo-folder))
+  ((folder elmo-folder) &optional visible-only)
   t)
 
 (luna-define-method elmo-folder-list-unreads-internal
@@ -488,7 +519,18 @@ Return newly created temporary directory name which contains temporary files.")
   ((folder elmo-folder) important-mark)
   t)
 
-(defun elmo-message-encache (folder number)
+(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 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 marked as read.")
+
+(luna-define-method elmo-message-encache ((folder elmo-folder) number
+                                         &optional read)
   (elmo-message-fetch
    folder number
    (elmo-make-fetch-strategy 'entire
@@ -496,7 +538,8 @@ Return newly created temporary directory name which contains temporary files.")
                             t   ;save-cache
                             (elmo-file-cache-get-path
                              (elmo-message-field
-                              folder number 'message-id)))))
+                              folder number 'message-id)))
+   nil nil (not read)))
 
 (luna-define-generic elmo-message-fetch (folder number strategy
                                                &optional
@@ -514,6 +557,39 @@ inserted to the buffer and returns t if fetch was ended successfully.
 If third optional argument UNREAD is non-nil, message is not marked 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.
+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 marked as read.
+Returns non-nil if fetching was succeed.")
+
+(luna-define-generic elmo-message-fetch-internal (folder number strategy
+                                                        &optional
+                                                        section
+                                                        unread)
+  "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.
+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 marked as read.
+Returns non-nil if fetching was succeed.")
+
+(luna-define-generic elmo-message-fetch-field (folder number field)
+  "Fetch a message field value.
+FOLDER is the ELMO folder structure.
+NUMBER is the number of the message in the FOLDER.
+FIELD is a symbol of the field name.")
+
 (luna-define-generic elmo-message-folder (folder number)
   "Get primitive folder of the message.")
 
@@ -527,14 +603,23 @@ 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-method elmo-folder-open ((folder elmo-folder))
-  (elmo-generic-folder-open folder))
+(luna-define-generic elmo-folder-newsgroups (folder)
+  "Return list of newsgroup name of FOLDER.")
+
+(luna-define-method elmo-folder-newsgroups ((folder elmo-folder))
+  nil)
 
-(defun elmo-generic-folder-open (folder)
-  (elmo-folder-set-msgdb-internal folder (elmo-msgdb-load folder))
-  (elmo-folder-set-killed-list-internal
-   folder
-   (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
+(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)))
+    (elmo-folder-set-killed-list-internal
+     folder
+     (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder))))
   (elmo-folder-open-internal folder))
 
 (luna-define-method elmo-folder-open-internal ((folder elmo-folder))
@@ -552,14 +637,14 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
     (when (elmo-folder-message-modified-internal folder)
       (elmo-msgdb-overview-save
        (elmo-folder-msgdb-path folder)
-       (elmo-msgdb-get-overview (elmo-folder-msgdb-internal folder)))
+       (elmo-msgdb-get-overview (elmo-folder-msgdb folder)))
       (elmo-msgdb-number-save
        (elmo-folder-msgdb-path folder)
-       (elmo-msgdb-get-number-alist (elmo-folder-msgdb-internal folder)))
+       (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))
       (elmo-folder-set-info-max-by-numdb
        folder
        (elmo-msgdb-get-number-alist
-       (elmo-folder-msgdb-internal folder)))
+       (elmo-folder-msgdb folder)))
       (elmo-folder-set-message-modified-internal folder nil)
       (elmo-msgdb-killed-list-save
        (elmo-folder-msgdb-path folder)
@@ -567,7 +652,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
     (when (elmo-folder-mark-modified-internal folder)
       (elmo-msgdb-mark-save
        (elmo-folder-msgdb-path folder)
-       (elmo-msgdb-get-mark-alist (elmo-folder-msgdb-internal folder)))
+       (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))
       (elmo-folder-set-mark-modified-internal folder nil))))
 
 (luna-define-method elmo-folder-close-internal ((folder elmo-folder))
@@ -600,7 +685,10 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
   t) ; default is creatable.
 
 (luna-define-method elmo-folder-writable-p ((folder elmo-folder))
-  t) ; default is writable.
+  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)))
@@ -635,6 +723,9 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
 (luna-define-method elmo-folder-local-p ((folder elmo-folder))
   t)   ; default is local.
 
+(luna-define-method elmo-folder-have-subfolder-p ((folder elmo-folder))
+  t)
+
 ;;; Folder info
 ;; Folder info is a message number information cache (hashtable)
 (defsubst elmo-folder-get-info (folder &optional hashtb)
@@ -692,11 +783,24 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
      info-alist)
     (setq elmo-folder-info-hashtb hashtb)))
 
+(defsubst elmo-diff-new (diff)
+  (when (consp (cdr diff))
+    (car diff)))
+
+(defsubst elmo-diff-unread (diff)
+  (if (consp (cdr diff))
+      (nth 1 diff)
+    (car 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))
-        (nalist (or (elmo-folder-msgdb-internal folder)
-                    (elmo-msgdb-number-load dir)))
+        (nalist (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))
         (in-db (sort (mapcar 'car nalist) '<))
         (in-folder  (elmo-folder-list-messages folder))
         append-list delete-list diff)
@@ -780,33 +884,50 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
 
 (defun elmo-generic-folder-append-messages (folder src-folder numbers
                                                   unread-marks same-number)
-  (let (unseen seen-list succeed-numbers failure)
+  (let (unseen seen-list succeed-numbers failure cache)
     (with-temp-buffer
       (while numbers
        (setq failure nil)
        (condition-case nil
-           (progn
-             (elmo-message-fetch src-folder (car numbers)
-                                 (elmo-make-fetch-strategy
-                                  'entire)
-                                 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))
+                                         unread-marks))
+                    (if same-number (car numbers))))))
          (error (setq failure t)))
        ;; FETCH & APPEND finished
        (unless failure
-         (if unseen (setq seen-list (cons
-                                     (elmo-message-field
-                                      src-folder (car numbers)
-                                      'message-id)
-                                     seen-list)))
+         (unless unseen
+           (setq seen-list (cons (elmo-message-field
+                                  src-folder (car numbers)
+                                  '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)
@@ -817,7 +938,7 @@ 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
@@ -825,16 +946,16 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
                                             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)
-      (unless (eq dst-folder 'null)
-       ;; src is already opened.
+      (if (eq dst-folder 'null)
+         (setq succeeds messages)
+       (unless (elmo-folder-writable-p dst-folder)
+         (error "move: %d is not writable"
+                (elmo-folder-name-internal dst-folder)))
        (when messages
+         ;; src is already opened.
          (elmo-folder-open-internal dst-folder)
          (unless (setq succeeds (elmo-folder-append-messages dst-folder
                                                              src-folder
@@ -851,20 +972,16 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
                 (seen-list (elmo-msgdb-seen-load dir)))
            (setq seen-list
                  (elmo-msgdb-add-msgs-to-seen-list
-                  msgs (elmo-folder-msgdb-internal src-folder)
+                  msgs (elmo-folder-msgdb src-folder)
                   unread-marks 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)
                (message "Cleaning up src folder..."))
            (if (and (elmo-folder-delete-messages src-folder succeeds)
-                    (elmo-msgdb-delete-msgs src-folder succeeds))
+                    (elmo-msgdb-delete-msgs
+                     (elmo-folder-msgdb src-folder) succeeds))
                (setq result t)
              (message "move: delete messages from %s failed."
                       (elmo-folder-name-internal src-folder))
@@ -890,11 +1007,6 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
        folder
        (elmo-folder-expand-msgdb-path folder))))
 
-(defun elmo-folder-msgdb (folder)
-  "Return the msgdb of FOLDER (on-demand loading)."
-  (or (elmo-folder-msgdb-internal folder)
-      (elmo-msgdb-load folder)))
-
 (defun elmo-message-mark (folder number)
   "Get mark of the message.
 FOLDER is the ELMO folder structure.
@@ -939,9 +1051,9 @@ FIELD is a symbol of the 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
-   (elmo-folder-msgdb-internal folder)
+   (elmo-folder-msgdb folder)
    (elmo-msgdb-mark-set
-    (elmo-msgdb-get-mark-alist (elmo-folder-msgdb-internal folder))
+    (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder))
     number mark)))
 
 (luna-define-method elmo-message-use-cache-p ((folder elmo-folder) number)
@@ -974,10 +1086,10 @@ FIELD is a symbol of the field."
       (let* ((number-alist (elmo-msgdb-get-number-alist append-msgdb))
             (all-alist (copy-sequence (append
                                        (elmo-msgdb-get-number-alist
-                                        (elmo-folder-msgdb-internal folder))
+                                        (elmo-folder-msgdb folder))
                                        number-alist)))
             (cur number-alist)
-            pair
+            pair overview
             to-be-deleted
             mark-alist)
        (while cur
@@ -986,16 +1098,28 @@ FIELD is a symbol of the field."
          (if (setq pair (rassoc (cdr (car cur)) all-alist))
              (setq to-be-deleted (nconc to-be-deleted (list (car pair)))))
          (setq cur (cdr cur)))
-       ;; XXXX If caching is enabled, read-uncached mark should be set.
-       (setq mark-alist (elmo-delete-if
-                         (function
-                          (lambda (x)
-                            (memq (car x) to-be-deleted)))
-                         (elmo-msgdb-get-mark-alist append-msgdb)))
-       (elmo-msgdb-set-mark-alist append-msgdb mark-alist)
+       (cond ((eq (elmo-folder-process-duplicates-internal folder)
+                  'hide)
+              ;; Hide duplicates.
+              (setq overview (elmo-delete-if
+                              (lambda (x)
+                                (memq (elmo-msgdb-overview-entity-get-number
+                                       x)
+                                      to-be-deleted))
+                              (elmo-msgdb-get-overview append-msgdb)))
+              ;; Should be mark as read.
+              (elmo-folder-mark-as-read folder to-be-deleted)
+              (elmo-msgdb-set-overview append-msgdb overview))
+             ((eq (elmo-folder-process-duplicates-internal folder)
+                  'read)
+              ;; Mark as read duplicates.
+              (elmo-folder-mark-as-read folder to-be-deleted))
+             (t
+              ;; Do nothing.
+              (setq to-be-deleted nil)))
        (elmo-folder-set-msgdb-internal folder
                                        (elmo-msgdb-append
-                                        (elmo-folder-msgdb-internal folder)
+                                        (elmo-folder-msgdb folder)
                                         append-msgdb t))
        (length to-be-deleted))
     0))
@@ -1007,9 +1131,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
@@ -1019,22 +1144,82 @@ 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))))
 
+(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)
+  (let ((cache-path (elmo-fetch-strategy-cache-path strategy))
+       (method-priorities
+        (cond ((eq (elmo-fetch-strategy-use-cache strategy) 'meybe)
+               '(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)
+  (unless keep-killed
+    (elmo-folder-set-killed-list-internal folder nil))
+  (elmo-folder-set-msgdb-internal folder (elmo-msgdb-clear)))
+
 (defun elmo-folder-synchronize (folder
-                               new-mark             ;"N"
+                               new-mark             ;"N"
                                unread-uncached-mark ;"U"
                                unread-cached-mark   ;"!"
                                read-uncached-mark   ;"u"
                                important-mark       ;"$"
-                               &optional ignore-msgdb)
+                               &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
@@ -1042,25 +1227,28 @@ 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
-are thrown away and synchronized.
+\(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."
+CROSSED is cross-posted message number.
+If update process is interrupted, return nil."
   (let ((killed-list (elmo-folder-killed-list-internal folder))
        (before-append t)
-       number-alist mark-alist 
+       number-alist mark-alist
        old-msgdb diff diff-2 delete-list new-list new-msgdb mark
        seen-list crossed after-append)
-    (setq old-msgdb (elmo-folder-msgdb-internal folder))
+    (setq old-msgdb (elmo-folder-msgdb folder))
     ;; Load seen-list.
     (setq seen-list (elmo-msgdb-seen-load (elmo-folder-msgdb-path folder)))
     (setq number-alist (elmo-msgdb-get-number-alist
-                       (elmo-folder-msgdb-internal folder)))
+                       (elmo-folder-msgdb folder)))
     (setq mark-alist (elmo-msgdb-get-mark-alist
-                     (elmo-folder-msgdb-internal folder)))
+                     (elmo-folder-msgdb folder)))
     (if ignore-msgdb
        (progn
          (setq seen-list (nconc
@@ -1068,12 +1256,8 @@ CROSSED is cross-posted message number."
                            number-alist mark-alist
                            (concat important-mark read-uncached-mark))
                           seen-list))
-         ;; Make killed list as nil.
-         (unless (eq ignore-msgdb 'visible-only)
-           (elmo-folder-set-killed-list-internal folder nil))
-         (elmo-folder-set-msgdb-internal folder
-                                         (elmo-msgdb-clear))))
-    (elmo-folder-check folder)
+         (elmo-folder-clear folder (eq ignore-msgdb 'visible-only))))
+    (unless no-check (elmo-folder-check folder))
     (condition-case nil
        (progn
          (message "Checking folder diff...")
@@ -1083,8 +1267,8 @@ CROSSED is cross-posted message number."
                                      folder
                                      (eq 'visible-only ignore-msgdb))
                                     (unless ignore-msgdb
-                                      (sort (mapcar 
-                                             'car 
+                                      (sort (mapcar
+                                             'car
                                              number-alist)
                                             '<))))
          (message "Checking folder diff...done")
@@ -1094,14 +1278,7 @@ CROSSED is cross-posted message number."
                              (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
-               (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)
@@ -1109,9 +1286,10 @@ CROSSED is cross-posted message number."
              (progn
                (elmo-folder-update-number folder)
                (elmo-folder-process-crosspost folder)
-               nil ; no update.
+               (list nil nil nil) ; no updates.
                )
-           (if delete-list (elmo-msgdb-delete-msgs folder delete-list))
+           (if delete-list (elmo-msgdb-delete-msgs
+                            (elmo-folder-msgdb folder) delete-list))
            (when new-list
              (setq new-msgdb (elmo-folder-msgdb-create
                               folder
@@ -1119,7 +1297,7 @@ CROSSED is cross-posted message number."
                               new-mark unread-cached-mark
                               read-uncached-mark important-mark
                               seen-list))
-             (elmo-msgdb-change-mark (elmo-folder-msgdb-internal folder)
+             (elmo-msgdb-change-mark (elmo-folder-msgdb folder)
                                      new-mark unread-uncached-mark)
              ;; Clear seen-list.
              (if (elmo-folder-persistent-p folder)
@@ -1131,9 +1309,9 @@ CROSSED is cross-posted message number."
              ;; Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).
              (elmo-folder-process-crosspost folder)
              (elmo-folder-set-message-modified-internal folder t)
-             (elmo-folder-set-mark-modified-internal folder t)
-             ;; return value.
-             (list new-msgdb delete-list crossed))))
+             (elmo-folder-set-mark-modified-internal folder t))
+           ;; return value.
+           (list new-msgdb delete-list crossed)))
       (quit
        ;; Resume to the original status.
        (if before-append
@@ -1145,7 +1323,7 @@ CROSSED is cross-posted message number."
   "Return number of messages in the FOLDER."
   (length
    (elmo-msgdb-get-number-alist
-    (elmo-folder-msgdb-internal folder))))
+    (elmo-folder-msgdb folder))))
 
 ;;;
 (defun elmo-msgdb-search (folder condition msgdb)
@@ -1157,7 +1335,7 @@ CROSSED is cross-posted message number."
         (length (length overview))
         (i 0)
         result)
-    (if (elmo-condition-find-key condition "body")
+    (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)
@@ -1239,7 +1417,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
@@ -1251,12 +1429,13 @@ Return a hashtable for newsgroups."
 (defun elmo-init ()
   "Initialize ELMO module."
   (elmo-crosspost-message-alist-load)
-  (elmo-resque-obsolete-variables))
+  (elmo-resque-obsolete-variables)
+  (elmo-dop-queue-load))
 
 (defun elmo-quit ()
   "Quit and cleanup ELMO."
-;  (setq elmo-newsgroups-hashtb nil)
   (elmo-crosspost-message-alist-save)
+  (elmo-dop-queue-save)
   ;; Not implemented yet.
   (let ((types elmo-folder-type-alist)
        class)
@@ -1283,11 +1462,50 @@ Return a hashtable for newsgroups."
 (elmo-define-folder ?|  'pipe)
 (elmo-define-folder ?.  'maildir)
 (elmo-define-folder ?'  'internal)
-(elmo-define-folder ?[  'nmz)
+(elmo-define-folder ?\[  'nmz)
+(elmo-define-folder ?@  'shimbun)
+
+;;; Obsolete variables.
+(elmo-define-obsolete-variable 'elmo-default-imap4-mailbox
+                              'elmo-imap4-default-mailbox)
+(elmo-define-obsolete-variable 'elmo-default-imap4-server
+                              'elmo-imap4-default-server)
+(elmo-define-obsolete-variable 'elmo-default-imap4-authenticate-type
+                              'elmo-imap4-default-authenticate-type)
+(elmo-define-obsolete-variable 'elmo-default-imap4-user
+                              'elmo-imap4-default-user)
+(elmo-define-obsolete-variable 'elmo-default-imap4-port
+                              'elmo-imap4-default-port)
+(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-pop3-server
+                              'elmo-pop3-default-server)
+(elmo-define-obsolete-variable 'elmo-default-pop3-user
+                              'elmo-pop3-default-user)
+(elmo-define-obsolete-variable 'elmo-default-pop3-authenticate-type
+                              'elmo-pop3-default-authenticate-type)
+(elmo-define-obsolete-variable 'elmo-default-pop3-port
+                              'elmo-pop3-default-port)
+(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")
 
+(require 'product)
 (product-provide (provide 'elmo) (require 'elmo-version))
 
-;; elmo.el ends here.
-(provide 'elmo)
-
 ;;; elmo.el ends here