NNTP.java

  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. package org.apache.commons.net.nntp;

  18. import java.io.BufferedReader;
  19. import java.io.BufferedWriter;
  20. import java.io.IOException;
  21. import java.io.InputStreamReader;
  22. import java.io.OutputStreamWriter;
  23. import java.nio.charset.Charset;
  24. import java.nio.charset.StandardCharsets;

  25. import org.apache.commons.net.MalformedServerReplyException;
  26. import org.apache.commons.net.ProtocolCommandSupport;
  27. import org.apache.commons.net.SocketClient;
  28. import org.apache.commons.net.io.CRLFLineReader;

  29. /**
  30.  * 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
  31.  * 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
  32.  * 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
  33.  * own clients. A set of methods with names corresponding to the NNTP command names are provided to facilitate this interaction.
  34.  * <p>
  35.  * 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
  36.  * 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
  37.  * a {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } response to a command. When that occurs, the NNTP class
  38.  * method encountering that reply will throw an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} . <code>NNTPConectionClosedException</code> is
  39.  * 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
  40.  * appear before the more general <code>IOException</code> catch block. When you encounter an
  41.  * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} , you must disconnect the connection with {@link #disconnect disconnect() } to properly
  42.  * clean up the system resources used by NNTP. Before disconnecting, you may check the last reply code and text with {@link #getReplyCode getReplyCode } and
  43.  * {@link #getReplyString getReplyString }.
  44.  * </p>
  45.  * <p>
  46.  * 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
  47.  * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
  48.  * 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
  49.  * lenient as possible.
  50.  * </p>
  51.  *
  52.  * @see NNTPClient
  53.  * @see NNTPConnectionClosedException
  54.  * @see org.apache.commons.net.MalformedServerReplyException
  55.  */

  56. public class NNTP extends SocketClient {
  57.     /** The default NNTP port. Its value is 119 according to RFC 977. */
  58.     public static final int DEFAULT_PORT = 119;

  59.     // We have to ensure that the protocol communication is in ASCII,
  60.     // but we use ISO-8859-1 just in case 8-bit characters cross
  61.     // the wire.
  62.     private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;

  63.     boolean _isAllowedToPost;
  64.     private int replyCode;
  65.     private String replyString;

  66.     /**
  67.      * Wraps {@link SocketClient#_input_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
  68.      * variable.
  69.      */
  70.     protected BufferedReader _reader_;

  71.     /**
  72.      * Wraps {@link SocketClient#_output_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
  73.      * variable.
  74.      */
  75.     protected BufferedWriter _writer_;

  76.     /**
  77.      * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
  78.      */
  79.     protected ProtocolCommandSupport _commandSupport_;

  80.     /**
  81.      * The default NNTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving NNTP reply
  82.      * information.
  83.      */
  84.     public NNTP() {
  85.         setDefaultPort(DEFAULT_PORT);
  86.         replyString = null;
  87.         _reader_ = null;
  88.         _writer_ = null;
  89.         _isAllowedToPost = false;
  90.         _commandSupport_ = new ProtocolCommandSupport(this);
  91.     }

  92.     /**
  93.      * Initiates control connections and gets initial reply, determining if the client is allowed to post to the server. Initializes {@link #_reader_} and
  94.      * {@link #_writer_} to wrap {@link SocketClient#_input_} and {@link SocketClient#_output_}.
  95.      */
  96.     @Override
  97.     protected void _connectAction_() throws IOException {
  98.         super._connectAction_();
  99.         _reader_ = new CRLFLineReader(new InputStreamReader(_input_, DEFAULT_ENCODING));
  100.         _writer_ = new BufferedWriter(new OutputStreamWriter(_output_, DEFAULT_ENCODING));
  101.         getReply();

  102.         _isAllowedToPost = replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED;
  103.     }

  104.     /**
  105.      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
  106.      *
  107.      * @return The reply code received from the server.
  108.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  109.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  110.      *                                       independently as itself.
  111.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  112.      */
  113.     public int article() throws IOException {
  114.         return sendCommand(NNTPCommand.ARTICLE);
  115.     }

  116.     /**
  117.      * @param a article number
  118.      * @return number
  119.      * @throws IOException on error
  120.      * @deprecated - for API compatibility only - DO NOT USE
  121.      */
  122.     @Deprecated
  123.     public int article(final int a) throws IOException {
  124.         return article((long) a);
  125.     }

  126.     /**
  127.      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
  128.      *
  129.      * @param articleNumber The number of the article to request from the currently selected newsgroup.
  130.      * @return The reply code received from the server.
  131.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  132.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  133.      *                                       independently as itself.
  134.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  135.      */
  136.     public int article(final long articleNumber) throws IOException {
  137.         return sendCommand(NNTPCommand.ARTICLE, Long.toString(articleNumber));
  138.     }

  139.     /**
  140.      * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
  141.      *
  142.      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
  143.      * @return The reply code received from the server.
  144.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  145.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  146.      *                                       independently as itself.
  147.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  148.      */
  149.     public int article(final String messageId) throws IOException {
  150.         return sendCommand(NNTPCommand.ARTICLE, messageId);
  151.     }

  152.     /**
  153.      * 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
  154.      * immediately follow the AUTHINFO USER command (See RFC 2980)
  155.      *
  156.      * @param password a valid password.
  157.      * @return The reply code received from the server. The server should return a 281 or 502 for this command.
  158.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  159.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  160.      *                                       independently as itself.
  161.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  162.      */
  163.     public int authinfoPass(final String password) throws IOException {
  164.         final String passParameter = "PASS " + password;
  165.         return sendCommand(NNTPCommand.AUTHINFO, passParameter);
  166.     }

  167.     /**
  168.      * A convenience method to send the AUTHINFO USER command to the server, receive the reply, and return the reply code. (See RFC 2980)
  169.      *
  170.      * @param user A valid user name.
  171.      * @return The reply code received from the server. The server should return a 381 or 281 for this command.
  172.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  173.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  174.      *                                       independently as itself.
  175.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  176.      */
  177.     public int authinfoUser(final String user) throws IOException {
  178.         final String userParameter = "USER " + user;
  179.         return sendCommand(NNTPCommand.AUTHINFO, userParameter);
  180.     }

  181.     /**
  182.      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
  183.      *
  184.      * @return The reply code received from the server.
  185.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  186.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  187.      *                                       independently as itself.
  188.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  189.      */
  190.     public int body() throws IOException {
  191.         return sendCommand(NNTPCommand.BODY);
  192.     }

  193.     /**
  194.      * @param a article number
  195.      * @return number
  196.      * @throws IOException on error
  197.      * @deprecated - for API compatibility only - DO NOT USE
  198.      */
  199.     @Deprecated
  200.     public int body(final int a) throws IOException {
  201.         return body((long) a);
  202.     }

  203.     /**
  204.      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
  205.      *
  206.      * @param articleNumber The number of the article to request from the currently selected newsgroup.
  207.      * @return The reply code received from the server.
  208.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  209.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  210.      *                                       independently as itself.
  211.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  212.      */
  213.     public int body(final long articleNumber) throws IOException {
  214.         return sendCommand(NNTPCommand.BODY, Long.toString(articleNumber));
  215.     }

  216.     /**
  217.      * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
  218.      *
  219.      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
  220.      * @return The reply code received from the server.
  221.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  222.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  223.      *                                       independently as itself.
  224.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  225.      */
  226.     public int body(final String messageId) throws IOException {
  227.         return sendCommand(NNTPCommand.BODY, messageId);
  228.     }

  229.     /**
  230.      * 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
  231.      * and code information from the last command is voided so that the memory it used may be reclaimed.
  232.      *
  233.      * @throws IOException If an error occurs while disconnecting.
  234.      */
  235.     @Override
  236.     public void disconnect() throws IOException {
  237.         super.disconnect();
  238.         _reader_ = null;
  239.         _writer_ = null;
  240.         replyString = null;
  241.         _isAllowedToPost = false;
  242.     }

  243.     /**
  244.      * Provide command support to super-class
  245.      */
  246.     @Override
  247.     protected ProtocolCommandSupport getCommandSupport() {
  248.         return _commandSupport_;
  249.     }

  250.     /**
  251.      * 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
  252.      * {@link #getReplyString getReplyString }. Only use this method if you are implementing your own NNTP client or if you need to fetch a secondary response
  253.      * from the NNTP server.
  254.      *
  255.      * @return The integer value of the reply code of the fetched NNTP reply. in response to the command.
  256.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  257.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  258.      *                                       independently as itself.
  259.      * @throws IOException                   If an I/O error occurs while receiving the server reply.
  260.      */
  261.     public int getReply() throws IOException {
  262.         replyString = _reader_.readLine();

  263.         if (replyString == null) {
  264.             throw new NNTPConnectionClosedException("Connection closed without indication.");
  265.         }

  266.         // In case we run into an anomaly we don't want fatal index exceptions
  267.         // to be thrown.
  268.         if (replyString.length() < 3) {
  269.             throw new MalformedServerReplyException("Truncated server reply: " + replyString);
  270.         }

  271.         try {
  272.             replyCode = Integer.parseInt(replyString.substring(0, 3));
  273.         } catch (final NumberFormatException e) {
  274.             throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + replyString);
  275.         }

  276.         fireReplyReceived(replyCode, replyString + SocketClient.NETASCII_EOL);

  277.         if (replyCode == NNTPReply.SERVICE_DISCONTINUED) {
  278.             throw new NNTPConnectionClosedException("NNTP response 400 received.  Server closed connection.");
  279.         }
  280.         return replyCode;
  281.     }

  282.     /**
  283.      * 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
  284.      * that the connection was successful since <code>connect</code> is of type void.
  285.      *
  286.      * @return The integer value of the reply code of the last NNTP reply.
  287.      */
  288.     public int getReplyCode() {
  289.         return replyCode;
  290.     }

  291.     /**
  292.      * Returns the entire text of the last NNTP server response exactly as it was received, not including the end of line marker.
  293.      *
  294.      * @return The entire text from the last NNTP response as a String.
  295.      */
  296.     public String getReplyString() {
  297.         return replyString;
  298.     }

  299.     /**
  300.      * A convenience method to send the NNTP GROUP command to the server, receive the reply, and return the reply code.
  301.      *
  302.      * @param newsgroup The name of the newsgroup to select.
  303.      * @return The reply code received from the server.
  304.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  305.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  306.      *                                       independently as itself.
  307.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  308.      */
  309.     public int group(final String newsgroup) throws IOException {
  310.         return sendCommand(NNTPCommand.GROUP, newsgroup);
  311.     }

  312.     /**
  313.      * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
  314.      *
  315.      * @return The reply code received from the server.
  316.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  317.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  318.      *                                       independently as itself.
  319.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  320.      */
  321.     public int head() throws IOException {
  322.         return sendCommand(NNTPCommand.HEAD);
  323.     }

  324.     /**
  325.      * @param a article number
  326.      * @return number
  327.      * @throws IOException on error
  328.      * @deprecated - for API compatibility only - DO NOT USE
  329.      */
  330.     @Deprecated
  331.     public int head(final int a) throws IOException {
  332.         return head((long) a);
  333.     }

  334.     /**
  335.      * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
  336.      *
  337.      * @param articleNumber The number of the article to request from the currently selected newsgroup.
  338.      * @return The reply code received from the server.
  339.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  340.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  341.      *                                       independently as itself.
  342.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  343.      */
  344.     public int head(final long articleNumber) throws IOException {
  345.         return sendCommand(NNTPCommand.HEAD, Long.toString(articleNumber));
  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.      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
  351.      * @return The reply code received from the server.
  352.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  353.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  354.      *                                       independently as itself.
  355.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  356.      */
  357.     public int head(final String messageId) throws IOException {
  358.         return sendCommand(NNTPCommand.HEAD, messageId);
  359.     }

  360.     /**
  361.      * A convenience method to send the NNTP HELP command to the server, receive the reply, and return the reply code.
  362.      *
  363.      * @return The reply code received from the server.
  364.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  365.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  366.      *                                       independently as itself.
  367.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  368.      */
  369.     public int help() throws IOException {
  370.         return sendCommand(NNTPCommand.HELP);
  371.     }

  372.     /**
  373.      * A convenience method to send the NNTP IHAVE command to the server, receive the reply, and return the reply code.
  374.      *
  375.      * @param messageId The article identifier, including the encapsulating &lt; and &gt; characters.
  376.      * @return The reply code received from the server.
  377.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  378.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  379.      *                                       independently as itself.
  380.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  381.      */
  382.     public int ihave(final String messageId) throws IOException {
  383.         return sendCommand(NNTPCommand.IHAVE, messageId);
  384.     }

  385.     /**
  386.      * Indicates whether or not the client is allowed to post articles to the server it is currently connected to.
  387.      *
  388.      * @return True if the client can post articles to the server, false otherwise.
  389.      */
  390.     public boolean isAllowedToPost() {
  391.         return _isAllowedToPost;
  392.     }

  393.     /**
  394.      * A convenience method to send the NNTP LAST command to the server, receive the reply, and return the reply code.
  395.      *
  396.      * @return The reply code received from the server.
  397.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  398.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  399.      *                                       independently as itself.
  400.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  401.      */
  402.     public int last() throws IOException {
  403.         return sendCommand(NNTPCommand.LAST);
  404.     }

  405.     /**
  406.      * A convenience method to send the NNTP LIST command to the server, receive the reply, and return the reply code.
  407.      *
  408.      * @return The reply code received from the server.
  409.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  410.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  411.      *                                       independently as itself.
  412.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  413.      */
  414.     public int list() throws IOException {
  415.         return sendCommand(NNTPCommand.LIST);
  416.     }

  417.     /**
  418.      * A convenience wrapper for the extended LIST command that takes an argument, allowing us to selectively list multiple groups.
  419.      *
  420.      * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for details.
  421.      * @return the reply code received from the server.
  422.      * @throws IOException if the command fails
  423.      */
  424.     public int listActive(final String wildmat) throws IOException {
  425.         final StringBuilder command = new StringBuilder("ACTIVE ");
  426.         command.append(wildmat);
  427.         return sendCommand(NNTPCommand.LIST, command.toString());
  428.     }

  429.     /**
  430.      * A convenience method to send the "NEWGROUPS" command to the server, receive the reply, and return the reply code.
  431.      *
  432.      * @param date          The date after which to check for new groups. Date format is YYMMDD
  433.      * @param time          The time after which to check for new groups. Time format is HHMMSS using a 24-hour clock.
  434.      * @param GMT           True if the time is in GMT, false if local server time.
  435.      * @param distributions Comma-separated distribution list to check for new groups. Set to null if no distributions.
  436.      * @return The reply code received from the server.
  437.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  438.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  439.      *                                       independently as itself.
  440.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  441.      */
  442.     public int newgroups(final String date, final String time, final boolean GMT, final String distributions) throws IOException {
  443.         final StringBuilder buffer = new StringBuilder();

  444.         buffer.append(date);
  445.         buffer.append(' ');
  446.         buffer.append(time);

  447.         if (GMT) {
  448.             buffer.append(' ');
  449.             buffer.append("GMT");
  450.         }

  451.         if (distributions != null) {
  452.             buffer.append(" <");
  453.             buffer.append(distributions);
  454.             buffer.append('>');
  455.         }

  456.         return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
  457.     }

  458.     /**
  459.      * A convenience method to send the "NEWNEWS" command to the server, receive the reply, and return the reply code.
  460.      *
  461.      * @param newsgroups    A comma-separated list of newsgroups to check for new news.
  462.      * @param date          The date after which to check for new news. Date format is YYMMDD
  463.      * @param time          The time after which to check for new news. Time format is HHMMSS using a 24-hour clock.
  464.      * @param GMT           True if the time is in GMT, false if local server time.
  465.      * @param distributions Comma-separated distribution list to check for new news. Set to null if no distributions.
  466.      * @return The reply code received from the server.
  467.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  468.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  469.      *                                       independently as itself.
  470.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  471.      */
  472.     public int newnews(final String newsgroups, final String date, final String time, final boolean GMT, final String distributions) throws IOException {
  473.         final StringBuilder buffer = new StringBuilder();

  474.         buffer.append(newsgroups);
  475.         buffer.append(' ');
  476.         buffer.append(date);
  477.         buffer.append(' ');
  478.         buffer.append(time);

  479.         if (GMT) {
  480.             buffer.append(' ');
  481.             buffer.append("GMT");
  482.         }

  483.         if (distributions != null) {
  484.             buffer.append(" <");
  485.             buffer.append(distributions);
  486.             buffer.append('>');
  487.         }

  488.         return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
  489.     }

  490.     /**
  491.      * A convenience method to send the NNTP NEXT command to the server, receive the reply, and return the reply code.
  492.      *
  493.      * @return The reply code received from the server.
  494.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  495.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  496.      *                                       independently as itself.
  497.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  498.      */
  499.     public int next() throws IOException {
  500.         return sendCommand(NNTPCommand.NEXT);
  501.     }

  502.     /**
  503.      * A convenience method to send the NNTP POST command to the server, receive the reply, and return the reply code.
  504.      *
  505.      * @return The reply code received from the server.
  506.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  507.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  508.      *                                       independently as itself.
  509.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  510.      */
  511.     public int post() throws IOException {
  512.         return sendCommand(NNTPCommand.POST);
  513.     }

  514.     /**
  515.      * A convenience method to send the NNTP QUIT command to the server, receive the reply, and return the reply code.
  516.      *
  517.      * @return The reply code received from the server.
  518.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  519.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  520.      *                                       independently as itself.
  521.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  522.      */
  523.     public int quit() throws IOException {
  524.         return sendCommand(NNTPCommand.QUIT);
  525.     }

  526.     /**
  527.      * 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
  528.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
  529.      *
  530.      * @param command The NNTPCommand constant corresponding to the NNTP command to send.
  531.      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
  532.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  533.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  534.      *                                       independently as itself.
  535.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  536.      */
  537.     public int sendCommand(final int command) throws IOException {
  538.         return sendCommand(command, null);
  539.     }

  540.     /**
  541.      * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  542.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
  543.      *
  544.      * @param command The NNTPCommand constant corresponding to the NNTP command to send.
  545.      * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
  546.      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
  547.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  548.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  549.      *                                       independently as itself.
  550.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  551.      */
  552.     public int sendCommand(final int command, final String args) throws IOException {
  553.         return sendCommand(NNTPCommand.getCommand(command), args);
  554.     }

  555.     /**
  556.      * 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
  557.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
  558.      *
  559.      * @param command The text representation of the NNTP command to send.
  560.      * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
  561.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  562.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  563.      *                                       independently as itself.
  564.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  565.      */
  566.     public int sendCommand(final String command) throws IOException {
  567.         return sendCommand(command, null);
  568.     }

  569.     /**
  570.      * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  571.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
  572.      *
  573.      * @param command The text representation of the NNTP command to send.
  574.      * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
  575.      * @return The integer value of the NNTP reply code returned by the server in response to the command.
  576.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  577.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  578.      *                                       independently as itself.
  579.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  580.      */
  581.     public int sendCommand(final String command, final String args) throws IOException {
  582.         final StringBuilder __commandBuffer = new StringBuilder();
  583.         __commandBuffer.append(command);

  584.         if (args != null) {
  585.             __commandBuffer.append(' ');
  586.             __commandBuffer.append(args);
  587.         }
  588.         __commandBuffer.append(SocketClient.NETASCII_EOL);

  589.         final String message;
  590.         _writer_.write(message = __commandBuffer.toString());
  591.         _writer_.flush();

  592.         fireCommandSent(command, message);

  593.         return getReply();
  594.     }

  595.     /**
  596.      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
  597.      *
  598.      * @return The reply code received from the server.
  599.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  600.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  601.      *                                       independently as itself.
  602.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  603.      */
  604.     public int stat() throws IOException {
  605.         return sendCommand(NNTPCommand.STAT);
  606.     }

  607.     /**
  608.      * @param a article number
  609.      * @return number
  610.      * @throws IOException on error
  611.      * @deprecated - for API compatibility only - DO NOT USE
  612.      */
  613.     @Deprecated
  614.     public int stat(final int a) throws IOException {
  615.         return stat((long) a);
  616.     }

  617.     /**
  618.      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
  619.      *
  620.      * @param articleNumber The number of the article to request from the currently selected newsgroup.
  621.      * @return The reply code received from the server.
  622.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  623.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  624.      *                                       independently as itself.
  625.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  626.      */
  627.     public int stat(final long articleNumber) throws IOException {
  628.         return sendCommand(NNTPCommand.STAT, Long.toString(articleNumber));
  629.     }

  630.     /**
  631.      * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
  632.      *
  633.      * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
  634.      * @return The reply code received from the server.
  635.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  636.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  637.      *                                       independently as itself.
  638.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  639.      */
  640.     public int stat(final String messageId) throws IOException {
  641.         return sendCommand(NNTPCommand.STAT, messageId);
  642.     }

  643.     /**
  644.      * A convenience method to send the NNTP XHDR command to the server, receive the reply, and return the reply code.
  645.      *
  646.      * @param header           a String naming a header line (e.g., "subject"). See RFC-1036 for a list of valid header lines.
  647.      * @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
  648.      *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
  649.      *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
  650.      * @return The reply code received from the server.
  651.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  652.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  653.      *                                       independently as itself.
  654.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  655.      */
  656.     public int xhdr(final String header, final String selectedArticles) throws IOException {
  657.         final StringBuilder command = new StringBuilder(header);
  658.         command.append(" ");
  659.         command.append(selectedArticles);
  660.         return sendCommand(NNTPCommand.XHDR, command.toString());
  661.     }

  662.     /**
  663.      * A convenience method to send the NNTP XOVER command to the server, receive the reply, and return the reply code.
  664.      *
  665.      * @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
  666.      *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
  667.      *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
  668.      * @return The reply code received from the server.
  669.      * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
  670.      *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
  671.      *                                       independently as itself.
  672.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  673.      */
  674.     public int xover(final String selectedArticles) throws IOException {
  675.         return sendCommand(NNTPCommand.XOVER, selectedArticles);
  676.     }
  677. }