* test-dist.el (test-elmo-modules-trailing-whitespace)
[elisp/wanderlust.git] / elmo / modb.el
index d8e564f..6574e63 100644 (file)
 (eval-when-compile (require 'cl))
 
 (require 'luna)
+(require 'modb-entity)
 
 (eval-and-compile
-  (luna-define-class modb-generic () (location         ; location for save.
+  (luna-define-class modb-generic () (location        ; location for save.
                                      message-modified ; message is modified.
                                      flag-modified    ; flag is modified.
+                                     mime-charset     ; for encode & decode.
                                      ))
   (luna-define-internal-accessors 'modb-generic))
 
@@ -66,6 +68,9 @@ Return a list of messages which have duplicated message-id.")
 (luna-define-generic elmo-msgdb-length (msgdb)
   "Return number of messages in the MSGDB")
 
+(luna-define-generic elmo-msgdb-flag-available-p (msgdb flag)
+  "Return non-nil when FLAG is available.")
+
 (luna-define-generic elmo-msgdb-flags (msgdb number)
   "Return a list of flag which corresponds to the message with NUMBER.")
 
@@ -74,22 +79,33 @@ Return a list of messages which have duplicated message-id.")
 MSGDB is the ELMO msgdb.
 NUMBER is a message number to set flag.
 FLAG is a symbol which is one of the following:
-`new'       ... Message which is new.
-`read'      ... Message which is already read.
-`important' ... Message which is important.
-`answered'  ... Message which is answered.
-`cached'    ... Message which is cached.")
+  `new'       ... Message which is new.
+  `unread'    ... Message which is not read.
+  `important' ... Message which is important.
+  `answered'  ... Message which is answered.
+  `cached'    ... Message which is cached.
+'sugar' flag:
+  `read'      ... Message which is already read.
+  `uncached'  ... Message which is not cached.")
 
 (luna-define-generic elmo-msgdb-unset-flag (msgdb number flag)
   "Unset message flag.
 MSGDB is the ELMO msgdb.
 NUMBER is a message number to set flag.
 FLAG is a symbol which is one of the following:
-`new'       ... Message which is new.
-`read'      ... Message which is already read.
-`important' ... Message which is important.
-`answered'  ... Message which is answered.
-`cached'    ... Message which is cached.")
+  `new'       ... Message which is new.
+  `unread'    ... Message which is not read.
+  `important' ... Message which is important.
+  `answered'  ... Message which is answered.
+  `cached'    ... Message which is cached.
+'sugar' flag:
+  `read'      ... Message which is already read.
+  `uncached'  ... Message which is not cached.
+  `all'       ... Remove all flags.")
+
+(luna-define-generic elmo-msgdb-flag-count (msgdb)
+  "Return a list of cons cell as (flag . count).
+The count is number of message which is set flag in the MSGDB.")
 
 (luna-define-generic elmo-msgdb-list-messages (msgdb)
   "Return a list of message numbers in the MSGDB.")
@@ -97,19 +113,35 @@ FLAG is a symbol which is one of the following:
 (luna-define-generic elmo-msgdb-list-flagged (msgdb flag)
   "Return a list of message numbers which is set FLAG in the MSGDB.")
 
-;;; (luna-define-generic elmo-msgdb-search (msgdb condition &optional numbers)
-;;;   "Search and return list of message numbers.
-;;; MSGDB is the ELMO msgdb structure.
-;;; 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-msgdb-search (msgdb condition &optional numbers)
+  "Search and return list of message numbers.
+MSGDB is the ELMO msgdb structure.
+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.
+Return t if the condition is unsupported.")
+
+(luna-define-generic elmo-msgdb-match-condition (msgdb condition number
+                                                      &optional numbers)
+  "Check whether the condition of the message is satisfied or not.
+MSGDB is the msgdb to search from.
+CONDITION is the search condition.
+NUMBER is the message number to check.
+If optional argument NUMBERS is specified and is a list of message numbers,
+messages are searched from the list.
+Return CONDITION itself if no entity exists in msgdb.")
 
 (luna-define-generic elmo-msgdb-append-entity (msgdb entity &optional flags)
   "Append a ENTITY with FLAGS into the MSGDB.
 Return non-nil if message-id of entity is duplicated.")
 
+(luna-define-generic elmo-msgdb-update-entity (msgdb entity values)
+  "Update a ENTITY with VALUES into the MSGDB.
+VALUES is an alist of field-name and field-value.")
+
 (luna-define-generic elmo-msgdb-delete-messages (msgdb numbers)
-  "Delete messages which are contained NUMBERS from MSGDB.")
+  "Delete messages which are contained NUMBERS from MSGDB.
+Return non-nil if messages is deleted successfully.")
 
 (luna-define-generic elmo-msgdb-sort-entities (msgdb predicate
                                                     &optional app-data)
@@ -117,80 +149,34 @@ Return non-nil if message-id of entity is duplicated.")
 PREDICATE is called with two entities and APP-DATA.
 Should return non-nil if the first entity is \"less\" than the second.")
 
+(luna-define-generic elmo-msgdb-message-number (msgdb message-id)
+  "Get message number from MSGDB which corresponds to MESSAGE-ID.")
+
+(luna-define-method elmo-msgdb-message-number ((msgdb modb-generic)
+                                              message-id)
+  (elmo-message-entity-number
+   (elmo-msgdb-message-entity msgdb message-id)))
+
 (luna-define-generic elmo-msgdb-message-entity (msgdb key)
   "Return the message-entity structure which matches to the KEY.
 KEY is a number or a string.
 A number is for message number in the MSGDB.
 A string is for message-id of the message.")
 
-;; Message entity handling.
-(defvar modb-cache-internal nil)
-(defun elmo-message-entity-db (entity)
-  "Get modb instance which corresponds to the ENTITY."
-  (if (or (null (car entity))
-         (stringp (car entity)))
-      ;; Transitional implementation for modb-legacy.
-      (or modb-cache-internal
-         (progn
-           (require 'modb-legacy)
-           (setq modb-cache-internal (luna-make-entity 'modb-legacy))))
-    ;; XXX Next generation entity structure...not decided yet.
-    (car entity)))
-
-(luna-define-generic elmo-msgdb-make-message-entity (msgdb
-                                                    &rest args)
-  "Make a message entity for MSGDB.")
-
-(luna-define-generic elmo-msgdb-message-entity-number (msgdb entity)
-  "Number of the ENTITY.")
-
-(luna-define-generic elmo-msgdb-message-entity-set-number (msgdb entity number)
-  "Set number of the ENTITY.")
-
-(luna-define-generic elmo-msgdb-message-entity-field (msgdb
-                                                     entity field
-                                                     &optional decode)
-  "Retrieve field value of the message entity.
-MSGDB is the msgdb structure.
-ENTITY is the message entity structure.
+(luna-define-generic elmo-msgdb-message-field (msgdb number field
+                                                    &optional type)
+  "Get message field value in the MSGDB.
+NUMBER is a number of the message.
 FIELD is a symbol of the field.
-If optional DECODE is no-nil, the field value is decoded.")
+If optional argument TYPE is specified, return converted value.")
 
-(luna-define-generic elmo-msgdb-message-entity-set-field (msgdb
-                                                         entity field value)
-  "Set the field value of the message entity.
-MSGDB is the msgdb structure.
-ENTITY is the message entity structure.
-FIELD is a symbol of the field.
-VALUE is the field value to set.")
-
-(luna-define-generic elmo-msgdb-copy-message-entity (msgdb entity)
-  "Copy message entity.
-MSGDB is the msgdb structure.
-ENTITY is the message entity structure.")
-
-(luna-define-generic elmo-msgdb-create-message-entity-from-file (msgdb number
-                                                                      file)
-  "Create message entity from file.
-MSGDB is the msgdb structure.
-NUMBER is the number of the newly created message entity.
-FILE is the message file.")
-
-(luna-define-generic elmo-msgdb-create-message-entity-from-buffer (msgdb
-                                                                  number
-                                                                  &rest args)
-  "Create message entity from current buffer.
-NUMBER is the number of the newly created message entity.
-Rest of the ARGS is a plist of message entity field for initial value.
-Header region is supposed to be narrowed.")
-
-;; Transitional interface.
-(luna-define-generic elmo-msgdb-match-condition-internal (msgdb
-                                                         condition
-                                                         entity
-                                                         flags
-                                                         numbers)
-  "Return non-nil when the entity matches the condition.")
+(luna-define-method elmo-msgdb-message-field ((msgdb modb-generic)
+                                             number field &optional type)
+  (elmo-message-entity-field (elmo-msgdb-message-entity msgdb number)
+                            field type))
+
+(luna-define-generic elmo-msgdb-message-entity-handler (msgdb)
+  "Get modb entity handler instance which corresponds to the MSGDB.")
 
 ;;; generic implement
 ;;
@@ -223,46 +209,65 @@ Header region is supposed to be narrowed.")
 (luna-define-method elmo-msgdb-length ((msgdb modb-generic))
   0)
 
-;; Generic method.
-(luna-define-method elmo-msgdb-create-message-entity-from-file
-  ((msgdb modb-generic) number file)
-  (let (insert-file-contents-pre-hook   ; To avoid autoconv-xmas...
-       insert-file-contents-post-hook header-end
-       (attrib (file-attributes file))
-       ret-val size mtime)
-    (with-temp-buffer
-      (if (not (file-exists-p file))
-         ()
-       (setq size (nth 7 attrib))
-       (setq mtime (timezone-make-date-arpa-standard
-                    (current-time-string (nth 5 attrib)) (current-time-zone)))
-       ;; insert header from file.
-       (catch 'done
-         (condition-case nil
-             (elmo-msgdb-insert-file-header file)
-           (error (throw 'done nil)))
-         (goto-char (point-min))
-         (setq header-end
-               (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
-                   (point)
-                 (point-max)))
-         (narrow-to-region (point-min) header-end)
-         (elmo-msgdb-create-message-entity-from-buffer
-          msgdb number :size size :date mtime))))))
-
-;; Dummy message-entity methods.
-(luna-define-method elmo-msgdb-make-message-entity ((msgdb modb-generic)
-                                                   args)
-  (cons msgdb args))
-
-(luna-define-method elmo-msgdb-message-entity-field ((msgdb modb-generic)
-                                                    entity field
-                                                    &optional decode)
-  (plist-get (cdr entity) (intern (concat ":" (symbol-name field)))))
-
-(luna-define-method elmo-msgdb-message-entity-number ((msgdb modb-generic)
-                                                     entity)
-  (plist-get (cdr entity) :number))
+(luna-define-method elmo-msgdb-search ((msgdb modb-generic)
+                                      condition &optional numbers)
+  t)
+
+(luna-define-method elmo-msgdb-match-condition ((msgdb modb-generic)
+                                               condition
+                                               number
+                                               &optional numbers)
+  (let ((entity (elmo-msgdb-message-entity msgdb number)))
+    (if entity
+       (elmo-condition-match
+        condition
+        #'elmo-msgdb-match-condition-primitive
+        (list msgdb number entity
+              (or numbers (elmo-msgdb-list-messages msgdb))))
+      condition)))
+
+(defun elmo-msgdb-match-condition-primitive (condition msgdb number entity
+                                                      population)
+  (let ((key (elmo-filter-key condition))
+       (case-fold-search t))
+    (cond
+     ((string= key "last")
+      (<= (length (memq number population))
+         (string-to-number (elmo-filter-value condition))))
+     ((string= key "first")
+      (< (- (length population)
+           (length (memq number population)))
+        (string-to-number (elmo-filter-value condition))))
+     ((string= key "flag")
+      (let ((flags (elmo-msgdb-flags msgdb number)))
+       (cond ((string= (elmo-filter-value condition) "any")
+              (and flags (not (equal flags '(cached)))))
+             ((string= (elmo-filter-value condition) "digest")
+              (catch 'found
+                (dolist (flag flags)
+                  (when (or (memq flag elmo-digest-flags)
+                            (elmo-global-flag-p flag))
+                    (throw 'found t)))))
+             ((string= (elmo-filter-value condition) "read")
+              (not (memq 'read flags)))
+             (t
+              (memq (intern (elmo-filter-value condition)) flags)))))
+     (t
+      (elmo-msgdb-message-match-condition (elmo-message-entity-handler entity)
+                                         condition entity)))))
+
+(luna-define-method elmo-msgdb-update-entity ((msgdb modb-generic)
+                                             entity values)
+  (when (elmo-msgdb-message-entity-update-fields
+        (elmo-message-entity-handler entity)
+        entity values)
+    (modb-generic-set-message-modified-internal msgdb t)
+    t))
+
+(luna-define-method elmo-msgdb-message-entity-handler ((msgdb modb-generic))
+  (or modb-entity-default-cache-internal
+      (setq modb-entity-default-cache-internal
+           (luna-make-entity modb-entity-default-handler))))
 
 ;; for on demand loading
 (provide 'modb-generic)