[gnu.emacs.gnus] A better patch to nntp-retrieve-headers

mly@AI.MIT.EDU (Richard Mlynarik) (08/21/89)

Gnu's NNTP interface dies (goes into a loop) when it encounters an
(illegal) header of the form "Date:" (ie a date header with no actual
header content.)

A few weeks ago Rob Austein sent in a patch to make
nntp-retrieve-header not choke and die on header continuation lines.
The below patch shoudl also fix that problem.

This version should also run faster (and be a little more correct)
than the original...

(defun nntp-retrieve-headers (sequence)
  "Return list of article headers specified by SEQUENCE of article id.
The format of list is `([NUMBER SUBJECT FROM XREF LINES DATE MESSAGE-ID] ...)'.
Reader macros for the vector are defined as `nntp-header-FIELD'.
Writer macros for the vector are defined as `nntp-set-header-FIELD'.
News group must be selected before calling me."
  (save-excursion
    (set-buffer nntp-server-buffer)
    (erase-buffer)
    (let ((number (length sequence))
	  (last-point (point-min))
	  (received 0)
	  (count 0)
	  (headers ()))		;Result list.
      ;; Send HEAD command.
      (while sequence
	(nntp-send-strings-to-server "HEAD" (car sequence))
	(setq sequence (cdr sequence))
	(setq count (1+ count))
	;; Every 400 header requests we have to read stream in order
	;;  to avoid deadlock.
	(if (or (null sequence)		;All requests have been sent.
		(zerop (mod count nntp-maximum-request)))
	    (progn
	      (accept-process-output)
	      (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))
		;; If number of headers is greater than 100, give
		;;  informative messages.
		(and (> number nntp-large-newsgroup)
		     (zerop (mod received 20))
		     (message "NNTP: %d%% of headers received."
			      (/ (* received 100) number)))
		(nntp-accept-response)))))
      ;; Wait for text of last command.
      (goto-char (point-max))
      (re-search-backward "^[0-9]" nil t)
      (if (looking-at "^[23]")
	  (while (progn
		   (goto-char (- (point-max) 3))
		   (not (looking-at "^\\.\r$")))
	    (nntp-accept-response)))
      (if (> number nntp-large-newsgroup)
	  (message "NNTP: 100%% of headers received."))
      ;; Now all of replies are received.
      (setq received number)
      ;; Now all of replies are received.
      ;; First, delete unnecessary lines.
      (goto-char (point-min))
      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
        (replace-match " " t t))
      ;; Then examines replies.
      (goto-char (point-min))
      (while (not (eobp))
	(if (not (looking-at "^[23][0-9][0-9][ \t]+\\([0-9]+\\)[ \t]+\\(<[^>]+>\\)"))
            (forward-line 1)	;Skip invalid field (ex. Subject:abc)
          (let ((article 0)
                (subject nil)
                (message-id nil)
                (from nil)
                (xref nil)
                (lines 0)
                (date nil))
            (setq article (string-to-int (buffer-substring (match-beginning 1)
                                                           (match-end 1))))
            (setq message-id (buffer-substring (match-beginning 2)
                                               (match-end 2)))
            (forward-line 1)
            (while (and (not (eobp))
                        (not (memq (following-char) '(?2 ?3))))
              (if (looking-at "\\(From\\|Subject\\|Date\\|Lines\\|Xref\\):[ \t]+\\([^ \t\n]+.*\\)\r$")
                  (let ((s (buffer-substring (match-beginning 2)
                                             (match-end 2)))
                        (c (char-after (match-beginning 0))))
                    (cond ((char-equal c ?S)
                           (setq subject (if subject (concat subject "\n" s) s)))
                          ((char-equal c ?F)
                           (setq from (if from (concat from ", " s) s)))
                          ((char-equal c ?D)
                           (setq date (or date s)))
                          ((char-equal c ?L)
                           (setq lines (string-to-int s)))
                          ((char-equal c ?X)
                           (setq xref (if xref (concat xref " " s) s))))))
              (forward-line 1))
            (setq subject (or subject "(None)"))
            (setq from (or from "(Unknown User)"))
            (setq headers (cons (vector article subject from
                                        xref lines date message-id)
                                headers))))
	(setq received (1- received))
	(and (> number nntp-large-newsgroup)
	     (zerop (mod received 20))
	     (message "NNTP: Parsing headers... %d%%"
		      (/ (* received 100) number))))
      (if (> number nntp-large-newsgroup)
	  (message "NNTP: Parsing headers... done"))
      (nreverse headers))))