* elmo.el (elmo-folder-search): Defined. Fixed docstring.
authorhmurata <hmurata>
Sun, 6 Jan 2002 10:46:18 +0000 (10:46 +0000)
committerhmurata <hmurata>
Sun, 6 Jan 2002 10:46:18 +0000 (10:46 +0000)
(elmo-message-match-condition): New method.
(elmo-folder-search-fast): New inline function.
(elmo-msgdb-search): Removed.

* elmo-filter.el (elmo-folder-msgdb-create): Create from msgdb of
target folder if it is unplugged.
(elmo-folder-list-messages-internal): Return t if target folder is
unplugged and itself is persistent; In this case, use list be
searched already.

* elmo-msgdb.el (elmo-msgdb-search-internal): Removed.
(elmo-msgdb-search-internal-primitive): Ditto.
(elmo-msgdb-match-condition): New function.
(elmo-msgdb-match-condition-primitive): Ditto.

* elmo-util.el (elmo-filter-condition-p): New macro.

* elmo-cache.el (elmo-folder-search): Removed.

* elmo-localdir.el (elmo-folder-search): Ditto.

* elmo-maildir.el (elmo-folder-search): Ditto.

* elmo-mark.el (elmo-folder-search): Ditto.

* elmo-nmz.el (elmo-folder-search): Ditto.

* elmo-sendlog.el (elmo-folder-search): Ditto.

* elmo-shimbun.el (elmo-folder-search): Ditto.

* elmo-imap4.el (elmo-folder-search): Call method of parent class
if folder is unplugged.

* elmo-nntp.el (elmo-folder-search): Likewise.
(elmo-nntp-search-internal): New function.

14 files changed:
elmo/ChangeLog
elmo/elmo-cache.el
elmo/elmo-filter.el
elmo/elmo-imap4.el
elmo/elmo-localdir.el
elmo/elmo-maildir.el
elmo/elmo-mark.el
elmo/elmo-msgdb.el
elmo/elmo-nmz.el
elmo/elmo-nntp.el
elmo/elmo-sendlog.el
elmo/elmo-shimbun.el
elmo/elmo-util.el
elmo/elmo.el

index 4b24448..95edb0f 100644 (file)
@@ -1,5 +1,43 @@
 2002-01-06  Hiroya Murata  <lapis-lazuli@pop06.odn.ne.jp>
 
+       * elmo.el (elmo-folder-search): Defined. Fixed docstring.
+       (elmo-message-match-condition): New method.
+       (elmo-folder-search-fast): New inline function.
+       (elmo-msgdb-search): Removed.
+
+       * elmo-filter.el (elmo-folder-msgdb-create): Create from msgdb of
+       target folder if it is unplugged.
+       (elmo-folder-list-messages-internal): Return t if target folder is
+       unplugged and itself is persistent; In this case, use list be
+       searched already.
+
+       * elmo-msgdb.el (elmo-msgdb-search-internal): Removed.
+       (elmo-msgdb-search-internal-primitive): Ditto.
+       (elmo-msgdb-match-condition): New function.
+       (elmo-msgdb-match-condition-primitive): Ditto.
+
+       * elmo-util.el (elmo-filter-condition-p): New macro.
+
+       * elmo-cache.el (elmo-folder-search): Removed.
+
+       * elmo-localdir.el (elmo-folder-search): Ditto.
+
+       * elmo-maildir.el (elmo-folder-search): Ditto.
+
+       * elmo-mark.el (elmo-folder-search): Ditto.
+
+       * elmo-nmz.el (elmo-folder-search): Ditto.
+
+       * elmo-sendlog.el (elmo-folder-search): Ditto.
+
+       * elmo-shimbun.el (elmo-folder-search): Ditto.
+
+       * elmo-imap4.el (elmo-folder-search): Call method of parent class
+       if folder is unplugged.
+
+       * elmo-nntp.el (elmo-folder-search): Likewise.
+       (elmo-nntp-search-internal): New function.
+
        * elmo-version.el (elmo-version): Up to 2.9.3.
 
 2001-12-27  Hiroya Murata  <lapis-lazuli@pop06.odn.ne.jp>
index 2824f85..b13248b 100644 (file)
 (luna-define-method elmo-folder-exists-p ((folder elmo-cache-folder))
   t)
 
