* wl.el (wl-init): Setup faces accoding to wl-summary-flag-alist.
[elisp/wanderlust.git] / elmo / elmo.el
index c76fdd5..c31befe 100644 (file)
@@ -83,11 +83,13 @@ Otherwise, entire fetching of the message is aborted without confirmation."
 (eval-and-compile
   (autoload 'elmo-dop-queue-flush "elmo-dop")
   (autoload 'elmo-nntp-post "elmo-nntp")
-  (autoload 'elmo-global-flag-initialize "elmo-flag")
   (autoload 'elmo-global-flag-p "elmo-flag")
   (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-set "elmo-flag")
+  (autoload 'elmo-get-global-flags "elmo-flag")
+  (autoload 'elmo-global-mark-migrate "elmo-flag")
+  (autoload 'elmo-folder-list-global-flag-messages "elmo-flag"))
 
 (defun elmo-define-folder (prefix backend)
   "Define a folder.
@@ -102,8 +104,10 @@ If a folder name begins with PREFIX, use BACKEND."
 
 (defmacro elmo-folder-type (name)
   "Get folder type from NAME string."
-  (` (and (stringp (, name))
-         (cdr (assoc (string-to-char (, name)) elmo-folder-type-alist)))))
+  `(and (stringp ,name)
+       (or (cdr (assoc (string-to-char ,name) elmo-folder-type-alist))
+           (when (string-match "\\([^:]*\\):" ,name)
+             (intern (match-string 1 ,name))))))
 
 ;;; ELMO folder
 ;; A elmo folder provides uniformed (orchestrated) access
@@ -236,12 +240,11 @@ If second optional IN-MSGDB is non-nil, only messages in the msgdb are listed.")
           #'delq)
        list))))
 
-(luna-define-generic elmo-folder-list-unreads (folder)
-  "Return a list of unread message numbers contained in FOLDER.")
-(luna-define-generic elmo-folder-list-importants (folder)
-  "Return a list of important message numbers contained in FOLDER.")
-(luna-define-generic elmo-folder-list-answereds (folder)
-  "Return a list of answered message numbers contained in FOLDER.")
+(luna-define-generic elmo-folder-list-messages-internal (folder &optional
+                                                               visible-only)
+  ;; Return a list of message numbers contained in FOLDER.
+  ;; Return t if the message list is not available.
+  )
 
 (luna-define-generic elmo-folder-list-flagged (folder flag &optional in-msgdb)
   "List messages in the FOLDER with FLAG.
@@ -252,30 +255,30 @@ FLAG is a symbol which is one of the following:
   `important'  (marked as important)
 'sugar' flags:
   `read'       (not unread)
-  `digest'     (unread + important)
-  `any'        (digest + answered)
-
+  `digest'     (unread + important + other flags)
+  `any'        (digest + answered + other flags)
 If optional IN-MSGDB is non-nil, retrieve flag information from msgdb.")
 
 (luna-define-method elmo-folder-list-flagged ((folder elmo-folder) flag
                                              &optional in-msgdb)
-  ;; Currently, only in-msgdb is implemented.
-  (elmo-msgdb-list-flagged (elmo-folder-msgdb folder) flag))
-
-(luna-define-method elmo-folder-list-unreads ((folder elmo-folder))
-  (elmo-folder-list-flagged folder 'unread))
-
-(luna-define-method elmo-folder-list-importants ((folder elmo-folder))
-  (elmo-folder-list-flagged folder 'important))
-
-(luna-define-method elmo-folder-list-answereds ((folder elmo-folder))
-  (elmo-folder-list-flagged folder 'answered))
-
-(luna-define-generic elmo-folder-list-messages-internal (folder &optional
-                                                               visible-only)
-  ;; Return a list of message numbers contained in FOLDER.
-  ;; Return t if the message list is not available.
-  )
+  (let ((msgs (if in-msgdb
+                 t
+               (elmo-folder-list-flagged-internal folder flag))))
+    (unless (listp msgs)
+      (setq msgs (elmo-msgdb-list-flagged (elmo-folder-msgdb folder) flag)))
+    (if in-msgdb
+       msgs
+      (elmo-uniq-list
+       (nconc (elmo-folder-list-global-flag-messages folder flag) msgs)
+       #'delq))))
+
+(luna-define-generic elmo-folder-list-flagged-internal (folder flag)
+  "Return a list of message in the FOLDER with FLAG.
+Return t if the message list is not available.")
+
+(luna-define-method elmo-folder-list-flagged-internal ((folder elmo-folder)
+                                                      flag)
+  t)
 
 (luna-define-generic elmo-folder-list-subfolders (folder &optional one-level)
   "Returns a list of subfolders contained in FOLDER.
@@ -338,47 +341,33 @@ FOLDER is the ELMO folder structure.
 NUMBERS is a list of message numbers to create msgdb.
 FLAG-TABLE is a hashtable of message-id and flag.")
 
-(luna-define-generic elmo-folder-unflag-important (folder
-                                                  numbers
-                                                  &optional is-local)
-  "Un-flag messages as important.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.
-If IS-LOCAL is non-nil, only the local flag is updated.")
-
-(luna-define-generic elmo-folder-flag-as-important (folder
-                                                   numbers
-                                                   &optional is-local)
-  "Flag messages as important.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.
-If IS-LOCAL is non-nil, only the local flag is updated.")
-
-(luna-define-generic elmo-folder-unflag-read (folder numbers
-                                                    &optional is-local)
-  "Un-flag messages as read.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.
-If IS-LOCAL is non-nil, only the local flag is updated.")
+(luna-define-generic elmo-folder-set-flag (folder numbers flag
+                                                 &optional is-local)
+  "Set messages flag.
+FOLDER is a ELMO folder structure.
+NUMBERS is a list of message number to set flag.
 
-(luna-define-generic elmo-folder-flag-as-read (folder numbers
-                                                     &optional is-local)
-  "Flag messages as read.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.
-If IS-LOCAL is non-nil, only the local flag is updated.")
+FLAG is a symbol which is one of the following:
+  `unread'    (set the message as unread)
+  `answered'  (set the message as answered)
+  `important' (set the message as important)
+'sugar' flag:
+  `read'      (remove new and unread flags)
+If optional IS-LOCAL is non-nil, update only local (not server) status.")
 
-(luna-define-generic elmo-folder-unflag-answered (folder numbers
-                                                        &optional is-local)
-  "Un-flag messages as answered.
-FOLDER is the ELMO folder structure.
-If IS-LOCAL is non-nil, only the local flag is updated.")
+(luna-define-generic elmo-folder-unset-flag (folder numbers flag
+                                                   &optional is-local)
+  "Unset messages flag.
+FOLDER is a ELMO folder structure.
+NUMBERS is a list of message number to unset flag.
 
-(luna-define-generic elmo-folder-flag-as-answered (folder numbers
-                                                         &optional is-local)
-  "Flag messages as answered.
-FOLDER is the ELMO folder structure.
-If IS-LOCAL is non-nil, only the local flag is updated.")
+FLAG is a symbol which is one of the following:
+  `unread'    (remove unread and new flag)
+  `answered'  (remove answered flag)
+  `important' (remove important flag)
+'sugar' flag:
+  `read'      (set unread flag)
+If optional IS-LOCAL is non-nil, update only local (not server) status.")
 
 (luna-define-generic elmo-folder-next-message-number (folder)
   "The next message number that will be assigned to a new message.
@@ -850,7 +839,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
   "Set FOLDER info by MSGDB-NUMBER in msgdb."
   (elmo-folder-set-info-hashtb
    folder
-   (or (car (sort numbers '>)) 0)
+   (if numbers (apply #'max numbers) 0)
    nil ;;(length num-db)
    ))
 
@@ -929,9 +918,8 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
          (let ((number-list (elmo-folder-list-messages folder
                                                        nil 'in-msgdb)))
            ;; No info-cache.
-           (setq in-db (sort number-list '<))
-           (setq in-db-max (or (nth (max 0 (1- (length in-db))) in-db)
-                               0))
+           (setq in-db number-list)
+           (setq in-db-max (if in-db (apply #'max in-db) 0))
            (elmo-folder-set-info-hashtb folder in-db-max nil))
        (setq in-db-max cached-in-db-max))
       (setq unsync (if (and in-db (car in-folder))
@@ -1163,15 +1151,7 @@ FLAG is a symbol which is one of the following:
   `read'      (remove new and unread flags)
 If optional IS-LOCAL is non-nil, update only local (not server) status."
   ;; XXX Transitional implementation.
-  (case flag
-    (unread
-     (elmo-folder-unflag-read folder (list number) is-local))
-    (read
-     (elmo-folder-flag-as-read folder (list number) is-local))
-    (answered
-     (elmo-folder-flag-as-answered folder (list number) is-local))
-    (important
-     (elmo-folder-flag-as-important folder (list number) is-local))))
+  (elmo-folder-set-flag folder (list number) flag is-local))
 
 (defun elmo-message-unset-flag (folder number flag &optional is-local)
   "Unset message flag.
@@ -1186,15 +1166,7 @@ FLAG is a symbol which is one of the following:
   `read'      (set unread flag)
 If optional IS-LOCAL is non-nil, update only local (not server) status."
   ;; XXX Transitional implementation.
-  (case flag
-    (unread
-     (elmo-folder-flag-as-read folder (list number) is-local))
-    (read
-     (elmo-folder-unflag-read folder (list number) is-local))
-    (answered
-     (elmo-folder-unflag-answered folder (list number) is-local))
-    (important
-     (elmo-folder-unflag-important folder (list number) is-local))))
+  (elmo-folder-unset-flag folder (list number) flag is-local))
 
 (luna-define-generic elmo-message-field (folder number field)
   "Get message field value in the msgdb.
@@ -1211,70 +1183,56 @@ FIELD is a symbol of the field.")
 (luna-define-method elmo-message-folder ((folder elmo-folder) number)
   folder) ; default is folder
 
-(luna-define-method elmo-folder-unflag-important ((folder elmo-folder)
-                                                 numbers
-                                                 &optional is-local)
-  (when (elmo-folder-msgdb-internal folder)
-    (dolist (number numbers)
-      (when (elmo-global-flag-p 'important)
-       (elmo-global-flag-detach 'important folder number 'always))
-      (elmo-msgdb-unset-flag (elmo-folder-msgdb folder)
-                            number
-                            'important))))
-
-(luna-define-method elmo-folder-flag-as-important ((folder elmo-folder)
-                                                  numbers
-                                                  &optional is-local)
-  (let (path message-id)
-    (when (elmo-folder-msgdb-internal folder)
-      (dolist (number numbers)
-       ;; important message should always be a read message.
-       (if (eq (elmo-file-cache-exists-p
-                (setq message-id
-                      (elmo-message-field folder number 'message-id)))
-               'entire)
-           (elmo-folder-flag-as-read folder (list number)))
-       (when (elmo-global-flag-p 'important)
-         (elmo-global-flag-set 'important folder number message-id))
-       (elmo-msgdb-set-flag (elmo-folder-msgdb folder)
-                            number
-                            'important)))))
-
-(luna-define-method elmo-folder-unflag-read ((folder elmo-folder)
-                                            numbers
-                                            &optional is-local)
-  (when (elmo-folder-msgdb-internal folder)
-    (dolist (number numbers)
-      (elmo-msgdb-unset-flag (elmo-folder-msgdb folder)
-                            number
-                            'read))))
-
-(luna-define-method elmo-folder-flag-as-read ((folder elmo-folder)
-                                             numbers
-                                             &optional is-local)
+(luna-define-method elmo-folder-set-flag ((folder elmo-folder)
+                                         numbers
+                                         flag
+                                         &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
+      (when (elmo-global-flag-p flag)
+       (let ((message-id (elmo-message-field folder number 'message-id)))
+         (elmo-global-flag-set flag folder number message-id)))
       (elmo-msgdb-set-flag (elmo-folder-msgdb folder)
                           number
-                          'read))))
-
-(luna-define-method elmo-folder-unflag-answered ((folder elmo-folder)
-                                                numbers
-                                                &optional is-local)
+                          flag))))
+
+(defun elmo-message-has-global-flag-p (folder number)
+  "Return non-nil when the message in the FOLDER with NUMBER has global flag."
+  (let ((flags (elmo-message-flags folder number))
+       result)
+    (while flags
+      (when (and (elmo-global-flag-p (car flags))
+                (not (memq (car flags) '(answered unread cached))))
+       (setq result t
+             flags nil))
+      (setq flags (cdr flags)))
+    result))
+
+(defun elmo-message-set-global-flags (folder number flags &optional local)
+  "Set global flags of the message in the FOLDER with NUMBER as FLAGS.
+If Optional LOCAL is non-nil, don't update server flag."
+  (dolist (flag flags)
+    (unless (elmo-global-flag-p flag)
+      (error "Not a global flag")))
+  (let ((old-flags (elmo-get-global-flags (elmo-message-flags folder number))))
+    (dolist (flag flags)
+      (unless (memq flag old-flags)
+       (elmo-message-set-flag folder number flag local)))
+    (dolist (flag old-flags)
+      (unless (memq flag flags)
+       (elmo-message-unset-flag folder number flag local)))))
+
+(luna-define-method elmo-folder-unset-flag ((folder elmo-folder)
+                                           numbers
+                                           flag
+                                           &optional is-local)
   (when (elmo-folder-msgdb-internal folder)
     (dolist (number numbers)
+      (when (elmo-global-flag-p flag)
+       (elmo-global-flag-detach flag folder number 'always))
       (elmo-msgdb-unset-flag (elmo-folder-msgdb folder)
                             number
-                            'answered))))
-
-(luna-define-method elmo-folder-flag-as-answered ((folder elmo-folder)
-                                                 numbers
-                                                 &optional is-local)
-  (when (elmo-folder-msgdb-internal folder)
-    (dolist (number numbers)
-      (elmo-msgdb-set-flag (elmo-folder-msgdb folder)
-                          number
-                          'answered))))
+                            flag))))
 
 (luna-define-method elmo-folder-process-crosspost ((folder elmo-folder))
   ;; Do nothing.
@@ -1302,11 +1260,11 @@ FIELD is a symbol of the field.")
               ;; Let duplicates be a temporary killed message.
               (elmo-folder-kill-messages folder duplicates)
               ;; Should be flag as read.
-              (elmo-folder-flag-as-read folder duplicates))
+              (elmo-folder-set-flag folder duplicates 'read))
              ((eq (elmo-folder-process-duplicates-internal folder)
                   'read)
               ;; Flag as read duplicates.
-              (elmo-folder-flag-as-read folder duplicates))
+              (elmo-folder-set-flag folder duplicates 'read))
              (t
               ;; Do nothing.
               (setq duplicates nil)))
@@ -1596,8 +1554,8 @@ Return a hashtable for newsgroups."
   "Initialize ELMO module."
   (elmo-crosspost-message-alist-load)
   (elmo-resque-obsolete-variables)
-  (elmo-global-flag-initialize)
-  (elmo-dop-queue-load))
+  (elmo-dop-queue-load)
+  (run-hooks 'elmo-init-hook))
 
 (defun elmo-quit ()
   "Quit and cleanup ELMO."