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  import java.nio.charset.Charset;
26  import java.nio.charset.StandardCharsets;
27  
28  import org.apache.commons.net.MalformedServerReplyException;
29  import org.apache.commons.net.ProtocolCommandSupport;
30  import org.apache.commons.net.SocketClient;
31  import org.apache.commons.net.io.CRLFLineReader;
32  
33  /**
34   * The NNTP class is not meant to be used by itself and is provided only so that you may easily implement your own NNTP client if you so desire. If you have no
35   * need to perform your own implementation, you should use {@link org.apache.commons.net.nntp.NNTPClient}. The NNTP class is made public to provide access to
36   * various NNTP constants and to make it easier for adventurous programmers (or those with special needs) to interact with the NNTP protocol and implement their
37   * own clients. A set of methods with names corresponding to the NNTP command names are provided to facilitate this interaction.
38   * <p>
39   * You should keep in mind that the NNTP server may choose to prematurely close a connection if the client has been idle for longer than a given time period or
40   * if the server is being shutdown by the operator or some other reason. The NNTP class will detect a premature NNTP server connection closing when it receives
41   * a {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } response to a command. When that occurs, the NNTP class
42   * method encountering that reply will throw an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} . <code>NNTPConectionClosedException</code> is
43   * a subclass of <code> IOException </code> and therefore need not be caught separately, but if you are going to catch it separately, its catch block must
44   * appear before the more general <code> IOException </code> catch block. When you encounter an
45   * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} , you must disconnect the connection with {@link #disconnect disconnect() } to properly
46   * clean up the system resources used by NNTP. Before disconnecting, you may check the last reply code and text with {@link #getReplyCode getReplyCode } and
47   * {@link #getReplyString getReplyString }.
48   * </p>
49   * <p>
50   * Rather than list it separately for each method, we mention here that every method communicating with the server and throwing an IOException can also throw a
51   * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
52   * reply received from the server deviates enough from the protocol specification that it cannot be interpreted in a useful manner despite attempts to be as
53   * lenient as possible.
54   * </p>
55   *
56   * @see NNTPClient
57   * @see NNTPConnectionClosedException
58   * @see org.apache.commons.net.MalformedServerReplyException
59   */
60  
61  public class NNTP extends SocketClient {
62      /** The default NNTP port. Its value is 119 according to RFC 977. */
63      public static final int DEFAULT_PORT = 119;
64  
65      // We have to ensure that the protocol communication is in ASCII,
66      // but we use ISO-8859-1 just in case 8-bit characters cross
67      // the wire.
68      private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
69  
70      boolean _isAllowedToPost;
71      private int replyCode;
72      private String replyString;
73  
74      /**
75       * Wraps {@link SocketClient#_input_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
76       * variable.
77       */
78      protected BufferedReader _reader_;
79  
80      /**
81       * Wraps {@link SocketClient#_output_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
82       * variable.
83       */
84      protected BufferedWriter _writer_;
85  
86      /**
87       * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
88       */
89      protected ProtocolCommandSupport _commandSupport_;
90  
91      /**
92       * The default NNTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving NNTP reply
93       * information.
94       */
95      public NNTP() {
96          setDefaultPort(DEFAULT_PORT);
97          replyString = null;
98          _reader_ = null;
99          _writer_ = null;
100         _isAllowedToPost = false;
101         _commandSupport_ = new ProtocolCommandSupport(this);
102     }
103 
104     /**
105      * Initiates control connections and gets initial reply, determining if the client is allowed to post to the server. Initializes {@link #_reader_} and
106      * {@link #_writer_} to wrap {@link SocketClient#_input_} and {@link SocketClient#_output_}.
107      */
108     @Override
109     protected void _connectAction_() throws IOException {
110         super._connectAction_();
111         _reader_ = new CRLFLineReader(new InputStreamReader(_input_, DEFAULT_ENCODING));
112         _writer_ = new BufferedWriter(new OutputStreamWriter(_output_, DEFAULT_ENCODING));
113         getReply();
114 
115         _isAllowedToPost = replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED;
116     }
117 
118     /**
119      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
120      *
121      * @return The reply code received from the server.
122      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
123      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
124      *                                       independently as itself.
125      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
126      */
127     public int article() throws IOException {
128         return sendCommand(NNTPCommand.ARTICLE);
129     }
130 
131     /**
132      * @param a article number
133      * @return number
134      * @throws IOException on error
135      * @deprecated - for API compatibility only - DO NOT USE
136      */
137     @Deprecated
138     public int article(final int a) throws IOException {
139         return article((long) a);
140     }
141 
142     /**
143      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
144      *
145      * @param articleNumber The number of the article to request from the currently selected newsgroup.
146      * @return The reply code received from the server.
147      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
148      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
149      *                                       independently as itself.
150      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
151      */
152     public int article(final long articleNumber) throws IOException {
153         return sendCommand(NNTPCommand.ARTICLE, Long.toString(articleNumber));
154     }
155 
156     /**
157      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
158      *
159      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
160      * @return The reply code received from the server.
161      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
162      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
163      *                                       independently as itself.
164      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
165      */
166     public int article(final String messageId) throws IOException {
167         return sendCommand(NNTPCommand.ARTICLE, messageId);
168     }
169 
170     /**
171      * A convenience method to send the AUTHINFO PASS command to the server, receive the reply, and return the reply code. If this step is required, it should
172      * immediately follow the AUTHINFO USER command (See RFC 2980)
173      *
174      * @param password a valid password.
175      * @return The reply code received from the server. The server should return a 281 or 502 for this command.
176      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
177      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
178      *                                       independently as itself.
179      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
180      */
181     public int authinfoPass(final String password) throws IOException {
182         final String passParameter = "PASS " + password;
183         return sendCommand(NNTPCommand.AUTHINFO, passParameter);
184     }
185 
186     /**
187      * A convenience method to send the AUTHINFO USER command to the server, receive the reply, and return the reply code. (See RFC 2980)
188      *
189      * @param user A valid user name.
190      * @return The reply code received from the server. The server should return a 381 or 281 for this command.
191      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
192      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
193      *                                       independently as itself.
194      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
195      */
196     public int authinfoUser(final String user) throws IOException {
197         final String userParameter = "USER " + user;
198         return sendCommand(NNTPCommand.AUTHINFO, userParameter);
199     }
200 
201     /**
202      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
203      *
204      * @return The reply code received from the server.
205      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
206      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
207      *                                       independently as itself.
208      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
209      */
210     public int body() throws IOException {
211         return sendCommand(NNTPCommand.BODY);
212     }
213 
214     /**
215      * @param a article number
216      * @return number
217      * @throws IOException on error
218      * @deprecated - for API compatibility only - DO NOT USE
219      */
220     @Deprecated
221     public int body(final int a) throws IOException {
222         return body((long) a);
223     }
224 
225     /**
226      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
227      *
228      * @param articleNumber The number of the article to request from the currently selected newsgroup.
229      * @return The reply code received from the server.
230      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
231      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
232      *                                       independently as itself.
233      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
234      */
235     public int body(final long articleNumber) throws IOException {
236         return sendCommand(NNTPCommand.BODY, Long.toString(articleNumber));
237     }
238 
239     /**
240      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
241      *
242      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
243      * @return The reply code received from the server.
244      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
245      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
246      *                                       independently as itself.
247      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
248      */
249     public int body(final String messageId) throws IOException {
250         return sendCommand(NNTPCommand.BODY, messageId);
251     }
252 
253     /**
254      * Closes the connection to the NNTP server and sets to null some internal data so that the memory may be reclaimed by the garbage collector. The reply text
255      * and code information from the last command is voided so that the memory it used may be reclaimed.
256      *
257      * @throws IOException If an error occurs while disconnecting.
258      */
259     @Override
260     public void disconnect() throws IOException {
261         super.disconnect();
262         _reader_ = null;
263         _writer_ = null;
264         replyString = null;
265         _isAllowedToPost = false;
266     }
267 
268     /**
269      * Provide command support to super-class
270      */
271     @Override
272     protected ProtocolCommandSupport getCommandSupport() {
273         return _commandSupport_;
274     }
275 
276     /**
277      * Fetches a reply from the NNTP server and returns the integer reply code. After calling this method, the actual reply text can be accessed from
278      * {@link #getReplyString getReplyString }. Only use this method if you are implementing your own NNTP client or if you need to fetch a secondary response
279      * from the NNTP server.
280      *
281      * @return The integer value of the reply code of the fetched NNTP reply. in response to the command.
282      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
283      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
284      *                                       independently as itself.
285      * @throws IOException                   If an I/O error occurs while receiving the server reply.
286      */
287     public int getReply() throws IOException {
288         replyString = _reader_.readLine();
289 
290         if (replyString == null) {
291             throw new NNTPConnectionClosedException("Connection closed without indication.");
292         }
293 
294         // In case we run into an anomaly we don't want fatal index exceptions
295         // to be thrown.
296         if (replyString.length() < 3) {
297             throw new MalformedServerReplyException("Truncated server reply: " + replyString);
298         }
299 
300         try {
301             replyCode = Integer.parseInt(replyString.substring(0, 3));
302         } catch (final NumberFormatException e) {
303             throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + replyString);
304         }
305 
306         fireReplyReceived(replyCode, replyString + SocketClient.NETASCII_EOL);
307 
308         if (replyCode == NNTPReply.SERVICE_DISCONTINUED) {
309             throw new NNTPConnectionClosedException("NNTP response 400 received.  Server closed connection.");
310         }
311         return replyCode;
312     }
313 
314     /**
315      * Returns the integer value of the reply code of the last NNTP reply. You will usually only use this method after you connect to the NNTP server to check
316      * that the connection was successful since <code> connect </code> is of type void.
317      *
318      * @return The integer value of the reply code of the last NNTP reply.
319      */
320     public int getReplyCode() {
321         return replyCode;
322     }
323 
324     /**
325      * Returns the entire text of the last NNTP server response exactly as it was received, not including the end of line marker.
326      *
327      * @return The entire text from the last NNTP response as a String.
328      */
329     public String getReplyString() {
330         return replyString;
331     }
332 
333     /**
334      * A convenience method to send the NNTP GROUP command to the server, receive the reply, and return the reply code.
335      *
336      * @param newsgroup The name of the newsgroup to select.
337      * @return The reply code received from the server.
338      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
339      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
340      *                                       independently as itself.
341      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
342      */
343     public int group(final String newsgroup) throws IOException {
344         return sendCommand(NNTPCommand.GROUP, newsgroup);
345     }
346 
347     /**
348      * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
349      *
350      * @return The reply code received from the server.
351      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
352      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
353      *                                       independently as itself.
354      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
355      */
356     public int head() throws IOException {
357         return sendCommand(NNTPCommand.HEAD);
358     }
359 
360     /**
361      * @param a article number
362      * @return number
363      * @throws IOException on error
364      * @deprecated - for API compatibility only - DO NOT USE
365      */
366     @Deprecated
367     public int head(final int a) throws IOException {
368         return head((long) a);
369     }
370 
371     /**
372      * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
373      *
374      * @param articleNumber The number of the article to request from the currently selected newsgroup.
375      * @return The reply code received from the server.
376      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
377      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
378      *                                       independently as itself.
379      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
380      */
381     public int head(final long articleNumber) throws IOException {
382         return sendCommand(NNTPCommand.HEAD, Long.toString(articleNumber));
383     }
384 
385     /**
386      * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
387      *
388      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
389      * @return The reply code received from the server.
390      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
391      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
392      *                                       independently as itself.
393      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
394      */
395     public int head(final String messageId) throws IOException {
396         return sendCommand(NNTPCommand.HEAD, messageId);
397     }
398 
399     /**
400      * A convenience method to send the NNTP HELP command to the server, receive the reply, and return the reply code.
401      *
402      * @return The reply code received from the server.
403      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
404      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
405      *                                       independently as itself.
406      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
407      */
408     public int help() throws IOException {
409         return sendCommand(NNTPCommand.HELP);
410     }
411 
412     /**
413      * A convenience method to send the NNTP IHAVE command to the server, receive the reply, and return the reply code.
414      *
415      * @param messageId The article identifier, including the encapsulating &lt; and &gt; characters.
416      * @return The reply code received from the server.
417      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
418      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
419      *                                       independently as itself.
420      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
421      */
422     public int ihave(final String messageId) throws IOException {
423         return sendCommand(NNTPCommand.IHAVE, messageId);
424     }
425 
426     /**
427      * Indicates whether or not the client is allowed to post articles to the server it is currently connected to.
428      *
429      * @return True if the client can post articles to the server, false otherwise.
430      */
431     public boolean isAllowedToPost() {
432         return _isAllowedToPost;
433     }
434 
435     /**
436      * A convenience method to send the NNTP LAST command to the server, receive the reply, and return the reply code.
437      *
438      * @return The reply code received from the server.
439      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
440      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
441      *                                       independently as itself.
442      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
443      */
444     public int last() throws IOException {
445         return sendCommand(NNTPCommand.LAST);
446     }
447 
448     /**
449      * A convenience method to send the NNTP LIST command to the server, receive the reply, and return the reply code.
450      *
451      * @return The reply code received from the server.
452      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
453      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
454      *                                       independently as itself.
455      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
456      */
457     public int list() throws IOException {
458         return sendCommand(NNTPCommand.LIST);
459     }
460 
461     /**
462      * A convenience wrapper for the extended LIST command that takes an argument, allowing us to selectively list multiple groups.
463      *
464      * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for details.
465      * @return the reply code received from the server.
466      * @throws IOException if the command fails
467      */
468     public int listActive(final String wildmat) throws IOException {
469         final StringBuilder command = new StringBuilder("ACTIVE ");
470         command.append(wildmat);
471         return sendCommand(NNTPCommand.LIST, command.toString());
472     }
473 
474     /**
475      * A convenience method to send the "NEWGROUPS" command to the server, receive the reply, and return the reply code.
476      *
477      * @param date          The date after which to check for new groups. Date format is YYMMDD
478      * @param time          The time after which to check for new groups. Time format is HHMMSS using a 24-hour clock.
479      * @param GMT           True if the time is in GMT, false if local server time.
480      * @param distributions Comma-separated distribution list to check for new groups. Set to null if no distributions.
481      * @return The reply code received from the server.
482      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
483      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
484      *                                       independently as itself.
485      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
486      */
487     public int newgroups(final String date, final String time, final boolean GMT, final String distributions) throws IOException {
488         final StringBuilder buffer = new StringBuilder();
489 
490         buffer.append(date);
491         buffer.append(' ');
492         buffer.append(time);
493 
494         if (GMT) {
495             buffer.append(' ');
496             buffer.append("GMT");
497         }
498 
499         if (distributions != null) {
500             buffer.append(" <");
501             buffer.append(distributions);
502             buffer.append('>');
503         }
504 
505         return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
506     }
507 
508     /**
509      * A convenience method to send the "NEWNEWS" command to the server, receive the reply, and return the reply code.
510      *
511      * @param newsgroups    A comma-separated list of newsgroups to check for new news.
512      * @param date          The date after which to check for new news. Date format is YYMMDD
513      * @param time          The time after which to check for new news. Time format is HHMMSS using a 24-hour clock.
514      * @param GMT           True if the time is in GMT, false if local server time.
515      * @param distributions Comma-separated distribution list to check for new news. Set to null if no distributions.
516      * @return The reply code received from the server.
517      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
518      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
519      *                                       independently as itself.
520      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
521      */
522     public int newnews(final String newsgroups, final String date, final String time, final boolean GMT, final String distributions) throws IOException {
523         final StringBuilder buffer = new StringBuilder();
524 
525         buffer.append(newsgroups);
526         buffer.append(' ');
527         buffer.append(date);
528         buffer.append(' ');
529         buffer.append(time);
530 
531         if (GMT) {
532             buffer.append(' ');
533             buffer.append("GMT");
534         }
535 
536         if (distributions != null) {
537             buffer.append(" <");
538             buffer.append(distributions);
539             buffer.append('>');
540         }
541 
542         return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
543     }
544 
545     /**
546      * A convenience method to send the NNTP NEXT command to the server, receive the reply, and return the reply code.
547      *
548      * @return The reply code received from the server.
549      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
550      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
551      *                                       independently as itself.
552      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
553      */
554     public int next() throws IOException {
555         return sendCommand(NNTPCommand.NEXT);
556     }
557 
558     /**
559      * A convenience method to send the NNTP POST command to the server, receive the reply, and return the reply code.
560      *
561      * @return The reply code received from the server.
562      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
563      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
564      *                                       independently as itself.
565      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
566      */
567     public int post() throws IOException {
568         return sendCommand(NNTPCommand.POST);
569     }
570 
571     /**
572      * A convenience method to send the NNTP QUIT command to the server, receive the reply, and return the reply code.
573      *
574      * @return The reply code received from the server.
575      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
576      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
577      *                                       independently as itself.
578      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
579      */
580     public int quit() throws IOException {
581         return sendCommand(NNTPCommand.QUIT);
582     }
583 
584     /**
585      * Sends an NNTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
586      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
587      *
588      * @param command The NNTPCommand constant corresponding to the NNTP command to send.
589      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
590      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
591      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
592      *                                       independently as itself.
593      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
594      */
595     public int sendCommand(final int command) throws IOException {
596         return sendCommand(command, null);
597     }
598 
599     /**
600      * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
601      * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
602      *
603      * @param command The NNTPCommand constant corresponding to the NNTP command to send.
604      * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
605      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
606      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
607      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
608      *                                       independently as itself.
609      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
610      */
611     public int sendCommand(final int command, final String args) throws IOException {
612         return sendCommand(NNTPCommand.getCommand(command), args);
613     }
614 
615     /**
616      * Sends an NNTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
617      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
618      *
619      * @param command The text representation of the NNTP command to send.
620      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
621      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
622      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
623      *                                       independently as itself.
624      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
625      */
626     public int sendCommand(final String command) throws IOException {
627         return sendCommand(command, null);
628     }
629 
630     /**
631      * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
632      * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
633      *
634      * @param command The text representation of the NNTP command to send.
635      * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
636      * @return The integer value of the NNTP reply code returned by the server in response to the command.
637      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
638      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
639      *                                       independently as itself.
640      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
641      */
642     public int sendCommand(final String command, final String args) throws IOException {
643         final StringBuilder __commandBuffer = new StringBuilder();
644         __commandBuffer.append(command);
645 
646         if (args != null) {
647             __commandBuffer.append(' ');
648             __commandBuffer.append(args);
649         }
650         __commandBuffer.append(SocketClient.NETASCII_EOL);
651 
652         final String message;
653         _writer_.write(message = __commandBuffer.toString());
654         _writer_.flush();
655 
656         fireCommandSent(command, message);
657 
658         return getReply();
659     }
660 
661     /**
662      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
663      *
664      * @return The reply code received from the server.
665      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
666      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
667      *                                       independently as itself.
668      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
669      */
670     public int stat() throws IOException {
671         return sendCommand(NNTPCommand.STAT);
672     }
673 
674     /**
675      * @param a article number
676      * @return number
677      * @throws IOException on error
678      * @deprecated - for API compatibility only - DO NOT USE
679      */
680     @Deprecated
681     public int stat(final int a) throws IOException {
682         return stat((long) a);
683     }
684 
685     /**
686      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
687      *
688      * @param articleNumber The number of the article to request from the currently selected newsgroup.
689      * @return The reply code received from the server.
690      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
691      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
692      *                                       independently as itself.
693      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
694      */
695     public int stat(final long articleNumber) throws IOException {
696         return sendCommand(NNTPCommand.STAT, Long.toString(articleNumber));
697     }
698 
699     /**
700      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
701      *
702      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
703      * @return The reply code received from the server.
704      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
705      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
706      *                                       independently as itself.
707      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
708      */
709     public int stat(final String messageId) throws IOException {
710         return sendCommand(NNTPCommand.STAT, messageId);
711     }
712 
713     /**
714      * A convenience method to send the NNTP XHDR command to the server, receive the reply, and return the reply code.
715      *
716      * @param header           a String naming a header line (e.g., "subject"). See RFC-1036 for a list of valid header lines.
717      * @param selectedArticles a String representation of the range of article headers required. This may be an article number, or a range of article numbers in
718      *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
719      *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
720      * @return The reply code received from the server.
721      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
722      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
723      *                                       independently as itself.
724      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
725      */
726     public int xhdr(final String header, final String selectedArticles) throws IOException {
727         final StringBuilder command = new StringBuilder(header);
728         command.append(" ");
729         command.append(selectedArticles);
730         return sendCommand(NNTPCommand.XHDR, command.toString());
731     }
732 
733     /**
734      * A convenience method to send the NNTP XOVER command to the server, receive the reply, and return the reply code.
735      *
736      * @param selectedArticles a String representation of the range of article headers required. This may be an article number, or a range of article numbers in
737      *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
738      *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
739      * @return The reply code received from the server.
740      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
741      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
742      *                                       independently as itself.
743      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
744      */
745     public int xover(final String selectedArticles) throws IOException {
746         return sendCommand(NNTPCommand.XOVER, selectedArticles);
747     }
748 }