*** empty log message ***
[gnus] / lisp / nntp.el
index 99e1504..4d6a408 100644 (file)
@@ -50,6 +50,9 @@ to allow posting from the server.  Note that this is only necessary to
 do on servers that use strict access control.")  
 (add-hook 'nntp-server-opened-hook 'nntp-send-mode-reader)
 
+(defvoo nntp-authinfo-function 'nntp-send-authinfo
+  "Function used to send AUTHINFO to the server.")
+
 (defvoo nntp-server-action-alist 
   '(("nntpd 1\\.5\\.11t" 
      (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader)))
@@ -141,6 +144,13 @@ server there that you can connect to. See also `nntp-open-connection-function'")
 
 ;;; Internal variables.
 
+(defvar nntp-process-wait-for nil)
+(defvar nntp-process-to-buffer nil)
+(defvar nntp-process-callback nil)
+(defvar nntp-process-decode nil)
+(defvar nntp-process-start-point nil)
+(defvar nntp-inside-change-function nil)
+
 (defvoo nntp-server-type nil)
 (defvoo nntp-connection-alist nil)
 (defvoo nntp-status-string "")
@@ -229,12 +239,86 @@ server there that you can connect to. See also `nntp-open-connection-function'")
        (copy-to-buffer nntp-server-buffer (point-min) (point-max))
        'headers))))
 
