* mm-view.el (mml-smime): Require.
[gnus] / lisp / nnimap.el
index 4bdf96b..1899b0e 100644 (file)
@@ -1,6 +1,6 @@
 ;;; nnimap.el --- IMAP interface for Gnus
 
-;; Copyright (C) 2010 Free Software Foundation, Inc.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;         Simon Josefsson <simon@josefsson.org>
@@ -47,9 +47,6 @@
 (require 'nnmail)
 (require 'proto-stream)
 
-(eval-when-compile
-  (require 'gnus-sum))
-
 (autoload 'auth-source-forget-user-or-password "auth-source")
 (autoload 'auth-source-user-or-password "auth-source")
 
@@ -142,6 +139,9 @@ textual parts.")
     (download "gnus-download")
     (forward "gnus-forward")))
 
+(defvar nnimap-quirks
+  '(("QRESYNC" "Zimbra" "QRESYNC ")))
+
 (defun nnimap-buffer ()
   (nnimap-find-process-buffer nntp-server-buffer))
 
@@ -167,7 +167,8 @@ textual parts.")
          (nnimap-article-ranges (gnus-compress-sequence articles))
          (nnimap-header-parameters))
         t)
-       (nnimap-transform-headers))
+       (nnimap-transform-headers)
+       (nnheader-remove-cr-followed-by-lf))
       (insert-buffer-substring
        (nnimap-find-process-buffer (current-buffer))))
     'headers))
@@ -345,20 +346,20 @@ textual parts.")
              '("143" "993" "imap" "imaps"))
             (t
              (error "Unknown stream type: %s" nnimap-stream))))
