View Javadoc

1   /*
2    * Copyright 2001-2005 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.net.nntp;
17  
18  import java.io.BufferedReader;
19  import java.io.BufferedWriter;
20  import java.io.IOException;
21  import java.io.InputStreamReader;
22  import java.io.OutputStreamWriter;
23  import org.apache.commons.net.MalformedServerReplyException;
24  import org.apache.commons.net.ProtocolCommandSupport;
25  import org.apache.commons.net.ProtocolCommandListener;
26  import org.apache.commons.net.SocketClient;
27  
28  /***
29   * The NNTP class is not meant to be used by itself and is provided
30   * only so that you may easily implement your own NNTP client if
31   * you so desire.  If you have no need to perform your own implementation,
32   * you should use {@link org.apache.commons.net.nntp.NNTPClient}.
33   * The NNTP class is made public to provide access to various NNTP constants
34   * and to make it easier for adventurous programmers (or those with special
35   * needs) to interact with the NNTP protocol and implement their own clients.
36   * A set of methods with names corresponding to the NNTP command names are
37   * provided to facilitate this interaction.
38   * <p>
39   * You should keep in mind that the NNTP server may choose to prematurely
40   * close a connection if the client has been idle for longer than a
41   * given time period or if the server is being shutdown by the operator or
42   * some other reason.  The NNTP class will detect a
43   * premature NNTP server connection closing when it receives a
44   * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED }
45   *  response to a command.
46   * When that occurs, the NNTP class method encountering that reply will throw
47   * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
48   * .
49   * <code>NNTPConectionClosedException</code>
50   * is a subclass of <code> IOException </code> and therefore need not be
51   * caught separately, but if you are going to catch it separately, its
52   * catch block must appear before the more general <code> IOException </code>
53   * catch block.  When you encounter an
54   * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
55   * , you must disconnect the connection with
56   * {@link #disconnect  disconnect() } to properly clean up the
57   * system resources used by NNTP.  Before disconnecting, you may check the
58   * last reply code and text with
59   * {@link #getReplyCode  getReplyCode } and
60   * {@link #getReplyString  getReplyString }.
61   * <p>
62   * Rather than list it separately for each method, we mention here that
63   * every method communicating with the server and throwing an IOException
64   * can also throw a
65   * {@link org.apache.commons.net.MalformedServerReplyException}
66   * , which is a subclass
67   * of IOException.  A MalformedServerReplyException will be thrown when
68   * the reply received from the server deviates enough from the protocol
69   * specification that it cannot be interpreted in a useful manner despite
70   * attempts to be as lenient as possible.
71   * <p>
72   * <p>
73   * @author Daniel F. Savarese
74   * @author Rory Winston
75   * @author Ted Wise
76   * @see NNTPClient
77   * @see NNTPConnectionClosedException
78   * @see org.apache.commons.net.MalformedServerReplyException
79   ***/
80  
81  public class NNTP extends SocketClient
82  {
83      /*** The default NNTP port.  Its value is 119 according to RFC 977. ***/
84      public static final int DEFAULT_PORT = 119;
85  
86      // We have to ensure that the protocol communication is in ASCII
87      // but we use ISO-8859-1 just in case 8-bit characters cross
88      // the wire.
89      private static final String __DEFAULT_ENCODING = "ISO-8859-1";
90  
91      private StringBuffer __commandBuffer;
92  
93      boolean _isAllowedToPost;
94      int _replyCode;
95      String _replyString;
96  
97      /**
98       * Wraps {@link SocketClient#_input_}
99       * to communicate with server.  Initialized by {@link #_connectAction_}.
100      * All server reads should be done through this variable.
101      */
102     protected BufferedReader _reader_;
103 
104     /**
105      * Wraps {@link SocketClient#_output_}
106      * to communicate with server.  Initialized by {@link #_connectAction_}.
107      * All server reads should be done through this variable.
108      */
109     protected BufferedWriter _writer_;
110 
111     /***
112      * A ProtocolCommandSupport object used to manage the registering of
113      * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
114      ***/
115     protected ProtocolCommandSupport _commandSupport_;
116 
117     /***
118      * The default NNTP constructor.  Sets the default port to
119      * <code>DEFAULT_PORT</code> and initializes internal data structures
120      * for saving NNTP reply information.
121      ***/
122     public NNTP()
123     {
124         setDefaultPort(DEFAULT_PORT);
125         __commandBuffer = new StringBuffer();
126         _replyString = null;
127         _reader_ = null;
128         _writer_ = null;
129         _isAllowedToPost = false;
130         _commandSupport_ = new ProtocolCommandSupport(this);
131     }
132 
133     private void __getReply() throws IOException
134     {
135         _replyString = _reader_.readLine();
136 
137         if (_replyString == null)
138             throw new NNTPConnectionClosedException(
139                 "Connection closed without indication.");
140 
141         // In case we run into an anomaly we don't want fatal index exceptions
142         // to be thrown.
143         if (_replyString.length() < 3)
144             throw new MalformedServerReplyException(
145                 "Truncated server reply: " + _replyString);
146         try
147         {
148             _replyCode = Integer.parseInt(_replyString.substring(0, 3));
149         }
150         catch (NumberFormatException e)
151         {
152             throw new MalformedServerReplyException(
153                 "Could not parse response code.\nServer Reply: " + _replyString);
154         }
155 
156         if (_commandSupport_.getListenerCount() > 0)
157             _commandSupport_.fireReplyReceived(_replyCode, _replyString +
158                                                SocketClient.NETASCII_EOL);
159 
160         if (_replyCode == NNTPReply.SERVICE_DISCONTINUED)
161             throw new NNTPConnectionClosedException(
162                 "NNTP response 400 received.  Server closed connection.");
163     }
164 
165     /***
166      * Initiates control connections and gets initial reply, determining
167      * if the client is allowed to post to the server.  Initializes
168      * {@link #_reader_} and {@link #_writer_} to wrap
169      * {@link SocketClient#_input_} and {@link SocketClient#_output_}.
170      ***/
171     protected void _connectAction_() throws IOException
172     {
173         super._connectAction_();
174         _reader_ =
175             new BufferedReader(new InputStreamReader(_input_,
176                                                      __DEFAULT_ENCODING));
177         _writer_ =
178             new BufferedWriter(new OutputStreamWriter(_output_,
179                                                       __DEFAULT_ENCODING));
180         __getReply();
181 
182         _isAllowedToPost = (_replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED);
183     }
184 
185     /***
186      * Adds a ProtocolCommandListener.  Delegates this task to
187      * {@link #_commandSupport_  _commandSupport_ }.
188      * <p>
189      * @param listener  The ProtocolCommandListener to add.
190      ***/
191     public void addProtocolCommandListener(ProtocolCommandListener listener)
192     {
193         _commandSupport_.addProtocolCommandListener(listener);
194     }
195 
196     /***
197      * Removes a ProtocolCommandListener.  Delegates this task to
198      * {@link #_commandSupport_  _commandSupport_ }.
199      * <p>
200      * @param listener  The ProtocolCommandListener to remove.
201      ***/
202     public void removeProtocolCommandListener(ProtocolCommandListener listener)
203     {
204         _commandSupport_.removeProtocolCommandListener(listener);
205     }
206 
207     /***
208      * Closes the connection to the NNTP server and sets to null
209      * some internal data so that the memory may be reclaimed by the
210      * garbage collector.  The reply text and code information from the
211      * last command is voided so that the memory it used may be reclaimed.
212      * <p>
213      * @exception IOException If an error occurs while disconnecting.
214      ***/
215     public void disconnect() throws IOException
216     {
217         super.disconnect();
218         _reader_ = null;
219         _writer_ = null;
220         _replyString = null;
221         _isAllowedToPost = false;
222     }
223 
224 
225     /***
226      * Indicates whether or not the client is allowed to post articles to
227      * the server it is currently connected to.
228      * <p>
229      * @return True if the client can post articles to the server, false
230      *         otherwise.
231      ***/
232     public boolean isAllowedToPost()
233     {
234         return _isAllowedToPost;
235     }
236 
237 
238     /***
239      * Sends an NNTP command to the server, waits for a reply and returns the
240      * numerical response code.  After invocation, for more detailed
241      * information, the actual reply text can be accessed by calling
242      * {@link #getReplyString  getReplyString }.
243      * <p>
244      * @param command  The text representation of the  NNTP command to send.
245      * @param args The arguments to the NNTP command.  If this parameter is
246      *             set to null, then the command is sent with no argument.
247      * @return The integer value of the NNTP reply code returned by the server
248      *         in response to the command.
249      * @exception NNTPConnectionClosedException
250      *      If the NNTP server prematurely closes the connection as a result
251      *      of the client being idle or some other reason causing the server
252      *      to send NNTP reply code 400.  This exception may be caught either
253      *      as an IOException or independently as itself.
254      * @exception IOException  If an I/O error occurs while either sending the
255      *      command or receiving the server reply.
256      ***/
257     public int sendCommand(String command, String args) throws IOException
258     {
259         String message;
260 
261         __commandBuffer.setLength(0);
262         __commandBuffer.append(command);
263 
264         if (args != null)
265         {
266             __commandBuffer.append(' ');
267             __commandBuffer.append(args);
268         }
269         __commandBuffer.append(SocketClient.NETASCII_EOL);
270 
271         _writer_.write(message = __commandBuffer.toString());
272         _writer_.flush();
273 
274         if (_commandSupport_.getListenerCount() > 0)
275             _commandSupport_.fireCommandSent(command, message);
276 
277         __getReply();
278         return _replyCode;
279     }
280 
281 
282     /***
283      * Sends an NNTP command to the server, waits for a reply and returns the
284      * numerical response code.  After invocation, for more detailed
285      * information, the actual reply text can be accessed by calling
286      * {@link #getReplyString  getReplyString }.
287      * <p>
288      * @param command  The NNTPCommand constant corresponding to the NNTP command
289      *                 to send.
290      * @param args The arguments to the NNTP command.  If this parameter is
291      *             set to null, then the command is sent with no argument.
292      * @return The integer value of the NNTP reply code returned by the server
293      *         in response to the command.
294      *         in response to the command.
295      * @exception NNTPConnectionClosedException
296      *      If the NNTP server prematurely closes the connection as a result
297      *      of the client being idle or some other reason causing the server
298      *      to send NNTP reply code 400.  This exception may be caught either
299      *      as an IOException or independently as itself.
300      * @exception IOException  If an I/O error occurs while either sending the
301      *      command or receiving the server reply.
302      ***/
303     public int sendCommand(int command, String args) throws IOException
304     {
305         return sendCommand(NNTPCommand._commands[command], args);
306     }
307 
308 
309     /***
310      * Sends an NNTP command with no arguments to the server, waits for a
311      * reply and returns the numerical response code.  After invocation, for
312      * more detailed information, the actual reply text can be accessed by
313      * calling {@link #getReplyString  getReplyString }.
314      * <p>
315      * @param command  The text representation of the  NNTP command to send.
316      * @return The integer value of the NNTP reply code returned by the server
317      *         in response to the command.
318      *         in response to the command.
319      * @exception NNTPConnectionClosedException
320      *      If the NNTP server prematurely closes the connection as a result
321      *      of the client being idle or some other reason causing the server
322      *      to send NNTP reply code 400.  This exception may be caught either
323      *      as an IOException or independently as itself.
324      * @exception IOException  If an I/O error occurs while either sending the
325      *      command or receiving the server reply.
326      ***/
327     public int sendCommand(String command) throws IOException
328     {
329         return sendCommand(command, null);
330     }
331 
332 
333     /***
334      * Sends an NNTP command with no arguments to the server, waits for a
335      * reply and returns the numerical response code.  After invocation, for
336      * more detailed information, the actual reply text can be accessed by
337      * calling {@link #getReplyString  getReplyString }.
338      * <p>
339      * @param command  The NNTPCommand constant corresponding to the NNTP command
340      *                 to send.
341      * @return The integer value of the NNTP reply code returned by the server
342      *         in response to the command.
343      *         in response to the command.
344      * @exception NNTPConnectionClosedException
345      *      If the NNTP server prematurely closes the connection as a result
346      *      of the client being idle or some other reason causing the server
347      *      to send NNTP reply code 400.  This exception may be caught either
348      *      as an IOException or independently as itself.
349      * @exception IOException  If an I/O error occurs while either sending the
350      *      command or receiving the server reply.
351      ***/
352     public int sendCommand(int command) throws IOException
353     {
354         return sendCommand(command, null);
355     }
356 
357 
358     /***
359      * Returns the integer value of the reply code of the last NNTP reply.
360      * You will usually only use this method after you connect to the
361      * NNTP server to check that the connection was successful since
362      * <code> connect </code> is of type void.
363      * <p>
364      * @return The integer value of the reply code of the last NNTP reply.
365      ***/
366     public int getReplyCode()
367     {
368         return _replyCode;
369     }
370 
371     /***
372      * Fetches a reply from the NNTP server and returns the integer reply
373      * code.  After calling this method, the actual reply text can be accessed
374      * from {@link #getReplyString  getReplyString }.  Only use this
375      * method if you are implementing your own NNTP client or if you need to
376      * fetch a secondary response from the NNTP server.
377      * <p>
378      * @return The integer value of the reply code of the fetched NNTP reply.
379      *         in response to the command.
380      * @exception NNTPConnectionClosedException
381      *      If the NNTP server prematurely closes the connection as a result
382      *      of the client being idle or some other reason causing the server
383      *      to send NNTP reply code 400.  This exception may be caught either
384      *      as an IOException or independently as itself.
385      * @exception IOException  If an I/O error occurs while
386      *      receiving the server reply.
387      ***/
388     public int getReply() throws IOException
389     {
390         __getReply();
391         return _replyCode;
392     }
393 
394 
395     /***
396      * Returns the entire text of the last NNTP server response exactly
397      * as it was received, not including the end of line marker.
398      * <p>
399      * @return The entire text from the last NNTP response as a String.
400      ***/
401     public String getReplyString()
402     {
403         return _replyString;
404     }
405 
406 
407     /***
408      * A convenience method to send the NNTP ARTICLE command to the server,
409      * receive the initial reply, and return the reply code.
410      * <p>
411      * @param messageId  The message identifier of the requested article,
412      *                   including the encapsulating &lt and &gt characters.
413      * @return The reply code received from the server.
414      * @exception NNTPConnectionClosedException
415      *      If the NNTP server prematurely closes the connection as a result
416      *      of the client being idle or some other reason causing the server
417      *      to send NNTP reply code 400.  This exception may be caught either
418      *      as an IOException or independently as itself.
419      * @exception IOException  If an I/O error occurs while either sending the
420      *      command or receiving the server reply.
421      ***/
422     public int article(String messageId) throws IOException
423     {
424         return sendCommand(NNTPCommand.ARTICLE, messageId);
425     }
426 
427     /***
428      * A convenience method to send the NNTP ARTICLE command to the server,
429      * receive the initial reply, and return the reply code.
430      * <p>
431      * @param articleNumber The number of the article to request from the
432      *                      currently selected newsgroup.
433      * @return The reply code received from the server.
434      * @exception NNTPConnectionClosedException
435      *      If the NNTP server prematurely closes the connection as a result
436      *      of the client being idle or some other reason causing the server
437      *      to send NNTP reply code 400.  This exception may be caught either
438      *      as an IOException or independently as itself.
439      * @exception IOException  If an I/O error occurs while either sending the
440      *      command or receiving the server reply.
441      ***/
442     public int article(int articleNumber) throws IOException
443     {
444         return sendCommand(NNTPCommand.ARTICLE, Integer.toString(articleNumber));
445     }
446 
447     /***
448      * A convenience method to send the NNTP ARTICLE command to the server,
449      * receive the initial reply, and return the reply code.
450      * <p>
451      * @return The reply code received from the server.
452      * @exception NNTPConnectionClosedException
453      *      If the NNTP server prematurely closes the connection as a result
454      *      of the client being idle or some other reason causing the server
455      *      to send NNTP reply code 400.  This exception may be caught either
456      *      as an IOException or independently as itself.
457      * @exception IOException  If an I/O error occurs while either sending the
458      *      command or receiving the server reply.
459      ***/
460     public int article() throws IOException
461     {
462         return sendCommand(NNTPCommand.ARTICLE);
463     }
464 
465 
466 
467     /***
468      * A convenience method to send the NNTP BODY command to the server,
469      * receive the initial reply, and return the reply code.
470      * <p>
471      * @param messageId  The message identifier of the requested article,
472      *                   including the encapsulating &lt and &gt characters.
473      * @return The reply code received from the server.
474      * @exception NNTPConnectionClosedException
475      *      If the NNTP server prematurely closes the connection as a result
476      *      of the client being idle or some other reason causing the server
477      *      to send NNTP reply code 400.  This exception may be caught either
478      *      as an IOException or independently as itself.
479      * @exception IOException  If an I/O error occurs while either sending the
480      *      command or receiving the server reply.
481      ***/
482     public int body(String messageId) throws IOException
483     {
484         return sendCommand(NNTPCommand.BODY, messageId);
485     }
486 
487     /***
488      * A convenience method to send the NNTP BODY command to the server,
489      * receive the initial reply, and return the reply code.
490      * <p>
491      * @param articleNumber The number of the article to request from the
492      *                      currently selected newsgroup.
493      * @return The reply code received from the server.
494      * @exception NNTPConnectionClosedException
495      *      If the NNTP server prematurely closes the connection as a result
496      *      of the client being idle or some other reason causing the server
497      *      to send NNTP reply code 400.  This exception may be caught either
498      *      as an IOException or independently as itself.
499      * @exception IOException  If an I/O error occurs while either sending the
500      *      command or receiving the server reply.
501      ***/
502     public int body(int articleNumber) throws IOException
503     {
504         return sendCommand(NNTPCommand.BODY, Integer.toString(articleNumber));
505     }
506 
507     /***
508      * A convenience method to send the NNTP BODY command to the server,
509      * receive the initial reply, and return the reply code.
510      * <p>
511      * @return The reply code received from the server.
512      * @exception NNTPConnectionClosedException
513      *      If the NNTP server prematurely closes the connection as a result
514      *      of the client being idle or some other reason causing the server
515      *      to send NNTP reply code 400.  This exception may be caught either
516      *      as an IOException or independently as itself.
517      * @exception IOException  If an I/O error occurs while either sending the
518      *      command or receiving the server reply.
519      ***/
520     public int body() throws IOException
521     {
522         return sendCommand(NNTPCommand.BODY);
523     }
524 
525 
526 
527     /***
528      * A convenience method to send the NNTP HEAD command to the server,
529      * receive the initial reply, and return the reply code.
530      * <p>
531      * @param messageId  The message identifier of the requested article,
532      *                   including the encapsulating &lt and &gt characters.
533      * @return The reply code received from the server.
534      * @exception NNTPConnectionClosedException
535      *      If the NNTP server prematurely closes the connection as a result
536      *      of the client being idle or some other reason causing the server
537      *      to send NNTP reply code 400.  This exception may be caught either
538      *      as an IOException or independently as itself.
539      * @exception IOException  If an I/O error occurs while either sending the
540      *      command or receiving the server reply.
541      ***/
542     public int head(String messageId) throws IOException
543     {
544         return sendCommand(NNTPCommand.HEAD, messageId);
545     }
546 
547     /***
548      * A convenience method to send the NNTP HEAD command to the server,
549      * receive the initial reply, and return the reply code.
550      * <p>
551      * @param articleNumber The number of the article to request from the
552      *                      currently selected newsgroup.
553      * @return The reply code received from the server.
554      * @exception NNTPConnectionClosedException
555      *      If the NNTP server prematurely closes the connection as a result
556      *      of the client being idle or some other reason causing the server
557      *      to send NNTP reply code 400.  This exception may be caught either
558      *      as an IOException or independently as itself.
559      * @exception IOException  If an I/O error occurs while either sending the
560      *      command or receiving the server reply.
561      ***/
562     public int head(int articleNumber) throws IOException
563     {
564         return sendCommand(NNTPCommand.HEAD, Integer.toString(articleNumber));
565     }
566 
567     /***
568      * A convenience method to send the NNTP HEAD command to the server,
569      * receive the initial reply, and return the reply code.
570      * <p>
571      * @return The reply code received from the server.
572      * @exception NNTPConnectionClosedException
573      *      If the NNTP server prematurely closes the connection as a result
574      *      of the client being idle or some other reason causing the server
575      *      to send NNTP reply code 400.  This exception may be caught either
576      *      as an IOException or independently as itself.
577      * @exception IOException  If an I/O error occurs while either sending the
578      *      command or receiving the server reply.
579      ***/
580     public int head() throws IOException
581     {
582         return sendCommand(NNTPCommand.HEAD);
583     }
584 
585 
586 
587     /***
588      * A convenience method to send the NNTP STAT command to the server,
589      * receive the initial reply, and return the reply code.
590      * <p>
591      * @param messageId  The message identifier of the requested article,
592      *                   including the encapsulating &lt and &gt characters.
593      * @return The reply code received from the server.
594      * @exception NNTPConnectionClosedException
595      *      If the NNTP server prematurely closes the connection as a result
596      *      of the client being idle or some other reason causing the server
597      *      to send NNTP reply code 400.  This exception may be caught either
598      *      as an IOException or independently as itself.
599      * @exception IOException  If an I/O error occurs while either sending the
600      *      command or receiving the server reply.
601      ***/
602     public int stat(String messageId) throws IOException
603     {
604         return sendCommand(NNTPCommand.STAT, messageId);
605     }
606 
607     /***
608      * A convenience method to send the NNTP STAT command to the server,
609      * receive the initial reply, and return the reply code.
610      * <p>
611      * @param articleNumber The number of the article to request from the
612      *                      currently selected newsgroup.
613      * @return The reply code received from the server.
614      * @exception NNTPConnectionClosedException
615      *      If the NNTP server prematurely closes the connection as a result
616      *      of the client being idle or some other reason causing the server
617      *      to send NNTP reply code 400.  This exception may be caught either
618      *      as an IOException or independently as itself.
619      * @exception IOException  If an I/O error occurs while either sending the
620      *      command or receiving the server reply.
621      ***/
622     public int stat(int articleNumber) throws IOException
623     {
624         return sendCommand(NNTPCommand.STAT, Integer.toString(articleNumber));
625     }
626 
627     /***
628      * A convenience method to send the NNTP STAT command to the server,
629      * receive the initial reply, and return the reply code.
630      * <p>
631      * @return The reply code received from the server.
632      * @exception NNTPConnectionClosedException
633      *      If the NNTP server prematurely closes the connection as a result
634      *      of the client being idle or some other reason causing the server
635      *      to send NNTP reply code 400.  This exception may be caught either
636      *      as an IOException or independently as itself.
637      * @exception IOException  If an I/O error occurs while either sending the
638      *      command or receiving the server reply.
639      ***/
640     public int stat() throws IOException
641     {
642         return sendCommand(NNTPCommand.STAT);
643     }
644 
645 
646     /***
647      * A convenience method to send the NNTP GROUP command to the server,
648      * receive the reply, and return the reply code.
649      * <p>
650      * @param newsgroup  The name of the newsgroup to select.
651      * @return The reply code received from the server.
652      * @exception NNTPConnectionClosedException
653      *      If the NNTP server prematurely closes the connection as a result
654      *      of the client being idle or some other reason causing the server
655      *      to send NNTP reply code 400.  This exception may be caught either
656      *      as an IOException or independently as itself.
657      * @exception IOException  If an I/O error occurs while either sending the
658      *      command or receiving the server reply.
659      ***/
660     public int group(String newsgroup) throws IOException
661     {
662         return sendCommand(NNTPCommand.GROUP, newsgroup);
663     }
664 
665 
666     /***
667      * A convenience method to send the NNTP HELP command to the server,
668      * receive the reply, and return the reply code.
669      * <p>
670      * @return The reply code received from the server.
671      * @exception NNTPConnectionClosedException
672      *      If the NNTP server prematurely closes the connection as a result
673      *      of the client being idle or some other reason causing the server
674      *      to send NNTP reply code 400.  This exception may be caught either
675      *      as an IOException or independently as itself.
676      * @exception IOException  If an I/O error occurs while either sending the
677      *      command or receiving the server reply.
678      ***/
679     public int help() throws IOException
680     {
681         return sendCommand(NNTPCommand.HELP);
682     }
683 
684 
685     /***
686      * A convenience method to send the NNTP IHAVE command to the server,
687      * receive the reply, and return the reply code.
688      * <p>
689      * @param messageId  The article identifier,
690      *                   including the encapsulating &lt and &gt characters.
691      * @return The reply code received from the server.
692      * @exception NNTPConnectionClosedException
693      *      If the NNTP server prematurely closes the connection as a result
694      *      of the client being idle or some other reason causing the server
695      *      to send NNTP reply code 400.  This exception may be caught either
696      *      as an IOException or independently as itself.
697      * @exception IOException  If an I/O error occurs while either sending the
698      *      command or receiving the server reply.
699      ***/
700     public int ihave(String messageId) throws IOException
701     {
702         return sendCommand(NNTPCommand.IHAVE, messageId);
703     }
704 
705 
706     /***
707      * A convenience method to send the NNTP LAST command to the server,
708      * receive the reply, and return the reply code.
709      * <p>
710      * @return The reply code received from the server.
711      * @exception NNTPConnectionClosedException
712      *      If the NNTP server prematurely closes the connection as a result
713      *      of the client being idle or some other reason causing the server
714      *      to send NNTP reply code 400.  This exception may be caught either
715      *      as an IOException or independently as itself.
716      * @exception IOException  If an I/O error occurs while either sending the
717      *      command or receiving the server reply.
718      ***/
719     public int last() throws IOException
720     {
721         return sendCommand(NNTPCommand.LAST);
722     }
723 
724 
725 
726     /***
727      * A convenience method to send the NNTP LIST command to the server,
728      * receive the reply, and return the reply code.
729      * <p>
730      * @return The reply code received from the server.
731      * @exception NNTPConnectionClosedException
732      *      If the NNTP server prematurely closes the connection as a result
733      *      of the client being idle or some other reason causing the server
734      *      to send NNTP reply code 400.  This exception may be caught either
735      *      as an IOException or independently as itself.
736      * @exception IOException  If an I/O error occurs while either sending the
737      *      command or receiving the server reply.
738      ***/
739     public int list() throws IOException
740     {
741         return sendCommand(NNTPCommand.LIST);
742     }
743 
744 
745 
746     /***
747      * A convenience method to send the NNTP NEXT command to the server,
748      * receive the reply, and return the reply code.
749      * <p>
750      * @return The reply code received from the server.
751      * @exception NNTPConnectionClosedException
752      *      If the NNTP server prematurely closes the connection as a result
753      *      of the client being idle or some other reason causing the server
754      *      to send NNTP reply code 400.  This exception may be caught either
755      *      as an IOException or independently as itself.
756      * @exception IOException  If an I/O error occurs while either sending the
757      *      command or receiving the server reply.
758      ***/
759     public int next() throws IOException
760     {
761         return sendCommand(NNTPCommand.NEXT);
762     }
763 
764 
765     /***
766      * A convenience method to send the NNTP NEWGROUPS command to the server,
767      * receive the reply, and return the reply code.
768      * <p>
769      * @param date The date after which to check for new groups.
770      *             Date format is YYMMDD
771      * @param time The time after which to check for new groups.
772      *             Time format is HHMMSS using a 24-hour clock.
773      * @param GMT  True if the time is in GMT, false if local server time.
774      * @param distributions  Comma-separated distribution list to check for
775      *            new groups. Set to null if no distributions.
776      * @return The reply code received from the server.
777      * @exception NNTPConnectionClosedException
778      *      If the NNTP server prematurely closes the connection as a result
779      *      of the client being idle or some other reason causing the server
780      *      to send NNTP reply code 400.  This exception may be caught either
781      *      as an IOException or independently as itself.
782      * @exception IOException  If an I/O error occurs while either sending the
783      *      command or receiving the server reply.
784      ***/
785     public int newgroups(String date, String time, boolean GMT,
786                          String distributions) throws IOException
787     {
788         StringBuffer buffer = new StringBuffer();
789 
790         buffer.append(date);
791         buffer.append(' ');
792         buffer.append(time);
793 
794         if (GMT)
795         {
796             buffer.append(' ');
797             buffer.append("GMT");
798         }
799 
800         if (distributions != null)
801         {
802             buffer.append(" <");
803             buffer.append(distributions);
804             buffer.append('>');
805         }
806 
807         return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
808     }
809 
810 
811     /***
812      * A convenience method to send the NNTP NEWGROUPS command to the server,
813      * receive the reply, and return the reply code.
814      * <p>
815      * @param newsgroups A comma-separated list of newsgroups to check for new
816      *             news.
817      * @param date The date after which to check for new news.
818      *             Date format is YYMMDD
819      * @param time The time after which to check for new news.
820      *             Time format is HHMMSS using a 24-hour clock.
821      * @param GMT  True if the time is in GMT, false if local server time.
822      * @param distributions  Comma-separated distribution list to check for
823      *            new news. Set to null if no distributions.
824      * @return The reply code received from the server.
825      * @exception NNTPConnectionClosedException
826      *      If the NNTP server prematurely closes the connection as a result
827      *      of the client being idle or some other reason causing the server
828      *      to send NNTP reply code 400.  This exception may be caught either
829      *      as an IOException or independently as itself.
830      * @exception IOException  If an I/O error occurs while either sending the
831      *      command or receiving the server reply.
832      ***/
833     public int newnews(String newsgroups, String date, String time, boolean GMT,
834                        String distributions) throws IOException
835     {
836         StringBuffer buffer = new StringBuffer();
837 
838         buffer.append(newsgroups);
839         buffer.append(' ');
840         buffer.append(date);
841         buffer.append(' ');
842         buffer.append(time);
843 
844         if (GMT)
845         {
846             buffer.append(' ');
847             buffer.append("GMT");
848         }
849 
850         if (distributions != null)
851         {
852             buffer.append(" <");
853             buffer.append(distributions);
854             buffer.append('>');
855         }
856 
857         return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
858     }
859 
860 
861 
862     /***
863      * A convenience method to send the NNTP POST command to the server,
864      * receive the reply, and return the reply code.
865      * <p>
866      * @return The reply code received from the server.
867      * @exception NNTPConnectionClosedException
868      *      If the NNTP server prematurely closes the connection as a result
869      *      of the client being idle or some other reason causing the server
870      *      to send NNTP reply code 400.  This exception may be caught either
871      *      as an IOException or independently as itself.
872      * @exception IOException  If an I/O error occurs while either sending the
873      *      command or receiving the server reply.
874      ***/
875     public int post() throws IOException
876     {
877         return sendCommand(NNTPCommand.POST);
878     }
879 
880 
881 
882     /***
883      * A convenience method to send the NNTP QUIT command to the server,
884      * receive the reply, and return the reply code.
885      * <p>
886      * @return The reply code received from the server.
887      * @exception NNTPConnectionClosedException
888      *      If the NNTP server prematurely closes the connection as a result
889      *      of the client being idle or some other reason causing the server
890      *      to send NNTP reply code 400.  This exception may be caught either
891      *      as an IOException or independently as itself.
892      * @exception IOException  If an I/O error occurs while either sending the
893      *      command or receiving the server reply.
894      ***/
895     public int quit() throws IOException
896     {
897         return sendCommand(NNTPCommand.QUIT);
898     }
899 
900     /***
901      * A convenience method to send the AUTHINFO USER command to the server,
902      *  receive the reply, and return the reply code. (See RFC 2980)
903      * <p>
904      * @param username A valid username.
905      * @return The reply code received from the server. The server should
906      *          return a 381 or 281 for this command.
907      * @exception NNTPConnectionClosedException
908      *      If the NNTP server prematurely closes the connection as a result
909      *      of the client being idle or some other reason causing the server
910      *      to send NNTP reply code 400.  This exception may be caught either
911      *      as an IOException or independently as itself.
912      * @exception IOException  If an I/O error occurs while either sending the
913      *      command or receiving the server reply.
914      ***/
915     public int authinfoUser(String username) throws IOException {
916         String userParameter = "USER " + username;
917         return sendCommand(NNTPCommand.AUTHINFO, userParameter);
918     }
919 
920     /***
921      * A convenience method to send the AUTHINFO PASS command to the server,
922      * receive the reply, and return the reply code.  If this step is
923      * required, it should immediately follow the AUTHINFO USER command
924      * (See RFC 2980)
925      * <p>
926      * @param password a valid password.
927      * @return The reply code received from the server. The server should
928      *         return a 281 or 502 for this command.
929      * @exception NNTPConnectionClosedException
930      *      If the NNTP server prematurely closes the connection as a result
931      *      of the client being idle or some other reason causing the server
932      *      to send NNTP reply code 400.  This exception may be caught either
933      *      as an IOException or independently as itself.
934      * @exception IOException  If an I/O error occurs while either sending the
935      *      command or receiving the server reply.
936      ***/
937     public int authinfoPass(String password) throws IOException {
938         String passParameter = "PASS " + password;
939         return sendCommand(NNTPCommand.AUTHINFO, passParameter);
940     }
941 
942     /***
943      * A convenience method to send the NNTP XOVER command to the server,
944      * receive the reply, and return the reply code.
945      * <p>
946      * @param selectedArticles a String representation of the range of
947      * article headers required. This may be an article number, or a
948      * range of article numbers in the form "XXXX-YYYY", where XXXX
949      * and YYYY are valid article numbers in the current group.  It
950      * also may be of the form "XXX-", meaning "return XXX and all
951      * following articles" In this revision, the last format is not
952      * possible (yet).
953      * @return The reply code received from the server.
954      * @exception NNTPConnectionClosedException
955      *      If the NNTP server prematurely closes the connection as a result
956      *      of the client being idle or some other reason causing the server
957      *      to send NNTP reply code 400.  This exception may be caught either
958      *      as an IOException or independently as itself.
959      * @exception IOException  If an I/O error occurs while either sending the
960      *      command or receiving the server reply.
961      ***/
962     public int xover(String selectedArticles) throws IOException {
963         return sendCommand(NNTPCommand.XOVER, selectedArticles);
964     }
965 
966     /***
967      * A convenience method to send the NNTP XHDR command to the server,
968      * receive the reply, and return the reply code.
969      * <p>
970      * @param header a String naming a header line (e.g., "subject").  See
971      * RFC-1036 for a list of valid header lines.
972      * @param selectedArticles a String representation of the range of
973      * article headers required. This may be an article number, or a
974      * range of article numbers in the form "XXXX-YYYY", where XXXX
975      * and YYYY are valid article numbers in the current group.  It
976      * also may be of the form "XXX-", meaning "return XXX and all
977      * following articles" In this revision, the last format is not
978      * possible (yet).
979      * @return The reply code received from the server.
980      * @exception NNTPConnectionClosedException
981      *      If the NNTP server prematurely closes the connection as a result
982      *      of the client being idle or some other reason causing the server
983      *      to send NNTP reply code 400.  This exception may be caught either
984      *      as an IOException or independently as itself.
985      * @exception IOException  If an I/O error occurs while either sending the
986      *      command or receiving the server reply.
987      ***/
988     public int xhdr(String header, String selectedArticles) throws IOException {
989         StringBuffer command = new StringBuffer(header);
990         command.append(" ");
991         command.append(selectedArticles);
992         return sendCommand(NNTPCommand.XHDR, command.toString());
993     }
994 
995     /**
996      * A convenience wrapper for the extended LIST command that takes
997      * an argument, allowing us to selectively list multiple groups.
998      * <p>
999      * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for
1000      *                details.
1001      * @return the reply code received from the server.
1002      * @throws IOException
1003      */
1004     public int listActive(String wildmat) throws IOException {
1005         StringBuffer command = new StringBuffer("ACTIVE ");
1006         command.append(wildmat);
1007         return sendCommand(NNTPCommand.LIST, command.toString());
1008     }
1009 }
1010 
1011 /* Emacs configuration
1012  * Local variables:        **
1013  * mode:             java  **
1014  * c-basic-offset:   4     **
1015  * indent-tabs-mode: nil   **
1016  * End:                    **
1017  */