+(deffoo nntp-retrieve-groups (groups &optional server)
+  "Retrieve group info on GROUPS."
+  (nntp-possibly-change-group nil server)
+  (save-excursion
+    (set-buffer (nntp-find-connection-buffer nntp-server-buffer))
+    ;; The first time this is run, this variable is `try'.  So we
+    ;; try.   
+    (when (eq nntp-server-list-active-group 'try)
+      (nntp-try-list-active (car groups)))
+    (erase-buffer)
+    (let ((count 0)
+         (received 0)
+         (last-point (point-min))
+         (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP")))
+      (while groups
+       ;; Send the command to the server.
+       (nntp-send-command nil command (car groups))
+       (setq groups (cdr groups))
+       (setq count (1+ count))
+       ;; Every 400 requests we have to read the stream in
+       ;; order to avoid deadlocks.
+       (when (or (null groups)         ;All requests have been sent.
+                 (zerop (% count nntp-maximum-request)))
+         (nntp-accept-response)
+         (while (progn
+                  (goto-char last-point)
+                  ;; Count replies.
+                  (while (re-search-forward "^[0-9]" nil t)
+                    (setq received (1+ received)))
+                  (setq last-point (point))
+                  (< received count))
+           (nntp-accept-response))))
+
+      ;; Wait for the reply from the final command.
+      (when nntp-server-list-active-group
+       (goto-char (point-max))
+       (re-search-backward "^[0-9]" nil t)
+       (when (looking-at "^[23]")
+         (while (progn
+                  (goto-char (- (point-max) 3))
+                  (not (looking-at "^\\.\r?\n")))
+           (nntp-accept-response))))
+
+      ;; Now all replies are received. We remove CRs.
+      (goto-char (point-min))
+      (while (search-forward "\r" nil t)
+       (replace-match "" t t))
+
+      (if (not nntp-server-list-active-group)
+         'group
+       ;; We have read active entries, so we just delete the
+       ;; superfluos gunk.
+       (goto-char (point-min))
+       (while (re-search-forward "^[.2-5]" nil t)
+         (delete-region (match-beginning 0) 
+                        (progn (forward-line 1) (point))))
+       (copy-to-buffer nntp-server-buffer (point-min) (point-max))
+       'active))))
+
+(defun nntp-try-list-active (group)
+  (nntp-list-active-group group)
+  (save-excursion
+    (goto-char (point-min))
+    (cond ((looking-at "5[0-9]+")
+          (setq nntp-server-list-active-group nil))
+         (t
+          (setq nntp-server-list-active-group t)))))
+
+(deffoo nntp-list-active-group (group &optional server)
+  "Return the active info on GROUP (which can be a regexp."
+  (nntp-possibly-change-group group server)
+  (nntp-send-command "^.*\r?\n" "LIST ACTIVE" group))
+
 (deffoo nntp-request-article (article &optional group server buffer command)
   (nntp-possibly-change-group group server)
   (when (nntp-send-command-and-decode
         "\r?\n\\.\r?\n" "ARTICLE"
         (if (numberp article) (int-to-string article) article))
-    (when buffer
+    (when (and buffer
+              (not (equal buffer nntp-server-buffer)))
       (save-excursion
        (set-buffer nntp-server-buffer)
        (copy-to-buffer buffer (point-min) (point-max))
@@ -290,7 +374,6 @@ server there that you can connect to. See also `nntp-open-connection-function'")
     (while (setq process (car (pop nntp-connection-alist)))
       (when (memq (process-status process) '(open run))
        (set-process-sentinel process nil)
-       (set-process-filter process nil)
        (nntp-send-string process "QUIT"))
       (when (buffer-name (process-buffer process))
        (kill-buffer (process-buffer process))))
@@ -306,19 +389,18 @@ server there that you can connect to. See also `nntp-open-connection-function'")
 
 (deffoo nntp-request-newgroups (date &optional server)
   (nntp-possibly-change-group nil server)
-  (let* ((date (timezone-parse-date date))
-        (time-string
-         (format "%s%02d%02d %s%s%s"
-                 (substring (aref date 0) 2) (string-to-int (aref date 1)) 
-                 (string-to-int (aref date 2)) (substring (aref date 3) 0 2)
-                 (substring 
-                  (aref date 3) 3 5) (substring (aref date 3) 6 8))))
-    (prog1
-       (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string)
-      (nntp-decode-text))))
-
-(deffoo nntp-asynchronous-p ()
-  t)
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    (let* ((date (timezone-parse-date date))
+          (time-string
+           (format "%s%02d%02d %s%s%s"
+                   (substring (aref date 0) 2) (string-to-int (aref date 1)) 
+                   (string-to-int (aref date 2)) (substring (aref date 3) 0 2)
+                   (substring 
+                    (aref date 3) 3 5) (substring (aref date 3) 6 8))))
+      (prog1
+         (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string)
+       (nntp-decode-text)))))
 
 (deffoo nntp-request-post (&optional server)
   (nntp-possibly-change-group nil server)
@@ -328,6 +410,9 @@ server there that you can connect to. See also `nntp-open-connection-function'")
 (deffoo nntp-request-type (group article)
   'news)
   
+(deffoo nntp-asynchronous-p ()
+  t)
+
 ;;; Hooky functions.
 
 (defun nntp-send-mode-reader ()
@@ -344,7 +429,7 @@ It will prompt for a password."
   (nntp-send-command "^.*\r?\n" "AUTHINFO USER"
                     (read-string "NNTP user name: "))
   (nntp-send-command "^.*\r?\n" "AUTHINFO PASS" 
-                    (read-string "NNTP password: ")))
+                    (nnmail-read-passwd "NNTP password: ")))
 
 (defun nntp-send-authinfo ()
   "Send the AUTHINFO to the nntp server.
@@ -442,17 +527,27 @@ It will prompt for a password."
     (when process
       (process-buffer process))))
 
+(defun nntp-make-process-buffer (buffer)
+  "Create a new, fresh buffer usable for nntp process connections."
+  (save-excursion
+    (set-buffer 
+     (generate-new-buffer
+      (format " *server %s %s %s*"
+             nntp-address nntp-port-number
+             (buffer-name (get-buffer buffer)))))
+    (buffer-disable-undo (current-buffer))
+    (set (make-local-variable 'after-change-functions) nil)
+    (set (make-local-variable 'nntp-process-wait-for) nil)
+    (set (make-local-variable 'nntp-process-callback) nil)
+    (set (make-local-variable 'nntp-process-to-buffer) nil)
+    (set (make-local-variable 'nntp-process-start-point) nil)
+    (set (make-local-variable 'nntp-process-decode) nil)
+    (current-buffer)))
+
 (defun nntp-open-connection (buffer)
   "Open a connection to PORT on ADDRESS delivering output to BUFFER."
   (run-hooks 'nntp-prepare-server-hook)
-  (let* ((pbuffer (save-excursion
-                   (set-buffer 
-                    (generate-new-buffer
-                     (format " *server %s %s %s*"
-                             nntp-address nntp-port-number
-                             (buffer-name (get-buffer buffer)))))
-                   (buffer-disable-undo (current-buffer))
-                   (current-buffer)))
+  (let* ((pbuffer (nntp-make-process-buffer buffer))
         (process
          (condition-case ()
              (funcall
@@ -489,46 +584,41 @@ It will prompt for a password."
            (eval (cadr entry))
          (funcall (cadr entry)))))))
 
-(defvar nntp-tmp-first)
-(defvar nntp-tmp-wait-for)
-(defvar nntp-tmp-callback)
-(defvar nntp-tmp-buffer)
-
-(defun nntp-make-process-filter (wait-for callback buffer decode)
-  `(lambda (proc string)
-     (let ((nntp-tmp-wait-for ,wait-for)
-          (nntp-tmp-callback ,callback)
-          (nntp-tmp-buffer ,buffer))
-       (nntp-process-filter proc string))))
-
-(defun nntp-process-filter (proc string)
-  "Process filter used for waiting a calling back."
-  (let ((old-buffer (current-buffer)))
-    (unwind-protect
-       (let (point)
-         (set-buffer (process-buffer proc))
-         ;; Insert the text, moving the process-marker.
-         (setq point (goto-char (process-mark proc)))
-         (insert string)
-         (set-marker (process-mark proc) (point))
-         (if (and (= point (point-min))
-                  (string-match "^45" string))
-             (progn
-               (nntp-snarf-error-message)
-               (set-process-filter proc nil)
-               (funcall nntp-tmp-callback nil))
-           (setq nntp-tmp-first nil)
-           (if (re-search-backward nntp-tmp-wait-for nil t)
-               (progn
-                 (if (buffer-name (get-buffer nntp-tmp-buffer))
-                     (save-excursion
-                       (set-buffer (get-buffer nntp-tmp-buffer))
-                       (goto-char (point-max))
-                       (insert-buffer-substring (process-buffer proc))))
-                 (set-process-filter proc nil)
-                 (erase-buffer)
-                 (funcall nntp-tmp-callback t)))))
-      (set-buffer old-buffer))))
+(defun nntp-after-change-function (beg end len)
+  (when nntp-process-callback
+    (save-match-data
+      (if (and (= beg (point-min))
+              (memq (char-after beg) '(?4 ?5)))
+         ;; Report back error messages.
+         (save-excursion
+           (goto-char beg)
+           (if (looking-at "480")
+               (funcall nntp-authinfo-function)
+             (nntp-snarf-error-message)
+             (funcall nntp-process-callback nil)))
+       (goto-char end)
+       (when (and (> (point) nntp-process-start-point)
+                  (re-search-backward nntp-process-wait-for
+                                      nntp-process-start-point t))
+         (when (buffer-name (get-buffer nntp-process-to-buffer))
+           (let ((cur (current-buffer))
+                 (start nntp-process-start-point))
+             (save-excursion
+               (set-buffer (get-buffer nntp-process-to-buffer))
+               (goto-char (point-max))
+               (let ((b (point)))
+                 (insert-buffer-substring cur start)
+                 (narrow-to-region b (point-max))
+                 (nntp-decode-text)
+                 (goto-char (point-min))
+                 (gnus-delete-line)
+                 (widen)))))
+         (goto-char end)
+         (let ((callback nntp-process-callback)
+               (nntp-inside-change-function t))
+           (setq nntp-process-callback nil)
+           (save-excursion
+             (funcall callback t))))))))
 
 (defun nntp-retrieve-data (command address port buffer
                                   &optional wait-for callback decode)
@@ -537,7 +627,7 @@ It will prompt for a password."
                     (nntp-open-connection buffer))))
     (if (not process)
        (nnheader-report 'nntp "Couldn't open connection to %a" address)
-      (unless nntp-inhibit-erase
+      (unless (or nntp-inhibit-erase nnheader-callback-function)
        (save-excursion
          (set-buffer (process-buffer process))
          (erase-buffer)))
@@ -547,11 +637,18 @@ It will prompt for a password."
        ((eq callback 'ignore)
        t)
        ((and callback wait-for)
-       (set-process-filter
-        process (nntp-make-process-filter wait-for callback buffer decode))
+       (save-excursion
+         (set-buffer (process-buffer process))
+         (unless nntp-inside-change-function 
+           (erase-buffer))
+         (setq nntp-process-decode decode
+               nntp-process-to-buffer buffer
+               nntp-process-wait-for wait-for
+               nntp-process-callback callback
+               nntp-process-start-point (point-max)
+               after-change-functions (list 'nntp-after-change-function)))
        t)
        (wait-for 
-       (set-process-filter process nil)
        (nntp-wait-for process wait-for buffer decode))
        (t t)))))
 
@@ -564,7 +661,11 @@ It will prompt for a password."
   (save-excursion
     (set-buffer (process-buffer process))
     (goto-char (point-min))
-    (while (not (looking-at "[2345]"))
+    (while (or (not (memq (following-char) '(?2 ?3 ?4 ?5)))
+              (looking-at "480"))
+      (when (looking-at "480")
+       (erase-buffer)
+       (funcall nntp-authinfo-function))
       (nntp-accept-process-output process)
       (goto-char (point-min)))
     (prog1