    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.nntp;
    019
    020import java.io.BufferedReader;
    021import java.io.BufferedWriter;
    022import java.io.IOException;
    023import java.io.InputStreamReader;
    024import java.io.OutputStreamWriter;
    025import java.nio.charset.Charset;
    026import java.nio.charset.StandardCharsets;
    027
    028import org.apache.commons.net.MalformedServerReplyException;
    029import org.apache.commons.net.ProtocolCommandSupport;
    030import org.apache.commons.net.SocketClient;
    031import org.apache.commons.net.io.CRLFLineReader;
    032
    033/**
    034 * 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
    035 * 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
    036 * 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
    037 * own clients. A set of methods with names corresponding to the NNTP command names are provided to facilitate this interaction.
    038 * <p>
    039 * 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
    040 * 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
    041 * a {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } response to a command. When that occurs, the NNTP class
    042 * method encountering that reply will throw an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} . <code>NNTPConectionClosedException</code> is
    043 * 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
    044 * appear before the more general <code> IOException </code> catch block. When you encounter an
    045 * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} , you must disconnect the connection with {@link #disconnect disconnect() } to properly
    046 * clean up the system resources used by NNTP. Before disconnecting, you may check the last reply code and text with {@link #getReplyCode getReplyCode } and
    047 * {@link #getReplyString getReplyString }.
    048 * <p>
    049 * 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
    050 * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
    051 * 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
    052 * lenient as possible.
    053 *
    054 * @see NNTPClient
    055 * @see NNTPConnectionClosedException
    056 * @see org.apache.commons.net.MalformedServerReplyException
    057 */
    058
    059public class NNTP extends SocketClient {
    060    /** The default NNTP port. Its value is 119 according to RFC 977. */
    061    public static final int DEFAULT_PORT = 119;
    062
    063    // We have to ensure that the protocol communication is in ASCII
    064    // but we use ISO-8859-1 just in case 8-bit characters cross
    065    // the wire.
    066    private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
    067
    068    boolean _isAllowedToPost;
    069    private int replyCode;
    070    private String replyString;
    071
    072    /**
    073     * Wraps {@link SocketClient#_input_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
    074     * variable.
    075     */
    076    protected BufferedReader _reader_;
    077
    078    /**
    079     * Wraps {@link SocketClient#_output_} to communicate with server. Initialized by {@link #_connectAction_}. All server reads should be done through this
    080     * variable.
    081     */
    082    protected BufferedWriter _writer_;
    083
    084    /**
    085     * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
    086     */
    087    protected ProtocolCommandSupport _commandSupport_;
    088
    089    /**
    090     * The default NNTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving NNTP reply
    091     * information.
    092     */
    093    public NNTP() {
    094        setDefaultPort(DEFAULT_PORT);
    095        replyString = null;
    096        _reader_ = null;
    097        _writer_ = null;
    098        _isAllowedToPost = false;
    099        _commandSupport_ = new ProtocolCommandSupport(this);
    100    }
    101
    102    /**
    103     * Initiates control connections and gets initial reply, determining if the client is allowed to post to the server. Initializes {@link #_reader_} and
    104     * {@link #_writer_} to wrap {@link SocketClient#_input_} and {@link SocketClient#_output_}.
    105     */
    106    @Override
    107    protected void _connectAction_() throws IOException {
    108        super._connectAction_();
    109        _reader_ = new CRLFLineReader(new InputStreamReader(_input_, DEFAULT_ENCODING));
    110        _writer_ = new BufferedWriter(new OutputStreamWriter(_output_, DEFAULT_ENCODING));
    111        getReply();
    112
    113        _isAllowedToPost = replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED;
    114    }
    115
    116    /**
    117     * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
    118     * <p>
    119     *
    120     * @return The reply code received from the server.
    121     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    122     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    123     *                                       independently as itself.
    124     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    125     */
    126    public int article() throws IOException {
    127        return sendCommand(NNTPCommand.ARTICLE);
    128    }
    129
    130    /**
    131     * @param a article number
    132     * @return number
    133     * @throws IOException on error
    134     * @deprecated - for API compatibility only - DO NOT USE
    135     */
    136    @Deprecated
    137    public int article(final int a) throws IOException {
    138        return article((long) a);
    139    }
    140
    141    /**
    142     * A convenience method to send the NNTP ARTICLE command to the server, receive the initial reply, and return the reply code.
    143     * <p>
    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     * <p>
    159     *
    160     * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
    161     * @return The reply code received from the server.
    162     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    163     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    164     *                                       independently as itself.
    165     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    166     */
    167    public int article(final String messageId) throws IOException {
    168        return sendCommand(NNTPCommand.ARTICLE, messageId);
    169    }
    170
    171    /**
    172     * 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
    173     * immediately follow the AUTHINFO USER command (See RFC 2980)
    174     * <p>
    175     *
    176     * @param password a valid password.
    177     * @return The reply code received from the server. The server should return a 281 or 502 for this command.
    178     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    179     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    180     *                                       independently as itself.
    181     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    182     */
    183    public int authinfoPass(final String password) throws IOException {
    184        final String passParameter = "PASS " + password;
    185        return sendCommand(NNTPCommand.AUTHINFO, passParameter);
    186    }
    187
    188    /**
    189     * A convenience method to send the AUTHINFO USER command to the server, receive the reply, and return the reply code. (See RFC 2980)
    190     * <p>
    191     *
    192     * @param username A valid username.
    193     * @return The reply code received from the server. The server should return a 381 or 281 for this command.
    194     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    195     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    196     *                                       independently as itself.
    197     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    198     */
    199    public int authinfoUser(final String username) throws IOException {
    200        final String userParameter = "USER " + username;
    201        return sendCommand(NNTPCommand.AUTHINFO, userParameter);
    202    }
    203
    204    /**
    205     * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
    206     * <p>
    207     *
    208     * @return The reply code received from the server.
    209     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    210     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    211     *                                       independently as itself.
    212     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    213     */
    214    public int body() throws IOException {
    215        return sendCommand(NNTPCommand.BODY);
    216    }
    217
    218    /**
    219     * @param a article number
    220     * @return number
    221     * @throws IOException on error
    222     * @deprecated - for API compatibility only - DO NOT USE
    223     */
    224    @Deprecated
    225    public int body(final int a) throws IOException {
    226        return body((long) a);
    227    }
    228
    229    /**
    230     * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
    231     * <p>
    232     *
    233     * @param articleNumber The number of the article to request from the currently selected newsgroup.
    234     * @return The reply code received from the server.
    235     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    236     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    237     *                                       independently as itself.
    238     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    239     */
    240    public int body(final long articleNumber) throws IOException {
    241        return sendCommand(NNTPCommand.BODY, Long.toString(articleNumber));
    242    }
    243
    244    /**
    245     * A convenience method to send the NNTP BODY command to the server, receive the initial reply, and return the reply code.
    246     * <p>
    247     *
    248     * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
    249     * @return The reply code received from the server.
    250     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    251     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    252     *                                       independently as itself.
    253     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    254     */
    255    public int body(final String messageId) throws IOException {
    256        return sendCommand(NNTPCommand.BODY, messageId);
    257    }
    258
    259    /**
    260     * 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
    261     * and code information from the last command is voided so that the memory it used may be reclaimed.
    262     * <p>
    263     *
    264     * @throws IOException If an error occurs while disconnecting.
    265     */
    266    @Override
    267    public void disconnect() throws IOException {
    268        super.disconnect();
    269        _reader_ = null;
    270        _writer_ = null;
    271        replyString = null;
    272        _isAllowedToPost = false;
    273    }
    274
    275    /**
    276     * Provide command support to super-class
    277     */
    278    @Override
    279    protected ProtocolCommandSupport getCommandSupport() {
    280        return _commandSupport_;
    281    }
    282
    283    /**
    284     * 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
    285     * {@link #getReplyString getReplyString }. Only use this method if you are implementing your own NNTP client or if you need to fetch a secondary response
    286     * from the NNTP server.
    287     * <p>
    288     *
    289     * @return The integer value of the reply code of the fetched NNTP reply. in response to the command.
    290     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    291     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    292     *                                       independently as itself.
    293     * @throws IOException                   If an I/O error occurs while receiving the server reply.
    294     */
    295    public int getReply() throws IOException {
    296        replyString = _reader_.readLine();
    297
    298        if (replyString == null) {
    299            throw new NNTPConnectionClosedException("Connection closed without indication.");
    300        }
    301
    302        // In case we run into an anomaly we don't want fatal index exceptions
    303        // to be thrown.
    304        if (replyString.length() < 3) {
    305            throw new MalformedServerReplyException("Truncated server reply: " + replyString);
    306        }
    307
    308        try {
    309            replyCode = Integer.parseInt(replyString.substring(0, 3));
    310        } catch (final NumberFormatException e) {
    311            throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + replyString);
    312        }
    313
    314        fireReplyReceived(replyCode, replyString + SocketClient.NETASCII_EOL);
    315
    316        if (replyCode == NNTPReply.SERVICE_DISCONTINUED) {
    317            throw new NNTPConnectionClosedException("NNTP response 400 received.  Server closed connection.");
    318        }
    319        return replyCode;
    320    }
    321
    322    /**
    323     * 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
    324     * that the connection was successful since <code> connect </code> is of type void.
    325     * <p>
    326     *
    327     * @return The integer value of the reply code of the last NNTP reply.
    328     */
    329    public int getReplyCode() {
    330        return replyCode;
    331    }
    332
    333    /**
    334     * Returns the entire text of the last NNTP server response exactly as it was received, not including the end of line marker.
    335     * <p>
    336     *
    337     * @return The entire text from the last NNTP response as a String.
    338     */
    339    public String getReplyString() {
    340        return replyString;
    341    }
    342
    343    /**
    344     * A convenience method to send the NNTP GROUP command to the server, receive the reply, and return the reply code.
    345     * <p>
    346     *
    347     * @param newsgroup The name of the newsgroup to select.
    348     * @return The reply code received from the server.
    349     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    350     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    351     *                                       independently as itself.
    352     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    353     */
    354    public int group(final String newsgroup) throws IOException {
    355        return sendCommand(NNTPCommand.GROUP, newsgroup);
    356    }
    357
    358    /**
    359     * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
    360     * <p>
    361     *
    362     * @return The reply code received from the server.
    363     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    364     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    365     *                                       independently as itself.
    366     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    367     */
    368    public int head() throws IOException {
    369        return sendCommand(NNTPCommand.HEAD);
    370    }
    371
    372    /**
    373     * @param a article number
    374     * @return number
    375     * @throws IOException on error
    376     * @deprecated - for API compatibility only - DO NOT USE
    377     */
    378    @Deprecated
    379    public int head(final int a) throws IOException {
    380        return head((long) a);
    381    }
    382
    383    /**
    384     * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
    385     * <p>
    386     *
    387     * @param articleNumber The number of the article to request from the currently selected newsgroup.
    388     * @return The reply code received from the server.
    389     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    390     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    391     *                                       independently as itself.
    392     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    393     */
    394    public int head(final long articleNumber) throws IOException {
    395        return sendCommand(NNTPCommand.HEAD, Long.toString(articleNumber));
    396    }
    397
    398    /**
    399     * A convenience method to send the NNTP HEAD command to the server, receive the initial reply, and return the reply code.
    400     * <p>
    401     *
    402     * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
    403     * @return The reply code received from the server.
    404     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    405     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    406     *                                       independently as itself.
    407     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    408     */
    409    public int head(final String messageId) throws IOException {
    410        return sendCommand(NNTPCommand.HEAD, messageId);
    411    }
    412
    413    /**
    414     * A convenience method to send the NNTP HELP command to the server, receive the reply, and return the reply code.
    415     * <p>
    416     *
    417     * @return The reply code received from the server.
    418     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    419     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    420     *                                       independently as itself.
    421     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    422     */
    423    public int help() throws IOException {
    424        return sendCommand(NNTPCommand.HELP);
    425    }
    426
    427    /**
    428     * A convenience method to send the NNTP IHAVE command to the server, receive the reply, and return the reply code.
    429     * <p>
    430     *
    431     * @param messageId The article identifier, including the encapsulating &lt; and &gt; characters.
    432     * @return The reply code received from the server.
    433     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    434     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    435     *                                       independently as itself.
    436     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    437     */
    438    public int ihave(final String messageId) throws IOException {
    439        return sendCommand(NNTPCommand.IHAVE, messageId);
    440    }
    441
    442    /**
    443     * Indicates whether or not the client is allowed to post articles to the server it is currently connected to.
    444     * <p>
    445     *
    446     * @return True if the client can post articles to the server, false otherwise.
    447     */
    448    public boolean isAllowedToPost() {
    449        return _isAllowedToPost;
    450    }
    451
    452    /**
    453     * A convenience method to send the NNTP LAST command to the server, receive the reply, and return the reply code.
    454     * <p>
    455     *
    456     * @return The reply code received from the server.
    457     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    458     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    459     *                                       independently as itself.
    460     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    461     */
    462    public int last() throws IOException {
    463        return sendCommand(NNTPCommand.LAST);
    464    }
    465
    466    /**
    467     * A convenience method to send the NNTP LIST command to the server, receive the reply, and return the reply code.
    468     * <p>
    469     *
    470     * @return The reply code received from the server.
    471     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    472     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    473     *                                       independently as itself.
    474     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    475     */
    476    public int list() throws IOException {
    477        return sendCommand(NNTPCommand.LIST);
    478    }
    479
    480    /**
    481     * A convenience wrapper for the extended LIST command that takes an argument, allowing us to selectively list multiple groups.
    482     * <p>
    483     *
    484     * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for details.
    485     * @return the reply code received from the server.
    486     * @throws IOException if the command fails
    487     */
    488    public int listActive(final String wildmat) throws IOException {
    489        final StringBuilder command = new StringBuilder("ACTIVE ");
    490        command.append(wildmat);
    491        return sendCommand(NNTPCommand.LIST, command.toString());
    492    }
    493
    494    /**
    495     * A convenience method to send the "NEWGROUPS" command to the server, receive the reply, and return the reply code.
    496     * <p>
    497     *
    498     * @param date          The date after which to check for new groups. Date format is YYMMDD
    499     * @param time          The time after which to check for new groups. Time format is HHMMSS using a 24-hour clock.
    500     * @param GMT           True if the time is in GMT, false if local server time.
    501     * @param distributions Comma-separated distribution list to check for new groups. Set to null if no distributions.
    502     * @return The reply code received from the server.
    503     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    504     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    505     *                                       independently as itself.
    506     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    507     */
    508    public int newgroups(final String date, final String time, final boolean GMT, final String distributions) throws IOException {
    509        final StringBuilder buffer = new StringBuilder();
    510
    511        buffer.append(date);
    512        buffer.append(' ');
    513        buffer.append(time);
    514
    515        if (GMT) {
    516            buffer.append(' ');
    517            buffer.append("GMT");
    518        }
    519
    520        if (distributions != null) {
    521            buffer.append(" <");
    522            buffer.append(distributions);
    523            buffer.append('>');
    524        }
    525
    526        return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
    527    }
    528
    529    /**
    530     * A convenience method to send the "NEWNEWS" command to the server, receive the reply, and return the reply code.
    531     * <p>
    532     *
    533     * @param newsgroups    A comma-separated list of newsgroups to check for new news.
    534     * @param date          The date after which to check for new news. Date format is YYMMDD
    535     * @param time          The time after which to check for new news. Time format is HHMMSS using a 24-hour clock.
    536     * @param GMT           True if the time is in GMT, false if local server time.
    537     * @param distributions Comma-separated distribution list to check for new news. Set to null if no distributions.
    538     * @return The reply code received from the server.
    539     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    540     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    541     *                                       independently as itself.
    542     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    543     */
    544    public int newnews(final String newsgroups, final String date, final String time, final boolean GMT, final String distributions) throws IOException {
    545        final StringBuilder buffer = new StringBuilder();
    546
    547        buffer.append(newsgroups);
    548        buffer.append(' ');
    549        buffer.append(date);
    550        buffer.append(' ');
    551        buffer.append(time);
    552
    553        if (GMT) {
    554            buffer.append(' ');
    555            buffer.append("GMT");
    556        }
    557
    558        if (distributions != null) {
    559            buffer.append(" <");
    560            buffer.append(distributions);
    561            buffer.append('>');
    562        }
    563
    564        return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
    565    }
    566
    567    /**
    568     * A convenience method to send the NNTP NEXT command to the server, receive the reply, and return the reply code.
    569     * <p>
    570     *
    571     * @return The reply code received from the server.
    572     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    573     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    574     *                                       independently as itself.
    575     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    576     */
    577    public int next() throws IOException {
    578        return sendCommand(NNTPCommand.NEXT);
    579    }
    580
    581    /**
    582     * A convenience method to send the NNTP POST command to the server, receive the reply, and return the reply code.
    583     * <p>
    584     *
    585     * @return The reply code received from the server.
    586     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    587     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    588     *                                       independently as itself.
    589     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    590     */
    591    public int post() throws IOException {
    592        return sendCommand(NNTPCommand.POST);
    593    }
    594
    595    /**
    596     * A convenience method to send the NNTP QUIT command to the server, receive the reply, and return the reply code.
    597     * <p>
    598     *
    599     * @return The reply code received from the server.
    600     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    601     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    602     *                                       independently as itself.
    603     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    604     */
    605    public int quit() throws IOException {
    606        return sendCommand(NNTPCommand.QUIT);
    607    }
    608
    609    /**
    610     * 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
    611     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
    612     * <p>
    613     *
    614     * @param command The NNTPCommand constant corresponding to the NNTP command to send.
    615     * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
    616     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    617     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    618     *                                       independently as itself.
    619     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    620     */
    621    public int sendCommand(final int command) throws IOException {
    622        return sendCommand(command, null);
    623    }
    624
    625    /**
    626     * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    627     * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
    628     * <p>
    629     *
    630     * @param command The NNTPCommand constant corresponding to the NNTP command to send.
    631     * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
    632     * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
    633     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    634     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    635     *                                       independently as itself.
    636     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    637     */
    638    public int sendCommand(final int command, final String args) throws IOException {
    639        return sendCommand(NNTPCommand.getCommand(command), args);
    640    }
    641
    642    /**
    643     * 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
    644     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
    645     * <p>
    646     *
    647     * @param command The text representation of the NNTP command to send.
    648     * @return The integer value of the NNTP reply code returned by the server in response to the command. in response to the command.
    649     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    650     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    651     *                                       independently as itself.
    652     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    653     */
    654    public int sendCommand(final String command) throws IOException {
    655        return sendCommand(command, null);
    656    }
    657
    658    /**
    659     * Sends an NNTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    660     * actual reply text can be accessed by calling {@link #getReplyString getReplyString }.
    661     * <p>
    662     *
    663     * @param command The text representation of the NNTP command to send.
    664     * @param args    The arguments to the NNTP command. If this parameter is set to null, then the command is sent with no argument.
    665     * @return The integer value of the NNTP reply code returned by the server in response to the command.
    666     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    667     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    668     *                                       independently as itself.
    669     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    670     */
    671    public int sendCommand(final String command, final String args) throws IOException {
    672        final StringBuilder __commandBuffer = new StringBuilder();
    673        __commandBuffer.append(command);
    674
    675        if (args != null) {
    676            __commandBuffer.append(' ');
    677            __commandBuffer.append(args);
    678        }
    679        __commandBuffer.append(SocketClient.NETASCII_EOL);
    680
    681        final String message;
    682        _writer_.write(message = __commandBuffer.toString());
    683        _writer_.flush();
    684
    685        fireCommandSent(command, message);
    686
    687        return getReply();
    688    }
    689
    690    /**
    691     * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
    692     * <p>
    693     *
    694     * @return The reply code received from the server.
    695     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    696     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    697     *                                       independently as itself.
    698     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    699     */
    700    public int stat() throws IOException {
    701        return sendCommand(NNTPCommand.STAT);
    702    }
    703
    704    // DEPRECATED METHODS - for API compatibility only - DO NOT USE
    705
    706    /**
    707     * @param a article number
    708     * @return number
    709     * @throws IOException on error
    710     * @deprecated - for API compatibility only - DO NOT USE
    711     */
    712    @Deprecated
    713    public int stat(final int a) throws IOException {
    714        return stat((long) a);
    715    }
    716
    717    /**
    718     * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
    719     * <p>
    720     *
    721     * @param articleNumber The number of the article to request from the currently selected newsgroup.
    722     * @return The reply code received from the server.
    723     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    724     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    725     *                                       independently as itself.
    726     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    727     */
    728    public int stat(final long articleNumber) throws IOException {
    729        return sendCommand(NNTPCommand.STAT, Long.toString(articleNumber));
    730    }
    731
    732    /**
    733     * A convenience method to send the NNTP STAT command to the server, receive the initial reply, and return the reply code.
    734     * <p>
    735     *
    736     * @param messageId The message identifier of the requested article, including the encapsulating &lt; and &gt; characters.
    737     * @return The reply code received from the server.
    738     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    739     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    740     *                                       independently as itself.
    741     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    742     */
    743    public int stat(final String messageId) throws IOException {
    744        return sendCommand(NNTPCommand.STAT, messageId);
    745    }
    746
    747    /**
    748     * A convenience method to send the NNTP XHDR command to the server, receive the reply, and return the reply code.
    749     * <p>
    750     *
    751     * @param header           a String naming a header line (e.g., "subject"). See RFC-1036 for a list of valid header lines.
    752     * @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
    753     *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
    754     *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
    755     * @return The reply code received from the server.
    756     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    757     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    758     *                                       independently as itself.
    759     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    760     */
    761    public int xhdr(final String header, final String selectedArticles) throws IOException {
    762        final StringBuilder command = new StringBuilder(header);
    763        command.append(" ");
    764        command.append(selectedArticles);
    765        return sendCommand(NNTPCommand.XHDR, command.toString());
    766    }
    767
    768    /**
    769     * A convenience method to send the NNTP XOVER command to the server, receive the reply, and return the reply code.
    770     * <p>
    771     *
    772     * @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
    773     *                         the form "XXXX-YYYY", where XXXX and YYYY are valid article numbers in the current group. It also may be of the form "XXX-",
    774     *                         meaning "return XXX and all following articles" In this revision, the last format is not possible (yet).
    775     * @return The reply code received from the server.
    776     * @throws NNTPConnectionClosedException If the NNTP server prematurely closes the connection as a result of the client being idle or some other reason
    777     *                                       causing the server to send NNTP reply code 400. This exception may be caught either as an IOException or
    778     *                                       independently as itself.
    779     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    780     */
    781    public int xover(final String selectedArticles) throws IOException {
    782        return sendCommand(NNTPCommand.XOVER, selectedArticles);
    783    }
    784}