-(luna-define-method elmo-folder-search ((folder elmo-cache-folder)
-                                       condition &optional from-msgs)
-  (let* ((msgs (or from-msgs (elmo-folder-list-messages folder)))
-        (number-list msgs)
-        (i 0)
-        (num (length msgs))
-        file
-        matched
-        case-fold-search)
-    (while msgs
-      (if (and (setq file (elmo-message-file-name folder (car msgs)))
-              (file-exists-p file)
-              (elmo-file-field-condition-match file
-                                               condition
-                                               (car msgs)
-                                               number-list))
-         (setq matched (nconc matched (list (car msgs)))))
-      (elmo-display-progress
-       'elmo-internal-folder-search "Searching..."
-       (/ (* (setq i (1+ i)) 100) num))
-      (setq msgs (cdr msgs)))
-    matched))
-
 (luna-define-method elmo-message-file-p ((folder elmo-cache-folder) number)
   t)
 
index abaf702..3a29327 100644 (file)
                                              numlist new-mark already-mark
                                              seen-mark important-mark
                                              seen-list)
-  (elmo-folder-msgdb-create (elmo-filter-folder-target-internal folder)
-                           numlist
-                           new-mark
-                           already-mark
-                           seen-mark important-mark seen-list))
+  (let ((target-folder (elmo-filter-folder-target-internal folder)))
+    (if (elmo-folder-plugged-p target-folder)
+       (elmo-folder-msgdb-create target-folder
+                                 numlist
+                                 new-mark
+                                 already-mark
+                                 seen-mark important-mark seen-list)
+      ;; Copy from msgdb of target folder if it is unplugged.
+      (let ((len (length numlist))
+           (msgdb (elmo-folder-msgdb target-folder))
+           overview number-alist mark-alist
+           message-id seen gmark)
+       (when (> len elmo-display-progress-threshold)
+         (elmo-progress-set 'elmo-folder-msgdb-create
+                            len "Creating msgdb..."))
+       (unwind-protect
+           (dolist (number numlist)
+             (let ((entity (elmo-msgdb-overview-get-entity number msgdb)))
+               (when entity
+                 (setq entity (elmo-msgdb-copy-overview-entity entity)
+                       overview (elmo-msgdb-append-element overview entity)
+                       message-id (elmo-msgdb-overview-entity-get-id entity)
+                       number-alist (elmo-msgdb-number-add number-alist
+                                                           number
+                                                           message-id)
+                       seen (member message-id seen-list))
+                 (if (setq gmark (or (elmo-msgdb-global-mark-get message-id)
+                                     (if (elmo-file-cache-exists-p message-id)
+                                         (if seen
+                                             nil
+                                           already-mark)
+                                       (if seen
+                                           nil ;;seen-mark
+                                         new-mark))))
+                     (setq mark-alist
+                           (elmo-msgdb-mark-append
+                            mark-alist
+                            number
+                            gmark)))))
+             (elmo-progress-notify 'elmo-folder-msgdb-create))
+         (elmo-progress-clear 'elmo-folder-msgdb-create))
+       (list overview number-alist mark-alist)))))
 
 (luna-define-method elmo-folder-append-buffer ((folder elmo-filter-folder)
                                               unread &optional number)
 
 (luna-define-method elmo-folder-list-messages-internal
   ((folder elmo-filter-folder) &optional nohide)
-  (elmo-folder-search (elmo-filter-folder-target-internal folder)
-                     (elmo-filter-folder-condition-internal folder)))
+  (let ((target (elmo-filter-folder-target-internal folder)))
+    (if (or (elmo-folder-plugged-p target)
+           (not (elmo-folder-persistent-p folder)))
+       ;; search target folder
+       (elmo-folder-search
+        target
+        (elmo-filter-folder-condition-internal folder))
+      ;; not available
+      t)))
 
 (defsubst elmo-filter-folder-list-unreads-internal (folder unread-marks
                                                           mark-alist)
index c9ae6e2..355b111 100644 (file)
@@ -2205,14 +2205,16 @@ If optional argument REMOVE is non-nil, remove FLAG."
                            folder session (nth 2 condition) from-msgs)))
            result (sort result '<))))))
 
-(luna-define-method elmo-folder-search ((folder elmo-imap4-folder)
-                                       condition &optional numbers)
-  (save-excursion
-    (let ((session (elmo-imap4-get-session folder)))
-      (elmo-imap4-session-select-mailbox
-       session
-       (elmo-imap4-folder-mailbox-internal folder))
-      (elmo-imap4-search-internal folder session condition numbers))))
+(luna-define-method elmo-folder-search :around ((folder elmo-imap4-folder)
+                                               condition &optional numbers)
+  (if (elmo-folder-plugged-p folder)
+      (save-excursion
+       (let ((session (elmo-imap4-get-session folder)))
+         (elmo-imap4-session-select-mailbox
+          session
+          (elmo-imap4-folder-mailbox-internal folder))
+         (elmo-imap4-search-internal folder session condition numbers)))
+    (luna-call-next-method)))
 
 (luna-define-method elmo-folder-msgdb-create-plugged
   ((folder elmo-imap4-folder) numbers &rest args)
index b1f9ef9..f9e5c2f 100644 (file)
                     (elmo-localdir-folder-directory-internal folder))
    condition number number-list))
 
