Don't message so much when reading nnimap stuff.
[gnus] / lisp / nnimap.el
index 44caaed..49cceaa 100644 (file)
 
 (eval-and-compile
   (require 'nnheader)
-  (require 'network-stream))
+  ;; In Emacs 24, `open-protocol-stream' is an autoloaded alias for
+  ;; `make-network-stream'.
+  (unless (fboundp 'open-protocol-stream)
+    (require 'proto-stream)))
 
 (eval-when-compile
   (require 'cl))
@@ -55,6 +58,9 @@
 (defvoo nnimap-address nil
   "The address of the IMAP server.")
 
+(defvoo nnimap-user nil
+  "Username to use for authentication to the IMAP server.")
+
 (defvoo nnimap-server-port nil
   "The IMAP port used.
 If nnimap-stream is `ssl', this will default to `imaps'.  If not,
@@ -162,6 +168,8 @@ textual parts.")
                   nnmail-extra-headers))))
 
 (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
   (with-current-buffer nntp-server-buffer
     (erase-buffer)
     (when (nnimap-possibly-change-group group server)
@@ -184,7 +192,7 @@ textual parts.")
   (let (article bytes lines size string)
     (block nil
       (while (not (eobp))
-       (while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
+       (while (not (looking-at "\\* [0-9]+ FETCH.+?UID \\([0-9]+\\)"))
          (delete-region (point) (progn (forward-line 1) (point)))
          (when (eobp)
            (return)))
@@ -210,9 +218,14 @@ textual parts.")
          (let ((structure (ignore-errors
                             (read (current-buffer)))))
            (while (and (consp structure)
-                       (not (stringp (car structure))))
+                       (not (atom (car structure))))
              (setq structure (car structure)))
-           (setq lines (nth 7 structure))))
+           (setq lines (if (and
+                            (stringp (car structure))
+                            (equal (upcase (nth 0 structure)) "MESSAGE")
+                            (equal (upcase (nth 1 structure)) "RFC822"))
+                           (nth 9 structure)
+                         (nth 7 structure)))))
        (delete-region (line-beginning-position) (line-end-position))
        (insert (format "211 %s Article retrieved." article))
        (forward-line 1)
@@ -280,13 +293,14 @@ textual parts.")
     (push (current-buffer) nnimap-process-buffers)
     (current-buffer)))
 
-(defun nnimap-credentials (address ports)
+(defun nnimap-credentials (address ports user)
   (let* ((auth-source-creation-prompts
           '((user  . "IMAP user at %h: ")
             (secret . "IMAP password for %u@%h: ")))
          (found (nth 0 (auth-source-search :max 1
                                            :host address
                                            :port ports
+                                           :user user
                                            :require '(:user :secret)
                                            :create t))))
     (if found
@@ -331,6 +345,11 @@ textual parts.")
        nil
       stream)))
 
+(defun nnimap-map-port (port)
+  (if (equal port "imaps")
+      "993"
+    port))
+
 (defun nnimap-open-connection-1 (buffer)
   (unless nnimap-keepalive-timer
     (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
@@ -338,7 +357,6 @@ textual parts.")
   (with-current-buffer (nnimap-make-process-buffer buffer)
     (let* ((coding-system-for-read 'binary)
           (coding-system-for-write 'binary)
-          (port nil)
           (ports
            (cond
             ((memq nnimap-stream '(network plain starttls))
@@ -360,7 +378,8 @@ textual parts.")
        (push nnimap-server-port ports))
       (let* ((stream-list
              (open-protocol-stream
-              "*nnimap*" (current-buffer) nnimap-address (car ports)
+              "*nnimap*" (current-buffer) nnimap-address
+              (nnimap-map-port (car ports))
               :type nnimap-stream
               :return-list t
               :shell-command nnimap-shell-program
@@ -383,7 +402,7 @@ textual parts.")
        (if (not stream)
            (progn
              (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
-                              nnimap-address port nnimap-stream)
+                              nnimap-address (car ports) nnimap-stream)
              'no-connect)
          (gnus-set-process-query-on-exit-flag stream nil)
          (if (not (gnus-string-match-p "[*.] \\(OK\\|PREAUTH\\)" greeting))
@@ -405,16 +424,17 @@ textual parts.")
                                 (list
                                  nnimap-address
                                  (nnoo-current-server 'nnimap)))
-                                ports))))
+                                ports
+                                nnimap-user))))
                  (setq nnimap-object nil)
                (let ((nnimap-inhibit-logging t))
                  (setq login-result
                        (nnimap-login (car credentials) (cadr credentials))))
                (if (car login-result)
                    (progn
-                    ;; Save the credentials if a save function exists
-                    ;; (such a function will only be passed if a new
-                    ;; token was created).
+                     ;; Save the credentials if a save function exists
+                     ;; (such a function will only be passed if a new
+                     ;; token was created).
                      (when (functionp (nth 2 credentials))
                        (funcall (nth 2 credentials)))
                      ;; See if CAPABILITY is set as part of login
@@ -511,6 +531,8 @@ textual parts.")
   nnimap-status-string)
 
 (deffoo nnimap-request-article (article &optional group server to-buffer)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
   (with-current-buffer nntp-server-buffer
     (let ((result (nnimap-possibly-change-group group server))
          parts structure)
@@ -537,12 +559,13 @@ textual parts.")
                  (nnimap-get-whole-article article))
            (let ((buffer (current-buffer)))
              (with-current-buffer (or to-buffer nntp-server-buffer)
-               (erase-buffer)
-               (insert-buffer-substring buffer)
-               (nnheader-ms-strip-cr)
-               (cons group article)))))))))
+               (nnheader-insert-buffer-substring buffer)
+               (nnheader-ms-strip-cr)))
+           (cons group article)))))))
 
 (deffoo nnimap-request-head (article &optional group server to-buffer)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
   (when (nnimap-possibly-change-group group server)
     (with-current-buffer (nnimap-buffer)
       (when (stringp article)
@@ -689,7 +712,11 @@ textual parts.")
        (incf num)))
     (nreverse parts)))
 
+(defun nnimap-decode-gnus-group (group)
+  (decode-coding-string group 'utf-8))
+
 (deffoo nnimap-request-group (group &optional server dont-check info)
+  (setq group (nnimap-decode-gnus-group group))
   (let ((result (nnimap-possibly-change-group
                 ;; Don't SELECT the group if we're going to select it
                 ;; later, anyway.
@@ -739,16 +766,19 @@ textual parts.")
        t))))
 
 (deffoo nnimap-request-create-group (group &optional server args)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group nil server)
     (with-current-buffer (nnimap-buffer)
       (car (nnimap-command "CREATE %S" (utf7-encode group t))))))
 
 (deffoo nnimap-request-delete-group (group &optional force server)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group nil server)
     (with-current-buffer (nnimap-buffer)
       (car (nnimap-command "DELETE %S" (utf7-encode group t))))))
 
 (deffoo nnimap-request-rename-group (group new-name &optional server)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group nil server)
     (with-current-buffer (nnimap-buffer)
       (nnimap-unselect-group)
@@ -763,6 +793,7 @@ textual parts.")
   (nnimap-command "EXAMINE DOES.NOT.EXIST"))
 
 (deffoo nnimap-request-expunge-group (group &optional server)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group group server)
     (with-current-buffer (nnimap-buffer)
       (car (nnimap-command "EXPUNGE")))))
@@ -790,6 +821,7 @@ textual parts.")
 
 (deffoo nnimap-request-move-article (article group server accept-form
                                             &optional last internal-move-group)
+  (setq group (nnimap-decode-gnus-group group))
   (with-temp-buffer
     (mm-disable-multibyte)
     (when (funcall (if internal-move-group
@@ -818,6 +850,7 @@ textual parts.")
              result)))))))
 
 (deffoo nnimap-request-expire-articles (articles group &optional server force)
+  (setq group (nnimap-decode-gnus-group group))
   (cond
    ((null articles)
     nil)
@@ -873,15 +906,18 @@ textual parts.")
          (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)))
+             (if (and target
+                      (not (eq target 'delete)))
+                 (if (or (gnus-request-group target t)
+                         (gnus-request-create-group target))
+                     (progn
+                       (nnmail-expiry-target-group target group)
+                       (nnheader-message 7 "Expiring article %s:%d to %s"
+                                         group article target))
+                   (setq target nil))
+               (nnheader-message 7 "Expiring article %s:%d" group article))
              (when target
                (push article deleted-articles))))))))
     ;; Change back to the current group again.
