;;; -*- Mode:Common-Lisp; Package:NEWS; Base:10; Fonts:(CPTFONT HL12B HL12I MEDFNB) -*-


(defun 4EN-ARTICLE-HELP* ()
    
  (format t "~:|~%
Article Selction Commands:

<abort>              Abort out of the middle of reading an article.  The article will be marked as read.
<number>             Go to the numbered article.
c                    Catch up in this newsgroup; i.e., mark all articles as read.
f                    Post a followup article to this newsgroup.  If on a non-existent article such as \"End of newsgroup\"
                     then post an original article.
F                    Same as f but include the old article.
<meta-f>             Reselect the followup article buffer.
h,<help>             Help.
j                    Mark the article as read.
k                    Mark as read all articles with the same subject as the current article.
m                    Mark the current article as still unread.
n,<space>,<return>   Scan forward for the next unread article.
N                    Go to the next article.
^n                   Scan forward for the next article with the same subject, and make ^n default.
p, P                 Same as n, N only scan backwards.
<meta-p>             Print the current article on a selected printer.
q,<end>              Quit newsgroup.
^r                   Restart the current article.
r                    Reply through mail.
R                    Reply through mail including the current article.
s                    Save to a file.
S                    Save to a ZMACS buffer.
u                    Unsubscribe to this newsgroup.
v                    Restart the current article verbosely, displaying the entire header.
x                    Quit newsgroup restoring the unread article state to its state before entering this newsgroup.
/pattern             Scan forward for article containing pattern in the subject.
/pattern/h           Scan forward for article containing pattern in the header.
/pattern/r           Scan read articles also.  /pattern/rh will scan all headers of all articles.
#                    Display the newsgroup and current article number.
-                    Go to the previously displayed article.
^                    Go to the first article.
$                    Go to the last article (actually, one past the last article).
=                    List subjects of unread articles.
_                    List subjects of all articles.
<mouse-r>            General news menu.
")
  )


(defun 4EN-ARTICLE-SELECTION-LEVEL* (&optional (prompt-type t))
  "2Handle article level prompting, input, and output. * 2The prompt-type is T on a
normal call to this function, :LIST-SUBJECTS to list the subjects of all unread
articles,* 2or, LIST-ALL-SUBJECTS to list the subjects of all articles.*"

  (condition-case (cond-obj)

      (en-article-selection-level-1 prompt-type)
    (sys:abort
     (progn
       (en-close)
       (en-open nil)
       t))))


(defun 4EN-ARTICLE-SELECTION-LEVEL-1* (prompt-type)
  
  (let* (x y char (article-number "") (digit-mode-p nil) prompt (npq "npq") (subject-search-mode nil)
	 saved-articles-read-bitmap 
	(newsgroup-component (get-current-newsgroup)) (first-time t) (ctrl-n-subject nil) (/-string nil) (end-of-n nil)
	(saved-low-article-number (send newsgroup-component :low-article-number)))
    
    ;1;;We save the articles read bitmap because this way because of the chance that the background news daemon will extend*
    ;1;;the bitmap before we have a chance to copy the bits into the saved version.*
    (setf saved-articles-read-bitmap (make-array (length (send newsgroup-component :articles-read-bitmap)) :element-type 'bit
						 :initial-value 0))
    (loop for i from 0 to (1- (length saved-articles-read-bitmap)) do
	  (setf (aref saved-articles-read-bitmap i) (aref (send newsgroup-component :articles-read-bitmap) i)))

    ;1;;Make sure we are able to access the newsgroup.*
    (unless (en-group newsgroup-component)
      (return-from en-article-selection-level-1))
    
    (send newsgroup-component :initialize-current-article-number)
    (setf *start* (send newsgroup-component :current-article-number))
    (if *subject-search-mode* (setf subject-search-mode t))
    
    ;1;;Set the initial command.*
    (cond
      ((equal prompt-type :list-subjects)
       (setf char #\=))
      ((equal prompt-type :list-all-subjects)
       (setf char #\_))
      (t
       (setf char #\n)))
    
    (loop
      (cond
	;1;;Article number + return.  Select the article.*
	((and (char= char #\return) digit-mode-p)
	 (send newsgroup-component :update-current-article-number (parse-number article-number))
	 (send newsgroup-component :mark-article t)
	 (setf digit-mode-p nil)
	 (setf article-number "")
	 (cond
	   ((en-display-article t newsgroup-component)
	    (setf end-of-n nil)
	    (setf ctrl-n-subject (cons (get-header-field newsgroup-component
							 (send newsgroup-component :current-article-number) :subject)
				       (send newsgroup-component :current-article-number)))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   ;1;;Article does not exist.*
	   (t
	    (format t "~:|~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "Article ~a of ~a is not available.~2%What next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :newsgroup-string)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;Digit.  Append the digit to the article number string in preparation for redisplay.*
	((member char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) :test #'char=)
	 (setf article-number (string-append article-number (format nil "~c" char)))
	 (send *standard-output* :set-cursorpos x y)
	 (setf digit-mode-p t)
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;Rubout.*
	((char= char #\rubout)
	 (cond
	   (digit-mode-p
	    ;1;;Remove the digit from the article number string.*
	    (setf article-number (subseq article-number 0 (1- (length article-number))))
	    ;1;;Erase line to remove the previous digit from the display.*
	    (send *standard-output* :set-cursorpos x y)
	    (send *standard-output* :clear-eol)	
	    (send *standard-output* :set-cursorpos x y)
	    ;1;;If no more digits are left then we need to exit digit mode.*
	    (when (zerop (length article-number))
	      (setf digit-mode-p nil))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   ;1;;Error.  Can't press the rubout key at the beginning of a line.*
	   (t
	    (format t "~%Type h for help.~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;Error.  A non digit was entered while in digit mode.*
	(digit-mode-p
	 (format t "~%Type h for help.~%")
	 (setf digit-mode-p nil)
	 (setf article-number "")
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\c  Catch up in this newsgroup; i.e., mark all articles as read.*
	((char= char #\c)
	 (cond
	   ((y-or-n-p "Do you really want to mark everything as read?")
	    (send newsgroup-component :mark-all-articles t)
	    (format t "~:|~%End of newsgroup ~a~%" (send newsgroup-component :newsgroup-string))
	    (return nil))
	   (t
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\f  Submit a followup article.*
	;1;;#\F  Submit a followup article, and include the old article.*
	((member char '(#\f #\F))
	 (cond
	   ((not (equal *nntp-server-status* *server-ready-with-posting-code*))
	    (format t "~2%Posting is not permitted with your account.  Please check with your system adminstrator.")
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (en-f newsgroup-component (when (char= char #\F) t))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\m-f   Reselect the followup article buffer.*
	((char= char #\m-f)
	 (cond
	   ((zwei:find-buffer-named *default-postnews-buffer-name*)
	    (find-and-select-news-buffer *default-postnews-buffer-name*)
	    (en-post-prompt *default-postnews-buffer-name*)
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~2%No previous followup article found.  Use the f or F command.~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\h  Help.*
	((member char '(#\h #\help) :test #'char=)
	 (en-article-help)
	 (format t "~2%")
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\j  Mark the article as read.*
	((char= char #\j)
	 (send newsgroup-component :mark-article t)
	 (format t "~%Article ~a marked as read.~%" (send newsgroup-component :current-article-number))
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\k  Mark as read all articles with the same subject as the current article.*
	((char= char #\k)
	 (cond
	   ((article-selected-p newsgroup-component)
	    (format t "~%Searching...")
	    (en-k newsgroup-component)
	    (setf ctrl-n-subject nil)
	    (setf char #\space))
	   (t
	    (format t "~%Cannot delete null subject.~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\m  Mark the current article as still unread.*
	((char= char #\m)
	 (send newsgroup-component :mark-article nil)
	 (format t "~%Article ~a marked as still unread.~%" (send newsgroup-component :current-article-number))
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\n, #\space, #\return  Scan forward for the next unread article.*
	;1;;#\N  Scan for the next article.*
	;1;;#\c-n.  Scan forward for the next article with the same subject, and make <ctrl-n> default (subject*
	;1;;         search mode).*
	((member char '(#\space #\n #\return #\N #\c-n) :test #'char=)
	 (cond
	   ;1;;We are at the end of the newsgroup and there are no more unread articles.*
	   ((and (send newsgroup-component :end-of-newsgroup-p) (< (send newsgroup-component :unread-article-count) 1))
	    (format t "~:|~%End of newsgroup ~a~%" (send newsgroup-component :newsgroup-string))
	    (return nil))
	   
	   ;1;;Display the next article.  We will be at the end of the newsgroup if there isn't a next article.*
	   ((cond
	      ;1;;Ctrl-n mode wraps.  That is, if the article is not found from the current article to the end of the newsgroup*
	      ;1;;then we will start at the beginning and search to the end again.  If not found, then we will be positioned*
	      ;1;;at the end of the newsgroup and NIL we be returned.  If we find an article then display it and return T.*
	      ((or (char= char #\c-n) (and subject-search-mode (char= char #\space)))
	       (when (send newsgroup-component :end-of-newsgroup-p)
		 (send newsgroup-component :set-current-article-number *start-index*))
	       (setf end-of-n nil)
	       (setf subject-search-mode t)
	       (let (ret)
		 (format t "~%Searching")
		 (multiple-value-setq (ret ctrl-n-subject) (en-ctrl-n newsgroup-component ctrl-n-subject))
		 (cond
		   (ret
		    (en-display-article t newsgroup-component)
		    t)
		   (t
		    nil))))
	      ;1;;N or n does not wrap the first time through.  That is, if we get to the end of the newsgroup, NIL is returned*
	      ;1;;and this section is bypassed.  If we get here again then we will start at the beginning of the newsgroup*
	      ;1;;and display the next article.*
	      ((cond
		 ((send newsgroup-component :get-next-article-number (if (char= char #\N) t nil))
		  (setf end-of-n nil)
		  t)
		 (end-of-n
		  (setf end-of-n nil)
		  (send newsgroup-component :set-current-article-number *start-index*)
		  (send newsgroup-component :get-next-article-number (if (char= char #\N) t nil)))
		 (t
		  (setf end-of-n t)
		  nil))
	       (unless first-time (setf subject-search-mode nil))
	       (loop with count = 0
 		       until (en-display-article t newsgroup-component)
		       finally
		       (progn
			 (setf ctrl-n-subject (cons (get-header-field newsgroup-component
								(send newsgroup-component :current-article-number)
								:subject)
						    (send newsgroup-component :current-article-number)))
			 (return t))
		       do
		       (cond
			 ((zerop count)
			  (format t "~%Skipping unavailable article(s)"))
			 ((zerop (mod count 10))
			  (format t "...~d" count)))
		       (incf count)
		       (unless (send newsgroup-component :get-next-article-number (if (char= char #\N) t nil))
			 (setf ctrl-n-subject nil)
			 (return nil)))))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   
	   ;1;;If this is the first time this function has been called and there are no to read.*
	   ((and first-time
		 (send newsgroup-component :end-of-newsgroup-p)
		 (< (send newsgroup-component :unread-article-count) 1))
	    (format t "~:|~%End of newsgroup ~a.~2%" (send newsgroup-component :newsgroup-string))
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))	       
	    (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   
	   ;1;;We've scanned to the end of the newsgroup and there are still articles unread.*
	   ((> (send newsgroup-component :unread-article-count) 0)
	    (format t "~:|~%End of newsgroup ~a." (send newsgroup-component :newsgroup-string))
	    (if (> (send newsgroup-component :unread-article-count) 0)
		(format t "  (~d article~:p still unread)" (send newsgroup-component :unread-article-count)))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))	       
	    (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   
	   ;1;;All articles have been read, exit article selection mode.*
	   (t
	    (format t "~:|~%End of newsgroup ~a~%" (send newsgroup-component :newsgroup-string))
	    (return nil))))
	
	;1;;#\p.  Scan backward for the next unread article.*
	((char= char #\p)
	 (cond
	   ((send newsgroup-component :get-previous-article-number nil)
	    (en-display-article t newsgroup-component)
	    (setf end-of-n nil)
	    (setf ctrl-n-subject (cons (get-header-field newsgroup-component
							 (send newsgroup-component :current-article-number) :subject)
				       (send newsgroup-component :current-article-number)))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~%There are no articles prior to this one.~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))	    
	
	;1;;#\P.  Go to the previous article.*
	((char= char #\P)
	 (cond
	   ((send newsgroup-component :get-previous-article-number t)
	    (en-display-article t newsgroup-component)
	    (setf end-of-n nil)
	    (setf ctrl-n-subject (cons (get-header-field newsgroup-component
							 (send newsgroup-component :current-article-number) :subject)
				       (send newsgroup-component :current-article-number)))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~%There are no articles prior to this one.~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))

	;1;;#\M-p.  Print the current article.*
	((char= char #\m-p)
	 (cond
	   ((and (article-selected-p newsgroup-component) (en-print newsgroup-component))
	    (format t "~%Article queued for printing~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~%No article selected for printing.~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\q  Quit newsgroup.*
	((char= char #\q)
	 (format t "~:|~%")
	 (return nil))
	
	;1;;#\r   Reply through mail.*
	;1;;#\R   Reply through mail including the current article.*
	((member char '(#\r #\R))
	 (en-r newsgroup-component (when (char= char #\R) t))
	 (send *standard-output* :set-cursorpos x y)
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\S  Save to a buffername.*
	((char= char #\S)
	 (cond
	   ((send newsgroup-component :end-of-newsgroup-p)
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (let ((buffername (prompt-and-read :string-or-nil "~%Save into Buffer:  ")))
	      (when (and buffername (write-to-buffer-p buffername))
		(zwei:with-editor-stream (stream :buffer-name buffername)
		  (format t "~%Saving article into ~a..." buffername)
		  (en-display-article stream newsgroup-component)
		  (format t "Done")))
	      (format t "~%")
	      (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	      (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				   (send newsgroup-component :current-article-number)
				   (send newsgroup-component :high-article-number)
				   (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	      (setf char (en-prompt-and-read (string-append prompt article-number)))))))
	
	;1;;#\s  Save to a filename (in Unix mail format).*
	((char= char #\s)
	 (cond
	   ((send newsgroup-component :end-of-newsgroup-p)
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (let ((filename (prompt-and-read :string-or-nil "~%Save into Filename:  ")) append-p)
	      (when (or filename *default-save-pathname*)
		(if filename
		    (setf filename (fs:merge-pathname-defaults filename *default-save-pathname*))
		    (setf filename *default-save-pathname*))
		(condition-case (cond-obj)
		    (progn
		     (setf append-p (fs:probe-file filename))
		     (with-open-file (stream filename :direction :output :if-exists :append :if-does-not-exist :create
					     :error t)
		       (format t "~%~:[Saving~;Appending~] article into ~a..." append-p (send stream :pathname))
		       (format stream "From ~a  "
			       (if (null mail:*user-mail-address*) "unknown" mail:*user-mail-address*))
		       (multiple-value-bind (sec min hour date month year day)
			   (time:decode-universal-time (GET-UNIVERSAL-TIME))
			 (format stream "~A ~A ~2D ~2,48D:~2,48D:~2,48D ~D"
				 (time:day-of-the-week-string day :short)
				 (time:month-string month :short)
				 date hour min sec year))
		       (en-display-article stream newsgroup-component t)
		       (format stream "~2%")
		       (format t "Done")))
		  (error (format t "~%Can't save article.  ~a." cond-obj)))))
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\u  Unsubscribe to this newsgroup.*
	((char= char #\u)
	 (subscribe-newsgroup newsgroup-component nil)
	 (format t "~:|~%Unsubscribed to newsgroup ~a~%" (send newsgroup-component :newsgroup-string))
	 (return nil))
	
	;1;;#\v  Restart the current article verbosely, displaying the entire header.*
	((char= char #\v)
	 (cond
	   ((article-selected-p newsgroup-component)
	    (en-display-article t newsgroup-component t)
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))

	;1;;#\x  Quit restoring the unread article state to its state before entering this newsgroup.*
	((char= char #\x)
	 (loop for i from 0 to (1- (length saved-articles-read-bitmap)) do
	       (when (= (aref saved-articles-read-bitmap i) 0)
		 (send newsgroup-component :set-current-article-number (+ saved-low-article-number i))
		 (send newsgroup-component :mark-article nil)))
	 (format t "~:|~%")
	 (return nil))

	;1;;#\/  Scan forward for article containing pattern in the subject.*
	((char= char #\/)
	 (format t "/")
	 (let ((string (or (prompt-and-read :string-or-nil "") /-string)))
	   (cond
	     (string
	      (setf /-string string)
	      (format t "~%Searching for ~a" (subseq /-string 0 (position #\/ string :start 0)))
	      (cond
		((en-/ newsgroup-component string)
		 (en-display-article t newsgroup-component nil)
		 (setf ctrl-n-subject (cons (get-header-field newsgroup-component
							(send newsgroup-component :current-article-number) :subject)
				       (send newsgroup-component :current-article-number)))
		 (format t "~2%")
		 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		 (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				      (send newsgroup-component :current-article-number)
				      (send newsgroup-component :high-article-number)
				      (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		 (setf char (en-prompt-and-read (string-append prompt article-number))))
		(t
		 (format t "~2%Not Found.~%")
		 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		 (if (or (send newsgroup-component :end-of-newsgroup-p) (send newsgroup-component :start-of-newsgroup-p))
		    (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		     (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
					  (send newsgroup-component :current-article-number)
					  (send newsgroup-component :high-article-number)
					  (format nil "~@[^N~*~]~a" subject-search-mode npq))))
		 (setf char (en-prompt-and-read (string-append prompt article-number))))))
	     (t
	      (format t "~2%")
	      (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	      (if (or (send newsgroup-component :end-of-newsgroup-p) (send newsgroup-component :start-of-newsgroup-p))
		  (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		  (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				       (send newsgroup-component :current-article-number)
				       (send newsgroup-component :high-article-number)
				       (format nil "~@[^N~*~]~a" subject-search-mode npq))))
	      (setf char (en-prompt-and-read (string-append prompt article-number)))))))
	
	;1;;#\#  Print the newsgroup and current article number.*
	((char= char #\#)
	 (format t "~2%Newsgroup:  ~a.  Article number = ~a~2%" (send newsgroup-component :newsgroup-string)
		 (cond
		   ((send newsgroup-component :start-of-newsgroup-p)
		    "<beginning>")
		   ((send newsgroup-component :end-of-newsgroup-p)
		    "<end>")
		   (t
		    (send newsgroup-component :current-article-number))))
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))	       
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\-  Go to the previously displayed article.*
	((char= char #\-)
	 (cond
	   ((equal (send newsgroup-component :previous-article-number) *start-index*)
	    (setf char #\space))
	   (t
	    (let ((temp (send newsgroup-component :current-article-number)))
	      (send newsgroup-component :set-current-article-number (send newsgroup-component :previous-article-number))
	      (send newsgroup-component :set-previous-article-number temp)
	      (cond
		((send newsgroup-component :end-of-newsgroup-p)
		 (format t "~:|~%End of newsgroup ~a." (send newsgroup-component :newsgroup-string))
		 (if (> (send newsgroup-component :unread-article-count) 0)
		     (format t "  (~d article~:p still unread)" (send newsgroup-component :unread-article-count)))
		 (format t "~2%")
		 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))	       
		 (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		 (setf char (en-prompt-and-read (string-append prompt article-number))))
		(t
		 (en-display-article t newsgroup-component)
		 (setf end-of-n nil)
		 (setf ctrl-n-subject (cons (get-header-field newsgroup-component
							(send newsgroup-component :current-article-number) :subject)
				       (send newsgroup-component :current-article-number)))
		 (format t "~%")
		 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		 (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				      (send newsgroup-component :current-article-number)
				      (send newsgroup-component :high-article-number)
				      (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		 (setf char (en-prompt-and-read (string-append prompt article-number)))))))))
	
	;1;;#\^.  Go to the first unread article.*
	((char= char #\^)
	 (send newsgroup-component :initialize-current-article-number)
	 (cond
	   ((send newsgroup-component :get-next-article-number t)
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~:|~%End of newsgroup ~a~%" (send newsgroup-component :newsgroup-string))
	    (return nil))))
	
	;1;;#\$  Go to the last article (actually, one past the last article).*
	((char= char #\$)
	 (send newsgroup-component :set-previous-article-number (send newsgroup-component :current-article-number))
	 (send newsgroup-component :set-current-article-number *end-index*)
	 (format t "~:|~%End of newsgroup ~a." (send newsgroup-component :newsgroup-string))
	 (if (> (send newsgroup-component :unread-article-count) 0)
	     (format t "  (~d article~:p still unread)" (send newsgroup-component :unread-article-count)))
	 (format t "~2%")
	 (setf end-of-n t)
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))	       
	 (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	 (setf char (en-prompt-and-read (string-append prompt article-number))))
	
	;1;;#\=  List subjects.*
	((char= char #\=)
	 (let ((saved-current-article-number (send newsgroup-component :current-article-number))
	       (saved-previous-article-number (send newsgroup-component :previous-article-number)))
	   (send newsgroup-component :get-previous-article-number t)
	   (setf *start* (send newsgroup-component :current-article-number))
	   (loop
	     (format t "~:|~%Newsgroup:  ~a (~a unread articles)~%" (send newsgroup-component :newsgroup-string)
		     (send newsgroup-component :unread-article-count))
	     (cond
	       ((not (en-list-subjects nil))
		(send newsgroup-component :set-current-article-number saved-current-article-number)
		(send newsgroup-component :set-previous-article-number saved-previous-article-number)
		(format t "~2%")
		(multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		(if (<= (send newsgroup-component :low-article-number)
			saved-current-article-number
			(send newsgroup-component :high-article-number))
		    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
					 (send newsgroup-component :current-article-number)
					 (send newsgroup-component :high-article-number)
					 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		    (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq))))
		(setf char (en-prompt-and-read (string-append prompt article-number)))
		(return))
	       (t
		(format t "~%")
		(multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		(setf prompt (format nil "Press the space key to continue the list "))
		(setf char (en-prompt-and-read (string-append prompt article-number)))
		(cond
		  ((char= char #\space)
		   (setf *start* (send newsgroup-component :current-article-number)))
		  (t
		   (send newsgroup-component :set-current-article-number saved-current-article-number)
		   (send newsgroup-component :set-previous-article-number saved-previous-article-number)
		   (return))))))))
	
	;1;;#\_  List subjects of all articles (read and unread).*
	((char= char #\_)
	 (let ((saved-current-article-number (send newsgroup-component :current-article-number))
	       (saved-previous-article-number (send newsgroup-component :previous-article-number)))
	   (send newsgroup-component :get-previous-article-number t)
	   (setf *start* (send newsgroup-component :current-article-number))
	   (loop
	     (format t "~:|~%Newsgroup:  ~a~%" (send newsgroup-component :newsgroup-string))
	     (cond
	       ((not (en-list-subjects t)) 
		(send newsgroup-component :set-current-article-number saved-current-article-number)
		(send newsgroup-component :set-previous-article-number saved-previous-article-number)
		(format t "~2%")
		(multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		(if (<= (send newsgroup-component :low-article-number)
			saved-current-article-number
			(send newsgroup-component :high-article-number))
		    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
					 (send newsgroup-component :current-article-number)
					 (send newsgroup-component :high-article-number)
					 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
		    (setf prompt (format nil "What next? [~a]" (format nil "~@[^N~*~]~a" subject-search-mode npq))))
		(setf char (en-prompt-and-read (string-append prompt article-number)))
		(return))
	       (t
		(format t "~%")
		(multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
		(setf prompt (format nil "Press the space key to continue the list "))
		(setf char (en-prompt-and-read (string-append prompt article-number)))
		(cond
		  ((char= char #\space)
		   (setf *start* (send newsgroup-component :current-article-number)))
		  (t
		   (send newsgroup-component :set-current-article-number saved-current-article-number)
		   (send newsgroup-component :set-previous-article-number saved-previous-article-number)
		   (return))))))))
	
	;1;;#\c-r  Restart the current article.*
	((char= char #\c-r)
	 (cond
	   ((article-selected-p newsgroup-component)
	    (en-display-article t newsgroup-component)
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf prompt (format nil "End of Article ~a (of ~a)--what next? [~a]"
				 (send newsgroup-component :current-article-number)
				 (send newsgroup-component :high-article-number)
				 (format nil "~@[^N~*~]~a" subject-search-mode npq)))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (t
	    (format t "~%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\mouse-r  Configuration commands.*
	((char= char #\mouse-r)
	 (case (en-mouse-r)
	   ('t
	    (return))
	   (':abort
	    (send *standard-output* :set-cursorpos x y)
	    (setf char (en-prompt-and-read (string-append prompt article-number))))
	   (otherwise
	    ;1;;Make sure we are able to access the newsgroup.*
	    (unless (en-group newsgroup-component)
	      (return-from en-article-selection-level-1))
	    (format t "~2%")
	    (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	    (setf char (en-prompt-and-read (string-append prompt article-number))))))
	
	;1;;#\END  Bury this window.*
	((char= char #\END)
	 (return))
	
	;1;;Error.  Invalid command.*
	(t
	 (format t "~%Type h for help.~%")
	 (multiple-value-setq (x y) (send *standard-output* :read-cursorpos))
	 (setf char (en-prompt-and-read (string-append prompt article-number)))))
      	 
      (setf first-time nil))))
