Fix typo (falgs => flags).
[elisp/wanderlust.git] / elmo / elmo-imap4.el
index 2eba4d6..e1b7e39 100644 (file)
@@ -52,8 +52,7 @@
 (eval-when-compile (require 'cl))
 
 (defvar elmo-imap4-disuse-server-flag-mailbox-regexp "^#mh" ; UW imapd
-  "Regexp to match IMAP4 mailbox names whose message flags on server should be ignored.
-(Except `\\Deleted' flag).")
+  "Regexp to match IMAP4 mailbox names whose message flags on server should be ignored (For STATUS command).")
 
 (defvar elmo-imap4-overview-fetch-chop-length 200
   "*Number of overviews to fetch in one request.")
@@ -82,7 +81,7 @@
 
 (defvar elmo-imap4-use-select-to-update-status nil
   "*Some imapd have to send select command to update status.
-(ex. UW imapd 4.5-BETA?).  For these imapd, you must set this variable t.")
+\(ex. UW imapd 4.5-BETA?\).  For these imapd, you must set this variable t.")
 
 (defvar elmo-imap4-use-modified-utf7 nil
   "*Use mofidied UTF-7 (rfc2060) encoding for IMAP4 folder name.")
@@ -92,7 +91,7 @@
 
 (defvar elmo-imap4-extra-namespace-alist
   '(("^\\({.*/nntp}\\).*$" . ".")) ; Default is for UW's remote nntp mailbox...
-  "Extra namespace alist. 
+  "Extra namespace alist.
 A list of cons cell like: (REGEXP . DELIMITER).
 REGEXP should have a grouping for namespace prefix.")
 ;;
@@ -165,6 +164,11 @@ REGEXP should have a grouping for namespace prefix.")
 (defconst elmo-imap4-literal-threshold 1024
  "Limitation of characters that can be used in a quoted string.")
 
+(defconst elmo-imap4-flag-specs '((important "\\Flagged")
+                                 (read "\\Seen")
+                                 (unread "\\Seen" 'remove)
+                                 (answered "\\Answered")))
+
 ;; For debugging.
 (defvar elmo-imap4-debug nil
   "Non-nil forces IMAP4 folder as debug mode.
@@ -181,7 +185,7 @@ Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
 ;;; Session
 (eval-and-compile
   (luna-define-class elmo-imap4-session (elmo-network-session)
-                    (capability current-mailbox read-only))
+                    (capability current-mailbox read-only flags))
   (luna-define-internal-accessors 'elmo-imap4-session))
 
 ;;; MIME-ELMO-IMAP Location
@@ -291,8 +295,11 @@ Returns a TAG string which is assigned to the COMMAND."
       (when (elmo-imap4-response-bye-p elmo-imap4-current-response)
        (elmo-imap4-process-bye session))
       (setq elmo-imap4-current-response nil)
-      (if elmo-imap4-parsing
-         (error "IMAP process is running. Please wait (or plug again)"))
+      (when elmo-imap4-parsing
+       (message "Waiting for IMAP response...")
+       (accept-process-output (elmo-network-session-process-internal
+                               session))
+       (message "Waiting for IMAP response...done"))
       (setq elmo-imap4-parsing t)
       (elmo-imap4-debug "<-(%s)- %s" tag command)
       (while (setq token (car command-args))
@@ -354,7 +361,7 @@ TAG is the tag of the command"
                    (elmo-imap4-response-bye-p elmo-imap4-current-response)
                    (when (elmo-imap4-response-garbage-p
                           elmo-imap4-current-response)
-                     (message "Garbage response: %s" 
+                     (message "Garbage response: %s"
                               (elmo-imap4-response-value
                                elmo-imap4-current-response
                                'garbage))
@@ -450,7 +457,7 @@ If response is not `OK' response, causes error with IMAP response text."
 
 (luna-define-method mime-imap-location-bodystructure
   ((location mime-elmo-imap-location))
-  (elmo-imap4-fetch-bodystructure
+  (elmo-message-fetch-bodystructure
    (mime-elmo-imap-location-folder-internal location)
    (mime-elmo-imap-location-number-internal location)
    (mime-elmo-imap-location-strategy-internal location)))
@@ -474,7 +481,7 @@ If response is not `OK' response, causes error with IMAP response text."
   (with-current-buffer (elmo-network-session-buffer session)
     (setq elmo-imap4-fetch-callback nil)
     (setq elmo-imap4-fetch-callback-data nil))
-  (elmo-imap4-send-command-wait session "check"))
+  (elmo-imap4-send-command session "check"))
 
 (defun elmo-imap4-atom-p (string)
   "Return t if STRING is an atom defined in rfc2060."
@@ -607,12 +614,13 @@ BUFFER must be a single-byte buffer."
        (mapcar
         (lambda (entry)
           (if (and (eq 'list (car entry))
-                   (not (member "\\NoSelect" (nth 1 (nth 1 entry)))))
+                   (not (elmo-string-member-ignore-case "\\Noselect" (nth 1 (nth 1 entry)))))
               (car (nth 1 entry))))
         response)))
 
-(defun elmo-imap4-fetch-bodystructure (folder number strategy)
-  "Fetch BODYSTRUCTURE for the message in the FOLDER with NUMBER using STRATEGY."
+(luna-define-method elmo-message-fetch-bodystructure ((folder
+                                                      elmo-imap4-folder)
+                                                     number strategy)
   (if (elmo-fetch-strategy-use-cache strategy)
       (elmo-object-load
        (elmo-file-cache-expand-path
@@ -690,15 +698,19 @@ Returns response value if selecting folder succeed. "
              (elmo-imap4-session-set-current-mailbox-internal session mailbox)
              (elmo-imap4-session-set-read-only-internal
               session
-              (nth 1 (assq 'read-only (assq 'ok response)))))
+              (nth 1 (assq 'read-only (assq 'ok response))))
+             (elmo-imap4-session-set-flags-internal
+              session
+              (nth 1 (or (assq 'permanentflags response)
+                         (assq 'flags response)))))
          (elmo-imap4-session-set-current-mailbox-internal session nil)
          (if (and (eq no-error 'notify-bye)
                   (elmo-imap4-response-bye-p response))
              (elmo-imap4-process-bye session)
            (unless no-error
-             (error (or
-                     (elmo-imap4-response-error-text response)
-                     (format "Select %s failed" mailbox)))))))
+             (error "%s"
+                    (or (elmo-imap4-response-error-text response)
+                        (format "Select %s failed" mailbox)))))))
       (and result response))))
 
 (defun elmo-imap4-check-validity (spec validity-file)
@@ -727,6 +739,61 @@ Returns response value if selecting folder succeed. "
                "search %s") flag))
      'search)))
 
+(defun elmo-imap4-session-flag-available-p (session flag)
+  (case flag
+    ((read unread) (elmo-string-member-ignore-case
+                   "\\seen" (elmo-imap4-session-flags-internal session)))
+    (important
+     (elmo-string-member-ignore-case
+      "\\flagged" (elmo-imap4-session-flags-internal session)))
+    (digest
+     (or (elmo-string-member-ignore-case
+         "\\seen" (elmo-imap4-session-flags-internal session))
+        (elmo-string-member-ignore-case
+         "\\flagged" (elmo-imap4-session-flags-internal session))))
+    (answered
+     (elmo-string-member-ignore-case
+      (concat "\\" (symbol-name flag))
+      (elmo-imap4-session-flags-internal session)))
+    (t
+     (member "\\*" (elmo-imap4-session-flags-internal session)))))
+
+(defun elmo-imap4-folder-list-flagged (folder flag)
+  "List flagged message numbers in the FOLDER.
+FLAG is one of the `unread', `read', `important', `answered', `any'."
+  (let ((session (elmo-imap4-get-session folder))
+       (criteria (case flag
+                   (read "seen")
+                   (unread "unseen")
+                   (important "flagged")
+                   (answered "answered")
+                   (new "new")
+                   (any "or answered or unseen flagged")
+                   (digest "or unseen flagged")
+                   (t (concat "keyword " (capitalize (symbol-name flag)))))))
+    ;; Add search keywords
+    (when (or (eq flag 'digest)(eq flag 'any))
+      (let ((flags (delq 'important (elmo-get-global-flags t t))))
+       (while flags
+         (setq criteria (concat "or keyword "
+                                (symbol-name (car flags))
+                                " "
+                                criteria))
+         (setq flags (cdr flags)))))
+    (if (elmo-imap4-session-flag-available-p session flag)
+       (progn
+         (elmo-imap4-session-select-mailbox
+          session
+          (elmo-imap4-folder-mailbox-internal folder))
+         (elmo-imap4-response-value
+          (elmo-imap4-send-command-wait
+           session
+           (format (if elmo-imap4-use-uid "uid search %s"
+                     "search %s") criteria))
+          'search))
+      ;; List flagged messages in the msgdb.
+      (elmo-msgdb-list-flagged (elmo-folder-msgdb folder) flag))))
+
 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
 (defvar elmo-imap4-rfc822-text "RFC822\.TEXT")
 (defvar elmo-imap4-rfc822-header "RFC822\.HEADER")
@@ -770,63 +837,56 @@ If CHOP-LENGTH is not specified, message set is not chopped."
 
 ;;
 ;; app-data:
-;; cons of list
-;; 0: new-mark 1: already-mark 2: seen-mark 3: important-mark
-;; 4: seen-list
-;; and result of use-flag-p.
+;; cons of flag-table and folder structure
 (defsubst elmo-imap4-fetch-callback-1-subr (entity flags app-data)
   "A msgdb entity callback function."
-  (let* ((use-flag (cdr app-data))
-        (app-data (car app-data))
-        (seen (member (car entity) (nth 4 app-data)))
-        mark)
-    (if (member "\\Flagged" flags)
-       (elmo-msgdb-global-mark-set (car entity) (nth 3 app-data)))
-    (if (setq mark (elmo-msgdb-global-mark-get (car entity)))
-       (unless (member "\\Seen" flags)
-         (setq elmo-imap4-seen-messages
-               (cons
-                (elmo-msgdb-overview-entity-get-number entity)
-                elmo-imap4-seen-messages)))
-      (setq mark (or (if (elmo-file-cache-status
-                         (elmo-file-cache-get (car entity)))
-                        (if (or seen
-                                (and use-flag
-                                     (member "\\Seen" flags)))
-                            nil
-                          (nth 1 app-data))
-                      (if (or seen
-                              (and use-flag
-                                   (member "\\Seen" flags)))
-                          (if elmo-imap4-use-cache
-                              (nth 2 app-data))
-                        (nth 0 app-data))))))
-    (setq elmo-imap4-current-msgdb
-         (elmo-msgdb-append
-          elmo-imap4-current-msgdb
-          (list (list entity)
-                (list (cons (elmo-msgdb-overview-entity-get-number entity)
-                            (car entity)))
-                (if mark
-                    (list
-                     (list (elmo-msgdb-overview-entity-get-number entity)
-                           mark))))))))
+  (let ((use-flag (elmo-folder-use-flag-p (cdr app-data)))
+       (flag-table (car app-data))
+       (msg-id (elmo-message-entity-field entity 'message-id))
+       saved-flags flag-list)
+;;    (when (elmo-string-member-ignore-case "\\Flagged" flags)
+;;      (elmo-msgdb-global-mark-set msg-id elmo-msgdb-important-mark))
+    (setq saved-flags (elmo-flag-table-get flag-table msg-id)
+         flag-list
+         (if use-flag
+             (append
+              (and (memq 'new saved-flags)
+                   (not (elmo-string-member-ignore-case "\\Seen" flags))
+                   '(new))
+              (and (elmo-string-member-ignore-case "\\Flagged" flags)
+                   '(important))
+              (and (not (elmo-string-member-ignore-case "\\Seen" flags))
+                   '(unread))
+              (and (elmo-string-member-ignore-case "\\Answered" flags)
+                   '(answered))
+              (and (elmo-file-cache-exists-p msg-id)
+                   '(cached)))
+           saved-flags))
+    (when (and (or (memq 'important flag-list)
+                  (memq 'answered flag-list))
+              (memq 'unread flag-list))
+      (setq elmo-imap4-seen-messages
+           (cons (elmo-message-entity-number entity)
+                 elmo-imap4-seen-messages)))
+    (elmo-msgdb-append-entity elmo-imap4-current-msgdb
+                             entity
+                             flag-list)))
 
 ;; Current buffer is process buffer.
 (defun elmo-imap4-fetch-callback-1 (element app-data)
-  (elmo-imap4-fetch-callback-1-subr
-   (with-temp-buffer
-     (insert (or (elmo-imap4-response-bodydetail-text element)
-                ""))
-     ;; Delete CR.
-     (goto-char (point-min))
-     (while (search-forward "\r\n" nil t)
-       (replace-match "\n"))
-     (elmo-msgdb-create-overview-from-buffer
-      (elmo-imap4-response-value element 'uid)
-      (elmo-imap4-response-value element 'rfc822size)))
-   (elmo-imap4-response-value element 'flags)
-   app-data))
+  (let ((handler (elmo-msgdb-message-entity-handler elmo-imap4-current-msgdb)))
+    (elmo-imap4-fetch-callback-1-subr
+     (with-temp-buffer
+       (insert (or (elmo-imap4-response-bodydetail-text element)
+                  ""))
+       ;; Replace all CRLF with LF.
+       (elmo-delete-cr-buffer)
+       (elmo-msgdb-create-message-entity-from-buffer
+       handler
+       (elmo-imap4-response-value element 'uid)
+       :size (elmo-imap4-response-value element 'rfc822size)))
+     (elmo-imap4-response-value element 'flags)
+     app-data)))
 
 (defun elmo-imap4-parse-capability (string)
   (if (string-match "^\\*\\(.*\\)$" string)
@@ -1804,15 +1864,16 @@ Return nil if no complete line has arrived."
         (setq mailbox "inbox"))
      (if (eq (string-to-char mailbox) ?/)
         (setq mailbox (substring mailbox 1 (length mailbox))))
-     (expand-file-name
-      mailbox
+     ;; don't use expand-file-name (e.g. %~/something)
+     (concat
       (expand-file-name
        (or (elmo-net-folder-user-internal folder) "nobody")
        (expand-file-name (or (elmo-net-folder-server-internal folder)
                             "nowhere")
                         (expand-file-name
                          "imap"
-                         elmo-msgdb-directory)))))))
+                         elmo-msgdb-directory)))
+      "/" mailbox))))
 
 (luna-define-method elmo-folder-status-plugged ((folder
                                                 elmo-imap4-folder))
@@ -1844,22 +1905,22 @@ Return nil if no complete line has arrived."
 
 (luna-define-method elmo-folder-list-messages-plugged ((folder
                                                        elmo-imap4-folder)
-                                                      &optional nohide)
+                                                      &optional
+                                                      enable-killed)
   (elmo-imap4-list folder
-                  (let ((max (elmo-msgdb-max-of-killed
-                              (elmo-folder-killed-list-internal folder))))
-                    (if (or nohide
-                            (null (eq max 0)))
-                        (format "uid %d:*" (1+ max))
+                  (let ((killed
+                         (elmo-folder-killed-list-internal
+                          folder)))
+                    (if (and killed
+                             (eq (length killed) 1)
+                             (consp (car killed))
+                             (eq (car (car killed)) 1))
+                        (format "uid %d:*" (cdr (car killed)))
                       "all"))))
 
-(luna-define-method elmo-folder-list-unreads-plugged
-  ((folder elmo-imap4-folder))
-  (elmo-imap4-list folder "unseen"))
-
-(luna-define-method elmo-folder-list-importants-plugged
-  ((folder elmo-imap4-folder))
-  (elmo-imap4-list folder "flagged"))
+(luna-define-method elmo-folder-list-flagged-plugged
+  ((folder elmo-imap4-folder) flag)
+  (elmo-imap4-folder-list-flagged folder flag))
 
 (luna-define-method elmo-folder-use-flag-p ((folder elmo-imap4-folder))
   (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
@@ -1889,6 +1950,14 @@ Return nil if no complete line has arrived."
                  (elmo-imap4-send-command-wait
                   session
                   (list "list " (elmo-imap4-mailbox root) " *"))))
+    ;; The response of Courier-imap doesn't contain a specified folder itself.
+    (unless (member root result)
+      (setq result
+           (append result
+                   (elmo-imap4-response-get-selectable-mailbox-list
+                    (elmo-imap4-send-command-wait
+                     session
+                     (list "list \"\" " (elmo-imap4-mailbox root)))))))
     (when (or (not (string= (elmo-net-folder-user-internal folder)
                            elmo-imap4-default-user))
              (not (eq (elmo-net-folder-auth-internal folder)
@@ -1973,18 +2042,25 @@ Return nil if no complete line has arrived."
 (luna-define-method elmo-folder-writable-p ((folder elmo-imap4-folder))
   t)
 
-(luna-define-method elmo-folder-delete :before ((folder elmo-imap4-folder))
-  (let ((session (elmo-imap4-get-session folder))
-       msgs)
-    (when (elmo-imap4-folder-mailbox-internal folder)
-      (when (setq msgs (elmo-folder-list-messages folder))
-       (elmo-folder-delete-messages folder msgs))
-      (elmo-imap4-send-command-wait session "close")
-      (elmo-imap4-send-command-wait
-       session
-       (list "delete "
-            (elmo-imap4-mailbox
-             (elmo-imap4-folder-mailbox-internal folder)))))))
+(luna-define-method elmo-folder-delete ((folder elmo-imap4-folder))
+  (let ((msgs (and (elmo-folder-exists-p folder)
+                  (elmo-folder-list-messages folder))))
+    (when (yes-or-no-p (format "%sDelete msgdb and substance of \"%s\"? "
+                              (if (> (length msgs) 0)
+                                  (format "%d msg(s) exists. " (length msgs))
+                                "")
+                              (elmo-folder-name-internal folder)))
+      (let ((session (elmo-imap4-get-session folder)))
+       (when (elmo-imap4-folder-mailbox-internal folder)
+         (when msgs (elmo-folder-delete-messages folder msgs))
+         (elmo-imap4-send-command-wait session "close")
+         (elmo-imap4-send-command-wait
+          session
+          (list "delete "
+                (elmo-imap4-mailbox
+                 (elmo-imap4-folder-mailbox-internal folder))))))
+      (elmo-msgdb-delete-path folder)
+      t)))
 
 (luna-define-method elmo-folder-rename-internal ((folder elmo-imap4-folder)
                                                 new-folder)
@@ -2040,32 +2116,41 @@ If optional argument REMOVE is non-nil, remove FLAG."
     (elmo-imap4-session-select-mailbox session
                                       (elmo-imap4-folder-mailbox-internal
                                        folder))
-    (setq set-list (elmo-imap4-make-number-set-list
-                   numbers
-                   elmo-imap4-number-set-chop-length))
-    (while set-list
-      (with-current-buffer (elmo-network-session-buffer session)
-       (setq elmo-imap4-fetch-callback nil)
-       (setq elmo-imap4-fetch-callback-data nil))
-      (unless (elmo-imap4-response-ok-p
-              (elmo-imap4-send-command-wait
-               session
-               (format
-                (if elmo-imap4-use-uid
-                    "uid store %s %sflags.silent (%s)"
-                  "store %s %sflags.silent (%s)")
-                (cdr (car set-list))
-                (if remove "-" "+")
-                flag)))
-       (setq response 'fail))
-      (setq set-list (cdr set-list)))
-    (not (eq response 'fail))))
+    (when (or (elmo-string-member-ignore-case
+              flag
+              (elmo-imap4-session-flags-internal session))
+             (member "\\*" (elmo-imap4-session-flags-internal session))
+             (string= flag "\\Deleted")) ; XXX Humm..
+      (setq set-list (elmo-imap4-make-number-set-list
+                     numbers
+                     elmo-imap4-number-set-chop-length))
+      (while set-list
+       (with-current-buffer (elmo-network-session-buffer session)
+         (setq elmo-imap4-fetch-callback nil)
+         (setq elmo-imap4-fetch-callback-data nil))
+       (unless (elmo-imap4-response-ok-p
+                (elmo-imap4-send-command-wait
+                 session
+                 (format
+                  (if elmo-imap4-use-uid
+                      "uid store %s %sflags.silent (%s)"
+                    "store %s %sflags.silent (%s)")
+                  (cdr (car set-list))
+                  (if remove "-" "+")
+                  flag)))
+         (setq response 'fail))
+       (setq set-list (cdr set-list)))
+      (not (eq response 'fail)))))
 
 (luna-define-method elmo-folder-delete-messages-plugged
   ((folder elmo-imap4-folder) numbers)
   (let ((session (elmo-imap4-get-session folder)))
-    (elmo-imap4-set-flag folder numbers "\\Deleted")
-    (elmo-imap4-send-command-wait session "expunge")))
+    (elmo-imap4-session-select-mailbox
+     session
+     (elmo-imap4-folder-mailbox-internal folder))
+    (unless (elmo-imap4-set-flag folder numbers "\\Deleted")
+      (error "Failed to set deleted flag"))
+    (elmo-imap4-send-command session "expunge")))
 
 (defmacro elmo-imap4-detect-search-charset (string)
   (` (with-temp-buffer
@@ -2075,7 +2160,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
 (defun elmo-imap4-search-internal-primitive (folder session filter from-msgs)
   (let ((search-key (elmo-filter-key filter))
        (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to"
-                           "larger" "smaller"))
+                           "larger" "smaller" "flag"))
        (total 0)
        (length (length from-msgs))
        charset set-list end results)
@@ -2093,6 +2178,9 @@ If optional argument REMOVE is non-nil, remove FLAG."
                           numbers)))
        (mapcar '(lambda (x) (delete x numbers)) rest)
        numbers))
+     ((string= "flag" search-key)
+      (elmo-imap4-folder-list-flagged
+       folder (intern (elmo-filter-value filter))))
      ((or (string= "since" search-key)
          (string= "before" search-key))
       (setq search-key (concat "sent" search-key)
@@ -2220,7 +2308,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
     (luna-call-next-method)))
 
 (luna-define-method elmo-folder-msgdb-create-plugged
-  ((folder elmo-imap4-folder) numbers &rest args)
+  ((folder elmo-imap4-folder) numbers flag-table)
   (when numbers
     (let ((session (elmo-imap4-get-session folder))
          (headers
@@ -2230,6 +2318,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
            elmo-msgdb-extra-fields))
          (total 0)
          (length (length numbers))
+         print-length print-depth
          rfc2060 set-list)
       (setq rfc2060 (memq 'imap4rev1
                          (elmo-imap4-session-capability-internal
@@ -2242,12 +2331,10 @@ If optional argument REMOVE is non-nil, remove FLAG."
                      elmo-imap4-overview-fetch-chop-length))
       ;; Setup callback.
       (with-current-buffer (elmo-network-session-buffer session)
-       (setq elmo-imap4-current-msgdb nil
+       (setq elmo-imap4-current-msgdb (elmo-make-msgdb)
              elmo-imap4-seen-messages nil
              elmo-imap4-fetch-callback 'elmo-imap4-fetch-callback-1
-             elmo-imap4-fetch-callback-data (cons args
-                                                  (elmo-folder-use-flag-p
-                                                   folder)))
+             elmo-imap4-fetch-callback-data (cons flag-table folder))
        (while set-list
          (elmo-imap4-send-command-wait
           session
@@ -2267,23 +2354,30 @@ If optional argument REMOVE is non-nil, remove FLAG."
        (message "Getting overview...done")
        (when elmo-imap4-seen-messages
          (elmo-imap4-set-flag folder elmo-imap4-seen-messages "\\Seen"))
+       ;; cannot setup the global flag while retrieval.
+       (dolist (number (elmo-msgdb-list-messages elmo-imap4-current-msgdb))
+         (elmo-global-flags-set (elmo-msgdb-flags elmo-imap4-current-msgdb
+                                                  number)
+                                folder number
+                                (elmo-message-entity-field
+                                 (elmo-msgdb-message-entity
+                                  elmo-imap4-current-msgdb number)
+                                 'message-id)))
        elmo-imap4-current-msgdb))))
 
-(luna-define-method elmo-folder-unmark-important-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Flagged" 'remove))
-
-(luna-define-method elmo-folder-mark-as-important-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Flagged"))
-
-(luna-define-method elmo-folder-unmark-read-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Seen" 'remove))
+(luna-define-method elmo-folder-set-flag-plugged ((folder elmo-imap4-folder)
+                                                 numbers flag)
+  (let ((spec (cdr (assq flag elmo-imap4-flag-specs))))
+    (elmo-imap4-set-flag folder numbers (or (car spec)
+                                           (capitalize (symbol-name flag)))
+                        (nth 1 spec))))
 
-(luna-define-method elmo-folder-mark-as-read-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Seen"))
+(luna-define-method elmo-folder-unset-flag-plugged ((folder elmo-imap4-folder)
+                                                   numbers flag)
+  (let ((spec (cdr (assq flag elmo-imap4-flag-specs))))
+    (elmo-imap4-set-flag folder numbers (or (car spec)
+                                           (capitalize (symbol-name flag)))
+                        (not (nth 1 spec)))))
 
 (luna-define-method elmo-message-use-cache-p ((folder elmo-imap4-folder)
                                              number)
@@ -2310,11 +2404,15 @@ If optional argument REMOVE is non-nil, remove FLAG."
 
 (defsubst elmo-imap4-folder-diff-plugged (folder)
   (let ((session (elmo-imap4-get-session folder))
-       messages new unread response killed)
+       messages new unread response killed uidnext)
 ;;; (elmo-imap4-commit spec)
     (with-current-buffer (elmo-network-session-buffer session)
       (setq elmo-imap4-status-callback nil)
       (setq elmo-imap4-status-callback-data nil))
+    (if elmo-imap4-use-select-to-update-status
+       (elmo-imap4-session-select-mailbox
+        session
+        (elmo-imap4-folder-mailbox-internal folder)))
     (setq response
          (elmo-imap4-send-command-wait session
                                        (list
@@ -2322,14 +2420,18 @@ If optional argument REMOVE is non-nil, remove FLAG."
                                         (elmo-imap4-mailbox
                                          (elmo-imap4-folder-mailbox-internal
                                           folder))
-                                        " (recent unseen messages)")))
+                                        " (recent unseen messages uidnext)")))
     (setq response (elmo-imap4-response-value response 'status))
     (setq messages (elmo-imap4-response-value response 'messages))
+    (setq uidnext (elmo-imap4-response-value response 'uidnext))
     (setq killed (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
-    (if killed
-       (setq messages (- messages
-                         (elmo-msgdb-killed-list-length
-                          killed))))
+    ;;
+    (when killed
+      (when (and (consp (car killed))
+                (eq (car (car killed)) 1))
+       (setq messages (- uidnext (cdr (car killed)) 1)))
+      (setq messages (- messages
+                       (elmo-msgdb-killed-list-length (cdr killed)))))
     (setq new (elmo-imap4-response-value response 'recent)
          unread (elmo-imap4-response-value response 'unseen))
     (if (< unread new) (setq new unread))
@@ -2338,8 +2440,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
 (luna-define-method elmo-folder-diff-plugged ((folder elmo-imap4-folder))
   (elmo-imap4-folder-diff-plugged folder))
 
-(luna-define-method elmo-folder-diff-async ((folder elmo-imap4-folder)
-                                           &optional number-alist)
+(luna-define-method elmo-folder-diff-async ((folder elmo-imap4-folder))
   (setq elmo-imap4-server-diff-async-callback
        elmo-folder-diff-async-callback)
   (setq elmo-imap4-server-diff-async-callback-data
@@ -2361,7 +2462,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
              (message "Selecting %s..."
                       (elmo-folder-name-internal folder))
              (if load-msgdb
-                 (setq msgdb (elmo-msgdb-load folder 'silent)))
+                 (setq msgdb (elmo-folder-msgdb-load folder 'silent)))
              (elmo-folder-set-killed-list-internal
               folder
               (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
@@ -2373,13 +2474,17 @@ If optional argument REMOVE is non-nil, remove FLAG."
                     session mailbox)
                    (elmo-imap4-session-set-read-only-internal
                     session
-                    (nth 1 (assq 'read-only (assq 'ok response)))))
+                    (nth 1 (assq 'read-only (assq 'ok response))))
+                   (elmo-imap4-session-set-flags-internal
+                    session
+                    (nth 1 (or (assq 'permanentflags response)
+                               (assq 'flags response)))))
                (elmo-imap4-session-set-current-mailbox-internal session nil)
                (if (elmo-imap4-response-bye-p response)
                    (elmo-imap4-process-bye session)
-                 (error (or
-                         (elmo-imap4-response-error-text response)
-                         (format "Select %s failed" mailbox)))))
+                 (error "%s"
+                        (or (elmo-imap4-response-error-text response)
+                            (format "Select %s failed" mailbox)))))
              (message "Selecting %s...done"
                       (elmo-folder-name-internal folder))
              (elmo-folder-set-msgdb-internal
@@ -2404,10 +2509,10 @@ If optional argument REMOVE is non-nil, remove FLAG."
 
 (luna-define-method elmo-find-fetch-strategy
   ((folder elmo-imap4-folder) entity &optional ignore-cache)
-  (let ((number (elmo-msgdb-overview-entity-get-number entity))
+  (let ((number (elmo-message-entity-number entity))
        cache-file size message-id)
-    (setq size (elmo-msgdb-overview-entity-get-size entity))
-    (setq message-id (elmo-msgdb-overview-entity-get-id entity))
+    (setq size (elmo-message-entity-field entity 'size))
+    (setq message-id (elmo-message-entity-field entity 'message-id))
     (setq cache-file (elmo-file-cache-get message-id))
     (if (or ignore-cache
            (null (elmo-file-cache-status cache-file)))
@@ -2457,7 +2562,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
          (elmo-imap4-folder-mailbox-internal folder)))))
 
 (luna-define-method elmo-folder-append-buffer
-  ((folder elmo-imap4-folder) unread &optional number)
+  ((folder elmo-imap4-folder) &optional flags number)
   (if (elmo-folder-plugged-p folder)
       (let ((session (elmo-imap4-get-session folder))
            send-buffer result)
@@ -2473,13 +2578,30 @@ If optional argument REMOVE is non-nil, remove FLAG."
                    "append "
                    (elmo-imap4-mailbox (elmo-imap4-folder-mailbox-internal
                                         folder))
-                   (if unread " () " " (\\Seen) ")
+                   (if (and flags (elmo-folder-use-flag-p folder))
+                       (concat " ("
+                               (mapconcat
+                                'identity
+                                (append
+                                 (and (memq 'important flags)
+                                      '("\\Flagged"))
+                                 (and (not (memq 'unread flags))
+                                      '("\\Seen"))
+                                 (and (memq 'answered flags)
+                                      '("\\Answered")))
+                                " ")
+                               ;; XX KEYWORD flags
+                               ") ")
+                     " () ")
                    (elmo-imap4-buffer-literal send-buffer))))
          (kill-buffer send-buffer))
+       (when result
+         (elmo-folder-preserve-flags
+          folder (elmo-msgdb-get-message-id-from-buffer) flags))
        result)
     ;; Unplugged
     (if elmo-enable-disconnected-operation
-       (elmo-folder-append-buffer-dop folder unread number)
+       (elmo-folder-append-buffer-dop folder flags number)
       (error "Unplugged"))))
 
 (eval-when-compile
@@ -2492,9 +2614,30 @@ If optional argument REMOVE is non-nil, remove FLAG."
            (string= (elmo-net-folder-user-internal (, folder1))
                     (elmo-net-folder-user-internal (, folder2)))))))
 
+(luna-define-method elmo-folder-next-message-number-plugged
+  ((folder elmo-imap4-folder))
+  (let ((session (elmo-imap4-get-session folder))
+       messages new unread response killed uidnext)
+    (with-current-buffer (elmo-network-session-buffer session)
+      (setq elmo-imap4-status-callback nil)
+      (setq elmo-imap4-status-callback-data nil))
+    (if elmo-imap4-use-select-to-update-status
+       (elmo-imap4-session-select-mailbox
+        session
+        (elmo-imap4-folder-mailbox-internal folder)))
+    (setq response
+         (elmo-imap4-send-command-wait session
+                                       (list
+                                        "status "
+                                        (elmo-imap4-mailbox
+                                         (elmo-imap4-folder-mailbox-internal
+                                          folder))
+                                        " (uidnext)"))
+         response (elmo-imap4-response-value response 'status))
+    (elmo-imap4-response-value response 'uidnext)))
+
 (luna-define-method elmo-folder-append-messages :around
-  ((folder elmo-imap4-folder) src-folder numbers unread-marks
-   &optional same-number)
+  ((folder elmo-imap4-folder) src-folder numbers &optional same-number)
   (if (and (eq (elmo-folder-type-internal src-folder) 'imap4)
           (elmo-imap4-identical-system-p folder src-folder)
           (elmo-folder-plugged-p folder))
@@ -2552,6 +2695,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
        (with-current-buffer outbuf
          (erase-buffer)
          (insert response)
+         (elmo-delete-cr-buffer)
          t))))
 
 (luna-define-method elmo-message-fetch-plugged ((folder elmo-imap4-folder)
@@ -2585,7 +2729,13 @@ If optional argument REMOVE is non-nil, remove FLAG."
       (goto-char (point-min))
       (std11-field-body (symbol-name field)))))
 
+(luna-define-method elmo-folder-search-requires-msgdb-p ((folder
+                                                         elmo-imap4-folder)
+                                                        condition)
+  nil)
 
+(autoload 'elmo-global-flags-set "elmo-flag")
+(autoload 'elmo-get-global-flags "elmo-flag")
 
 (require 'product)
 (product-provide (provide 'elmo-imap4) (require 'elmo-version))