-          connection-result login-result credentials)
+          (proto-stream-always-use-starttls t)
+           login-result credentials)
       (when nnimap-server-port
-       (push (format "%s" nnimap-server-port) ports))
+       (setq ports (append ports (list nnimap-server-port))))
       (destructuring-bind (stream greeting capabilities)
          (open-protocol-stream
           "*nnimap*" (current-buffer) nnimap-address (car (last ports))
           :type nnimap-stream
           :shell-command nnimap-shell-program
           :capability-command "1 CAPABILITY\r\n"
+          :success " OK "
           :starttls-function
           (lambda (capabilities)
-            (if (not (string-match "STARTTLS" capabilities))
-                ;; Not a STARTTLS-capable server.
-                nil
+            (when (gnus-string-match-p "STARTTLS" capabilities)
               "1 STARTTLS\r\n")))
        (setf (nnimap-process nnimap-object) stream)
        (if (not stream)
@@ -367,14 +368,14 @@ textual parts.")
                               nnimap-address port nnimap-stream)
              'no-connect)
          (gnus-set-process-query-on-exit-flag stream nil)
-         (if (not (string-match "[*.] OK" greeting))
+         (if (not (gnus-string-match-p "[*.] \\(OK\\|PREAUTH\\)" greeting))
              (nnheader-report 'nnimap "%s" greeting)
            ;; Store the greeting (for debugging purposes).
            (setf (nnimap-greeting nnimap-object) greeting)
            (setf (nnimap-capabilities nnimap-object)
                  (mapcar #'upcase
                          (split-string capabilities)))
-           (unless (equal connection-result "PREAUTH")
+           (unless (gnus-string-match-p "[*.] PREAUTH" greeting)
              (if (not (setq credentials
                             (if (eq nnimap-authenticator 'anonymous)
                                 (list "anonymous"
@@ -638,7 +639,7 @@ textual parts.")
   (let ((result (nnimap-possibly-change-group
                 ;; Don't SELECT the group if we're going to select it
                 ;; later, anyway.
-                (if (and dont-check
+                (if (and (not dont-check)
                          (assoc group nnimap-current-infos))
                     nil
                   group)
@@ -793,22 +794,42 @@ textual parts.")
 
 (defun nnimap-process-expiry-targets (articles group server)
   (let ((deleted-articles nil))
-    (dolist (article articles)
-      (let ((target nnmail-expiry-target))
-       (with-temp-buffer
-          (mm-disable-multibyte)
-         (when (nnimap-request-article article group server (current-buffer))
-           (nnheader-message 7 "Expiring article %s:%d" group article)
-           (when (functionp target)
-             (setq target (funcall target group)))
-           (when (and target
-                      (not (eq target 'delete)))
-             (if (or (gnus-request-group target t)
-                     (gnus-request-create-group target))
-                 (nnmail-expiry-target-group target group)
-               (setq target nil)))
-           (when target
-             (push article deleted-articles))))))
+    (cond
+     ;; shortcut further processing if we're going to delete the articles
+     ((eq nnmail-expiry-target 'delete)
+      (setq deleted-articles articles)
+      t)
+     ;; or just move them to another folder on the same IMAP server
+     ((and (not (functionp nnmail-expiry-target))
+          (gnus-server-equal (gnus-group-method nnmail-expiry-target)
+                             (gnus-server-to-method
+                              (format "nnimap:%s" server))))
+      (and (nnimap-possibly-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)))
+      t)
+     (t
+      (dolist (article articles)
+       (let ((target nnmail-expiry-target))
+         (with-temp-buffer
+           (mm-disable-multibyte)
+           (when (nnimap-request-article article group server (current-buffer))
+             (nnheader-message 7 "Expiring article %s:%d" group article)
+             (when (functionp target)
+               (setq target (funcall target group)))
+             (when (and target
+                        (not (eq target 'delete)))
+               (if (or (gnus-request-group target t)
+                       (gnus-request-create-group target))
+                   (nnmail-expiry-target-group target group)
+                 (setq target nil)))
+             (when target
+               (push article deleted-articles))))))))
     ;; Change back to the current group again.
     (nnimap-possibly-change-group group server)
     (setq deleted-articles (nreverse deleted-articles))
@@ -880,6 +901,16 @@ textual parts.")
        (push flag flags)))
     flags))
 
+(deffoo nnimap-request-update-group-status (group status &optional server)
+  (when (nnimap-possibly-change-group nil server)
+    (let ((command (assoc
+                   status
+                   '((subscribe "SUBSCRIBE")
+                     (unsubscribe "UNSUBSCRIBE")))))
+      (when command
+       (with-current-buffer (nnimap-buffer)
+         (nnimap-command "%s %S" (cadr command) (utf7-encode group t)))))))
+
 (deffoo nnimap-request-set-mark (group actions &optional server)
   (when (nnimap-possibly-change-group group server)
     (let (sequence)
@@ -1063,8 +1094,9 @@ textual parts.")
                   uidvalidity
                   modseq)
              (push
-              (list (nnimap-send-command "EXAMINE %S (QRESYNC  (%s %s))"
+              (list (nnimap-send-command "EXAMINE %S (%s (%s %s))"
                                          (utf7-encode group t)
+                                         (nnimap-quirk "QRESYNC")
                                          uidvalidity modseq)
                     'qresync
                     nil group 'qresync)
@@ -1090,6 +1122,15 @@ textual parts.")
                    sequences))))
        sequences))))
 
+(defun nnimap-quirk (command)
+  (let ((quirk (assoc command nnimap-quirks)))
+    ;; If this server is of a type that matches a quirk, then return
+    ;; the "quirked" command instead of the proper one.
+    (if (or (null quirk)
+           (not (string-match (nth 1 quirk) (nnimap-greeting nnimap-object))))
+       command
+      (nth 2 quirk))))
+
 (deffoo nnimap-finish-retrieve-group-infos (server infos sequences)
   (when (and sequences
             (nnimap-possibly-change-group nil server))
@@ -1367,7 +1408,7 @@ textual parts.")
                 (goto-char start)
                 (setq vanished
                       (and (eq flag-sequence 'qresync)
-                           (re-search-forward "VANISHED.* \\([0-9:,]+\\)"
+                           (re-search-forward "^\\* VANISHED .* \\([0-9:,]+\\)"
                                               (or end (point-min)) t)
                            (match-string 1)))
                 (goto-char start)
@@ -1406,9 +1447,10 @@ textual parts.")
   (setq nnimap-status-string "Read-only server")
   nil)
 
-(deffoo nnimap-request-thread (id)
-  (let* ((refs (split-string
-               (or (mail-header-references (gnus-summary-article-header))
+(deffoo nnimap-request-thread (header)
+  (let* ((id (mail-header-id header))
+        (refs (split-string
+               (or (mail-header-references header)
                    "")))
         (cmd (let ((value
                     (format
@@ -1523,7 +1565,12 @@ textual parts.")
                      (not (re-search-backward
                            (format "^%d .*\n" sequence)
                            (if nnimap-streaming
-                               (max (point-min) (- (point) 500))
+                               (max (point-min)
+                                    (min
+                                     (- (point) 500)
+                                     (save-excursion
+                                       (forward-line -3)
+                                       (point))))
                              (point-min))
                            t)))
            (when messagep