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