Fix typo (falgs => flags).
[elisp/wanderlust.git] / elmo / elmo-imap4.el
index 3ab05a3..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.")
@@ -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
@@ -453,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)))
@@ -614,8 +618,9 @@ BUFFER must be a single-byte buffer."
               (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
@@ -693,7 +698,11 @@ 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))
@@ -730,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")
@@ -773,68 +837,56 @@ If CHOP-LENGTH is not specified, message set is not chopped."
 
 ;;
 ;; app-data:
-;; cons of flag-table 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))
-        mark)
-    (if (elmo-string-member-ignore-case "\\Flagged" flags)
-       (elmo-msgdb-global-mark-set (car entity)
-                                   elmo-msgdb-important-mark))
-    (if (setq mark (elmo-msgdb-global-mark-get (car entity)))
-       (unless (elmo-string-member-ignore-case "\\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)))
-                        ;; cached.
-                        (if (and use-flag (member "\\Seen" flags))
-                            (if (elmo-string-member-ignore-case
-                                 "\\Answered" flags)
-                                elmo-msgdb-answered-cached-mark
-                              nil)
-                          elmo-msgdb-unread-cached-mark)
-                      ;; uncached.
-                      (if (elmo-string-member-ignore-case "\\Answered" flags)
-                          elmo-msgdb-answered-uncached-mark
-                        (if (and use-flag
-                                 (elmo-string-member-ignore-case
-                                  "\\Seen" flags))
-                            (if (elmo-string-member-ignore-case
-                                 "\\Answered" flags)
-                                elmo-msgdb-answered-uncached-mark
-                              (if elmo-imap4-use-cache
-                                  elmo-msgdb-read-uncached-mark))
-                          elmo-msgdb-new-mark))))))
-    (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)
@@ -1866,23 +1918,9 @@ Return nil if no complete line has arrived."
                         (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-answereds-plugged
-  ((folder elmo-imap4-folder))
-  (elmo-imap4-list folder "answered"))
-
-(defun elmo-imap4-folder-list-any-plugged (folder)
-  (elmo-imap4-list folder "or answered or unseen flagged"))
-
-(defun elmo-imap4-folder-list-digest-plugged (folder)
-  (elmo-imap4-list folder "or unseen 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
@@ -1912,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)
@@ -2070,26 +2116,31 @@ 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)
@@ -2109,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" "mark"))
+                           "larger" "smaller" "flag"))
        (total 0)
        (length (length from-msgs))
        charset set-list end results)
@@ -2128,17 +2179,8 @@ If optional argument REMOVE is non-nil, remove FLAG."
        (mapcar '(lambda (x) (delete x numbers)) rest)
        numbers))
      ((string= "flag" search-key)
-      (cond
-       ((string= "unread" (elmo-filter-value filter))
-       (elmo-folder-list-unreads folder))
-       ((string= "important" (elmo-filter-value filter))
-       (elmo-folder-list-importants folder))
-       ((string= "answered" (elmo-filter-value filter))
-       (elmo-folder-list-answereds folder))
-       ((string= "digest" (elmo-filter-value filter))
-       (elmo-imap4-folder-list-digest-plugged folder))
-       ((string= "any" (elmo-filter-value filter))
-       (elmo-imap4-folder-list-any-plugged folder))))
+      (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)
@@ -2289,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 flag-table
-                                                  (elmo-folder-use-flag-p
-                                                   folder)))
+             elmo-imap4-fetch-callback-data (cons flag-table folder))
        (while set-list
          (elmo-imap4-send-command-wait
           session
@@ -2314,31 +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-mark-as-read-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Seen"))
+(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-unmark-answered-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Answered" 'remove))
-
-(luna-define-method elmo-folder-mark-as-answered-plugged
-  ((folder elmo-imap4-folder) numbers)
-  (elmo-imap4-set-flag folder numbers "\\Answered"))
+(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)
@@ -2370,6 +2409,10 @@ If optional argument REMOVE is non-nil, remove FLAG."
     (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
@@ -2382,7 +2425,7 @@ If optional argument REMOVE is non-nil, remove FLAG."
     (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)))
-    ;; 
+    ;;
     (when killed
       (when (and (consp (car killed))
                 (eq (car (car killed)) 1))
@@ -2397,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
@@ -2420,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)))
@@ -2432,7 +2474,11 @@ 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)
@@ -2463,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)))
@@ -2516,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) &optional flag number)
+  ((folder elmo-imap4-folder) &optional flags number)
   (if (elmo-folder-plugged-p folder)
       (let ((session (elmo-imap4-get-session folder))
            send-buffer result)
@@ -2532,16 +2578,30 @@ If optional argument REMOVE is non-nil, remove FLAG."
                    "append "
                    (elmo-imap4-mailbox (elmo-imap4-folder-mailbox-internal
                                         folder))
-                   (cond 
-                    ((eq flag 'read) " (\\Seen) ")
-                    ((eq flag 'answered) " (\\Answered)")
-                    (t " () "))
+                   (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 flag number)
+       (elmo-folder-append-buffer-dop folder flags number)
       (error "Unplugged"))))
 
 (eval-when-compile
@@ -2554,6 +2614,28 @@ 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 &optional same-number)
   (if (and (eq (elmo-folder-type-internal src-folder) 'imap4)
@@ -2613,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)
@@ -2651,6 +2734,9 @@ If optional argument REMOVE is non-nil, remove FLAG."
                                                         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))