Subject: Re: [PATCH] Use IMAP MOVE extension if available

From: Nikolaus Rath <[email-masked]>
Date: Wed, 15 Jul 2015 17:29:47 -0700

Hello,

The attached revision fixes a small error when parsing the response to
the UID MOVE command. Previously, it would fail to find the COPYUID
response and fall back to using the message id to determine the UID of
the copied message.

Best,
-Nikolaus

-- 
GPG encrypted emails preferred. Key id: 0xD113FCAC3C4E599F
Fingerprint: ED31 791B 2C5C 1613 AF38 8B8A D113 FCAC 3C4E 599F

             »Time flies like an arrow, fruit flies like a Banana.«
>From f7cff6a6068079ecfb31d31986902b5b17cee0b5 Mon Sep 17 00:00:00 2001
From: Nikolaus Rath <[email-masked]>
Date: Thu, 9 Jul 2015 20:01:12 -0700
Subject: [PATCH] nnimap.el: use IMAP MOVE extension if available

* lisp/nnimap.el (nnimap-request-move-article)
(nnimap-process-expiry-targets, nnimap-split-incoming-mail): use MOVE
extension if available.
---
 lisp/ChangeLog |  6 ++++++
 lisp/nnimap.el | 59 ++++++++++++++++++++++++++++++++++------------------------
 2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index d4af26a..58d00ed 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,11 @@
 2015-07-11 Nikolaus Rath <[email-masked]>
 
+	* nnimap.el (nnimap-request-move-article)
+	(nnimap-process-expiry-targets, nnimap-split-incoming-mail): use MOVE
+	extension if available.
+	
+2015-07-09 Nikolaus Rath <[email-masked]>
+
 	* nnimap.el (nnimap-hide-deleted): introduced as new server variable.
 	(nnimap-header-parameters): also request flags.
 	(nnimap-transform-headers): parse flags and conditionally skip over
diff --git a/lisp/nnimap.el b/lisp/nnimap.el
index 2f4a818..f56fb83 100644
--- a/lisp/nnimap.el
+++ b/lisp/nnimap.el
@@ -960,17 +960,19 @@ If non-nil, articles flagged as deleted (using the IMAP
       ;; way.
       (let ((message-id (message-field-value "message-id")))
 	(if internal-move-group
-	    (let ((result
-		   (with-current-buffer (nnimap-buffer)
-		     (nnimap-command "UID COPY %d %S"
-				     article
-				     (utf7-encode internal-move-group t)))))
-	      (when (car result)
-		(nnimap-delete-article article)
-		(cons internal-move-group
-		      (or (nnimap-find-uid-response "COPYUID" (cadr result))
-			  (nnimap-find-article-by-message-id
-			   internal-move-group server message-id
+            (with-current-buffer (nnimap-buffer)
+              (let* ((can-move (nnimap-capability "MOVE"))
+                    (command (if can-move
+                                 "UID MOVE %d %S"
+                               "UID COPY %d %S"))
+                    (result (nnimap-command command article
+                                            (utf7-encode internal-move-group t))))
+                (when (and (car result) (not can-move))
+                  (nnimap-delete-article article))
+                (cons internal-move-group
+                      (or (nnimap-find-uid-response "COPYUID" (caddr result))
+                          (nnimap-find-article-by-message-id
+                           internal-move-group server message-id
                            nnimap-request-articles-find-limit)))))
 	  ;; Move the article to a different method.
 	  (let ((result (eval accept-form)))
@@ -1009,11 +1011,12 @@ If non-nil, articles flagged as deleted (using the IMAP
 	(gnus-sorted-complement articles deletable-articles))))))
 
 (defun nnimap-process-expiry-targets (articles group server)
-  (let ((deleted-articles nil))
+  (let ((deleted-articles nil)
+        (articles-to-delete nil))
     (cond
      ;; shortcut further processing if we're going to delete the articles
      ((eq nnmail-expiry-target 'delete)
-      (setq deleted-articles articles)
+      (setq articles-to-delete articles)
       t)
      ;; or just move them to another folder on the same IMAP server
      ((and (not (functionp nnmail-expiry-target))
@@ -1023,11 +1026,14 @@ If non-nil, articles flagged as deleted (using the IMAP
       (and (nnimap-change-group group server)
 	   (with-current-buffer (nnimap-buffer)
 	     (nnheader-message 7 "Expiring articles from %s: %s" group articles)
-	     (nnimap-command
-	      "UID COPY %s %S"
-	      (nnimap-article-ranges (gnus-compress-sequence articles))
-	      (utf7-encode (gnus-group-real-name nnmail-expiry-target) t))
-	     (setq deleted-articles articles)))
+             (let ((can-move (nnimap-capability "MOVE")))
+               (nnimap-command
+                (if can-move
+                    "UID MOVE %s %S"
+                  "UID COPY %s %S")
+                (nnimap-article-ranges (gnus-compress-sequence articles))
+                (utf7-encode (gnus-group-real-name nnmail-expiry-target) t))
+               (set (if can-move 'deleted-articles 'articles-to-delete) articles))))
       t)
      (t
       (dolist (article articles)
@@ -1048,11 +1054,13 @@ If non-nil, articles flagged as deleted (using the IMAP
 		    (setq target nil))
 		(nnheader-message 7 "Expiring article %s:%d" group article))
 	      (when target
-		(push article deleted-articles))))))
-      (setq deleted-articles (nreverse deleted-articles))))
+		(push article articles-to-delete))))))
+      (setq articles-to-delete (nreverse articles-to-delete))))
     ;; Change back to the current group again.
     (nnimap-change-group group server)
-    (nnimap-delete-article (gnus-compress-sequence deleted-articles))
+    (when articles-to-delete
+      (nnimap-delete-article (gnus-compress-sequence articles-to-delete))
+      (setq deleted-articles articles-to-delete))
     deleted-articles))
 
 (defun nnimap-find-expired-articles (group)
@@ -2103,6 +2111,7 @@ Return the server's response to the SELECT or EXAMINE command."
 				  nnmail-split-fancy))
 	  (nnmail-inhibit-default-split-group t)
 	  (groups (nnimap-get-groups))
+          (can-move (nnimap-capability "MOVE"))
 	  new-articles)
       (erase-buffer)
       (nnimap-command "SELECT %S" nnimap-inbox)
@@ -2137,14 +2146,16 @@ Return the server's response to the SELECT or EXAMINE command."
 		  ;; Don't copy if the message is already in its
 		  ;; target group.
 		  (unless (string= group nnimap-inbox)
-		   (push (list (nnimap-send-command
-				"UID COPY %s %S"
+                    (push (list (nnimap-send-command
+                                 (if can-move
+                                     "UID MOVE %d %S"
+                                     "UID COPY %s %S")
 				(nnimap-article-ranges ranges)
 				(utf7-encode group t))
 			       ranges)
 			 sequences)))))
 	    ;; Wait for the last COPY response...
-	    (when sequences
+	    (when (and (not can-move) sequences)
 	      (nnimap-wait-for-response (caar sequences))
 	      ;; And then mark the successful copy actions as deleted,
 	      ;; and possibly expunge them.
-- 
2.1.4