* nnimap.el: Use nnheader-message throughout.
[gnus] / lisp / nnimap.el
index aaa6420..8f0a112 100644 (file)
 
 ;;; Code:
 
+;; For Emacs <22.2 and XEmacs.
+(eval-and-compile
+  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
+
 (eval-and-compile
   (require 'nnheader))
 
@@ -284,6 +288,8 @@ textual parts.")
                        (* 5 60)))
            (nnimap-send-command "NOOP")))))))
 
+(declare-function gnutls-negotiate "subr" (fn file &optional arglist fileonly))
+
 (defun nnimap-open-connection (buffer)
   (unless nnimap-keepalive-timer
     (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
@@ -295,7 +301,11 @@ textual parts.")
             (port nil)
             (ports
              (cond
-              ((eq nnimap-stream 'network)
+              ((or (eq nnimap-stream 'network)
+                   (and (eq nnimap-stream 'starttls)
+                        (fboundp 'open-gnutls-stream)))
+               (nnheader-message 7 "Opening connection to %s..."
+                                 nnimap-address)
                (open-network-stream
                 "*nnimap*" (current-buffer) nnimap-address
                 (setq port
@@ -305,18 +315,24 @@ textual parts.")
                             "143"))))
                '("143" "imap"))
               ((eq nnimap-stream 'shell)
+               (nnheader-message 7 "Opening connection to %s via shell..."
+                                 nnimap-address)
                (nnimap-open-shell-stream
                 "*nnimap*" (current-buffer) nnimap-address
                 (setq port (or nnimap-server-port "imap")))
                '("imap"))
               ((eq nnimap-stream 'starttls)
-               (let ((tls-program (nnimap-extend-tls-programs)))
+               (nnheader-message 7 "Opening connection to %s via starttls..."
+                        nnimap-address)
+               (let ((tls-program
+                      '("openssl s_client -connect %h:%p -no_ssl2 -ign_eof -starttls imap")))
                  (open-tls-stream
                   "*nnimap*" (current-buffer) nnimap-address
-                  (setq port (or nnimap-server-port "imap"))
-                  'starttls))
+                  (setq port (or nnimap-server-port "imap"))))
                '("imap"))
               ((memq nnimap-stream '(ssl tls))
+               (nnheader-message 7 "Opening connection to %s via tls..."
+                                 nnimap-address)
                (funcall (if (fboundp 'open-gnutls-stream)
                             'open-gnutls-stream
                           'open-tls-stream)
@@ -357,8 +373,16 @@ textual parts.")
              (push (format "%s" nnimap-server-port) ports))
            ;; If this is a STARTTLS-capable server, then sever the
            ;; connection and start a STARTTLS connection instead.
-           (when (and (eq nnimap-stream 'network)
-                      (member "STARTTLS" (nnimap-capabilities nnimap-object)))
+           (cond
+            ((and (or (and (eq nnimap-stream 'network)
+                           (member "STARTTLS"
+                                   (nnimap-capabilities nnimap-object)))
+                      (eq nnimap-stream 'starttls))
+                  (fboundp 'open-gnutls-stream))
+             (nnimap-command "STARTTLS")
+             (gnutls-negotiate (nnimap-process nnimap-object) nil))
+            ((and (eq nnimap-stream 'network)
+                  (member "STARTTLS" (nnimap-capabilities nnimap-object)))
              (let ((nnimap-stream 'starttls))
                (let ((tls-process
                       (nnimap-open-connection buffer)))
@@ -369,7 +393,7 @@ textual parts.")
                  (when (memq (process-status tls-process) '(open run))
                    (delete-process (nnimap-process nnimap-object))
                    (kill-buffer (current-buffer))
-                   (return tls-process)))))
+                   (return tls-process))))))
            (unless (equal connection-result "PREAUTH")
              (if (not (setq credentials
                             (if (eq nnimap-authenticator 'anonymous)
@@ -403,19 +427,6 @@ textual parts.")
                (nnimap-command "ENABLE QRESYNC"))
              (nnimap-process nnimap-object))))))))
 
-(defun nnimap-extend-tls-programs ()
-  (let ((programs tls-program)
-       result)
-    (unless (consp programs)
-      (setq programs (list programs)))
-    (dolist (program programs)
-      (when (assoc (car (split-string program)) tls-starttls-switches)
-       (push (if (not (string-match "%s" program))
-                 (concat program " " "%s")
-               program)
-             result)))
-    (nreverse result)))
-
 (defun nnimap-find-parameter (parameter elems)
   (let (result)
     (dolist (elem elems)
@@ -432,6 +443,7 @@ textual parts.")
   (when (nnoo-change-server 'nnimap server nil)
     (ignore-errors
       (delete-process (get-buffer-process (nnimap-buffer))))
+    (nnoo-close-server 'nnimap server)
     t))
 
 (deffoo nnimap-request-close ()
@@ -657,6 +669,12 @@ textual parts.")
 (deffoo nnimap-request-rename-group (group new-name &optional server)
   (when (nnimap-possibly-change-group nil server)
     (with-current-buffer (nnimap-buffer)
+      ;; Make sure we don't have this group open read/write by asking
+      ;; to examine a mailbox that doesn't exist.  This seems to be
+      ;; the only way that allows us to reliably go back to unselected
+      ;; state on Courier.
+      (nnimap-command "EXAMINE DOES.NOT.EXIST")
+      (setf (nnimap-group nnimap-object) nil)
       (car (nnimap-command "RENAME %S %S"
                           (utf7-encode group t) (utf7-encode new-name t))))))
 
@@ -719,7 +737,7 @@ textual parts.")
    ((and force
         (eq nnmail-expiry-target 'delete))
     (unless (nnimap-delete-article (gnus-compress-sequence articles))
-      (message "Article marked for deletion, but not expunged."))
+      (nnheader-message 7 "Article marked for deletion, but not expunged."))
     nil)
    (t
     (let ((deletable-articles
@@ -745,7 +763,7 @@ textual parts.")
       (let ((target nnmail-expiry-target))
        (with-temp-buffer
          (when (nnimap-request-article article group server (current-buffer))
-           (message "Expiring article %s:%d" group article)
+           (nnheader-message 7 "Expiring article %s:%d" group article)
            (when (functionp target)
              (setq target (funcall target group)))
            (when (and target
@@ -815,7 +833,7 @@ textual parts.")
   (when (and (nnimap-possibly-change-group nil server)
             nnimap-inbox
             nnimap-split-methods)
-    (message "nnimap %s splitting mail..." server)
+    (nnheader-message 7 "nnimap %s splitting mail..." server)
     (nnimap-split-incoming-mail)))
 
 (defun nnimap-marks-to-flags (marks)
@@ -867,7 +885,7 @@ textual parts.")
        (let ((result (nnimap-get-response sequence)))
          (if (not (car result))
              (progn
-               (message "%s" (nnheader-get-report-string 'nnimap))
+               (nnheader-message 7 "%s" (nnheader-get-report-string 'nnimap))
                nil)
            (cons group
                  (nnimap-find-article-by-message-id group message-id))))))))
@@ -964,7 +982,8 @@ textual parts.")
                   modseq)
              (push
               (list (nnimap-send-command "EXAMINE %S (QRESYNC (%s %s))"
-                                         group uidvalidity modseq)
+                                         (utf7-encode group t)
+                                         uidvalidity modseq)
                     'qresync
                     nil group 'qresync)
               sequences)
@@ -982,7 +1001,8 @@ textual parts.")
                     ;; examine), but will tell us whether the group
                     ;; is read-only or not.
                     "SELECT")))
-             (push (list (nnimap-send-command "%s %S" command group)
+             (push (list (nnimap-send-command "%s %S" command
+                                              (utf7-encode group t))
                          (nnimap-send-command "UID FETCH %d:* FLAGS" start)
                          start group command)
                    sequences)))
@@ -1056,8 +1076,8 @@ textual parts.")
       (let* ((group (gnus-info-group info))
             (completep (and start-article
                             (= start-article 1)))
-            (active (or (cdr (assq 'active (gnus-info-params info)))
-                        (gnus-active group))))
+            (active (or (gnus-active group)
+                        (cdr (assq 'active (gnus-info-params info))))))
        (when uidnext
          (setq high (1- uidnext)))
        ;; First set the active ranges based on high/low.
@@ -1147,8 +1167,12 @@ textual parts.")
   ;; Add all the vanished articles to the list of read articles.
   (gnus-info-set-read
    info
-   (gnus-range-add (gnus-info-read info)
-                  vanished))
+   (gnus-add-to-range
+    (gnus-add-to-range
+     (gnus-range-add (gnus-info-read info)
+                    vanished)
+     (cdr (assq '%Flagged flags)))
+    (cdr (assq '%Seen flags))))
   (let ((marks (gnus-info-marks info)))
     (dolist (type (cdr nnimap-mark-alist))
       (let ((ticks (assoc (car type) marks))
@@ -1275,7 +1299,7 @@ textual parts.")
                (setq start end))
            (setq start (point))
            (goto-char end))
-         (while (search-forward " FETCH " start t)
+         (while (re-search-forward "^\\* [0-9]+ FETCH " start t)
            (setq elems (read (current-buffer)))
            (push (cons (cadr (memq 'UID elems))
                        (cadr (memq 'FLAGS elems)))
@@ -1295,6 +1319,25 @@ 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))
+                  "")))
+          (cmd (let ((value
+                      (format
+                       "(OR HEADER REFERENCES %s HEADER Message-Id %s)"
+                       id id)))
+                 (dolist (refid refs value)
+                   (setq value (format
+                                "(OR (OR HEADER Message-Id %s HEADER REFERENCES %s) %s)"
+                                refid refid value)))))
+          (result
+           (with-current-buffer (nnimap-buffer)
+             (nnimap-command  "UID SEARCH %s" cmd))))
+      (gnus-fetch-headers (and (car result)
+          (delete 0 (mapcar #'string-to-number
+                            (cdr (assoc "SEARCH" (cdr result)))))))))
+
 (defun nnimap-possibly-change-group (group server)
   (let ((open-result t))
     (when (and server
@@ -1391,7 +1434,7 @@ textual parts.")
                              (point-min))
                            t)))
            (when messagep
-             (message "nnimap read %dk" (/ (buffer-size) 1000)))
+             (nnheader-message 7 "nnimap read %dk" (/ (buffer-size) 1000)))
            (nnheader-accept-process-output process)
            (goto-char (point-max)))
           openp)
@@ -1611,8 +1654,10 @@ textual parts.")
        (forward-char (1+ bytes))
        (setq bytes (nnimap-get-length))
        (delete-region (line-beginning-position) (line-end-position))
-       (forward-char (1+ bytes))
-       (delete-region (line-beginning-position) (line-end-position))))))
+       ;; There's a body; skip past that.
+       (when bytes
+         (forward-char (1+ bytes))
+         (delete-region (line-beginning-position) (line-end-position)))))))
 
 (defun nnimap-dummy-active-number (group &optional server)
   1)