Indent.
[gnus] / lisp / nnimap.el
index 0926414..f6c3705 100644 (file)
@@ -1,5 +1,5 @@
 ;;; nnimap.el --- imap backend for Gnus
-;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 ;; Author: Simon Josefsson <jas@pdc.kth.se>
 ;;         Jim Radford <radford@robby.caltech.edu>
@@ -42,7 +42,7 @@
 ;;   o Split up big fetches (1,* header especially) in smaller chunks
 ;;   o What do I do with gnus-newsgroup-*?
 ;;   o Tell Gnus about new groups (how can we tell?)
-;;   o Respooling (fix Gnus?) (unnecessery?)
+;;   o Respooling (fix Gnus?) (unnecessary?)
 ;;   o Add support for the following: (if applicable)
 ;;       request-list-newsgroups, request-regenerate
 ;;       list-active-group,
@@ -55,6 +55,7 @@
 ;;   o What about Gnus's article editing, can we support it?  NO!
 ;;   o Use \Draft to support the draft group??
 ;;   o Duplicate suppression
+;;   o Rewrite UID SEARCH UID X as UID FETCH X (UID) for those with slow servers
 
 ;;; Code:
 
@@ -114,7 +115,7 @@ loaded function will not match.  Use with care."
   (functionp value))
 
 (defcustom nnimap-split-rule nil
-  "Mail will be split according to theese rules.
+  "Mail will be split according to these rules.
 
 Mail is read from mailbox(es) specified in `nnimap-split-inbox'.
 
@@ -126,10 +127,10 @@ this:
 \(setq nnimap-split-rule '((\"INBOX.gnus-imap\"   \"From:.*gnus-imap\")
                          (\"INBOX.junk\"        \"Subject:.*buy\")))
 
-As you can see, `nnimap-split-rule' is a list of lists, where the first
-element in each \"rule\" is the name of the IMAP mailbox, and the
-second is a regexp that nnimap will try to match on the header to find
-a fit.
+As you can see, `nnimap-split-rule' is a list of lists, where the
+first element in each \"rule\" is the name of the IMAP mailbox (or the
+symbol `junk' if you want to remove the mail), and the second is a
+regexp that nnimap will try to match on the header to find a fit.
 
 The second element can also be a function.  In that case, it will be
 called narrowed to the headers with the first element of the rule as
@@ -190,10 +191,18 @@ RFC2060 section 6.4.4."
   :type 'string)
 
 (defcustom nnimap-split-fancy nil
-  "Like `nnmail-split-fancy', which see."
+  "Like the variable `nnmail-split-fancy', which see."
   :group 'nnimap
   :type 'sexp)
 
+(defcustom nnimap-split-download-body nil
+  "Whether to download entire articles during splitting.
+This is generally not required, and will slow things down considerably.
+You may need it if you want to use an advanced splitting function that
+analyses the body before splitting the article."
+  :group 'nnimap
+  :type 'boolean)
+
 ;; Performance / bug workaround variables
 
 (defcustom nnimap-close-asynchronous t
@@ -212,6 +221,18 @@ the same mailbox will be faster though."
   :type 'boolean
   :group 'nnimap)
 
+(defcustom nnimap-retrieve-groups-asynchronous t
+  "Send asynchronous STATUS commands for each mailbox before checking mail.
+If you have mailboxes that rarely receives mail, this speeds up new
+mail checking.  It works by first sending STATUS commands for each
+mailbox, and then only checking groups which has a modified UIDNEXT
+more carefully for new mail.
+
+In summary, the default is O((1-p)*k+p*n) and changing it to nil makes
+it O(n).  If p is small, then the default is probably faster."
+  :type 'boolean
+  :group 'nnimap)
+
 (defvoo nnimap-need-unselect-to-notice-new-mail nil
   "Unselect mailboxes before looking for new mail in them.
 Some servers seem to need this under some circumstances.")
@@ -267,9 +288,12 @@ typical complete file name would be
 (defvoo nnimap-nov-file-name-suffix ".novcache"
   "Suffix for NOV cache base filename.")
 
-(defvoo nnimap-nov-is-evil nil
-  "If non-nil, nnimap will never generate or use a local nov database for this backend.
-Using nov databases will speed up header fetching considerably.
+(defvoo nnimap-nov-is-evil gnus-agent
+  "If non-nil, never generate or use a local nov database for this backend.
+Using nov databases should speed up header fetching considerably.
+However, it will invoke a UID SEARCH UID command on the server, and
+some servers implement this command inefficiently by opening each and
+every message in the group, thus making it quite slow.
 Unlike other backends, you do not need to take special care if you
 flip this variable.")
 
@@ -363,11 +387,15 @@ just like \"ticked\" articles, in other IMAP clients.")
 If this is 'imap-mailbox-lsub, then use a server-side subscription list to
 restrict visible folders.")
 
+(defcustom nnimap-debug nil
+  "If non-nil, random debug spews are placed in *nnimap-debug* buffer."
+  :group 'nnimap
+  :type 'boolean)
+
 ;; Internal variables:
 
-(defvar nnimap-debug nil
-  "Name of buffer to record debugging info.
-For example: (setq nnimap-debug \"*nnimap-debug*\")")
+(defvar nnimap-debug-buffer "*nnimap-debug*")
+(defvar nnimap-mailbox-info (gnus-make-hashtable 997))
 (defvar nnimap-current-move-server nil)
 (defvar nnimap-current-move-group nil)
 (defvar nnimap-current-move-article nil)
@@ -375,10 +403,6 @@ For example: (setq nnimap-debug \"*nnimap-debug*\")")
 (defvar nnimap-progress-chars '(?| ?/ ?- ?\\))
 (defvar nnimap-progress-how-often 20)
 (defvar nnimap-counter)
-(defvar nnimap-callback-callback-function nil
-  "Gnus callback the nnimap asynchronous callback should call.")
-(defvar nnimap-callback-buffer nil
-  "Which buffer the asynchronous article prefetch callback should work in.")
 (defvar nnimap-server-buffer-alist nil)        ;; Map server name to buffers.
 (defvar nnimap-current-server nil) ;; Current server
 (defvar nnimap-server-buffer nil) ;; Current servers' buffer
@@ -440,7 +464,7 @@ If SERVER is nil, uses the current server."
        (imap-mailbox-unselect nnimap-server-buffer))))
 
 (defun nnimap-find-minmax-uid (group &optional examine)
-  "Find lowest and highest active article nummber in GROUP.
+  "Find lowest and highest active article number in GROUP.
 If EXAMINE is non-nil the group is selected read-only."
   (with-current-buffer nnimap-server-buffer
     (when (or (string= group (imap-current-mailbox))
@@ -511,10 +535,7 @@ If EXAMINE is non-nil the group is selected read-only."
        (with-temp-buffer
         (buffer-disable-undo)
         (insert headers)
-        (nnheader-ms-strip-cr)
-        (nnheader-fold-continuation-lines)
-        (subst-char-in-region (point-min) (point-max) ?\t ? )
-        (let ((head (nnheader-parse-head 'naked)))
+        (let ((head (nnheader-parse-naked-head)))
           (mail-header-set-number head uid)
           (mail-header-set-chars head chars)
           (mail-header-set-lines head lines)
@@ -543,7 +564,7 @@ If EXAMINE is non-nil the group is selected read-only."
              articles))))
 
 (defun nnimap-group-overview-filename (group server)
-  "Make pathname for GROUP on SERVER."
+  "Make file name for GROUP on SERVER."
   (let* ((dir (file-name-as-directory (expand-file-name nnimap-directory)))
         (uidvalidity (gnus-group-get-parameter
                       (gnus-group-prefixed-name
@@ -657,7 +678,7 @@ If EXAMINE is non-nil the group is selected read-only."
                    (nnimap-retrieve-headers-from-server
                     (cons (1+ (cdr cached)) high) group server))
                  (when nnimap-prune-cache
-             ;; remove nov's for articles which has expired on server
+                   ;; remove nov's for articles which has expired on server
                    (goto-char (point-min))
                    (dolist (uid (gnus-set-difference articles uids))
                      (when (re-search-forward (format "^%d\t" uid) nil t)
@@ -667,8 +688,8 @@ If EXAMINE is non-nil the group is selected read-only."
               (cons low high) group server))
            (when (buffer-modified-p)
              (nnmail-write-region
-              1 (point-max) (nnimap-group-overview-filename group server)
-              nil 'nomesg))
+              (point-min) (point-max)
+              (nnimap-group-overview-filename group server) nil 'nomesg))
            (nnheader-nov-delete-outside-range low high))))
       'nov)))
 
@@ -717,7 +738,12 @@ If EXAMINE is non-nil the group is selected read-only."
     (with-current-buffer (get-buffer-create nnimap-server-buffer)
       (nnoo-change-server 'nnimap server defs))
     (or (and nnimap-server-buffer
-            (imap-opened nnimap-server-buffer))
+            (imap-opened nnimap-server-buffer)
+            (if (with-current-buffer nnimap-server-buffer
+                  (memq imap-state '(auth select examine)))
+                t
+              (imap-close nnimap-server-buffer)
+              (nnimap-open-connection server)))
        (nnimap-open-connection server))))
 
 (deffoo nnimap-server-opened (&optional server)
@@ -765,19 +791,26 @@ function is generally only called when Gnus is shutting down."
             'identity)
           (or string "")))
 
-(defun nnimap-callback ()
-  (remove-hook 'imap-fetch-data-hook 'nnimap-callback)
-  (with-current-buffer nnimap-callback-buffer
-    (insert
-     (with-current-buffer nnimap-server-buffer
-       (nnimap-demule
-       (if (imap-capability 'IMAP4rev1)
-           ;; xxx don't just use car? alist doesn't contain
-           ;; anything else now, but it might...
-           (nth 2 (car (imap-message-get (imap-current-message) 'BODYDETAIL)))
-         (imap-message-get (imap-current-message) 'RFC822)))))
-    (nnheader-ms-strip-cr)
-    (funcall nnimap-callback-callback-function t)))
+(defun nnimap-make-callback (article gnus-callback buffer)
+  "Return a callback function."
+  `(lambda () 
+     (nnimap-callback ,article ,gnus-callback ,buffer)))
+
+(defun nnimap-callback (article gnus-callback buffer)
+  (when (eq article (imap-current-message))
+    (remove-hook 'imap-fetch-data-hook
+                (nnimap-make-callback article gnus-callback buffer))
+    (with-current-buffer buffer
+      (insert
+       (with-current-buffer nnimap-server-buffer
+        (nnimap-demule
+         (if (imap-capability 'IMAP4rev1)
+             ;; xxx don't just use car? alist doesn't contain
+             ;; anything else now, but it might...
+             (nth 2 (car (imap-message-get article 'BODYDETAIL)))
+           (imap-message-get article 'RFC822)))))
+      (nnheader-ms-strip-cr)
+      (funcall gnus-callback t))))
 
 (defun nnimap-request-article-part (article part prop &optional
                                            group server to-buffer detail)
@@ -788,7 +821,9 @@ function is generally only called when Gnus is shutting down."
                                  nnimap-server-buffer))
                     article)))
       (when article
-       (gnus-message 10 "nnimap: Fetching (part of) article %d..." article)
+       (gnus-message 10 "nnimap: Fetching (part of) article %d from %s..."
+                     article (or group imap-current-mailbox
+                                 gnus-newsgroup-name))
        (if (not nnheader-callback-function)
            (with-current-buffer (or to-buffer nntp-server-buffer)
              (erase-buffer)
@@ -798,15 +833,19 @@ function is generally only called when Gnus is shutting down."
                                           (nth 2 (car data))
                                         data))))
              (nnheader-ms-strip-cr)
-             (gnus-message 10 "nnimap: Fetching (part of) article %d...done"
-                           article)
+             (gnus-message
+              10 "nnimap: Fetching (part of) article %d from %s...done"
+              article (or group imap-current-mailbox gnus-newsgroup-name))
              (if (bobp)
-                 (nnheader-report 'nnimap "No such article: %s"
+                 (nnheader-report 'nnimap "No such article %d in %s: %s"
+                                  article (or group imap-current-mailbox
+                                              gnus-newsgroup-name)
                                   (imap-error-text nnimap-server-buffer))
                (cons group article)))
-         (add-hook 'imap-fetch-data-hook 'nnimap-callback)
-         (setq nnimap-callback-callback-function nnheader-callback-function
-               nnimap-callback-buffer nntp-server-buffer)
+         (add-hook 'imap-fetch-data-hook
+                   (nnimap-make-callback article 
+                                         nnheader-callback-function 
+                                         nntp-server-buffer))
          (imap-fetch-asynch article part nil nnimap-server-buffer)
          (cons group article))))))
 
@@ -854,10 +893,22 @@ function is generally only called when Gnus is shutting down."
             (nnheader-report 'nnimap "Group %s selected" group)
             t)))))
 
+(defun nnimap-update-unseen (group &optional server)
+  "Update the unseen count in `nnimap-mailbox-info'."
+  (gnus-sethash
+   (gnus-group-prefixed-name group server)
+   (let ((old (gnus-gethash-safe (gnus-group-prefixed-name group server) 
+                                nnimap-mailbox-info)))
+     (list (nth 0 old) (nth 1 old)
+          (imap-mailbox-status group 'unseen nnimap-server-buffer)
+          (nth 3 old)))
+   nnimap-mailbox-info))
+
 (defun nnimap-close-group (group &optional server)
   (with-current-buffer nnimap-server-buffer
     (when (and (imap-opened)
               (nnimap-possibly-change-group group server))
+      (nnimap-update-unseen group server)
       (case nnimap-expunge-on-close
        (always (progn
                  (imap-mailbox-expunge nnimap-close-asynchronous)
@@ -925,24 +976,96 @@ function is generally only called when Gnus is shutting down."
 
 ;; Optional backend functions
 
+(defun nnimap-string-lessp-numerical (s1 s2)
+  "Return t if first arg string is less than second in numerical order."
+  (cond ((string= s1 s2)
+        nil)
+       ((> (length s1) (length s2))
+        nil)
+       ((< (length s1) (length s2))
+        t)
+       ((< (string-to-number (substring s1 0 1))
+           (string-to-number (substring s2 0 1)))
+        t)
+       ((> (string-to-number (substring s1 0 1))
+           (string-to-number (substring s2 0 1)))
+        nil)
+       (t
+        (nnimap-string-lessp-numerical (substring s1 1) (substring s2 1)))))
+
 (deffoo nnimap-retrieve-groups (groups &optional server)
   (when (nnimap-possibly-change-server server)
     (gnus-message 5 "nnimap: Checking mailboxes...")
     (with-current-buffer nntp-server-buffer
       (erase-buffer)
       (nnimap-before-find-minmax-bugworkaround)
-      (dolist (group groups)
-       (gnus-message 7 "nnimap: Checking mailbox %s" group)
-       (or (member "\\NoSelect"
-                   (imap-mailbox-get 'list-flags group nnimap-server-buffer))
-           (let ((info (nnimap-find-minmax-uid group 'examine)))
-             (when (> (or (imap-mailbox-get 'recent group
-                                            nnimap-server-buffer) 0)
-                      0)
-               (push (list (cons group 0)) nnmail-split-history))
-             (insert (format "\"%s\" %d %d y\n" group
-                             (or (nth 2 info) 0)
-                             (max 1 (or (nth 1 info) 1))))))))
+      (let (asyncgroups slowgroups)
+       (if (null nnimap-retrieve-groups-asynchronous)
+           (setq slowgroups groups)
+         (dolist (group groups)
+           (gnus-message 9 "nnimap: Quickly checking mailbox %s" group)
+           (add-to-list (if (gnus-gethash-safe
+                             (gnus-group-prefixed-name group server)
+                             nnimap-mailbox-info)
+                            'asyncgroups
+                          'slowgroups)
+                        (list group (imap-mailbox-status-asynch
+                                     group '(uidvalidity uidnext unseen) 
+                                     nnimap-server-buffer))))
+         (dolist (asyncgroup asyncgroups)
+           (let ((group (nth 0 asyncgroup))
+                 (tag   (nth 1 asyncgroup))
+                 new old)
+             (when (imap-ok-p (imap-wait-for-tag tag nnimap-server-buffer))
+               (if (or (not (string=
+                             (nth 0 (gnus-gethash (gnus-group-prefixed-name
+                                                   group server)
+                                                  nnimap-mailbox-info))
+                             (imap-mailbox-get 'uidvalidity group 
+                                               nnimap-server-buffer)))
+                       (not (string=
+                             (nth 1 (gnus-gethash (gnus-group-prefixed-name
+                                                   group server)
+                                                  nnimap-mailbox-info))
+                             (imap-mailbox-get 'uidnext group
+                                               nnimap-server-buffer))))
+                   (push (list group) slowgroups)
+                 (insert (nth 3 (gnus-gethash (gnus-group-prefixed-name
+                                               group server)
+                                              nnimap-mailbox-info))))))))
+       (dolist (group slowgroups)
+         (if nnimap-retrieve-groups-asynchronous
+             (setq group (car group)))
+         (gnus-message 7 "nnimap: Mailbox %s modified" group)
+         (imap-mailbox-put 'uidnext nil group nnimap-server-buffer)
+         (or (member "\\NoSelect" (imap-mailbox-get 'list-flags group
+                                                    nnimap-server-buffer))
+             (let* ((info (nnimap-find-minmax-uid group 'examine))
+                    (str (format "\"%s\" %d %d y\n" group
+                                 (or (nth 2 info) 0)
+                                 (max 1 (or (nth 1 info) 1)))))
+               (when (> (or (imap-mailbox-get 'recent group
+                                              nnimap-server-buffer) 0)
+                        0)
+                 (push (list (cons group 0)) nnmail-split-history))
+               (insert str)
+               (when nnimap-retrieve-groups-asynchronous
+                 (gnus-sethash
+                  (gnus-group-prefixed-name group server)
+                  (list (or (imap-mailbox-get
+                             'uidvalidity group nnimap-server-buffer)
+                            (imap-mailbox-status
+                             group 'uidvalidity nnimap-server-buffer))
+                        (or (imap-mailbox-get
+                             'uidnext group nnimap-server-buffer)
+                            (imap-mailbox-status
+                             group 'uidnext nnimap-server-buffer))
+                        (or (imap-mailbox-get
+                             'unseen group nnimap-server-buffer)
+                            (imap-mailbox-status
+                             group 'unseen nnimap-server-buffer))
+                        str)
+                  nnimap-mailbox-info)))))))
     (gnus-message 5 "nnimap: Checking mailboxes...done")
     'active))
 
@@ -991,7 +1114,7 @@ function is generally only called when Gnus is shutting down."
                gnus-article-mark-lists)
 
        (when nnimap-importantize-dormant
-      ;; nnimap mark dormant article as ticked too (for other clients)
+         ;; nnimap mark dormant article as ticked too (for other clients)
          ;; so we remove that mark for gnus since we support dormant
          (gnus-info-set-marks
           info
@@ -1062,7 +1185,7 @@ function is generally only called when Gnus is shutting down."
   nil)
 
 (defun nnimap-split-fancy ()
-  "Like nnmail-split-fancy, but uses nnimap-split-fancy."
+  "Like the function `nnmail-split-fancy', but uses `nnimap-split-fancy'."
   (let ((nnmail-split-fancy nnimap-split-fancy))
     (nnmail-split-fancy)))
 
@@ -1084,10 +1207,13 @@ function is generally only called when Gnus is shutting down."
              (goto-char (point-min))
              (when (and (if (stringp regexp)
                             (progn
-                              (setq regrepp (string-match "\\\\[0-9&]" group))
+                              (if (not (stringp group))
+                                  (setq group (eval group))
+                                (setq regrepp
+                                      (string-match "\\\\[0-9&]" group)))
                               (re-search-forward regexp nil t))
                           (funcall regexp group))
-                ;; Don't enter the article into the same group twice.
+                        ;; Don't enter the article into the same group twice.
                         (not (assoc group to-groups)))
                (push (if regrepp
                          (nnmail-expand-newtext group)
@@ -1128,7 +1254,10 @@ function is generally only called when Gnus is shutting down."
          (when (setq rule (nnimap-split-find-rule server inbox))
            ;; iterate over articles
            (dolist (article (imap-search nnimap-split-predicate))
-             (when (nnimap-request-head article)
+             (when (if nnimap-split-download-body
+                       (and (nnimap-request-article article)
+                            (mail-narrow-to-head))
+                     (nnimap-request-head article))
                ;; copy article to right group(s)
                (setq removeorig nil)
                (dolist (to-group (nnimap-split-to-groups rule))
@@ -1141,11 +1270,19 @@ function is generally only called when Gnus is shutting down."
                         (message "IMAP split moved %s:%s:%d to %s" server
                                  inbox article to-group)
                         (setq removeorig t)
+                        (when nnmail-cache-accepted-message-ids
+                          (with-current-buffer nntp-server-buffer
+                             (let (msgid)
+                               (and (setq msgid
+                                         (nnmail-fetch-field "message-id"))
+                                    (nnmail-cache-insert msgid to-group)))))
                         ;; Add the group-art list to the history list.
                         (push (list (cons to-group 0)) nnmail-split-history))
                        (t
                         (message "IMAP split failed to move %s:%s:%d to %s"
                                  server inbox article to-group))))
+               (if nnimap-split-download-body
+                   (widen))
                ;; remove article if it was successfully copied somewhere
                (and removeorig
                     (imap-message-flags-add (format "%d" article)
@@ -1154,6 +1291,8 @@ function is generally only called when Gnus is shutting down."
            ;; todo: UID EXPUNGE (if available) to remove splitted articles
            (imap-mailbox-expunge)
            (imap-mailbox-close)))
+       (when nnmail-cache-accepted-message-ids
+         (nnmail-cache-close))
        t))))
 
 (deffoo nnimap-request-scan (&optional group server)
@@ -1214,12 +1353,11 @@ function is generally only called when Gnus is shutting down."
   (gnus-message 5 "nnimap: Marking article %d for deletion..."
                imap-current-message))
 
-
 (defun nnimap-expiry-target (arts group server)
   (unless (eq nnmail-expiry-target 'delete)
     (with-temp-buffer
-      (dolist (art (gnus-uncompress-sequence arts))
-       (nnimap-request-article art group server  (current-buffer))
+      (dolist (art arts)
+       (nnimap-request-article art group server (current-buffer))
        ;; hints for optimization in `nnimap-request-accept-article'
        (let ((nnimap-current-move-article art)
              (nnimap-current-move-group group)
@@ -1234,35 +1372,34 @@ function is generally only called when Gnus is shutting down."
   (let ((artseq (gnus-compress-sequence articles)))
     (when (and artseq (nnimap-possibly-change-group group server))
       (with-current-buffer nnimap-server-buffer
-       (if force
-           (progn
-             (nnimap-expiry-target artseq group server)
-             (when (imap-message-flags-add (imap-range-to-message-set artseq)
-                                           "\\Deleted")
-               (setq articles nil)))
-         (let ((days (or (and nnmail-expiry-wait-function
-                              (funcall nnmail-expiry-wait-function group))
-                         nnmail-expiry-wait)))
-           (cond ((eq days 'immediate)
-                  (nnimap-expiry-target artseq group server)
-                  (when (imap-message-flags-add
-                         (imap-range-to-message-set artseq) "\\Deleted")
-                    (setq articles nil)))
-                 ((numberp days)
-                  (let ((oldarts (imap-search
-                                  (format nnimap-expunge-search-string
-                                          (imap-range-to-message-set artseq)
-                                          (nnimap-date-days-ago days))))
-                        (imap-fetch-data-hook
-                         '(nnimap-request-expire-articles-progress)))
+       (let ((days (or (and nnmail-expiry-wait-function
+                            (funcall nnmail-expiry-wait-function group))
+                       nnmail-expiry-wait)))
+         (cond ((or force (eq days 'immediate))
+                (let ((oldarts (imap-search
+                                (concat "UID " 
+                                        (imap-range-to-message-set artseq)))))
+                  (when oldarts
+                    (nnimap-expiry-target oldarts group server)
+                    (when (imap-message-flags-add
+                           (imap-range-to-message-set 
+                            (gnus-compress-sequence oldarts)) "\\Deleted")
+                      (setq articles (gnus-set-difference
+                                      articles oldarts))))))
+               ((numberp days)
+                (let ((oldarts (imap-search
+                                (format nnimap-expunge-search-string
+                                        (imap-range-to-message-set artseq)
+                                        (nnimap-date-days-ago days))))
+                      (imap-fetch-data-hook
+                       '(nnimap-request-expire-articles-progress)))
+                  (when oldarts
                     (nnimap-expiry-target oldarts group server)
-                    (and oldarts
-                         (imap-message-flags-add
-                          (imap-range-to-message-set
-                           (gnus-compress-sequence oldarts))
-                          "\\Deleted")
-                         (setq articles (gnus-set-difference
-                                         articles oldarts)))))))))))
+                    (when (imap-message-flags-add
+                           (imap-range-to-message-set 
+                            (gnus-compress-sequence oldarts)) "\\Deleted")
+                      (setq articles (gnus-set-difference 
+                                      articles oldarts)))))))))))
   ;; return articles not deleted
   articles)
 
@@ -1293,7 +1430,7 @@ function is generally only called when Gnus is shutting down."
     (let (uid)
       (if (setq uid
                (if (string= nnimap-current-server nnimap-current-move-server)
-                 ;; moving article within same server, speed it up...
+                   ;; moving article within same server, speed it up...
                    (and (nnimap-possibly-change-group
                          nnimap-current-move-group)
                         (imap-message-copy (number-to-string
@@ -1302,13 +1439,18 @@ function is generally only called when Gnus is shutting down."
                                            nnimap-server-buffer))
                  (with-current-buffer (current-buffer)
                    (goto-char (point-min))
-                 ;; remove any 'From blabla' lines, some IMAP servers
+                   ;; remove any 'From blabla' lines, some IMAP servers
                    ;; reject the entire message otherwise.
                    (when (looking-at "^From[^:]")
                      (kill-region (point) (progn (forward-line) (point))))
                    ;; turn into rfc822 format (\r\n eol's)
                    (while (search-forward "\n" nil t)
-                     (replace-match "\r\n")))
+                     (replace-match "\r\n"))
+                   (when nnmail-cache-accepted-message-ids
+                     (nnmail-cache-insert (nnmail-fetch-field "message-id")
+                                          group)))
+                 (when (and last nnmail-cache-accepted-message-ids)
+                   (nnmail-cache-close))
                  ;; this 'or' is for Cyrus server bug
                  (or (null (imap-current-mailbox nnimap-server-buffer))
                      (imap-mailbox-unselect nnimap-server-buffer))
@@ -1437,8 +1579,8 @@ be used in a STORE FLAGS command."
 
 (when nnimap-debug
   (require 'trace)
-  (buffer-disable-undo (get-buffer-create nnimap-debug))
-  (mapcar (lambda (f) (trace-function-background f nnimap-debug))
+  (buffer-disable-undo (get-buffer-create nnimap-debug-buffer))
+  (mapcar (lambda (f) (trace-function-background f nnimap-debug-buffer))
          '(
            nnimap-possibly-change-server
            nnimap-verify-uidvalidity