@@ -922,7 +958,7 @@ textual parts.")
                 (car (setq result (nnimap-parse-response))))
        ;; Select the last instance of the message in the group.
        (and (setq article
-                  (car (last (assoc "SEARCH" (cdr result)))))
+                  (car (last (cdr (assoc "SEARCH" (cdr result))))))
             (string-to-number article))))))
 
 (defun nnimap-delete-article (articles)
@@ -942,11 +978,14 @@ textual parts.")
                                 "delete this article now"))))))
 
 (deffoo nnimap-request-scan (&optional group server)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
   (when (and (nnimap-possibly-change-group nil server)
             nnimap-inbox
             nnimap-split-methods)
     (nnheader-message 7 "nnimap %s splitting mail..." server)
-    (nnimap-split-incoming-mail)))
+    (nnimap-split-incoming-mail)
+    (nnheader-message 7 "nnimap %s splitting mail...done" server)))
 
 (defun nnimap-marks-to-flags (marks)
   (let (flags flag)
@@ -956,6 +995,7 @@ textual parts.")
     flags))
 
 (deffoo nnimap-request-update-group-status (group status &optional server)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group nil server)
     (let ((command (assoc
                    status
@@ -966,6 +1006,7 @@ textual parts.")
          (nnimap-command "%s %S" (cadr command) (utf7-encode group t)))))))
 
 (deffoo nnimap-request-set-mark (group actions &optional server)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group group server)
     (let (sequence)
       (with-current-buffer (nnimap-buffer)
@@ -990,6 +1031,7 @@ textual parts.")
          (nnimap-wait-for-response sequence))))))
 
 (deffoo nnimap-request-accept-article (group &optional server last)
+  (setq group (nnimap-decode-gnus-group group))
   (when (nnimap-possibly-change-group nil server)
     (nnmail-check-syntax)
     (let ((message-id (message-field-value "message-id"))
@@ -1066,6 +1108,7 @@ textual parts.")
     result))
 
 (deffoo nnimap-request-replace-article (article group buffer)
+  (setq group (nnimap-decode-gnus-group group))
   (let (group-art)
     (when (and (nnimap-possibly-change-group group nil)
               ;; Put the article into the group.
@@ -1096,9 +1139,9 @@ textual parts.")
            (separator (read (current-buffer)))
            (group (read (current-buffer))))
        (unless (member '%NoSelect flags)
-         (push (if (stringp group)
-                   group
-                 (format "%s" group))
+         (push (utf7-decode (if (stringp group)
+                                group
+                              (format "%s" group)) t)
                groups))))
     (nreverse groups)))
 
@@ -1157,7 +1200,7 @@ textual parts.")
                       (nnimap-get-groups)))
        (unless (assoc group nnimap-current-infos)
          ;; Insert dummy numbers here -- they don't matter.
-         (insert (format "%S 0 1 y\n" group))))
+         (insert (format "%S 0 1 y\n" (utf7-encode group)))))
       t)))
 
 (deffoo nnimap-retrieve-group-data-early (server infos)
@@ -1171,7 +1214,8 @@ textual parts.")
        ;; what and how to request the data.
        (dolist (info infos)
          (setq params (gnus-info-params info)
-               group (gnus-group-real-name (gnus-info-group info))
+               group (nnimap-decode-gnus-group
+                      (gnus-group-real-name (gnus-info-group info)))
                active (cdr (assq 'active params))
                uidvalidity (cdr (assq 'uidvalidity params))
                modseq (cdr (assq 'modseq params)))
@@ -1220,6 +1264,10 @@ textual parts.")
 
 (deffoo nnimap-finish-retrieve-group-infos (server infos sequences)
   (when (and sequences
+            ;; Check that the process is still alive.
+            (get-buffer-process (nnimap-buffer))
+            (memq (process-status (get-buffer-process (nnimap-buffer)))
+                  '(open run))
             (nnimap-possibly-change-group nil server))
     (with-current-buffer (nnimap-buffer)
       ;; Wait for the final data to trickle in.
@@ -1243,13 +1291,15 @@ textual parts.")
                   (active (gnus-active group)))
              (when active
                (insert (format "%S %d %d y\n"
-                               (gnus-group-real-name group)
+                               (decode-coding-string
+                                (gnus-group-real-name group) 'utf-8)
                                (cdr active)
                                (car active)))))))))))
 
 (defun nnimap-update-infos (flags infos)
   (dolist (info infos)
-    (let* ((group (gnus-group-real-name (gnus-info-group info)))
+    (let* ((group (nnimap-decode-gnus-group
+                  (gnus-group-real-name (gnus-info-group info))))
           (marks (cdr (assoc group flags))))
       (when marks
        (nnimap-update-info info marks)))))
@@ -1507,7 +1557,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)
@@ -1550,26 +1600,20 @@ textual parts.")
 (declare-function gnus-fetch-headers "gnus-sum"
                  (articles &optional limit force-new dependencies))
 
-(deffoo nnimap-request-thread (header)
-  (let* ((id (mail-header-id header))
-        (refs (split-string
-               (or (mail-header-references 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))))
-    (when result
-      (gnus-fetch-headers
-       (and (car result) (delete 0 (mapcar #'string-to-number
-                                          (cdr (assoc "SEARCH" (cdr result))))))
-       nil t))))
+(deffoo nnimap-request-thread (header &optional group server)
+  (when group
+    (setq group (nnimap-decode-gnus-group group)))
+  (if gnus-refer-thread-use-nnir
+      (nnir-search-thread header)
+    (when (nnimap-possibly-change-group group server)
+      (let* ((cmd (nnimap-make-thread-query header))
+             (result (with-current-buffer (nnimap-buffer)
+                       (nnimap-command  "UID SEARCH %s" cmd))))
+        (when result
+          (gnus-fetch-headers
+           (and (car result) (delete 0 (mapcar #'string-to-number
+                                               (cdr (assoc "SEARCH" (cdr result))))))
+           nil t))))))
 
 (defun nnimap-possibly-change-group (group server)
   (let ((open-result t))
@@ -1679,7 +1723,8 @@ textual parts.")
                                      (looking-at "\\*"))))
                        (not (looking-at (format "%d .*\n" sequence)))))
            (when messagep
-             (nnheader-message 7 "nnimap read %dk" (/ (buffer-size) 1000)))
+             (nnheader-message-maybe
+              7 "nnimap read %dk" (/ (buffer-size) 1000)))
            (nnheader-accept-process-output process)
            (goto-char (point-max)))
           openp)
@@ -1791,9 +1836,14 @@ textual parts.")
 (defun nnimap-split-incoming-mail ()
   (with-current-buffer (nnimap-buffer)
     (let ((nnimap-incoming-split-list nil)
-         (nnmail-split-methods (if (eq nnimap-split-methods 'default)
-                                   nnmail-split-methods
-                                 nnimap-split-methods))
+         (nnmail-split-methods
+          (cond
+           ((eq nnimap-split-methods 'default)
+            nnmail-split-methods)
+           (nnimap-split-methods
+            nnimap-split-methods)
+           (nnimap-split-fancy
+            'nnmail-split-fancy)))
          (nnmail-split-fancy (or nnimap-split-fancy
                                  nnmail-split-fancy))
          (nnmail-inhibit-default-split-group t)
@@ -1897,7 +1947,7 @@ textual parts.")
   (let (article bytes)
     (block nil
       (while (not (eobp))
-       (while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
+       (while (not (looking-at "\\* [0-9]+ FETCH.+UID \\([0-9]+\\)"))
          (delete-region (point) (progn (forward-line 1) (point)))
          (when (eobp)
            (return)))
@@ -1930,6 +1980,21 @@ textual parts.")
                  group-art))
          nnimap-incoming-split-list)))
 
+(defun nnimap-make-thread-query (header)
+  (let* ((id  (mail-header-id header))
+        (refs (split-string
+               (or (mail-header-references header)
+                   "")))
+        (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)))))
+
+
 (provide 'nnimap)
 
 ;;; nnimap.el ends here