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