-(luna-define-method elmo-folder-search ((folder elmo-localdir-folder)
-                                       condition &optional numbers)
-  (let* ((msgs (or numbers (elmo-folder-list-messages folder)))
-        (num (length msgs))
-        (i 0)
-        last cur number-list case-fold-search ret-val)
-    (cond
-     ;; short cut.
-     ((and (vectorp condition)
-          (not (eq (elmo-filter-type condition) 'unmatch))
-          (string= (elmo-filter-key condition) "last"))
-      (nthcdr (max (- (length msgs)
-                     (string-to-int (elmo-filter-value condition)))
-                  0)
-             msgs))
-     ((and (vectorp condition)
-          (not (eq (elmo-filter-type condition) 'unmatch))
-          (string= (elmo-filter-key condition) "first"))
-      (let ((rest (nthcdr (string-to-int (elmo-filter-value condition) )
-                         msgs)))
-       (mapcar '(lambda (x)
-                  (delete x msgs)) rest))
-      msgs)
-     (t
-      (setq number-list msgs)
-      (while msgs
-       (if (elmo-localdir-field-condition-match folder condition
-                                                (car msgs) number-list)
-           (setq ret-val (cons (car msgs) ret-val)))
-       (when (> num elmo-display-progress-threshold)
-         (setq i (1+ i))
-         (setq cur (/ (* i 100) num))
-         (unless (eq cur last)
-           (elmo-display-progress
-            'elmo-localdir-search "Searching..."
-            cur)
-           (setq last cur)))
-       (setq msgs (cdr msgs)))
-      (nreverse ret-val)))))
-
 (luna-define-method elmo-folder-pack-numbers ((folder elmo-localdir-folder))
   (let* ((dir (elmo-localdir-folder-directory-internal folder))
         (msgdb (elmo-folder-msgdb folder))
index ab3bf6a..0a91115 100644 (file)
@@ -474,27 +474,6 @@ file name for maildir directories."
          t)
       (error nil))))
 
-(luna-define-method elmo-folder-search ((folder elmo-maildir-folder)
-                                       condition &optional numbers)
-  (save-excursion
-    (let* ((msgs (or numbers (elmo-folder-list-messages folder)))
-          (i 0)
-          case-fold-search matches
-          percent num
-          (len (length msgs))
-          number-list msg-num)
-      (setq number-list msgs)
-      (dolist (number numbers)
-       (if (elmo-file-field-condition-match
-            (elmo-message-file-name folder number)
-            condition number number-list)
-           (setq matches (cons number matches)))
-       (setq i (1+ i))
-       (elmo-display-progress
-        'elmo-maildir-search "Searching..."
-        (/ (* i 100) len)))
-      (nreverse matches))))
-
 (require 'product)
 (product-provide (provide 'elmo-maildir) (require 'elmo-version))
 
index 35352db..02cdde2 100644 (file)
 (luna-define-method elmo-folder-writable-p ((folder elmo-mark-folder))
   t)
 
-(luna-define-method elmo-folder-search ((folder elmo-mark-folder)
-                                       condition &optional from-msgs)
-  (let* ((msgs (or from-msgs (elmo-folder-list-messages folder)))
-        (number-list msgs)
-        (i 0)
-        (num (length msgs))
-        file
-        matched
-        case-fold-search)
-    (while msgs
-      (if (and (setq file (elmo-message-file-name folder (car msgs)))
-              (file-exists-p file)
-              (elmo-file-field-condition-match file
-                                               condition
-                                               (car msgs)
-                                               number-list))
-         (setq matched (nconc matched (list (car msgs)))))
-      (elmo-display-progress
-       'elmo-internal-folder-search "Searching..."
-       (/ (* (setq i (1+ i)) 100) num))
-      (setq msgs (cdr msgs)))
-    matched))
-
 ;;; To override elmo-map-folder methods.
 (luna-define-method elmo-folder-list-unreads-internal
   ((folder elmo-mark-folder) unread-marks &optional mark-alist)
index a1068dc..87c63d2 100644 (file)
@@ -274,77 +274,104 @@ header separator."
    (expand-file-name elmo-msgdb-overview-filename dir)
    overview))
 
-(defun elmo-msgdb-search-internal-primitive (condition entity number-list)
-  (let ((key (elmo-filter-key condition))
-       (case-fold-search t)
-       result)
-    (cond
-     ((string= key "last")
-      (setq result (<= (length (memq
-                               (elmo-msgdb-overview-entity-get-number entity)
-                               number-list))
-                      (string-to-int (elmo-filter-value condition)))))
-     ((string= key "first")
-      (setq result (< (-
-                      (length number-list)
-                      (length (memq
-                               (elmo-msgdb-overview-entity-get-number entity)
-                               number-list)))
-                     (string-to-int (elmo-filter-value condition)))))
-     ((string= key "from")
-      (setq result (string-match
-                   (elmo-filter-value condition)
-                   (elmo-msgdb-overview-entity-get-from entity))))
-     ((string= key "subject")
-      (setq result (string-match
-                   (elmo-filter-value condition)
-                   (elmo-msgdb-overview-entity-get-subject entity))))
-     ((string= key "to")
-      (setq result (string-match
-                   (elmo-filter-value condition)
-                   (elmo-msgdb-overview-entity-get-to entity))))
-     ((string= key "cc")
-      (setq result (string-match
-                   (elmo-filter-value condition)
-                   (elmo-msgdb-overview-entity-get-cc entity))))
-     ((or (string= key "since")
-         (string= key "before"))
-      (let ((field-date (elmo-date-make-sortable-string
-                        (timezone-fix-time
-                         (elmo-msgdb-overview-entity-get-date entity)
-                         (current-time-zone) nil)))
-           (specified-date
-            (elmo-date-make-sortable-string
-             (elmo-date-get-datevec
-              (elmo-filter-value condition)))))
-       (setq result (if (string= key "since")
-                        (or (string= specified-date field-date)
-                            (string< specified-date field-date))
-                      (string< field-date specified-date)))))
-     ((member key elmo-msgdb-extra-fields)
-      (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
-       (if (stringp extval)
+(defun elmo-msgdb-match-condition-primitive (condition entity numbers)
+  (catch 'unresolved
+    (let ((key (elmo-filter-key condition))
+         (case-fold-search t)
+         result)
+      (cond
+       ((string= key "last")
+       (setq result (<= (length (memq
+                                 (elmo-msgdb-overview-entity-get-number
+                                  entity)
+                                 numbers))
+                        (string-to-int (elmo-filter-value condition)))))
+       ((string= key "first")
+       (setq result (< (-
+                        (length numbers)
+                        (length (memq
+                                 (elmo-msgdb-overview-entity-get-number
+                                  entity)
+                                 numbers)))
+                       (string-to-int (elmo-filter-value condition)))))
+       ((string= key "from")
+       (setq result (string-match
+                     (elmo-filter-value condition)
+                     (elmo-msgdb-overview-entity-get-from entity))))
+       ((string= key "subject")
+       (setq result (string-match
+                     (elmo-filter-value condition)
+                     (elmo-msgdb-overview-entity-get-subject entity))))
+       ((string= key "to")
+       (setq result (string-match
+                     (elmo-filter-value condition)
+                     (elmo-msgdb-overview-entity-get-to entity))))
+       ((string= key "cc")
+       (setq result (string-match
+                     (elmo-filter-value condition)
+                     (elmo-msgdb-overview-entity-get-cc entity))))
+       ((or (string= key "since")
+           (string= key "before"))
+       (let ((field-date (elmo-date-make-sortable-string
+                          (timezone-fix-time
+                           (elmo-msgdb-overview-entity-get-date entity)
+                           (current-time-zone) nil)))
+             (specified-date
+              (elmo-date-make-sortable-string
+               (elmo-date-get-datevec
+                (elmo-filter-value condition)))))
+         (setq result (if (string= key "since")
+                          (or (string= specified-date field-date)
+                              (string< specified-date field-date))
+                        (string< field-date specified-date)))))
+       ((member key elmo-msgdb-extra-fields)
+       (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
+         (when (stringp extval)
            (setq result (string-match
                          (elmo-filter-value condition)
-                         extval))))))
-    (if (eq (elmo-filter-type condition) 'unmatch)
-       (setq result (not result)))
-    result))
-
-(defun elmo-msgdb-search-internal (condition entity number-list)
+                         extval)))))
+       (t
+       (throw 'unresolved condition)))
+      (if (eq (elmo-filter-type condition) 'unmatch)
+         (not result)
+       result))))
+
+(defun elmo-msgdb-match-condition (condition entity numbers)
   (cond
    ((vectorp condition)
-    (elmo-msgdb-search-internal-primitive condition entity number-list))
+    (elmo-msgdb-match-condition-primitive condition entity numbers))
    ((eq (car condition) 'and)
-    (and (elmo-msgdb-search-internal
-         (nth 1 condition) entity number-list)
-        (elmo-msgdb-search-internal
-         (nth 2 condition) entity number-list)))
+    (let ((lhs (elmo-msgdb-match-condition (nth 1 condition)
+                                          entity numbers)))
+      (cond
+       ((elmo-filter-condition-p lhs)
+       (let ((rhs (elmo-msgdb-match-condition (nth 2 condition)
+                                              entity numbers)))
+         (cond ((elmo-filter-condition-p rhs)
+                (list 'and lhs rhs))
+               (rhs
+                lhs))))
+       (lhs
+       (elmo-msgdb-match-condition (nth 2 condition)
+                                   entity numbers)))))
    ((eq (car condition) 'or)
-    (or (elmo-msgdb-search-internal
-        (nth 1 condition) entity number-list)
-       (elmo-msgdb-search-internal
-        (nth 2 condition) entity number-list)))))
+    (let ((lhs (elmo-msgdb-match-condition (nth 1 condition)
+                                          entity numbers)))
+      (cond
+       ((elmo-filter-condition-p lhs)
+       (let ((rhs (elmo-msgdb-match-condition (nth 2 condition)
+                                              entity numbers)))
+         (cond ((elmo-filter-condition-p rhs)
+                (list 'or lhs rhs))
+               (rhs
+                t)
+               (t
+                lhs))))
+       (lhs
+       t)
+       (t
+       (elmo-msgdb-match-condition (nth 2 condition)
+                                   entity numbers)))))))
 
 (defun elmo-msgdb-delete-msgs (msgdb msgs)
   "Delete MSGS from MSGDB
index d603b0d..8bfd7bc 100644 (file)
@@ -254,29 +254,6 @@ If the value is a list, all elements are used as index paths for namazu."
 (luna-define-method elmo-folder-exists-p ((folder elmo-nmz-folder))
   t)
 
-(luna-define-method elmo-folder-search ((folder elmo-nmz-folder)
-                                       condition &optional from-msgs)
-  (let* ((msgs (or from-msgs (elmo-folder-list-messages folder)))
-        (orig msgs)
-        (i 0)
-        case-fold-search matches
-        percent num
-        (num (length msgs)))
-    (while msgs
-      (if (elmo-file-field-condition-match
-          (elmo-map-message-location folder (car msgs))
-          condition
-          (car msgs)
-          orig)
-         (setq matches (cons (car msgs) matches)))
-       (setq i (1+ i))
-       (setq percent (/ (* i 100) num))
-       (elmo-display-progress
-       'elmo-nmz-search "Searching..."
-       percent)
-       (setq msgs (cdr msgs)))
-    matches))
-
 ;;; To override elmo-map-folder methods.
 (luna-define-method elmo-folder-list-unreads-internal
   ((folder elmo-nmz-folder) unread-marks &optional mark-alist)
index 151ec94..1769323 100644 (file)
@@ -1174,27 +1174,37 @@ Returns a list of cons cells like (NUMBER . VALUE)"
            (elmo-list-filter from-msgs result)
          result))))))
 
-(luna-define-method elmo-folder-search ((folder elmo-nntp-folder)
-                                       condition &optional from-msgs)
+(defun elmo-nntp-search-internal (folder condition from-msgs)
   (let (result)
     (cond
      ((vectorp condition)
       (setq result (elmo-nntp-search-primitive
                    folder condition from-msgs)))
      ((eq (car condition) 'and)
-      (setq result (elmo-folder-search folder (nth 1 condition) from-msgs)
+      (setq result (elmo-nntp-search-internal folder
+                                             (nth 1 condition)
+                                             from-msgs)
            result (elmo-list-filter result
-                                    (elmo-folder-search
+                                    (elmo-nntp-search-internal
                                      folder (nth 2 condition)
                                      from-msgs))))
      ((eq (car condition) 'or)
-      (setq result (elmo-folder-search folder (nth 1 condition) from-msgs)
+      (setq result (elmo-nntp-search-internal folder
+                                             (nth 1 condition)
+                                             from-msgs)
            result (elmo-uniq-list
                    (nconc result
-                          (elmo-folder-search folder (nth 2 condition)
-                                              from-msgs)))
+                          (elmo-nntp-search-internal folder
+                                                     (nth 2 condition)
+                                                     from-msgs)))
            result (sort result '<))))))
 
+(luna-define-method elmo-folder-search :around ((folder elmo-nntp-folder)
+                                               condition &optional from-msgs)
+  (if (elmo-folder-plugged-p folder)
+      (elmo-nntp-search-internal folder condition from-msgs)
+    (luna-call-next-method)))
+
 (defun elmo-nntp-get-folders-info-prepare (folder session-keys)
   (condition-case ()
       (let ((session (elmo-nntp-get-session folder))
index 87885fb..d0362c7 100644 (file)
     (elmo-folder-set-killed-list-internal folder killed-list))
   t)
 
-(luna-define-method elmo-folder-search ((folder elmo-sendlog-folder)
-                                       condition &optional from-msgs)
-  (let* ((msgs (or from-msgs (elmo-folder-list-messages folder)))
-        (number-list msgs)
-        (i 0)
-        (num (length msgs))
-        file
-        matched
-        case-fold-search)
-    (while msgs
-      (if (and (setq file (elmo-message-file-name folder (car msgs)))
-              (file-exists-p file)
-              (elmo-file-field-condition-match file
-                                               condition
-                                               (car msgs)
-                                               number-list))
-         (setq matched (nconc matched (list (car msgs)))))
-      (elmo-display-progress
-       'elmo-internal-folder-search "Searching..."
-       (/ (* (setq i (1+ i)) 100) num))
-      (setq msgs (cdr msgs)))
-    matched))
-
 (luna-define-method elmo-message-file-p ((folder elmo-sendlog-folder) number)
   t)
 
index c11e5e6..2828509 100644 (file)
@@ -479,10 +479,6 @@ update overview when message is fetched."
                          folder))))
     t))
 
-(luna-define-method elmo-folder-search ((folder elmo-shimbun-folder)
-                                       condition &optional from-msgs)
-  nil)
-
 ;;; To override elmo-map-folder methods.
 (luna-define-method elmo-folder-list-unreads-internal
   ((folder elmo-shimbun-folder) unread-marks &optional mark-alist)
index fe62464..cbb199c 100644 (file)
@@ -793,6 +793,9 @@ Return value is a cons cell of (STRUCTURE . REST)"
        (setq l1 (cdr l1)))
       (cons diff1 (list l2)))))
 
+(defmacro elmo-filter-condition-p (filter)
+  `(or (vectorp ,filter) (consp ,filter)))
+
 (defmacro elmo-filter-type (filter)
   (` (aref (, filter) 0)))
 
index a0d8cae..932c207 100644 (file)
@@ -316,10 +316,18 @@ 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-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 new-mark already-mark seen-mark important-mark seen-list)
   "Create a message database (implemented in each backends).
@@ -701,6 +709,77 @@ 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)))
 
+(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)))))
+
+(defsubst elmo-folder-search-fast (folder condition numbers)
+  (when (and numbers
+            (vectorp condition)
+            (member (elmo-filter-key condition) '("first" "last")))
+    (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-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.
 
@@ -1326,30 +1405,6 @@ If update process is interrupted, return nil."
     (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))