(elmo-flatten): Use `append' and `listp' instead of
[elisp/wanderlust.git] / elmo / elmo.el
index 15d7438..d23975a 100644 (file)
@@ -95,8 +95,8 @@ Otherwise, entire fetching of the message is aborted without confirmation."
 (elmo-define-signal flag-changed (numbers)
   "Notify the change flag of the messages with NUMBERS.")
 
-(elmo-define-signal cache-changed (number)
-  "Notify the change cache status of the message with NUMBER.")
+(elmo-define-signal status-changed (numbers)
+  "Notify the change status of the message with NUMBERS.")
 
 (elmo-define-signal update-overview (number)
   "Notify update overview of the message with NUMBER.")
@@ -114,10 +114,12 @@ Otherwise, entire fetching of the message is aborted without confirmation."
   (autoload 'elmo-global-flag-detach "elmo-flag")
   (autoload 'elmo-global-flag-detach-messages "elmo-flag")
   (autoload 'elmo-global-flag-set "elmo-flag")
+  (autoload 'elmo-global-flag-replace-referrer "elmo-flag")
   (autoload 'elmo-get-global-flags "elmo-flag")
   (autoload 'elmo-global-flags-initialize "elmo-flag")
   (autoload 'elmo-global-mark-migrate "elmo-flag")
-  (autoload 'elmo-folder-list-global-flag-messages "elmo-flag"))
+  (autoload 'elmo-folder-list-global-flag-messages "elmo-flag")
+  (autoload 'elmo-search-register-engine "elmo-search"))
 
 (defun elmo-define-folder (prefix backend)
   "Define a folder.
@@ -149,6 +151,7 @@ If a folder name begins with PREFIX, use BACKEND."
                                     persistent   ; non-nil if persistent.
                                     process-duplicates  ; read or hide
                                     biff   ; folder for biff
+                                    mime-charset ; charset for encode & decode
                                     ))
   (luna-define-internal-accessors 'elmo-folder))
 
@@ -161,9 +164,11 @@ If a folder name begins with PREFIX, use BACKEND."
   (` (luna-send (, folder) (, message) (, folder) (,@ args))))
 
 ;;;###autoload
-(defun elmo-make-folder (name &optional non-persistent)
+(defun elmo-make-folder (name &optional non-persistent mime-charset)
   "Make an ELMO folder structure specified by NAME.
-If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
+If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved.
+If optional argument MIME-CHARSET is specified, it is used for
+encode and decode a multibyte string."
   (let ((type (elmo-folder-type name))
        prefix split class folder original)
     (setq original (elmo-string name))
@@ -182,10 +187,18 @@ If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
                                   :type type
                                   :prefix prefix
                                   :name original
-                                  :persistent (not non-persistent)))
+                                  :persistent (not non-persistent)
+                                  :mime-charset mime-charset))
     (save-match-data
       (elmo-folder-send folder 'elmo-folder-initialize name))))
 
+(defvar elmo-get-folder-function nil)
+
+(defun elmo-get-folder (name)
+  (or (and elmo-get-folder-function
+          (funcall elmo-get-folder-function name))
+      (elmo-make-folder name)))
+
 ;; Note that this function is for internal use only.
 (luna-define-generic elmo-folder-msgdb (folder)
   "Return the msgdb of FOLDER (on-demand loading).
@@ -773,14 +786,19 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
     t))
 
 (luna-define-method elmo-folder-rename ((folder elmo-folder) new-name)
-  (let* ((new-folder (elmo-make-folder new-name)))
+  (let ((new-folder (elmo-make-folder
+                    new-name
+                    nil
+                    (elmo-folder-mime-charset-internal folder))))
     (unless (eq (elmo-folder-type-internal folder)
                (elmo-folder-type-internal new-folder))
       (error "Not same folder type"))
-    (if (or (file-exists-p (elmo-folder-msgdb-path new-folder))
-           (elmo-folder-exists-p new-folder))
-       (error "Already exists folder: %s" new-name))
+    (when (or (file-exists-p (elmo-folder-msgdb-path new-folder))
+             (elmo-folder-exists-p new-folder))
+      (error "Already exists folder: %s" new-name))
     (elmo-folder-send folder 'elmo-folder-rename-internal new-folder)
+    (elmo-global-flag-replace-referrer (elmo-folder-name-internal folder)
+                                      new-name)
     (elmo-msgdb-rename-path folder new-folder)))
 
 (luna-define-method elmo-folder-delete-messages ((folder elmo-folder)
@@ -797,6 +815,14 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
     (setq results (elmo-msgdb-search msgdb condition numbers))
     (if (listp results)
        results
+      (elmo-condition-optimize condition)
+      (when (and (consp condition)
+                (eq (car condition) 'and)
+                (listp (setq results (elmo-msgdb-search msgdb
+                                                        (nth 1 condition)
+                                                        numbers))))
+       (setq numbers results
+             condition (nth 2 condition)))
       (let ((len (length numbers))
            matched)
        (elmo-with-progress-display (> len elmo-display-progress-threshold)
@@ -818,6 +844,22 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
        (message "Searching...done")
        (nreverse matched)))))
 
+(defun elmo-message-buffer-match-condition (condition number)
+  (let* ((handler (luna-make-entity 'modb-buffer-entity-handler))
+        (result (elmo-condition-match
+                 condition
+                 (lambda (condition handler entity)
+                   (elmo-msgdb-message-match-condition handler
+                                                       condition
+                                                       entity))
+                 (list
+                  handler
+                  (elmo-msgdb-make-message-entity
+                   handler
+                   :number number
+                   :buffer (current-buffer))))))
+    (and result (not (elmo-filter-condition-p result)))))
+
 (luna-define-method elmo-message-match-condition ((folder elmo-folder)
                                                  number condition
                                                  numbers)
@@ -845,7 +887,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
        (set-buffer-multibyte default-enable-multibyte-characters)
        (decode-coding-region (point-min) (point-max)
                              elmo-mime-display-as-is-coding-system)
-       (elmo-buffer-field-condition-match condition number numbers)))))
+       (elmo-message-buffer-match-condition condition number)))))
 
 (luna-define-method elmo-folder-pack-numbers ((folder elmo-folder))
   nil) ; default is noop.
@@ -1165,6 +1207,14 @@ If optional argument IF-EXISTS is nil, load on demand.
 (luna-define-method elmo-message-cached-p ((folder elmo-folder) number)
   (elmo-message-flagged-p folder number 'cached))
 
+(luna-define-generic elmo-message-killed-p (folder number)
+  "Return non-nil if the message is killed.")
+
+(luna-define-method elmo-message-killed-p ((folder elmo-folder) number)
+  (let ((killed-list (elmo-folder-killed-list-internal folder)))
+    (and killed-list
+        (elmo-number-set-member number killed-list))))
+
 (defun elmo-message-accessible-p (folder number)
   "Get accessibility of the message.
 Return non-nil when message is accessible."
@@ -1184,7 +1234,7 @@ If CACHED is t, message is set as cached.")
   (if cached
       (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number 'cached)
     (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number 'cached))
-  (elmo-emit-signal 'cache-changed folder number))
+  (elmo-emit-signal 'status-changed folder (list number)))
 
 (defun elmo-message-copy-entity (entity)
   (elmo-msgdb-copy-message-entity (elmo-message-entity-handler entity)
@@ -1398,13 +1448,15 @@ If Optional LOCAL is non-nil, don't update server flag."
        (length duplicates))
     0))
 
-(defun elmo-folder-confirm-appends (appends)
+(defun elmo-folder-confirm-appends (folder appends)
   (let ((len (length appends))
        in)
     (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).  Update all? " len))
+       (if (y-or-n-p (format
+                      "Too many messages(%d) in %s.  Update all? "
+                      len (elmo-folder-name-internal folder)))
            appends
          (setq in elmo-folder-update-threshold)
          (catch 'end
@@ -1496,6 +1548,23 @@ If Optional LOCAL is non-nil, don't update server flag."
     numbers))
   (elmo-folder-unset-flag folder numbers 'all 'local-only))
 
+(luna-define-generic elmo-folder-recover-messages (folder numbers)
+  "Recover killed messages in the FOLDER with NUMBERS.")
+
+(luna-define-method elmo-folder-recover-messages ((folder elmo-folder) numbers)
+  (let ((msgdb (elmo-folder-msgdb folder)))
+    (elmo-folder-set-killed-list-internal
+     folder
+     (elmo-number-set-delete-list
+      (elmo-folder-killed-list-internal folder)
+      numbers))
+    (dolist (number numbers)
+      (if (elmo-file-cache-exists-p
+          (elmo-message-field folder number 'message-id))
+         (elmo-msgdb-set-flag msgdb number 'cached)
+       (elmo-msgdb-unset-flag msgdb number 'cached)))
+    (elmo-emit-signal 'status-changed folder numbers)))
+
 (luna-define-method elmo-folder-clear ((folder elmo-folder)
                                       &optional keep-killed)
   (unless keep-killed
@@ -1554,7 +1623,7 @@ If update process is interrupted, return nil.")
            (when (and mask (not ignore-msgdb))
              (setq diff-new (elmo-list-filter mask diff-new))))
          (message "Checking folder diff...done")
-         (setq new-list (elmo-folder-confirm-appends diff-new))
+         (setq new-list (elmo-folder-confirm-appends folder diff-new))
          ;; Append to killed list as (MIN-OF-DISAPPEARED . MAX-OF-DISAPPEARED)
          (when (not (eq (length diff-new)
                         (length new-list)))
@@ -1618,7 +1687,8 @@ If update process is interrupted, return nil.")
 (defun elmo-folder-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))))
+  (let ((msgdb (elmo-load-msgdb (elmo-folder-msgdb-path folder)
+                               (elmo-folder-mime-charset-internal folder))))
     (elmo-folder-set-info-max-by-numdb
      folder
      (elmo-msgdb-list-messages msgdb))
@@ -1690,6 +1760,42 @@ Return a hashtable for newsgroups."
     (elmo-make-directory temp-dir)
     temp-dir))
 
+;; ELMO status structure.
+(defmacro elmo-message-status (folder number &optional flags killed)
+  "Make ELMO status structure from FOLDER and NUMBER.
+A value in this structure is cached at first access."
+  `(vector ,folder ,number ,flags ,killed))
+
+(defmacro elmo-message-status-folder (status)
+  `(aref ,status 0))
+
+(defmacro elmo-message-status-number (status)
+  `(aref ,status 1))
+
+(defmacro elmo-message-status-set-flags (status flags)
+  `(aset ,status 2 (or ,flags '(read))))
+
+(defsubst elmo-message-status-flags (status)
+  (or (aref status 2)
+      (elmo-message-status-set-flags
+       status
+       (elmo-message-flags (elmo-message-status-folder status)
+                          (elmo-message-status-number status)))))
+
+(defsubst elmo-message-status-cached-p (status)
+  (memq 'cached (elmo-message-status-flags status)))
+
+(defmacro elmo-message-status-set-killed (status killed)
+  `(aset ,status 3 (if ,killed 'killed 'living)))
+
+(defsubst elmo-message-status-killed-p (status)
+  (eq 'killed
+      (or (aref status 3)
+         (elmo-message-status-set-killed
+          status
+          (elmo-message-killed-p (elmo-message-status-folder status)
+                                 (elmo-message-status-number status))))))
+
 ;;;
 (defun elmo-init ()
   "Initialize ELMO module."
@@ -1733,7 +1839,7 @@ Return a hashtable for newsgroups."
 (elmo-define-folder ?|  'pipe)
 (elmo-define-folder ?.  'maildir)
 (elmo-define-folder ?'  'internal)
-(elmo-define-folder ?\[  'nmz)
+(elmo-define-folder ?\[  'search)
 (elmo-define-folder ?@  'shimbun)
 
 ;;; Obsolete variables.
@@ -1773,6 +1879,13 @@ Return a hashtable for newsgroups."
                               'elmo-msgdb-directory)
 (elmo-define-obsolete-variable 'elmo-global-flag-list
                               'elmo-global-flags)
+(elmo-define-obsolete-variable 'elmo-nmz-default-index-path
+                              'elmo-search-namazu-default-index-path)
+(elmo-define-obsolete-variable 'elmo-nmz-index-alias-alist
+                              'elmo-search-namazu-index-alias-alist)
+(elmo-define-obsolete-variable 'elmo-nmz-use-drive-letter
+                              'elmo-search-use-drive-letter)
+
 
 ;; Obsolete functions.
 ;; 2001-12-11: *-dir -> *-directory